-
Notifications
You must be signed in to change notification settings - Fork 468
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check if Napi::Value is integer number? #265
Comments
How important/useful is it? We don't necessarily need everything which is in V8 to be exposed through Napi. As an example, if other JavaScript engines don't provide it we don't want to have to be building our own implementation. However, on the other hand if its important enough we could consider it. |
I am experimenting with node-rfc migration to Napi and my use-case is type check of JavaScript integer value, before passing to native C/C++ library: https://github.com/SAP/node-rfc/blob/master/src/rfcio.cc#L219 The native lib cannot check if supplied value is really integer and if the float for example is sent instead, the decimals are silently ignored. Catching such errors makes apps' troubleshooting easier and from that perspective the feature looks important to me. If not done in addon, the check is required on application level, or another addon wrapper, both less convenient. I could imagine such type check helpers interesting in general because addons are bridges between weak typed JavaScript and strong typed C/C++ and good validation helps. In my case also the performance of IsString and IsNumber is very important because methods can be invoked on bigger datasets. Are they fast enough for bigger datasets processing? |
@digitalinfinity does ChakraCore provide similar check methods? Just looking for additional data. |
Also @digitalinfinity if ChakraCore does provide the check does it use some information maintained on the Value to do the check efficiently? |
ChakraCore doesn't today AFAIK- JSRT has generally aligned with the ECMAScript spec. I imagine we could implement the API but we've generally avoided adding APIs that are easily implementable by the embedder. We could implement this in N-API without implementing a new ChakraCore API but the ChakraCore API would be more efficient since we do support natively tagged integers/numbers. cc @MSLaguana |
Found related issue #57 and in my case the These two missing methods are the only reason for keeping the napi branch of my project still experimental, beside the nan based master. |
@bsrdjan thanks for the update, I added a comment on #57 and will see if we can get an update from @anisha-rohra in this weeks meeting. |
you could do if (info[0].IsNumber()) {
Napi::Value num = info[0].ToNumber();
double numInt = (double)num.Int64Value();
double numDbl = num.DoubleValue();
if (abs(numInt - numDbl) < EPSILON) {
// maybe was an integer, hard to find the EPSILON,
// because it depends on the number range
}
} But I think this is not how we should check that. What is the difference between 1.0 and 1? Would it be a problem if internal representation of the number is 1.0, that you will not use |
@DaAitch, 1.0 and 1 might work well, I didn't test. The bigger issue is when 1.234 for example is sent, decimals are silently ignored by underlying c++ binary lib and 1.234 float becomes a regular integer 1. The gap was discovered when the frontend business app was sending 1.234, via nodejs/napi middleware to ABAP backend. App put 1.234 float into wrong JSON structure field, in which ABAP backend expects an integer. As a result, instead of 1.234 float, the int 1 was stored in another field, without complains. The gap was the reason for adding the check in addon, using handy Nan method: https://github.com/SAP/node-rfc/blob/master/src/rfcio.cc#L219 Seeing the check existing in v8, I expected having in N-API, would really help here: https://github.com/SAP/node-rfc/blob/napi/src/rfcio.cc#L240 The above logic like could work in user interactive apps I think. My concerns are batch processing and higher data volumes, when hundreds thousands of rows, each with hundreds of fields are processed. In that case, one simple IsInt() would be worth of gold :) |
@bsrdjan I understand. If you're brave enough this may help you (didn't test snippet) :) bool IsInt(Napi::Env& env, Napi::Value& num) {
return env.Global()
.Get("Number").As<Napi::Object>()
.Get("IsInteger").As<Napi::Function>()
.Call({num}).ToBoolean().Value();
} so you can also get rid of Number.isInteger(3); // true
Number.isInteger(3.4); // false
Number.isInteger('hi'); // false
Number.isInteger(Symbol(4)) // false |
no IsInteger() function: isIntegerFunction = env.Global().Get("Number").As<Napi::Object>().Get("IsInteger").As<Napi::Function>()
isIntegerFunction.IsUndefined() -> true |
Still refining the implementation, but this PR shows how to do IsData and IsRegex and Is32int type checks: mhdawson/node-sqlite3#3 |
+1 Migrating some code now which uses |
Edit: the problem I was having was another thing. I have a situation that JS code is passing Why |
Hi @asfernandes, |
Btw, there’s the related threads: nodejs/node#26323 and, to lesser degree, nodejs/node-addon-examples#91. tl;dr: If you want to check whether a number is an integer, you can use |
@NickNaso it seems my problem was another but my logs wasn't working properly. My usage of |
@bsrdjan We had the same requirements as you. This is what we ended up using to get an argument as an integer, rejecting NaN, +/-Infinity and floats: It's not engine dependent, but it is tricky, you have to check for undefined behavior before casting the double to an integer. I'm not sure even this is right and would appreciate feedback. Perhaps it makes sense to have this in N-API to get more eyes on it. #include <math.h>
static int arg_int(napi_env env, napi_value value, int* integer) {
double temp = 0;
if (
// We get the value as a double so we can check for NaN, Infinity and float:
// https://github.com/nodejs/node/issues/26323
napi_get_value_double(env, value, &temp) != napi_ok ||
// Reject NaN:
isnan(temp) ||
// Reject Infinity and avoid undefined behavior when casting double to int:
// https://groups.google.com/forum/#!topic/comp.lang.c/rhPzd4bgKJk
temp < INT_MIN ||
temp > INT_MAX ||
// Reject float by casting double to int:
(double) ((int) temp) != temp
) {
napi_throw_error(env, NULL, "argument must be an integer");
return 0;
}
*integer = (int) temp;
return 1;
} If need be, one could replace the ints above with |
I solved it using this as a reference. But instead of bool isNapiValueInt(Napi::Env& env, Napi::Value& num) {
return env.Global()
.Get("Number")
.ToObject()
.Get("isInteger")
.As<Napi::Function>()
.Call({num})
.ToBoolean()
.Value();
} |
Thanks @master-atul . I am actually fine with @jorangreef approach, using it slightly modified for my requirements. I am closing this issue, waiting for the related #57 resolution. |
How to check if Napi::Value is integer number?
v8::Value offers
IsNumber
,IsInt32
andIsUint32
methods and Napi::Value has onlyIsNumber
. Would it make sense to add integer checks to Napi::Value?The text was updated successfully, but these errors were encountered: