[njs] Array.prototype.find() method.

Igor Sysoev igor at sysoev.ru
Tue Apr 4 10:24:34 UTC 2017


details:   http://hg.nginx.org/njs/rev/52d53653ac52
branches:  
changeset: 330:52d53653ac52
user:      Andrey Zelenkov <zelenkov at nginx.com>
date:      Tue Apr 04 06:10:10 2017 +0300
description:
Array.prototype.find() method.

Also introduced njs_array_iterator_sparse_apply() function.

diffstat:

 njs/njs_array.c          |  106 +++++++++++++++++++++++++++++++++++++++++++++++
 njs/test/njs_unit_test.c |   43 +++++++++++++++++++
 2 files changed, 149 insertions(+), 0 deletions(-)

diffs (197 lines):

diff -r c46da90ca064 -r 52d53653ac52 njs/njs_array.c
--- a/njs/njs_array.c	Sun Apr 02 12:36:05 2017 +0300
+++ b/njs/njs_array.c	Tue Apr 04 06:10:10 2017 +0300
@@ -58,6 +58,12 @@ typedef struct {
 
 typedef struct {
     njs_array_iter_t        iter;
+    njs_value_t             value;
+} njs_array_find_t;
+
+
+typedef struct {
+    njs_array_iter_t        iter;
     njs_array_t             *array;
 } njs_array_map_t;
 
@@ -92,6 +98,8 @@ static njs_ret_t njs_array_prototype_eve
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
 static njs_ret_t njs_array_prototype_filter_continuation(njs_vm_t *vm,
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_array_prototype_find_continuation(njs_vm_t *vm,
+    njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
 static njs_ret_t njs_array_prototype_map_continuation(njs_vm_t *vm,
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
 static nxt_noinline uint32_t njs_array_prototype_map_index(njs_array_t *array,
@@ -102,6 +110,8 @@ static nxt_noinline uint32_t njs_array_i
     njs_array_iter_t *iter);
 static nxt_noinline njs_ret_t njs_array_iterator_apply(njs_vm_t *vm,
     njs_array_iter_t *iter, njs_value_t *args, nxt_uint_t nargs);
+static nxt_noinline njs_ret_t njs_array_prototype_find_apply(njs_vm_t *vm,
+    njs_array_iter_t *iter, njs_value_t *args, nxt_uint_t nargs);
 static njs_ret_t njs_array_prototype_reduce_continuation(njs_vm_t *vm,
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
 static njs_ret_t njs_array_prototype_reduce_right_continuation(njs_vm_t *vm,
@@ -1465,6 +1475,94 @@ njs_array_prototype_filter_continuation(
 
 
 static njs_ret_t
+njs_array_prototype_find(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    nxt_int_t         ret;
+    njs_array_find_t  *find;
+
+    ret = njs_array_iterator_args(vm, args, nargs);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return ret;
+    }
+
+    find = njs_vm_continuation(vm);
+    find->iter.u.cont.function = njs_array_prototype_find_continuation;
+    find->iter.retval.data.truth = 0;
+
+    return njs_array_prototype_find_continuation(vm, args, nargs, unused);
+}
+
+
+static njs_ret_t
+njs_array_prototype_find_continuation(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused)
+{
+    njs_array_t        *array;
+    njs_array_iter_t   *iter;
+    njs_array_find_t   *find;
+    const njs_value_t  *retval;
+
+    retval = &njs_value_void;
+
+    find = njs_vm_continuation(vm);
+    iter = &find->iter;
+
+    if (!njs_is_true(&iter->retval)) {
+        array = args[0].data.u.array;
+        iter->index++;
+
+        if (iter->index < iter->length && iter->index < array->length) {
+            /* GC: find->value */
+            find->value = array->start[iter->index];
+
+            return njs_array_prototype_find_apply(vm, iter, args, nargs);
+        }
+
+    } else {
+        if (njs_is_valid(&find->value)) {
+            retval = &find->value;
+        }
+    }
+
+    vm->retval = *retval;
+
+    return NXT_OK;
+}
+
+
+static nxt_noinline njs_ret_t
+njs_array_prototype_find_apply(njs_vm_t *vm, njs_array_iter_t *iter,
+    njs_value_t *args, nxt_uint_t nargs)
+{
+    uint32_t           n;
+    const njs_value_t  *value;
+    njs_value_t        arguments[4];
+
+    /* GC: array elt, array */
+
+    value = (nargs > 2) ? &args[2] : &njs_value_void;
+    arguments[0] = *value;
+
+    n = iter->index;
+    value = &args[0].data.u.array->start[n];
+
+    if (!njs_is_valid(value)) {
+        value = &njs_value_void;
+    }
+
+    arguments[1] = *value;
+
+    njs_number_set(&arguments[2], n);
+
+    arguments[3] = args[0];
+
+    return njs_function_apply(vm, args[1].data.u.function, arguments, 4,
+                              (njs_index_t) &iter->retval);
+}
+
+
+static njs_ret_t
 njs_array_prototype_map(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
@@ -2041,6 +2139,14 @@ static const njs_object_prop_t  njs_arra
                      njs_continuation_size(njs_array_filter_t), 0),
     },
 
+    /* ES6. */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("find"),
+        .value = njs_native_function(njs_array_prototype_find,
+                     njs_continuation_size(njs_array_find_t), 0),
+    },
+
     {
         .type = NJS_METHOD,
         .name = njs_string("map"),
diff -r c46da90ca064 -r 52d53653ac52 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Sun Apr 02 12:36:05 2017 +0300
+++ b/njs/test/njs_unit_test.c	Tue Apr 04 06:10:10 2017 +0300
@@ -2884,6 +2884,49 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("1,11,21,31,41,51,61") },
 
     { nxt_string("var a = [];"
+                 "a.find(function(v, i, a) { return v > 1 })"),
+      nxt_string("undefined") },
+
+    { nxt_string("var a = [,NaN,0,-1];"
+                 "a.find(function(v, i, a) { return v > 1 })"),
+      nxt_string("undefined") },
+
+    { nxt_string("var a = [,NaN,0,-1,2];"
+                 "a.find(function(v, i, a) { return v > 1 })"),
+      nxt_string("2") },
+
+    { nxt_string("var a = [1,2,3,-1,5];"
+                 "a.find(function(v, i, a) { return v > 1 })"),
+      nxt_string("2") },
+
+    { nxt_string("var a = [,1,,-1,5];"
+                 "a.find(function(v, i, a) { return v > 1 })"),
+      nxt_string("5") },
+
+    { nxt_string("var a = [,1,,-1,5,6];"
+                 "a.find(function(v, i, a) { return v > 1 })"),
+      nxt_string("5") },
+
+    { nxt_string("[].find(function(v) { return (v === undefined) })"),
+      nxt_string("undefined") },
+
+    { nxt_string("var a = [,3];"
+                 "a.find(function(v) { return (v === 3 || v === undefined) })"),
+      nxt_string("undefined") },
+
+    { nxt_string("var a = [1,,3];"
+                 "a.find(function(v) { return (v === 3 || v === undefined) })"),
+      nxt_string("undefined") },
+
+    { nxt_string("var a = [1,2,3,4,5,6];"
+                 "a.find(function(v, i, a) { a.shift(); return v == 3 })"),
+      nxt_string("3") },
+
+    { nxt_string("var a = [1,2,3,4,5,6];"
+                 "a.find(function(v, i, a) { a.shift(); return v == 4 })"),
+      nxt_string("undefined") },
+
+    { nxt_string("var a = [];"
                  "a.map(function(v, i, a) { return v + 1 })"),
       nxt_string("") },
 


More information about the nginx-devel mailing list