]> git.kaiwu.me - njs.git/commitdiff
Array.filter() function.
authorIgor Sysoev <igor@sysoev.ru>
Tue, 9 Aug 2016 11:10:29 +0000 (14:10 +0300)
committerIgor Sysoev <igor@sysoev.ru>
Tue, 9 Aug 2016 11:10:29 +0000 (14:10 +0300)
njs/njs_array.c
njs/test/njs_unit_test.c

index 35c0150015e2d19666f0016826acb1456bce784b..e1e1b9eb5190cbf3d6c9c5a3c0c098daccb7efea 100644 (file)
@@ -43,6 +43,8 @@ typedef struct {
      */
     njs_value_t             retval;
 
+    njs_value_t             value;
+    njs_array_t             *array;
     uint32_t                next_index;
     uint32_t                length;
 } njs_array_iter_t;
@@ -61,6 +63,8 @@ static nxt_noinline njs_ret_t njs_array_prototype_some_cont(njs_vm_t *vm,
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
 static nxt_noinline njs_ret_t njs_array_prototype_every_cont(njs_vm_t *vm,
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_array_prototype_filter_cont(njs_vm_t *vm,
+    njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
 static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm,
     njs_value_t *args, nxt_uint_t nargs);
 static nxt_noinline uint32_t njs_array_iterator_next(njs_array_t *array,
@@ -100,6 +104,25 @@ njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare)
 }
 
 
+static njs_ret_t
+njs_array_add(njs_vm_t *vm, njs_array_t *array, njs_value_t *value)
+{
+    njs_ret_t  ret;
+
+    if (array->size == array->length) {
+        ret = njs_array_realloc(vm, array, 0, array->size + 1);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return ret;
+        }
+    }
+
+    /* GC: retain value. */
+    array->start[array->length++] = *value;
+
+    return NXT_OK;
+}
+
+
 njs_ret_t
 njs_array_string_add(njs_vm_t *vm, njs_array_t *array, u_char *start,
     size_t size, size_t length)
@@ -904,6 +927,59 @@ njs_array_prototype_every_cont(njs_vm_t *vm, njs_value_t *args,
 }
 
 
+static njs_ret_t
+njs_array_prototype_filter(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    nxt_int_t         ret;
+    njs_array_iter_t  *iter;
+
+    ret = njs_array_iterator_args(vm, args, nargs);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return ret;
+    }
+
+    iter = njs_continuation(vm->frame);
+    iter->u.cont.function = njs_array_prototype_filter_cont;
+    iter->retval.data.truth = 0;
+
+    iter->array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE);
+    if (nxt_slow_path(iter->array == NULL)) {
+        return NXT_ERROR;
+    }
+
+    return njs_array_prototype_filter_cont(vm, args, nargs, unused);
+}
+
+
+static njs_ret_t
+njs_array_prototype_filter_cont(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused)
+{
+    nxt_int_t         ret;
+    njs_array_iter_t  *iter;
+
+    iter = njs_continuation(vm->frame);
+
+    if (njs_is_true(&iter->retval)) {
+        ret = njs_array_add(vm, iter->array, &iter->value);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return ret;
+        }
+    }
+
+    if (iter->next_index >= args[0].data.u.array->length) {
+        vm->retval.data.u.array = iter->array;
+        vm->retval.type = NJS_ARRAY;
+        vm->retval.data.truth = 1;
+
+        return NXT_OK;
+    }
+
+    return njs_array_iterator_apply(vm, iter, args, nargs);
+}
+
+
 static nxt_noinline njs_ret_t
 njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs)
 {
@@ -966,6 +1042,7 @@ njs_array_iterator_apply(njs_vm_t *vm, njs_array_iter_t *iter,
      */
     array = args[0].data.u.array;
     n = iter->next_index;
+    iter->value = array->start[n];
     arguments[1] = array->start[n];
 
     njs_number_set(&arguments[2], n);
@@ -1066,6 +1143,13 @@ static const njs_object_prop_t  njs_array_prototype_properties[] =
         .value = njs_native_function(njs_array_prototype_every,
                      njs_continuation_size(njs_array_iter_t), 0),
     },
+
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("filter"),
+        .value = njs_native_function(njs_array_prototype_filter,
+                     njs_continuation_size(njs_array_iter_t), 0),
+    },
 };
 
 
index 394e9ef1dcd39b1e7e0ad01352bba9eb15abda27..f5c616359703401e7533bf21af64d5cff77bb25b 100644 (file)
@@ -2333,6 +2333,38 @@ static njs_unit_test_t  njs_test[] =
                  "a.every(function(v, i, a) { return v > 0 })"),
       nxt_string("true") },
 
+    { nxt_string("var a = [];"
+                 "a.filter(function(v, i, a) { return v > 1 })"),
+      nxt_string("") },
+
+    { nxt_string("var a = [1,2,3,-1,5];"
+                 "a.filter(function(v, i, a) { return v > 1 })"),
+      nxt_string("2,3,5") },
+
+    { nxt_string("var a = [1,2,3,4,5,6,7,8];"
+                 "a.filter(function(v, i, a) { a.pop(); return v > 1 })"),
+      nxt_string("2,3,4") },
+
+    { nxt_string("var a = [1,2,3,4,5,6,7,8];"
+                 "a.filter(function(v, i, a) { a.shift(); return v > 1 })"),
+      nxt_string("3,5,7") },
+
+    { nxt_string("var a = [1,2,3,4,5,6,7];"
+                 "a.filter(function(v, i, a) { a.pop(); return v > 1 })"),
+      nxt_string("2,3,4") },
+
+    { nxt_string("var a = [1,2,3,4,5,6,7];"
+                 "a.filter(function(v, i, a) { a.shift(); return v > 1 })"),
+      nxt_string("3,5,7") },
+
+    { nxt_string("var a = [1,2,3,4,5,6,7];"
+                 "a.filter(function(v, i, a) { a[i] = v + 1; return true })"),
+      nxt_string("1,2,3,4,5,6,7") },
+
+    { nxt_string("var a = [1,2,3,4,5,6,7];"
+                 "a.filter(function(v, i, a) { a[i+1] = v+10; return true })"),
+      nxt_string("1,11,21,31,41,51,61") },
+
     /* Strings. */
 
     { nxt_string("var a = '0123456789' + '012345'"