From 706c7b79782c5addc4449ebb493d2147327d08f4 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Tue, 9 Aug 2016 14:10:29 +0300 Subject: [PATCH] Array.filter() function. --- njs/njs_array.c | 84 ++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 32 +++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/njs/njs_array.c b/njs/njs_array.c index 35c01500..e1e1b9eb 100644 --- a/njs/njs_array.c +++ b/njs/njs_array.c @@ -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), + }, }; diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 394e9ef1..f5c61635 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -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'" -- 2.47.3