[njs] Refactored Array.prototype.join() using njs_chb_t API.

Dmitry Volyntsev xeioex at nginx.com
Wed Dec 11 12:58:28 UTC 2019


details:   https://hg.nginx.org/njs/rev/5bf71dfc052f
branches:  
changeset: 1283:5bf71dfc052f
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Wed Dec 11 15:58:05 2019 +0300
description:
Refactored Array.prototype.join() using njs_chb_t API.

diffstat:

 src/njs_array.c            |  130 ++++++++++----------------------------------
 src/njs_number.c           |   34 +++++++++++
 src/njs_number.h           |    2 +
 src/njs_string.c           |   42 --------------
 src/njs_value.c            |   89 ++++++++++++++++++++++++++++++
 src/njs_value.h            |    2 +
 src/njs_value_conversion.h |   25 ++++++++
 src/test/njs_unit_test.c   |    6 ++
 8 files changed, 188 insertions(+), 142 deletions(-)

diffs (432 lines):

diff -r 5ba9145d9b0c -r 5bf71dfc052f src/njs_array.c
--- a/src/njs_array.c	Wed Dec 11 15:30:26 2019 +0300
+++ b/src/njs_array.c	Wed Dec 11 15:58:05 2019 +0300
@@ -1123,12 +1123,13 @@ njs_array_prototype_join(njs_vm_t *vm, n
     njs_index_t unused)
 {
     u_char             *p;
-    uint32_t           max;
-    size_t             size, length, mask;
+    size_t             size;
+    ssize_t            length;
     njs_int_t          ret;
-    njs_uint_t         i, n;
+    njs_chb_t          chain;
+    njs_uint_t         i;
     njs_array_t        *array;
-    njs_value_t        *value, *values;
+    njs_value_t        *value;
     njs_string_prop_t  separator, string;
 
     ret = njs_value_to_object(vm, &args[0]);
@@ -1159,117 +1160,46 @@ njs_array_prototype_join(njs_vm_t *vm, n
 
     array = njs_array(&args[0]);
 
-    max = 0;
-    values = NULL;
+    njs_chb_init(&chain, vm->mem_pool);
+
+    length = 0;
 
     for (i = 0; i < array->length; i++) {
         value = &array->start[i];
-
-        if (!njs_is_string(value)
-            && njs_is_valid(value)
-            && !njs_is_null_or_undefined(value))
-        {
-            max++;
-        }
-    }
-
-    if (max != 0) {
-        values = njs_mp_align(vm->mem_pool, sizeof(njs_value_t),
-                              sizeof(njs_value_t) * max);
-        if (njs_slow_path(values == NULL)) {
-            njs_memory_error(vm);
-            return NJS_ERROR;
-        }
-
-        n = 0;
-
-        for (i = 0; i < array->length; i++) {
-            value = &array->start[i];
-
-            if (!njs_is_string(value)
-                && njs_is_valid(value)
-                && !njs_is_null_or_undefined(value))
-            {
-                values[n++] = *value;
-
-                if (n >= max) {
-                    break;
+        if (njs_is_valid(value) && !njs_is_null_or_undefined(value)) {
+            if (!njs_is_string(value)) {
+                ret = njs_value_to_chain(vm, &chain, value);
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return ret;
                 }
+
+            } else {
+                (void) njs_string_prop(&string, value);
+                length += string.length;
+
+                njs_chb_append(&chain, string.start, string.size);
             }
         }
+
+        length += separator.length;
+        njs_chb_append(&chain, separator.start, separator.size);
     }
 
-    size = 0;
-    length = 0;
-    n = 0;
-    mask = -1;
-
-    array = njs_array(&args[0]);
-
-    for (i = 0; i < array->length; i++) {
-        value = &array->start[i];
-
-        if (njs_is_valid(value) && !njs_is_null_or_undefined(value)) {
-
-            if (!njs_is_string(value)) {
-                value = &values[n++];
-
-                if (!njs_is_string(value)) {
-                    ret = njs_value_to_string(vm, value, value);
-                    if (ret != NJS_OK) {
-                        return ret;
-                    }
-                }
-            }
-
-            (void) njs_string_prop(&string, value);
-
-            size += string.size;
-            length += string.length;
-
-            if (string.length == 0 && string.size != 0) {
-                mask = 0;
-            }
-        }
+    njs_chb_drop(&chain, separator.size);
+
+    size = njs_chb_size(&chain);
+
+    if (length != 0) {
+        length -= separator.length;
     }
 
-    size += separator.size * (array->length - 1);
-    length += separator.length * (array->length - 1);
-
-    length &= mask;
-
     p = njs_string_alloc(vm, &vm->retval, size, length);
     if (njs_slow_path(p == NULL)) {
         return NJS_ERROR;
     }
 
-    n = 0;
-
-    for (i = 0; i < array->length; i++) {
-        value = &array->start[i];
-
-        if (njs_is_valid(value) && !njs_is_null_or_undefined(value)) {
-            if (!njs_is_string(value)) {
-                value = &values[n++];
-            }
-
-            (void) njs_string_prop(&string, value);
-
-            p = memcpy(p, string.start, string.size);
-            p += string.size;
-        }
-
-        if (i < array->length - 1) {
-            p = memcpy(p, separator.start, separator.size);
-            p += separator.size;
-        }
-    }
-
-    for (i = 0; i < max; i++) {
-        njs_release(vm, &values[i]);
-    }
-
-    njs_mp_free(vm->mem_pool, values);
+    njs_chb_join_to(&chain, p);
+    njs_chb_destroy(&chain);
 
     return NJS_OK;
 }
diff -r 5ba9145d9b0c -r 5bf71dfc052f src/njs_number.c
--- a/src/njs_number.c	Wed Dec 11 15:30:26 2019 +0300
+++ b/src/njs_number.c	Wed Dec 11 15:58:05 2019 +0300
@@ -236,6 +236,40 @@ njs_number_to_string(njs_vm_t *vm, njs_v
 }
 
 
+void
+njs_number_to_chain(njs_vm_t *vm, njs_chb_t *chain, const njs_value_t *number)
+{
+    double             num;
+    size_t             size;
+    u_char   *p;
+
+    num = njs_number(number);
+
+    if (isnan(num)) {
+        njs_chb_append_literal(chain, "NaN");
+
+    } else if (isinf(num)) {
+
+        if (num < 0) {
+            njs_chb_append_literal(chain, "-Infinity");
+
+        } else {
+            njs_chb_append_literal(chain, "Infinity");
+        }
+
+    } else {
+        p = njs_chb_reserve(chain, 64);
+        if (njs_slow_path(p == NULL)) {
+            return;
+        }
+
+        size = njs_dtoa(num, (char *) p);
+
+        njs_chb_written(chain, size);
+    }
+}
+
+
 static njs_int_t
 njs_number_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
diff -r 5ba9145d9b0c -r 5bf71dfc052f src/njs_number.h
--- a/src/njs_number.h	Wed Dec 11 15:30:26 2019 +0300
+++ b/src/njs_number.h	Wed Dec 11 15:58:05 2019 +0300
@@ -17,6 +17,8 @@ int64_t njs_number_radix_parse(const u_c
     uint8_t radix);
 njs_int_t njs_number_to_string(njs_vm_t *vm, njs_value_t *string,
     const njs_value_t *number);
+void njs_number_to_chain(njs_vm_t *vm, njs_chb_t *chain,
+    const njs_value_t *number);
 njs_int_t njs_number_global_is_nan(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused);
 njs_int_t njs_number_global_is_finite(njs_vm_t *vm, njs_value_t *args,
diff -r 5ba9145d9b0c -r 5bf71dfc052f src/njs_string.c
--- a/src/njs_string.c	Wed Dec 11 15:30:26 2019 +0300
+++ b/src/njs_string.c	Wed Dec 11 15:58:05 2019 +0300
@@ -4254,48 +4254,6 @@ njs_string_replacement_copy(njs_string_r
 }
 
 
-njs_int_t
-njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst,
-    const njs_value_t *src)
-{
-    const njs_value_t  *value;
-
-    switch (src->type) {
-
-    case NJS_NULL:
-        value = &njs_string_null;
-        break;
-
-    case NJS_UNDEFINED:
-        value = &njs_string_undefined;
-        break;
-
-    case NJS_BOOLEAN:
-        value = njs_is_true(src) ? &njs_string_true : &njs_string_false;
-        break;
-
-    case NJS_NUMBER:
-        return njs_number_to_string(vm, dst, src);
-
-    case NJS_SYMBOL:
-        njs_symbol_conversion_failed(vm, 1);
-        return NJS_ERROR;
-
-    case NJS_STRING:
-        /* GC: njs_retain(src); */
-        value = src;
-        break;
-
-    default:
-        return NJS_ERROR;
-    }
-
-    *dst = *value;
-
-    return NJS_OK;
-}
-
-
 double
 njs_string_to_number(const njs_value_t *value, njs_bool_t parse_float)
 {
diff -r 5ba9145d9b0c -r 5bf71dfc052f src/njs_value.c
--- a/src/njs_value.c	Wed Dec 11 15:30:26 2019 +0300
+++ b/src/njs_value.c	Wed Dec 11 15:58:05 2019 +0300
@@ -1225,6 +1225,95 @@ njs_value_property_delete(njs_vm_t *vm, 
 
 
 njs_int_t
+njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst,
+    const njs_value_t *src)
+{
+    const njs_value_t  *value;
+
+    switch (src->type) {
+
+    case NJS_NULL:
+        value = &njs_string_null;
+        break;
+
+    case NJS_UNDEFINED:
+        value = &njs_string_undefined;
+        break;
+
+    case NJS_BOOLEAN:
+        value = njs_is_true(src) ? &njs_string_true : &njs_string_false;
+        break;
+
+    case NJS_NUMBER:
+        return njs_number_to_string(vm, dst, src);
+
+    case NJS_SYMBOL:
+        njs_symbol_conversion_failed(vm, 1);
+        return NJS_ERROR;
+
+    case NJS_STRING:
+        /* GC: njs_retain(src); */
+        value = src;
+        break;
+
+    default:
+        return NJS_ERROR;
+    }
+
+    *dst = *value;
+
+    return NJS_OK;
+}
+
+
+njs_int_t
+njs_primitive_value_to_chain(njs_vm_t *vm, njs_chb_t *chain,
+    const njs_value_t *src)
+{
+    njs_str_t  string;
+
+    switch (src->type) {
+
+    case NJS_NULL:
+        njs_chb_append_literal(chain, "null");
+        break;
+
+    case NJS_UNDEFINED:
+        njs_chb_append_literal(chain, "undefined");
+        break;
+
+    case NJS_BOOLEAN:
+        if (njs_is_true(src)) {
+            njs_chb_append_literal(chain, "true");
+
+        } else {
+            njs_chb_append_literal(chain, "false");
+        }
+
+        break;
+
+    case NJS_NUMBER:
+        njs_number_to_chain(vm, chain, src);
+        break;
+
+    case NJS_SYMBOL:
+        njs_symbol_conversion_failed(vm, 1);
+        return NJS_ERROR;
+
+    case NJS_STRING:
+        njs_string_get(src, &string);
+        njs_chb_append_str(chain, &string);
+        break;
+
+    default:
+        return NJS_ERROR;
+    }
+
+    return NJS_OK;
+}
+
+
+njs_int_t
 njs_value_to_object(njs_vm_t *vm, njs_value_t *value)
 {
     njs_object_t  *object;
diff -r 5ba9145d9b0c -r 5bf71dfc052f src/njs_value.h
--- a/src/njs_value.h	Wed Dec 11 15:30:26 2019 +0300
+++ b/src/njs_value.h	Wed Dec 11 15:58:05 2019 +0300
@@ -946,6 +946,8 @@ const char *njs_type_string(njs_value_ty
 
 njs_int_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst,
     const njs_value_t *src);
+njs_int_t njs_primitive_value_to_chain(njs_vm_t *vm, njs_chb_t *chain,
+    const njs_value_t *src);
 double njs_string_to_number(const njs_value_t *value, njs_bool_t parse_float);
 
 njs_bool_t njs_string_eq(const njs_value_t *v1, const njs_value_t *v2);
diff -r 5ba9145d9b0c -r 5bf71dfc052f src/njs_value_conversion.h
--- a/src/njs_value_conversion.h	Wed Dec 11 15:30:26 2019 +0300
+++ b/src/njs_value_conversion.h	Wed Dec 11 15:58:05 2019 +0300
@@ -199,4 +199,29 @@ njs_value_to_string(njs_vm_t *vm, njs_va
 }
 
 
+njs_inline njs_int_t
+njs_value_to_chain(njs_vm_t *vm, njs_chb_t *chain, njs_value_t *value)
+{
+    njs_int_t    ret;
+    njs_value_t  primitive;
+
+    if (njs_slow_path(!njs_is_primitive(value))) {
+        if (njs_slow_path(value->type == NJS_OBJECT_SYMBOL)) {
+            /* should fail */
+            value = njs_object_value(value);
+
+        } else {
+            ret = njs_value_to_primitive(vm, &primitive, value, 1);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return ret;
+            }
+
+            value = &primitive;
+        }
+    }
+
+    return njs_primitive_value_to_chain(vm, chain, value);
+}
+
+
 #endif /* _NJS_VALUE_CONVERSION_H_INCLUDED_ */
diff -r 5ba9145d9b0c -r 5bf71dfc052f src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Wed Dec 11 15:30:26 2019 +0300
+++ b/src/test/njs_unit_test.c	Wed Dec 11 15:58:05 2019 +0300
@@ -3876,6 +3876,12 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var a = [1,2,3]; a.join(':')"),
       njs_str("1:2:3") },
 
+    { njs_str("var a = ['#', '@']; var out= a.join('α'.repeat(33)); [out, out.length]"),
+      njs_str("#ααααααααααααααααααααααααααααααααα@,35") },
+
+    { njs_str("var a = ['β', 'γ']; var out= a.join('α'); [out, out.length]"),
+      njs_str("βαγ,3") },
+
     { njs_str("var a = []; a[5] = 5; a.join()"),
       njs_str(",,,,,5") },
 


More information about the nginx-devel mailing list