]> git.kaiwu.me - njs.git/commitdiff
Refactored Array.prototype.join() using njs_chb_t API.
authorDmitry Volyntsev <xeioex@nginx.com>
Wed, 11 Dec 2019 12:58:05 +0000 (15:58 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Wed, 11 Dec 2019 12:58:05 +0000 (15:58 +0300)
src/njs_array.c
src/njs_number.c
src/njs_number.h
src/njs_string.c
src/njs_value.c
src/njs_value.h
src/njs_value_conversion.h
src/test/njs_unit_test.c

index 00e34a397412854efec19ff78da05260bbbf5560..cd2bad3bbdaef77fc64bddd8182fefe51a66a531 100644 (file)
@@ -1123,12 +1123,13 @@ njs_array_prototype_join(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     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, njs_value_t *args, njs_uint_t nargs,
 
     array = njs_array(&args[0]);
 
-    max = 0;
-    values = NULL;
-
-    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];
+    njs_chb_init(&chain, vm->mem_pool);
 
-            if (!njs_is_string(value)
-                && njs_is_valid(value)
-                && !njs_is_null_or_undefined(value))
-            {
-                values[n++] = *value;
-
-                if (n >= max) {
-                    break;
-                }
-            }
-        }
-    }
-
-    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;
-                    }
+                ret = njs_value_to_chain(vm, &chain, value);
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return ret;
                 }
-            }
-
-            (void) njs_string_prop(&string, value);
 
-            size += string.size;
-            length += string.length;
+            } else {
+                (void) njs_string_prop(&string, value);
+                length += string.length;
 
-            if (string.length == 0 && string.size != 0) {
-                mask = 0;
+                njs_chb_append(&chain, string.start, string.size);
             }
         }
-    }
-
-    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;
+        length += separator.length;
+        njs_chb_append(&chain, separator.start, separator.size);
     }
 
-    n = 0;
+    njs_chb_drop(&chain, separator.size);
 
-    for (i = 0; i < array->length; i++) {
-        value = &array->start[i];
+    size = njs_chb_size(&chain);
 
-        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;
-        }
+    if (length != 0) {
+        length -= separator.length;
     }
 
-    for (i = 0; i < max; i++) {
-        njs_release(vm, &values[i]);
+    p = njs_string_alloc(vm, &vm->retval, size, length);
+    if (njs_slow_path(p == NULL)) {
+        return NJS_ERROR;
     }
 
-    njs_mp_free(vm->mem_pool, values);
+    njs_chb_join_to(&chain, p);
+    njs_chb_destroy(&chain);
 
     return NJS_OK;
 }
index c737023aa62478577b5d20d411d952cc46200e39..82fbcfdd2813f79d1e21fea67857c354ea847fc4 100644 (file)
@@ -236,6 +236,40 @@ njs_number_to_string(njs_vm_t *vm, njs_value_t *string,
 }
 
 
+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)
index ea0f021a4e54f6f7a65c6265e3953068e7d240e0..22d9140e26f2706498fbd7e67fcf220bb0753e30 100644 (file)
@@ -17,6 +17,8 @@ int64_t njs_number_radix_parse(const u_char **start, const u_char *end,
     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,
index 8b4818a6bb3cda502528adefe7cbcb170dbae233..19eeda3332d6a4748b61eecab03083e05f524199 100644 (file)
@@ -4254,48 +4254,6 @@ njs_string_replacement_copy(njs_string_replace_part_t *string,
 }
 
 
-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)
 {
index 2e3a65bf63e87fcc8caf9fe0f566bfa920825a19..9f3d273680ca2a67abfcf89eeedf1190531d3243 100644 (file)
@@ -1224,6 +1224,95 @@ njs_value_property_delete(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
 }
 
 
+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)
 {
index d36418f7f4c4ecd01e955f4038a5f980c76f685a..0af5dae9c27dbec35f5348711d9e4554c307d838 100644 (file)
@@ -946,6 +946,8 @@ const char *njs_type_string(njs_value_type_t type);
 
 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);
index 5cc5cfcbc5eb21e7ff18553a425a9b067a0c7676..7c706b151b21bffd18777ee32a93eff7940529ac 100644 (file)
@@ -199,4 +199,29 @@ njs_value_to_string(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
 }
 
 
+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_ */
index 488e17cc39d432aa9042235199f596a5170946c7..7482ed6e58ae3c48cf42e8827d59b813e21f3333 100644 (file)
@@ -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") },