details: https://hg.nginx.org/njs/rev/1af8f40573f2 branches: changeset: 682:1af8f40573f2 user: Valentin Bartenev <vb...@nginx.com> date: Mon Dec 03 19:20:58 2018 +0300 description: Object.values() method.
diffstat: njs/njs_json.c | 4 +- njs/njs_object.c | 169 +++++++++++++++++++++++++++++++++++++++------- njs/njs_object.h | 9 ++- njs/test/njs_unit_test.c | 38 ++++++++++ 4 files changed, 191 insertions(+), 29 deletions(-) diffs (347 lines): diff -r 4a543ed58c95 -r 1af8f40573f2 njs/njs_json.c --- a/njs/njs_json.c Sat Dec 01 22:32:33 2018 +0300 +++ b/njs/njs_json.c Mon Dec 03 19:20:58 2018 +0300 @@ -1095,7 +1095,7 @@ njs_json_push_parse_state(njs_vm_t *vm, } else { state->type = NJS_JSON_OBJECT_START; state->prop_value = NULL; - state->keys = njs_object_keys_array(vm, value); + state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS); if (state->keys == NULL) { return NULL; } @@ -1659,7 +1659,7 @@ njs_json_push_stringify_state(njs_vm_t * state->keys = njs_extern_keys_array(vm, value->external.proto); } else { - state->keys = njs_object_keys_array(vm, value); + state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS); } if (state->keys == NULL) { diff -r 4a543ed58c95 -r 1af8f40573f2 njs/njs_object.c --- a/njs/njs_object.c Sat Dec 01 22:32:33 2018 +0300 +++ b/njs/njs_object.c Mon Dec 03 19:20:58 2018 +0300 @@ -872,7 +872,7 @@ njs_object_keys(njs_vm_t *vm, njs_value_ return NXT_ERROR; } - keys = njs_object_keys_array(vm, value); + keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS); if (keys == NULL) { return NXT_ERROR; } @@ -885,20 +885,52 @@ njs_object_keys(njs_vm_t *vm, njs_value_ } +static njs_ret_t +njs_object_values(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) + { + njs_array_t *array; + const njs_value_t *value; + + value = njs_arg(args, nargs, 1); + + if (njs_is_null_or_void(value)) { + njs_type_error(vm, "cannot convert %s argument to object", + njs_type_string(value->type)); + + return NXT_ERROR; + } + + array = njs_object_enumerate(vm, value, NJS_ENUM_VALUES); + if (array == NULL) { + return NXT_ERROR; + } + + vm->retval.data.u.array = array; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; + + return NXT_OK; +} + + njs_array_t * -njs_object_keys_array(njs_vm_t *vm, const njs_value_t *value) +njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, + njs_object_enum_t kind) { - uint32_t i, n, length, keys_length, properties; - njs_value_t *string; - njs_array_t *keys, *array; + u_char *dst; + uint32_t i, length, size, items_length, properties; + njs_value_t *string, *item; + njs_array_t *items, *array; nxt_lvlhsh_t *hash; + const u_char *src, *end; njs_object_prop_t *prop; njs_string_prop_t string_prop; nxt_lvlhsh_each_t lhe; array = NULL; length = 0; - keys_length = 0; + items_length = 0; switch (value->type) { case NJS_ARRAY: @@ -907,7 +939,7 @@ njs_object_keys_array(njs_vm_t *vm, cons for (i = 0; i < length; i++) { if (njs_is_valid(&array->start[i])) { - keys_length++; + items_length++; } } @@ -923,7 +955,7 @@ njs_object_keys_array(njs_vm_t *vm, cons } length = njs_string_prop(&string_prop, string); - keys_length += length; + items_length += length; break; default: @@ -950,46 +982,123 @@ njs_object_keys_array(njs_vm_t *vm, cons } } - keys_length += properties; + items_length += properties; } - keys = njs_array_alloc(vm, keys_length, NJS_ARRAY_SPARE); - if (nxt_slow_path(keys == NULL)) { + items = njs_array_alloc(vm, items_length, NJS_ARRAY_SPARE); + if (nxt_slow_path(items == NULL)) { return NULL; } - n = 0; + item = items->start; if (array != NULL) { - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - njs_uint32_to_string(&keys->start[n++], i); + + switch (kind) { + case NJS_ENUM_KEYS: + for (i = 0; i < length; i++) { + if (njs_is_valid(&array->start[i])) { + njs_uint32_to_string(item++, i); + } } + + break; + + case NJS_ENUM_VALUES: + for (i = 0; i < length; i++) { + if (njs_is_valid(&array->start[i])) { + /* GC: retain. */ + *item++ = array->start[i]; + } + } + + break; } - } else { - for (i = 0; i < length; i++) { - njs_uint32_to_string(&keys->start[n++], i); + } else if (length != 0) { + + switch (kind) { + case NJS_ENUM_KEYS: + for (i = 0; i < length; i++) { + njs_uint32_to_string(item++, i); + } + + break; + + case NJS_ENUM_VALUES: + if (string_prop.size == (size_t) length) { + /* Byte or ASCII string. */ + + for (i = 0; i < length; i++) { + dst = njs_string_short_start(item); + dst[0] = string_prop.start[i]; + + njs_string_short_set(item, 1, 1); + + item++; + } + + } else { + /* UTF-8 string. */ + + src = string_prop.start; + end = src + string_prop.size; + + do { + dst = njs_string_short_start(item); + dst = nxt_utf8_copy(dst, &src, end); + size = dst - njs_string_short_start(value); + + njs_string_short_set(item, size, 1); + + item++; + + } while (src != end); + } + + break; } } if (nxt_fast_path(properties != 0)) { nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - for ( ;; ) { - prop = nxt_lvlhsh_each(hash, &lhe); - - if (prop == NULL) { - break; + switch (kind) { + + case NJS_ENUM_KEYS: + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + if (prop->type != NJS_WHITEOUT && prop->enumerable) { + njs_string_copy(item++, &prop->name); + } } - if (prop->type != NJS_WHITEOUT && prop->enumerable) { - njs_string_copy(&keys->start[n++], &prop->name); + break; + + case NJS_ENUM_VALUES: + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + if (prop->type != NJS_WHITEOUT && prop->enumerable) { + /* GC: retain. */ + *item++ = prop->value; + } } + + break; } } - return keys; + return items; } @@ -1853,6 +1962,14 @@ static const njs_object_prop_t njs_obje NJS_SKIP_ARG, NJS_OBJECT_ARG), }, + /* ES8: Object.values(). */ + { + .type = NJS_METHOD, + .name = njs_string("values"), + .value = njs_native_function(njs_object_values, 0, + NJS_SKIP_ARG, NJS_OBJECT_ARG), + }, + /* Object.defineProperty(). */ { .type = NJS_METHOD, diff -r 4a543ed58c95 -r 1af8f40573f2 njs/njs_object.h --- a/njs/njs_object.h Sat Dec 01 22:32:33 2018 +0300 +++ b/njs/njs_object.h Mon Dec 03 19:20:58 2018 +0300 @@ -17,6 +17,12 @@ typedef enum { } njs_object_property_type_t; +typedef enum { + NJS_ENUM_KEYS = 0, + NJS_ENUM_VALUES, +} njs_object_enum_t; + + /* * Attributes are generally used as Boolean values. * The UNSET value is used internally only by njs_define_property(). @@ -79,7 +85,8 @@ njs_object_t *njs_object_alloc(njs_vm_t njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value); njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value, nxt_uint_t type); -njs_array_t *njs_object_keys_array(njs_vm_t *vm, const njs_value_t *value); +njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, + njs_object_enum_t kind); njs_ret_t njs_value_property(njs_vm_t *vm, njs_value_t *value, const njs_value_t *property, njs_value_t *retval); njs_object_prop_t *njs_object_property(njs_vm_t *vm, const njs_object_t *obj, diff -r 4a543ed58c95 -r 1af8f40573f2 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sat Dec 01 22:32:33 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Dec 03 19:20:58 2018 +0300 @@ -7421,6 +7421,30 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.keys(true)"), nxt_string("") }, + { nxt_string("var o = {a:3, b:2, c:1}; Object.values(o)"), + nxt_string("3,2,1") }, + + { nxt_string("Object.values('s')"), + nxt_string("s") }, + + { nxt_string("Object.values('абв abc')"), + nxt_string("а,б,в, ,a,b,c") }, + + { nxt_string("var s = new String('abc'); s.three = 3; Object.values(s)"), + nxt_string("a,b,c,3") }, + + { nxt_string("var a = [,,5,,4,,,3,2]; a.one = 1; Object.values(a)"), + nxt_string("5,4,3,2,1") }, + + { nxt_string("Object.values([{}, null, false, NaN, function() {}])"), + nxt_string("[object Object],,false,NaN,[object Function]") }, + + { nxt_string("Object.values(1)"), + nxt_string("") }, + + { nxt_string("Object.values()"), + nxt_string("TypeError: cannot convert undefined argument to object") }, + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a"), nxt_string("undefined") }, @@ -7444,6 +7468,20 @@ static njs_unit_test_t njs_test[] = "Object.keys(o)"), nxt_string("a,c,b") }, + { nxt_string("var o = {a:1, c:2}; Object.defineProperty(o, 'b', {});" + "Object.values(o)"), + nxt_string("1,2") }, + + { nxt_string("var o = {a:1, c:2};" + "Object.defineProperty(o, 'b', {enumerable:false, value:3});" + "Object.values(o)"), + nxt_string("1,2") }, + + { nxt_string("var o = {a:1, c:3};" + "Object.defineProperty(o, 'b', {enumerable:true, value:2});" + "Object.values(o)"), + nxt_string("1,3,2") }, + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a = 1"), nxt_string("TypeError: Cannot assign to read-only property 'a' of object") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel