From: Dmitry Volyntsev Date: Wed, 11 Dec 2019 12:58:05 +0000 (+0300) Subject: Refactored Array.prototype.join() using njs_chb_t API. X-Git-Tag: 0.3.8~26 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=b2f0f5d0530b587e3884a908ab0069d8ee662163;p=njs.git Refactored Array.prototype.join() using njs_chb_t API. --- diff --git a/src/njs_array.c b/src/njs_array.c index 00e34a39..cd2bad3b 100644 --- a/src/njs_array.c +++ b/src/njs_array.c @@ -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; } diff --git a/src/njs_number.c b/src/njs_number.c index c737023a..82fbcfdd 100644 --- a/src/njs_number.c +++ b/src/njs_number.c @@ -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) diff --git a/src/njs_number.h b/src/njs_number.h index ea0f021a..22d9140e 100644 --- a/src/njs_number.h +++ b/src/njs_number.h @@ -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, diff --git a/src/njs_string.c b/src/njs_string.c index 8b4818a6..19eeda33 100644 --- a/src/njs_string.c +++ b/src/njs_string.c @@ -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) { diff --git a/src/njs_value.c b/src/njs_value.c index 2e3a65bf..9f3d2736 100644 --- a/src/njs_value.c +++ b/src/njs_value.c @@ -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) { diff --git a/src/njs_value.h b/src/njs_value.h index d36418f7..0af5dae9 100644 --- a/src/njs_value.h +++ b/src/njs_value.h @@ -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); diff --git a/src/njs_value_conversion.h b/src/njs_value_conversion.h index 5cc5cfcb..7c706b15 100644 --- a/src/njs_value_conversion.h +++ b/src/njs_value_conversion.h @@ -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_ */ diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 488e17cc..7482ed6e 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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") },