[njs] Improved functions for converting value to number.
Alexander Borisov
alexander.borisov at nginx.com
Mon Oct 21 13:44:07 UTC 2019
details: https://hg.nginx.org/njs/rev/55f49a991f4f
branches:
changeset: 1191:55f49a991f4f
user: Alexander Borisov <alexander.borisov at nginx.com>
date: Mon Oct 21 16:43:45 2019 +0300
description:
Improved functions for converting value to number.
Added functions:
njs_value_to_number(), njs_value_to_integer(), njs_value_to_length()
njs_value_to_int32(), njs_value_to_uint32(), njs_value_to_uint16().
Removed functions:
njs_primitive_value_to_number(), njs_primitive_value_to_integer(),
njs_primitive_value_to_int32(), njs_primitive_value_to_uint32(),
njs_primitive_value_to_length().
Changed return type for njs_number_to_integer() function from int32_t
to int64_t.
diffstat:
src/njs_array.c | 101 +++++++++++++++++++++++-----------------------
src/njs_builtin.c | 9 +++-
src/njs_number.c | 34 +++++++++++----
src/njs_number.h | 55 ++++++-------------------
src/njs_object.c | 11 +----
src/njs_string.c | 37 ++++++++++++-----
src/njs_value.h | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++--
src/njs_vmcode.c | 16 +++---
8 files changed, 238 insertions(+), 140 deletions(-)
diffs (691 lines):
diff -r f01ee3828b15 -r 55f49a991f4f src/njs_array.c
--- a/src/njs_array.c Mon Oct 21 15:10:34 2019 +0300
+++ b/src/njs_array.c Mon Oct 21 16:43:45 2019 +0300
@@ -332,14 +332,13 @@ static njs_int_t
njs_array_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval,
njs_value_t *retval)
{
- double num;
- int64_t size;
- uint32_t length;
- njs_int_t ret;
- njs_value_t *val;
- njs_array_t *array;
- njs_object_t *proto;
- njs_value_t val_length;
+ double num;
+ int64_t size;
+ uint32_t length;
+ njs_int_t ret;
+ njs_value_t *val;
+ njs_array_t *array;
+ njs_object_t *proto;
proto = njs_object(value);
@@ -369,18 +368,16 @@ njs_array_length(njs_vm_t *vm, njs_value
}
if (njs_slow_path(!njs_is_number(setval))) {
- ret = njs_value_to_numeric(vm, &val_length, setval);
- if (ret != NJS_OK) {
+ ret = njs_value_to_number(vm, setval, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- num = njs_number(&val_length);
-
} else {
num = njs_number(setval);
}
- length = njs_number_to_uint32(num);
+ length = njs_number_to_length(num);
if ((double) length != num) {
njs_range_error(vm, "Invalid array length");
@@ -422,28 +419,22 @@ static njs_int_t
njs_array_prototype_slice(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- int64_t start, end, length;
- njs_int_t ret;
- njs_value_t prop_length;
-
- static const njs_value_t string_length = njs_string("length");
-
- ret = njs_value_property(vm, &args[0], njs_value_arg(&string_length),
- &prop_length);
+ int64_t start, end, length;
+ uint32_t object_length;
+ njs_int_t ret;
+
+ ret = njs_object_length(vm, njs_arg(args, nargs, 0), &object_length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
- if (njs_slow_path(!njs_is_primitive(&prop_length))) {
- ret = njs_value_to_numeric(vm, &prop_length, &prop_length);
- if (ret != NJS_OK) {
- return ret;
- }
+ length = object_length;
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
- start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
- length = njs_primitive_value_to_length(&prop_length);
-
if (start < 0) {
start += length;
@@ -458,7 +449,10 @@ njs_array_prototype_slice(njs_vm_t *vm,
} else {
if (njs_is_defined(njs_arg(args, nargs, 2))) {
- end = njs_primitive_value_to_integer(njs_argument(args, 2));
+ ret = njs_value_to_integer(vm, njs_argument(args, 2), &end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
} else {
end = length;
@@ -1724,7 +1718,10 @@ njs_array_prototype_index_of(njs_vm_t *v
return ret;
}
- from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
if (length == 0 || from >= (int64_t) length) {
goto not_found;
@@ -1781,7 +1778,10 @@ njs_array_prototype_last_index_of(njs_vm
}
if (nargs > 2) {
- from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
} else {
from = length - 1;
@@ -1868,7 +1868,10 @@ njs_array_prototype_includes(njs_vm_t *v
goto not_found;
}
- from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
if (from < 0) {
from += length;
@@ -1906,14 +1909,13 @@ static njs_int_t
njs_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- njs_int_t ret;
- njs_int_t i, start, end, length;
+ int64_t start, end;
+ uint32_t length;
+ njs_int_t i, ret;
njs_array_t *array;
- njs_value_t name, prop_length, *this, *value;
+ njs_value_t name, *this, *value;
njs_object_t *object;
- static const njs_value_t string_length = njs_string("length");
-
this = njs_arg(args, nargs, 0);
if (njs_is_primitive(this)) {
@@ -1940,30 +1942,27 @@ njs_array_prototype_fill(njs_vm_t *vm, n
length = array->length;
} else {
- ret = njs_value_property(vm, this, njs_value_arg(&string_length),
- &prop_length);
+ ret = njs_object_length(vm, this, &length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
-
- if (njs_slow_path(!njs_is_primitive(&prop_length))) {
- ret = njs_value_to_numeric(vm, &prop_length, &prop_length);
- if (ret != NJS_OK) {
- return ret;
- }
- }
-
- length = njs_primitive_value_to_length(&prop_length);
}
- start = njs_primitive_value_to_integer(njs_arg(args, nargs, 2));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
start = (start < 0) ? njs_max(length + start, 0) : njs_min(start, length);
if (njs_is_undefined(njs_arg(args, nargs, 3))) {
end = length;
} else {
- end = njs_primitive_value_to_integer(njs_arg(args, nargs, 3));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 3), &end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
}
end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length);
diff -r f01ee3828b15 -r 55f49a991f4f src/njs_builtin.c
--- a/src/njs_builtin.c Mon Oct 21 15:10:34 2019 +0300
+++ b/src/njs_builtin.c Mon Oct 21 16:43:45 2019 +0300
@@ -992,14 +992,19 @@ static njs_int_t
njs_dump_value(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
+ uint32_t n;
+ njs_int_t ret;
njs_str_t str;
- njs_uint_t n;
njs_value_t *value, *indent;
value = njs_arg(args, nargs, 1);
indent = njs_arg(args, nargs, 2);
- n = njs_primitive_value_to_integer(indent);
+ ret = njs_value_to_uint32(vm, indent, &n);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
n = njs_min(n, 5);
if (njs_vm_value_dump(vm, &str, value, 1, n) != NJS_OK) {
diff -r f01ee3828b15 -r 55f49a991f4f src/njs_number.c
--- a/src/njs_number.c Mon Oct 21 15:10:34 2019 +0300
+++ b/src/njs_number.c Mon Oct 21 16:43:45 2019 +0300
@@ -547,10 +547,10 @@ njs_number_prototype_to_fixed(njs_vm_t *
njs_uint_t nargs, njs_index_t unused)
{
u_char *p;
- int32_t frac;
+ int64_t frac;
double number;
size_t length, size;
- njs_int_t point, prefix, postfix;
+ njs_int_t ret, point, prefix, postfix;
njs_value_t *value;
u_char buf[128], buf2[128];
@@ -569,7 +569,11 @@ njs_number_prototype_to_fixed(njs_vm_t *
}
}
- frac = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &frac);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
if (njs_slow_path(frac < 0 || frac > 100)) {
njs_range_error(vm, "digits argument must be between 0 and 100");
return NJS_ERROR;
@@ -582,7 +586,7 @@ njs_number_prototype_to_fixed(njs_vm_t *
}
point = 0;
- length = njs_fixed_dtoa(number, frac, (char *) buf, &point);
+ length = njs_fixed_dtoa(number, (njs_int_t) frac, (char *) buf, &point);
prefix = 0;
postfix = 0;
@@ -643,7 +647,8 @@ njs_number_prototype_to_precision(njs_vm
{
double number;
size_t size;
- int32_t precision;
+ int64_t precision;
+ njs_int_t ret;
njs_value_t *value;
u_char buf[128];
@@ -672,13 +677,17 @@ njs_number_prototype_to_precision(njs_vm
return njs_number_to_string(vm, &vm->retval, value);
}
- precision = njs_primitive_value_to_integer(njs_argument(args, 1));
+ ret = njs_value_to_integer(vm, njs_argument(args, 1), &precision);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
if (njs_slow_path(precision < 1 || precision > 100)) {
njs_range_error(vm, "precision argument must be between 1 and 100");
return NJS_ERROR;
}
- size = njs_dtoa_precision(number, (char *) buf, precision);
+ size = njs_dtoa_precision(number, (char *) buf, (size_t) precision);
return njs_string_new(vm, &vm->retval, buf, size, size);
}
@@ -690,7 +699,8 @@ njs_number_prototype_to_exponential(njs_
{
double number;
size_t size;
- int32_t frac;
+ int64_t frac;
+ njs_int_t ret;
njs_value_t *value;
u_char buf[128];
@@ -714,7 +724,11 @@ njs_number_prototype_to_exponential(njs_
}
if (njs_is_defined(njs_arg(args, nargs, 1))) {
- frac = njs_primitive_value_to_integer(njs_argument(args, 1));
+ ret = njs_value_to_integer(vm, njs_argument(args, 1), &frac);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
if (njs_slow_path(frac < 0 || frac > 100)) {
njs_range_error(vm, "digits argument must be between 0 and 100");
return NJS_ERROR;
@@ -724,7 +738,7 @@ njs_number_prototype_to_exponential(njs_
frac = -1;
}
- size = njs_dtoa_exponential(number, (char *) buf, frac);
+ size = njs_dtoa_exponential(number, (char *) buf, (njs_int_t) frac);
return njs_string_new(vm, &vm->retval, buf, size, size);
}
diff -r f01ee3828b15 -r 55f49a991f4f src/njs_number.h
--- a/src/njs_number.h Mon Oct 21 15:10:34 2019 +0300
+++ b/src/njs_number.h Mon Oct 21 16:43:45 2019 +0300
@@ -61,10 +61,21 @@ njs_number_to_int64(double num)
}
-njs_inline int32_t
+njs_inline int64_t
njs_number_to_integer(double num)
{
- return (int32_t) njs_number_to_int64(num);
+ if (njs_slow_path(isinf(num))) {
+ if (num < 0) {
+ return INT64_MIN;
+ }
+
+ return INT64_MAX;
+
+ } else if (njs_slow_path(isnan(num))) {
+ return 0;
+ }
+
+ return njs_number_to_int64(num);
}
@@ -131,46 +142,6 @@ njs_char_to_hex(u_char c)
return c;
}
-
-njs_inline double
-njs_primitive_value_to_number(const njs_value_t *value)
-{
- if (njs_fast_path(njs_is_numeric(value))) {
- return njs_number(value);
- }
-
- return njs_string_to_number(value, 0);
-}
-
-
-njs_inline int32_t
-njs_primitive_value_to_integer(const njs_value_t *value)
-{
- return njs_number_to_integer(njs_primitive_value_to_number(value));
-}
-
-
-njs_inline int32_t
-njs_primitive_value_to_int32(const njs_value_t *value)
-{
- return njs_number_to_int32(njs_primitive_value_to_number(value));
-}
-
-
-njs_inline uint32_t
-njs_primitive_value_to_uint32(const njs_value_t *value)
-{
- return njs_number_to_uint32(njs_primitive_value_to_number(value));
-}
-
-
-njs_inline uint32_t
-njs_primitive_value_to_length(const njs_value_t *value)
-{
- return njs_number_to_length(njs_primitive_value_to_number(value));
-}
-
-
njs_inline void
njs_uint32_to_string(njs_value_t *value, uint32_t u32)
{
diff -r f01ee3828b15 -r 55f49a991f4f src/njs_object.c
--- a/src/njs_object.c Mon Oct 21 15:10:34 2019 +0300
+++ b/src/njs_object.c Mon Oct 21 16:43:45 2019 +0300
@@ -2316,14 +2316,5 @@ njs_object_length(njs_vm_t *vm, njs_valu
return ret;
}
- if (!njs_is_primitive(&value_length)) {
- ret = njs_value_to_numeric(vm, &value_length, &value_length);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
- }
-
- *length = njs_primitive_value_to_length(&value_length);
-
- return NJS_OK;
+ return njs_value_to_length(vm, &value_length, length);
}
diff -r f01ee3828b15 -r 55f49a991f4f src/njs_string.c
--- a/src/njs_string.c Mon Oct 21 15:10:34 2019 +0300
+++ b/src/njs_string.c Mon Oct 21 16:43:45 2019 +0300
@@ -1235,16 +1235,22 @@ static njs_int_t
njs_string_prototype_char_at(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- ssize_t start, length;
+ size_t length;
+ int64_t start;
+ njs_int_t ret;
njs_slice_prop_t slice;
njs_string_prop_t string;
slice.string_length = njs_string_prop(&string, &args[0]);
- start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
length = 1;
- if (start < 0 || start >= (ssize_t) slice.string_length) {
+ if (start < 0 || start >= (int64_t) slice.string_length) {
start = 0;
length = 0;
}
@@ -1395,21 +1401,26 @@ njs_string_prototype_char_code_at(njs_vm
njs_uint_t nargs, njs_index_t unused)
{
double num;
- ssize_t index, length;
+ size_t length;
+ int64_t index;
uint32_t code;
+ njs_int_t ret;
const u_char *start, *end;
njs_string_prop_t string;
length = njs_string_prop(&string, &args[0]);
- index = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
-
- if (njs_slow_path(index < 0 || index >= length)) {
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &index);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_slow_path(index < 0 || index >= (int64_t) length)) {
num = NAN;
goto done;
}
- if ((uint32_t) length == string.size) {
+ if (length == string.size) {
/* Byte or ASCII string. */
code = string.start[index];
@@ -2501,11 +2512,15 @@ njs_string_prototype_repeat(njs_vm_t *vm
njs_index_t unused)
{
u_char *p, *start;
- int32_t n, max;
- uint32_t size, length;
+ int64_t n, max;
+ uint64_t size, length;
+ njs_int_t ret;
njs_string_prop_t string;
- n = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &n);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
(void) njs_string_prop(&string, &args[0]);
diff -r f01ee3828b15 -r 55f49a991f4f src/njs_value.h
--- a/src/njs_value.h Mon Oct 21 15:10:34 2019 +0300
+++ b/src/njs_value.h Mon Oct 21 16:43:45 2019 +0300
@@ -845,10 +845,12 @@ njs_int_t njs_value_property_delete(njs_
njs_value_t *key, njs_value_t *removed);
+#include "njs_number.h"
+
+
njs_inline njs_int_t
-njs_value_to_numeric(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
+njs_value_to_number(njs_vm_t *vm, njs_value_t *value, double *dst)
{
- double num;
njs_int_t ret;
njs_value_t primitive;
@@ -862,14 +864,30 @@ njs_value_to_numeric(njs_vm_t *vm, njs_v
}
if (njs_slow_path(!njs_is_numeric(value))) {
- num = NAN;
+ *dst = NAN;
if (njs_is_string(value)) {
- num = njs_string_to_number(value, 0);
+ *dst = njs_string_to_number(value, 0);
}
- } else {
- num = njs_number(value);
+ return NJS_OK;
+ }
+
+ *dst = njs_number(value);
+
+ return NJS_OK;
+}
+
+
+njs_inline njs_int_t
+njs_value_to_numeric(njs_vm_t *vm, njs_value_t *value, njs_value_t *dst)
+{
+ double num;
+ njs_int_t ret;
+
+ ret = njs_value_to_number(vm, value, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
njs_set_number(dst, num);
@@ -879,6 +897,91 @@ njs_value_to_numeric(njs_vm_t *vm, njs_v
njs_inline njs_int_t
+njs_value_to_integer(njs_vm_t *vm, njs_value_t *value, int64_t *dst)
+{
+ double num;
+ njs_int_t ret;
+
+ ret = njs_value_to_number(vm, value, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *dst = njs_number_to_integer(num);
+
+ return NJS_OK;
+}
+
+
+njs_inline njs_int_t
+njs_value_to_length(njs_vm_t *vm, njs_value_t *value, uint32_t *dst)
+{
+ double num;
+ njs_int_t ret;
+
+ ret = njs_value_to_number(vm, value, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *dst = njs_number_to_length(num);
+
+ return NJS_OK;
+}
+
+
+njs_inline njs_int_t
+njs_value_to_int32(njs_vm_t *vm, njs_value_t *value, int32_t *dst)
+{
+ double num;
+ njs_int_t ret;
+
+ ret = njs_value_to_number(vm, value, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *dst = njs_number_to_int32(num);
+
+ return NJS_OK;
+}
+
+
+njs_inline njs_int_t
+njs_value_to_uint32(njs_vm_t *vm, njs_value_t *value, uint32_t *dst)
+{
+ double num;
+ njs_int_t ret;
+
+ ret = njs_value_to_number(vm, value, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *dst = njs_number_to_uint32(num);
+
+ return NJS_OK;
+}
+
+
+njs_inline njs_int_t
+njs_value_to_uint16(njs_vm_t *vm, njs_value_t *value, uint16_t *dst)
+{
+ double num;
+ njs_int_t ret;
+
+ ret = njs_value_to_number(vm, value, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *dst = njs_number_to_uint16(num);
+
+ return NJS_OK;
+}
+
+
+njs_inline njs_int_t
njs_value_to_string(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
{
njs_int_t ret;
diff -r f01ee3828b15 -r 55f49a991f4f src/njs_vmcode.c
--- a/src/njs_vmcode.c Mon Oct 21 15:10:34 2019 +0300
+++ b/src/njs_vmcode.c Mon Oct 21 16:43:45 2019 +0300
@@ -183,7 +183,7 @@ next:
case NJS_VMCODE_DECREMENT:
case NJS_VMCODE_POST_DECREMENT:
if (njs_slow_path(!njs_is_numeric(value2))) {
- ret = njs_value_to_numeric(vm, &numeric1, value2);
+ ret = njs_value_to_numeric(vm, value2, &numeric1);
if (njs_slow_path(ret != NJS_OK)) {
goto error;
}
@@ -350,8 +350,8 @@ next:
case NJS_VMCODE_RIGHT_SHIFT:
case NJS_VMCODE_UNSIGNED_RIGHT_SHIFT:
if (njs_slow_path(!njs_is_numeric(value1))) {
- ret = njs_value_to_numeric(vm, &numeric1, value1);
- if (ret != NJS_OK) {
+ ret = njs_value_to_numeric(vm, value1, &numeric1);
+ if (njs_slow_path(ret != NJS_OK)) {
goto error;
}
@@ -359,8 +359,8 @@ next:
}
if (njs_slow_path(!njs_is_numeric(value2))) {
- ret = njs_value_to_numeric(vm, &numeric2, value2);
- if (ret != NJS_OK) {
+ ret = njs_value_to_numeric(vm, value2, &numeric2);
+ if (njs_slow_path(ret != NJS_OK)) {
goto error;
}
@@ -517,8 +517,8 @@ next:
case NJS_VMCODE_UNARY_NEGATION:
case NJS_VMCODE_BITWISE_NOT:
if (njs_slow_path(!njs_is_numeric(value1))) {
- ret = njs_value_to_numeric(vm, &numeric1, value1);
- if (ret != NJS_OK) {
+ ret = njs_value_to_numeric(vm, value1, &numeric1);
+ if (njs_slow_path(ret != NJS_OK)) {
goto error;
}
@@ -538,7 +538,7 @@ next:
break;
case NJS_VMCODE_BITWISE_NOT:
- njs_set_int32(retval, ~njs_number_to_integer(num));
+ njs_set_int32(retval, ~njs_number_to_uint32(num));
}
pc += sizeof(njs_vmcode_2addr_t);
More information about the nginx-devel
mailing list