[njs] Object.keys() method.

Dmitry Volyntsev xeioex at nginx.com
Wed Jun 7 11:16:53 UTC 2017


details:   http://hg.nginx.org/njs/rev/fb703c8f4292
branches:  
changeset: 352:fb703c8f4292
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Wed Jun 07 14:12:23 2017 +0300
description:
Object.keys() method.

diffstat:

 njs/njs_object.c         |  101 +++++++++++++++++++++++++++++++++++++++++++++++
 njs/njs_vm.h             |   13 ++++++
 njs/test/njs_unit_test.c |   19 ++++++++
 3 files changed, 133 insertions(+), 0 deletions(-)

diffs (178 lines):

diff -r 02a59fe82c7a -r fb703c8f4292 njs/njs_object.c
--- a/njs/njs_object.c	Mon Jun 05 14:59:28 2017 +0300
+++ b/njs/njs_object.c	Wed Jun 07 14:12:23 2017 +0300
@@ -19,7 +19,9 @@
 #include <njs_string.h>
 #include <njs_object.h>
 #include <njs_object_hash.h>
+#include <njs_array.h>
 #include <njs_function.h>
+#include <stdio.h>
 #include <string.h>
 
 
@@ -318,6 +320,97 @@ njs_object_create(njs_vm_t *vm, njs_valu
 }
 
 
+static njs_ret_t
+njs_object_keys(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    size_t             size;
+    uint32_t           i, n, keys_length, array_length;
+    njs_value_t        *value;
+    njs_array_t        *keys, *array;
+    nxt_lvlhsh_t       *hash;
+    njs_object_prop_t  *prop;
+    nxt_lvlhsh_each_t  lhe;
+
+    if (nargs < 2 || !njs_is_object(&args[1])) {
+        vm->exception = &njs_exception_type_error;
+        return NXT_ERROR;
+    }
+
+    keys_length = 0;
+    array_length = 0;
+
+    if (njs_is_array(&args[1])) {
+        array = args[1].data.u.array;
+        array_length = array->length;
+
+        for (i = 0; i < array_length; i++) {
+            if (njs_is_valid(&array->start[i])) {
+                keys_length++;
+            }
+        }
+    }
+
+    memset(&lhe, 0, sizeof(nxt_lvlhsh_each_t));
+    lhe.proto = &njs_object_hash_proto;
+
+    hash = &args[1].data.u.object->hash;
+
+    for ( ;; ) {
+        prop = nxt_lvlhsh_each(hash, &lhe);
+
+        if (prop == NULL) {
+            break;
+        }
+
+        if (prop->enumerable) {
+            keys_length++;
+        }
+    }
+
+    keys = njs_array_alloc(vm, keys_length, NJS_ARRAY_SPARE);
+    if (nxt_slow_path(keys == NULL)) {
+        return NXT_ERROR;
+    }
+
+    n = 0;
+
+    for (i = 0; i < array_length; i++) {
+        if (njs_is_valid(&array->start[i])) {
+            value = &keys->start[n++];
+            /*
+             * The maximum array index is 4294967294, so
+             * it can be stored as a short string inside value.
+             */
+            size = snprintf((char *) njs_string_short_start(value),
+                            NJS_STRING_SHORT, "%u", i);
+            njs_string_short_set(value, size, size);
+        }
+    }
+
+    memset(&lhe, 0, sizeof(nxt_lvlhsh_each_t));
+    lhe.proto = &njs_object_hash_proto;
+
+    for ( ;; ) {
+        prop = nxt_lvlhsh_each(hash, &lhe);
+
+        if (prop == NULL) {
+            break;
+        }
+
+        if (prop->enumerable) {
+            njs_string_copy(&keys->start[n++], &prop->name);
+        }
+    }
+
+    vm->retval.data.u.array = keys;
+    vm->retval.type = NJS_ARRAY;
+    vm->retval.data.truth = 1;
+
+    return NXT_OK;
+}
+
+
 /*
  * The __proto__ property of booleans, numbers and strings primitives,
  * of objects created by Boolean(), Number(), and String() constructors,
@@ -456,6 +549,14 @@ static const njs_object_prop_t  njs_obje
         .name = njs_string("create"),
         .value = njs_native_function(njs_object_create, 0, 0),
     },
+
+    /* Object.keys(). */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("keys"),
+        .value = njs_native_function(njs_object_keys, 0,
+                                     NJS_SKIP_ARG, NJS_OBJECT_ARG),
+    },
 };
 
 
diff -r 02a59fe82c7a -r fb703c8f4292 njs/njs_vm.h
--- a/njs/njs_vm.h	Mon Jun 05 14:59:28 2017 +0300
+++ b/njs/njs_vm.h	Wed Jun 07 14:12:23 2017 +0300
@@ -408,6 +408,19 @@ typedef njs_ret_t (*njs_vmcode_operation
 #define njs_string_truth(value, size)
 
 
+#define njs_string_short_start(value)                                         \
+    (value)->short_string.start
+
+
+#define njs_string_short_set(value, _size, _length)                           \
+    do {                                                                      \
+        (value)->type = NJS_STRING;                                           \
+        njs_string_truth(value, _size);                                       \
+        (value)->short_string.size = _size;                                   \
+        (value)->short_string.length = _length;                               \
+    } while (0)
+
+
 #define njs_is_primitive(value)                                               \
     ((value)->type <= NJS_STRING)
 
diff -r 02a59fe82c7a -r fb703c8f4292 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Mon Jun 05 14:59:28 2017 +0300
+++ b/njs/test/njs_unit_test.c	Wed Jun 07 14:12:23 2017 +0300
@@ -5843,6 +5843,25 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("var o = Object.create(null); '__proto__' in o"),
       nxt_string("false") },
 
+    { nxt_string("var o = {a:1, b:2, c:3};"
+                 "Object.keys(o)"),
+      nxt_string("a,b,c") },
+
+    { nxt_string("var a = []; a.one = 7; Object.keys(a)"),
+      nxt_string("one") },
+
+    { nxt_string("var a = [,,]; a.one = 7; Object.keys(a)"),
+      nxt_string("one") },
+
+    { nxt_string("var a = [,6,,3]; a.one = 7; Object.keys(a)"),
+      nxt_string("1,3,one") },
+
+    { nxt_string("Object.keys('a')"),
+      nxt_string("TypeError") },
+
+    { nxt_string("Object.keys(1)"),
+      nxt_string("TypeError") },
+
     { nxt_string("var d = new Date(''); d +' '+ d.getTime()"),
       nxt_string("Invalid Date NaN") },
 


More information about the nginx-devel mailing list