typedef struct {
- njs_function_t *function;
- njs_value_t *this_arg;
- njs_value_t *value;
+ njs_function_t *function;
+ njs_value_t *argument;
+ njs_value_t *value;
+
+ njs_array_t *array;
- njs_array_t *array;
+ uint32_t from;
+ uint32_t to;
} njs_array_iterator_args_t;
}
-static njs_int_t
-njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
+njs_inline njs_int_t
+njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_array_iterator_handler_t handler)
{
- uint64_t length;
- njs_uint_t i;
- njs_value_t *value;
- njs_array_t *array;
-
- length = 0;
+ uint32_t length, i, from, to;
+ njs_int_t ret;
+ njs_value_t *entry, *value, character, index, string_obj, prop;
+ njs_object_t *object;
+ const u_char *p, *end, *pos;
+ njs_string_prop_t string_prop;
- for (i = 0; i < nargs; i++) {
- if (njs_is_array(&args[i])) {
- length += njs_array_len(&args[i]);
+ value = args->value;
+ from = args->from;
+ to = args->to;
- } else {
- length++;
+ if (njs_is_array(value)) {
+ if (njs_slow_path(!njs_object_hash_is_empty(value))) {
+ goto process_object;
}
- }
-
- array = njs_array_alloc(vm, length, NJS_ARRAY_SPARE);
- if (njs_slow_path(array == NULL)) {
- return NJS_ERROR;
- }
- njs_set_array(&vm->retval, array);
+ for (i = from; i < to; i++) {
+ entry = &njs_array_start(value)[i];
- value = array->start;
+ ret = handler(vm, args, entry, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
- for (i = 0; i < nargs; i++) {
- value = njs_array_copy(value, &args[i]);
- }
+ return NJS_ERROR;
+ }
- return NJS_OK;
-}
+ to = njs_min(to, njs_array_len(value));
+ }
+ return NJS_OK;
+ }
-static njs_value_t *
-njs_array_copy(njs_value_t *dst, njs_value_t *src)
-{
- njs_uint_t n;
+ if (njs_is_string(value) || njs_is_object_string(value)) {
- n = 1;
+ if (njs_is_string(value)) {
+ object = njs_object_value_alloc(vm, value, NJS_STRING);
+ if (njs_slow_path(object == NULL)) {
+ return NJS_ERROR;
+ }
- if (njs_is_array(src)) {
- n = njs_array_len(src);
- src = njs_array_start(src);
- }
+ njs_set_type_object(&string_obj, object, NJS_OBJECT_STRING);
- while (n != 0) {
- /* GC: njs_retain src */
- *dst++ = *src++;
- n--;
- }
+ args->value = &string_obj;
+ }
+ else {
+ value = njs_object_value(value);
+ }
- return dst;
-}
+ length = (uint32_t) njs_string_prop(&string_prop, value);
+ p = string_prop.start;
+ end = p + string_prop.size;
-static njs_int_t
-njs_array_prototype_index_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- njs_int_t i, index, length;
- njs_value_t *value, *start;
- njs_array_t *array;
+ if (length == string_prop.size) {
+ /* Byte or ASCII string. */
- index = -1;
+ for (i = from; i < to; i++) {
+ /* This cannot fail. */
+ (void) njs_string_new(vm, &character, p + i, 1, 1);
- if (nargs < 2 || !njs_is_array(&args[0])) {
- goto done;
- }
+ ret = handler(vm, args, &character, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
- array = njs_array(&args[0]);
- length = array->length;
+ return NJS_ERROR;
+ }
+ }
- if (length == 0) {
- goto done;
- }
+ } else {
+ /* UTF-8 string. */
- i = 0;
+ for (i = from; i < to; i++) {
+ pos = njs_utf8_next(p, end);
- if (nargs > 2) {
- i = njs_number(&args[2]);
+ /* This cannot fail. */
+ (void) njs_string_new(vm, &character, p, pos - p, 1);
- if (i >= length) {
- goto done;
- }
+ ret = handler(vm, args, &character, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
- if (i < 0) {
- i += length;
+ return NJS_ERROR;
+ }
- if (i < 0) {
- i = 0;
+ p = pos;
}
}
+
+ return NJS_OK;
}
- value = &args[1];
- start = array->start;
+ if (!njs_is_object(value)) {
+ return NJS_OK;
+ }
- do {
- if (njs_values_strict_equal(value, &start[i])) {
- index = i;
- break;
- }
+process_object:
- i++;
+ for (i = from; i < to; i++) {
+ njs_uint32_to_string(&index, i);
- } while (i < length);
+ ret = njs_value_property(vm, value, &index, &prop);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
-done:
+ if (ret != NJS_DECLINED) {
+ ret = handler(vm, args, &prop, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
- njs_set_number(&vm->retval, index);
+ return NJS_ERROR;
+ }
+ }
+ }
return NJS_OK;
}
-static njs_int_t
-njs_array_prototype_last_index_of(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
+njs_inline njs_int_t
+njs_array_reverse_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_array_iterator_handler_t handler)
{
- njs_int_t k, n, index, length;
- njs_value_t *start;
- njs_array_t *array;
- njs_value_t *this, *value;
+ uint32_t i, from, to, length;
+ njs_int_t ret;
+ njs_value_t *entry, *value, character, index, string_obj, prop;
+ njs_object_t *object;
+ const u_char *p, *end, *pos;
+ njs_string_prop_t string_prop;
- index = -1;
+ value = args->value;
+ from = args->from;
+ to = args->to;
- this = njs_arg(args, nargs, 0);
+ if (njs_is_array(value)) {
+ if (njs_slow_path(!njs_object_hash_is_empty(value))) {
+ goto process_object;
+ }
- if (!njs_is_array(this)) {
- goto done;
- }
+ i = from + 1;
- array = njs_array(this);
- length = array->length;
+ while (i-- > to) {
+ entry = &njs_array_start(value)[i];
- if (length == 0) {
- goto done;
- }
+ ret = handler(vm, args, entry, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
- if (nargs > 2) {
- n = njs_primitive_value_to_integer(njs_argument(args, 2));
+ return NJS_ERROR;
+ }
+ }
- } else {
- n = length - 1;
+ return NJS_OK;
}
- if (n >= 0) {
- k = njs_min(n, length - 1);
-
- } else {
- k = n + length;
+ if (njs_is_string(value) || njs_is_object_string(value)) {
- if (k < 0) {
- goto done;
- }
- }
+ if (njs_is_string(value)) {
+ object = njs_object_value_alloc(vm, value, NJS_STRING);
+ if (njs_slow_path(object == NULL)) {
+ return NJS_ERROR;
+ }
- value = njs_arg(args, nargs, 1);
- start = array->start;
+ njs_set_type_object(&string_obj, object, NJS_OBJECT_STRING);
- do {
- if (njs_values_strict_equal(value, &start[k])) {
- index = k;
- break;
+ args->value = &string_obj;
+ }
+ else {
+ value = njs_object_value(value);
}
- k--;
+ length = (uint32_t) njs_string_prop(&string_prop, value);
+ end = string_prop.start + string_prop.size;
- } while (k >= 0);
+ if (length == string_prop.size) {
+ /* Byte or ASCII string. */
-done:
+ p = string_prop.start + from;
- njs_set_number(&vm->retval, index);
+ i = from + 1;
- return NJS_OK;
-}
+ while (i-- > to) {
+ /* This cannot fail. */
+ (void) njs_string_new(vm, &character, p, 1, 1);
+ ret = handler(vm, args, &character, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
-static njs_int_t
-njs_array_prototype_includes(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- njs_int_t i, length;
- njs_value_t *value, *start;
- njs_array_t *array;
- const njs_value_t *retval;
+ return NJS_ERROR;
+ }
- retval = &njs_value_false;
+ p--;
+ }
- if (nargs < 2 || !njs_is_array(&args[0])) {
- goto done;
- }
+ } else {
+ /* UTF-8 string. */
- array = njs_array(&args[0]);
- length = array->length;
+ p = njs_string_offset(string_prop.start, end, from + 1);
- if (length == 0) {
- goto done;
- }
+ i = from + 1;
- i = 0;
+ while (i-- > to) {
+ pos = njs_utf8_prev(p);
- if (nargs > 2) {
- i = njs_number(&args[2]);
+ /* This cannot fail. */
+ (void) njs_string_new(vm, &character, pos, p - pos , 1);
- if (i >= length) {
- goto done;
- }
+ ret = handler(vm, args, &character, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
- if (i < 0) {
- i += length;
+ return NJS_ERROR;
+ }
- if (i < 0) {
- i = 0;
+ p = pos;
}
}
+
+ return NJS_OK;
}
- start = array->start;
- value = &args[1];
+ if (!njs_is_object(value)) {
+ return NJS_OK;
+ }
- if (njs_is_number(value) && isnan(njs_number(value))) {
+process_object:
- do {
- value = &start[i];
+ i = from + 1;
- if (njs_is_number(value) && isnan(njs_number(value))) {
- retval = &njs_value_true;
- break;
- }
+ while (i-- > to) {
+ njs_uint32_to_string(&index, i);
- i++;
+ ret = njs_value_property(vm, value, &index, &prop);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
- } while (i < length);
+ if (ret != NJS_DECLINED) {
+ ret = handler(vm, args, &prop, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
- } else {
- do {
- if (njs_values_strict_equal(value, &start[i])) {
- retval = &njs_value_true;
- break;
+ return NJS_ERROR;
}
+ }
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ uint64_t length;
+ njs_uint_t i;
+ njs_value_t *value;
+ njs_array_t *array;
- i++;
+ length = 0;
- } while (i < length);
+ for (i = 0; i < nargs; i++) {
+ if (njs_is_array(&args[i])) {
+ length += njs_array_len(&args[i]);
+
+ } else {
+ length++;
+ }
}
-done:
+ array = njs_array_alloc(vm, length, NJS_ARRAY_SPARE);
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
- vm->retval = *retval;
+ njs_set_array(&vm->retval, array);
+
+ value = array->start;
+
+ for (i = 0; i < nargs; i++) {
+ value = njs_array_copy(value, &args[i]);
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_value_t *
+njs_array_copy(njs_value_t *dst, njs_value_t *src)
+{
+ njs_uint_t n;
+
+ n = 1;
+
+ if (njs_is_array(src)) {
+ n = njs_array_len(src);
+ src = njs_array_start(src);
+ }
+
+ while (n != 0) {
+ /* GC: njs_retain src */
+ *dst++ = *src++;
+ n--;
+ }
+
+ return dst;
+}
+
+
+static njs_int_t
+njs_array_handler_index_of(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, uint32_t n)
+{
+ if (njs_values_strict_equal(args->argument, entry)) {
+ njs_set_number(&vm->retval, n);
+
+ return 1;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_array_prototype_index_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ int64_t from;
+ uint32_t length;
+ njs_int_t ret;
+ njs_array_iterator_args_t iargs;
+
+ if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) {
+ njs_type_error(vm, "unexpected iterator arguments");
+ return NJS_ERROR;
+ }
+
+ iargs.value = njs_argument(args, 0);
+ iargs.argument = njs_arg(args, nargs, 1);
+
+ ret = njs_value_length(vm, iargs.value, &length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2));
+
+ if (length == 0 || from >= (int64_t) length) {
+ goto not_found;
+ }
+
+ if (from < 0) {
+ from = length + from;
+
+ if (from < 0) {
+ from = 0;
+ }
+ }
+
+ iargs.from = (uint32_t) from;
+ iargs.to = length;
+
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_index_of);
+ if (njs_fast_path(ret == NJS_DECLINED)) {
+ return NJS_OK;
+ }
+
+not_found:
+
+ njs_set_number(&vm->retval, -1);
+
+ return ret;
+}
+
+
+static njs_int_t
+njs_array_prototype_last_index_of(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ int64_t from;
+ uint32_t length;
+ njs_int_t ret;
+ njs_array_iterator_args_t iargs;
+
+ if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) {
+ njs_type_error(vm, "unexpected iterator arguments");
+ return NJS_ERROR;
+ }
+
+ iargs.value = njs_argument(args, 0);
+ iargs.argument = njs_arg(args, nargs, 1);
+
+ ret = njs_value_length(vm, iargs.value, &length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (length == 0) {
+ goto not_found;
+ }
+
+ if (nargs > 2) {
+ from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2));
+
+ } else {
+ from = length - 1;
+ }
+
+ if (from >= 0) {
+ from = njs_min(from, length - 1);
+
+ } else if (from < 0) {
+ from += length;
+
+ if (from <= 0) {
+ goto not_found;
+ }
+ }
+
+ iargs.from = from;
+ iargs.to = 0;
+
+ ret = njs_array_reverse_iterator(vm, &iargs, njs_array_handler_index_of);
+ if (njs_fast_path(ret == NJS_DECLINED)) {
+ return NJS_OK;
+ }
+
+not_found:
+
+ njs_set_number(&vm->retval, -1);
+
+ return ret;
+}
+
+
+static njs_int_t
+njs_array_handler_includes(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, uint32_t n)
+{
+ if (njs_values_strict_equal(args->argument, entry)) {
+ njs_set_true(&vm->retval);
+
+ return 1;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_array_handler_includes_nan(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, uint32_t n)
+{
+ if (njs_is_numeric(entry) && isnan(njs_number(entry))) {
+ njs_set_true(&vm->retval);
+
+ return 1;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_array_prototype_includes(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ int64_t from;
+ uint32_t length;
+ njs_int_t ret;
+ njs_array_iterator_args_t iargs;
+
+ if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) {
+ njs_type_error(vm, "unexpected iterator arguments");
+ return NJS_ERROR;
+ }
+
+ iargs.value = njs_argument(args, 0);
+ iargs.argument = njs_arg(args, nargs, 1);
+
+ ret = njs_value_length(vm, iargs.value, &length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (length == 0) {
+ goto not_found;
+ }
+
+ from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2));
+
+ if (from < 0) {
+ from += length;
+
+ if (from < 0) {
+ from = 0;
+ }
+ }
+
+ iargs.from = (uint32_t) from;
+ iargs.to = length;
+
+ if (njs_is_numeric(iargs.argument) && isnan(njs_number(iargs.argument))) {
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_includes_nan);
+ if (njs_fast_path(ret == NJS_DECLINED)) {
+ return NJS_OK;
+ }
+
+ } else {
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_includes);
+ if (njs_fast_path(ret == NJS_DECLINED)) {
+ return NJS_OK;
+ }
+ }
+
+not_found:
+
+ njs_set_false(&vm->retval);
return NJS_OK;
}
njs_set_number(&arguments[1], n);
arguments[2] = *args->value;
- return njs_function_call(vm, args->function, args->this_arg, arguments, 3,
+ return njs_function_call(vm, args->function, args->argument, arguments, 3,
&vm->retval);
}
-njs_inline njs_int_t
-njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
- njs_array_iterator_handler_t handler, uint32_t length)
-{
- uint32_t i;
- njs_int_t ret;
- njs_value_t *entry, *value, character, index, string_obj, prop;
- njs_object_t *object;
- const u_char *p, *end, *pos;
- njs_string_prop_t string_prop;
-
- value = args->value;
-
- if (njs_is_array(value)) {
- if (njs_slow_path(!njs_object_hash_is_empty(value))) {
- goto process_object;
- }
-
- length = njs_array_len(value);
-
- for (i = 0; i < length; i++) {
- entry = &njs_array_start(value)[i];
-
- ret = handler(vm, args, entry, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
- return NJS_ERROR;
- }
-
- length = njs_min(length, njs_array_len(value));
- }
-
- return NJS_OK;
- }
-
- if (njs_is_string(value) || njs_is_object_string(value)) {
-
- if (njs_is_string(value)) {
- object = njs_object_value_alloc(vm, value, NJS_STRING);
- if (njs_slow_path(object == NULL)) {
- return NJS_ERROR;
- }
-
- njs_set_type_object(&string_obj, object, NJS_OBJECT_STRING);
-
- args->value = &string_obj;
- }
- else {
- value = njs_object_value(value);
- }
-
- length = (uint32_t) njs_string_prop(&string_prop, value);
-
- p = string_prop.start;
- end = p + string_prop.size;
-
- if (length == string_prop.size) {
- /* Byte or ASCII string. */
-
- for (i = 0; i < length; i++) {
- /* This cannot fail. */
- (void) njs_string_new(vm, &character, p++, 1, 1);
-
- ret = handler(vm, args, &character, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
- return NJS_ERROR;
- }
- }
-
- } else {
- /* UTF-8 string. */
-
- for (i = 0; i < length; i++) {
- pos = njs_utf8_next(p, end);
-
- /* This cannot fail. */
- (void) njs_string_new(vm, &character, p, pos - p, 1);
-
- ret = handler(vm, args, &character, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
- return NJS_ERROR;
- }
-
- p = pos;
- }
- }
-
- return NJS_OK;
- }
-
- if (!njs_is_object(value)) {
- return NJS_OK;
- }
-
-process_object:
-
- if (length > NJS_ARRAY_MAX_LENGTH) {
- ret = njs_object_length(vm, value, &length);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- }
- }
-
- for (i = 0; i < length; i++) {
- njs_uint32_to_string(&index, i);
-
- ret = njs_value_property(vm, value, &index, &prop);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
-
- if (ret != NJS_DECLINED) {
- ret = handler(vm, args, &prop, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
- return NJS_ERROR;
- }
- }
- }
-
- return NJS_OK;
-}
-
-
static njs_int_t
njs_array_handler_for_each(njs_vm_t *vm, njs_array_iterator_args_t *args,
njs_value_t *entry, uint32_t n)
iargs.value = njs_argument(args, 0);
iargs.function = njs_function(&args[1]);
- iargs.this_arg = njs_arg(args, nargs, 2);
+ iargs.argument = njs_arg(args, nargs, 2);
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_for_each,
- NJS_ARRAY_MAX_LENGTH + 1);
+ iargs.from = 0;
+
+ ret = njs_value_length(vm, iargs.value, &iargs.to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_for_each);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
iargs.value = njs_argument(args, 0);
iargs.function = njs_function(&args[1]);
- iargs.this_arg = njs_arg(args, nargs, 2);
+ iargs.argument = njs_arg(args, nargs, 2);
+
+ iargs.from = 0;
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_some,
- NJS_ARRAY_MAX_LENGTH + 1);
+ ret = njs_value_length(vm, iargs.value, &iargs.to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_some);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
iargs.value = njs_argument(args, 0);
iargs.function = njs_function(&args[1]);
- iargs.this_arg = njs_arg(args, nargs, 2);
+ iargs.argument = njs_arg(args, nargs, 2);
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_every,
- NJS_ARRAY_MAX_LENGTH + 1);
+ iargs.from = 0;
+
+ ret = njs_value_length(vm, iargs.value, &iargs.to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_every);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
iargs.value = njs_argument(args, 0);
iargs.function = njs_function(&args[1]);
- iargs.this_arg = njs_arg(args, nargs, 2);
+ iargs.argument = njs_arg(args, nargs, 2);
+
+ iargs.from = 0;
+
+ ret = njs_value_length(vm, iargs.value, &iargs.to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
iargs.array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE);
if (njs_slow_path(iargs.array == NULL)) {
return NJS_ERROR;
}
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_filter,
- NJS_ARRAY_MAX_LENGTH + 1);
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_filter);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
iargs.value = njs_argument(args, 0);
iargs.function = njs_function(&args[1]);
- iargs.this_arg = njs_arg(args, nargs, 2);
+ iargs.argument = njs_arg(args, nargs, 2);
+
+ iargs.from = 0;
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_find,
- NJS_ARRAY_MAX_LENGTH + 1);
+ ret = njs_value_length(vm, iargs.value, &iargs.to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_find);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
iargs.value = njs_argument(args, 0);
iargs.function = njs_function(&args[1]);
- iargs.this_arg = njs_arg(args, nargs, 2);
+ iargs.argument = njs_arg(args, nargs, 2);
+
+ iargs.from = 0;
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_find_index,
- NJS_ARRAY_MAX_LENGTH + 1);
+ ret = njs_value_length(vm, iargs.value, &iargs.to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_find_index);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
iargs.value = njs_argument(args, 0);
iargs.function = njs_function(&args[1]);
- iargs.this_arg = njs_arg(args, nargs, 2);
+ iargs.argument = njs_arg(args, nargs, 2);
ret = njs_value_length(vm, iargs.value, &length);
if (njs_slow_path(ret != NJS_OK)) {
}
if (length > 0) {
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_map, length);
+ iargs.from = 0;
+ iargs.to = length;
+
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_map);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
/* GC: array elt, array */
njs_set_undefined(&arguments[0]);
- arguments[1] = *args->this_arg;
+ arguments[1] = *args->argument;
arguments[2] = *entry;
njs_set_number(&arguments[3], n);
arguments[4] = *args->value;
- return njs_function_apply(vm, args->function, arguments, 5, args->this_arg);
+ return njs_function_apply(vm, args->function, arguments, 5, args->argument);
}
if (njs_is_valid(entry)) {
- if (!njs_is_valid(args->this_arg)) {
- *(args->this_arg) = *entry;
+ if (!njs_is_valid(args->argument)) {
+ *(args->argument) = *entry;
return NJS_OK;
}
iargs.value = njs_argument(args, 0);
iargs.function = njs_function(&args[1]);
- iargs.this_arg = &accumulator;
+ iargs.argument = &accumulator;
+
+ iargs.from = 0;
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_reduce,
- NJS_ARRAY_MAX_LENGTH + 1);
+ ret = njs_value_length(vm, iargs.value, &iargs.to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_array_iterator(vm, &iargs, njs_array_handler_reduce);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
if (!njs_is_valid(&accumulator)) {
- njs_type_error(vm, "invalid index");
+ njs_type_error(vm, "Reduce of empty object with no initial value");
return NJS_ERROR;
}
njs_array_prototype_reduce_right(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused)
{
- int32_t i;
- uint32_t length;
njs_int_t ret;
- njs_value_t accumulator, *value, *entry;
- njs_array_iterator_args_t iter;
+ njs_value_t accumulator;
+ njs_array_iterator_args_t iargs;
- if (nargs < 2 || !njs_is_array(&args[0]) || !njs_is_function(&args[1])) {
+ if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
+ || !njs_is_function(njs_arg(args, nargs, 1)))
+ {
njs_type_error(vm, "unexpected iterator arguments");
return NJS_ERROR;
}
- value = &args[0];
- length = njs_array_len(value);
-
njs_set_invalid(&accumulator);
- if (nargs > 2) {
- accumulator = args[2];
- }
+ iargs.value = njs_argument(args, 0);
+ iargs.function = njs_function(&args[1]);
+ iargs.argument = &accumulator;
+ iargs.to = 0;
- iter.value = value;
- iter.function = njs_function(&args[1]);
- iter.this_arg = &accumulator;
+ ret = njs_value_length(vm, iargs.value, &iargs.from);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
- for (i = length - 1; i >= 0; i--) {
- entry = &njs_array_start(value)[i];
+ if (nargs > 2) {
+ accumulator = *njs_argument(args, 2);
+ }
- if (njs_is_valid(entry)) {
+ if (iargs.from == 0) {
+ if (nargs < 3) {
+ goto failed;
+ }
- if (!njs_is_valid(&accumulator)) {
- accumulator = njs_array_start(value)[i];
- continue;
- }
+ goto done;
+ }
- ret = njs_array_iterator_reduce(vm, &iter, entry, i);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
- }
+ iargs.from--;
- length = njs_min(length, njs_array_len(value));
+ ret = njs_array_reverse_iterator(vm, &iargs, njs_array_handler_reduce);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
if (!njs_is_valid(&accumulator)) {
- njs_type_error(vm, "invalid index");
- return NJS_ERROR;
+ goto failed;
}
+done:
+
vm->retval = accumulator;
return NJS_OK;
+
+failed:
+
+ njs_type_error(vm, "Reduce of empty object with no initial value");
+
+ return NJS_ERROR;
}
{ njs_str("[].indexOf.bind(0)(0, 0)"),
njs_str("-1") },
+ { njs_str("var o = 'abcd';"
+ "Array.prototype.indexOf.call(o, 'c')"),
+ njs_str("2") },
+
+ { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
+ "Object.defineProperty(o, 'length', {get: () => 4});"
+ "Object.defineProperty(o, '3', {get: () => 'd'});"
+ "Array.prototype.indexOf.call(o, 'd')"),
+ njs_str("3") },
+
{ njs_str("[].lastIndexOf(1, -1)"),
njs_str("-1") },
{ njs_str("[1,2,1].lastIndexOf(1)"),
njs_str("2") },
+ { njs_str("var o = 'addc';"
+ "Array.prototype.lastIndexOf.call(o, 'd')"),
+ njs_str("2") },
+
+ { njs_str("var o = 'dddd';"
+ "Array.prototype.lastIndexOf.call(o, 'd')"),
+ njs_str("3") },
+
+ { njs_str("var o = 'dabc';"
+ "Array.prototype.lastIndexOf.call(o, 'd')"),
+ njs_str("0") },
+
+ { njs_str("var o = 'АБВГ';"
+ "Array.prototype.lastIndexOf.call(o, 'Г')"),
+ njs_str("3") },
+
+ { njs_str("var o = 'ГВБА';"
+ "Array.prototype.lastIndexOf.call(o, 'Г')"),
+ njs_str("0") },
+
+ { njs_str("var o = 'ВГБА';"
+ "Array.prototype.lastIndexOf.call(o, 'Г')"),
+ njs_str("1") },
+
+ { njs_str("var o = {0: 'a', 1: 'd', 2: 'd'};"
+ "Object.defineProperty(o, 'length', {get: () => 4});"
+ "Object.defineProperty(o, '3', {get: () => 'd'});"
+ "Array.prototype.lastIndexOf.call(o, 'd')"),
+ njs_str("3") },
+
{ njs_str("[1,2,3,4].includes()"),
njs_str("false") },
{ njs_str("[].includes.bind(0)(0, 0)"),
njs_str("false") },
+ { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
+ "Object.defineProperty(o, 'length', {get: () => 4});"
+ "Object.defineProperty(o, '3', {get: () => 'd'});"
+ "Array.prototype.includes.call(o, 'd')"),
+ njs_str("true") },
+
{ njs_str("var a = []; var s = { sum: 0 };"
"a.forEach(function(v, i, a) { this.sum += v }, s); s.sum"),
njs_str("0") },
{ njs_str("var a = [];"
"a.reduce(function(p, v, i, a) { return p + v })"),
- njs_str("TypeError: invalid index") },
+ njs_str("TypeError: Reduce of empty object with no initial value") },
{ njs_str("var a = [];"
"a.reduce(function(p, v, i, a) { return p + v }, 10)"),
{ njs_str("var a = [,,];"
"a.reduce(function(p, v, i, a) { return p + v })"),
- njs_str("TypeError: invalid index") },
+ njs_str("TypeError: Reduce of empty object with no initial value") },
{ njs_str("var a = [,,];"
"a.reduce(function(p, v, i, a) { return p + v }, 10)"),
{ njs_str("var a = [];"
"a.reduceRight(function(p, v, i, a) { return p + v })"),
- njs_str("TypeError: invalid index") },
+ njs_str("TypeError: Reduce of empty object with no initial value") },
{ njs_str("var a = [];"
"a.reduceRight(function(p, v, i, a) { return p + v }, 10)"),
{ njs_str("var a = [,,];"
"a.reduceRight(function(p, v, i, a) { return p + v })"),
- njs_str("TypeError: invalid index") },
+ njs_str("TypeError: Reduce of empty object with no initial value") },
{ njs_str("var a = [,,];"
"a.reduceRight(function(p, v, i, a) { return p + v }, 10)"),
" { a.shift(); return p + v }, 10)"),
njs_str("19") },
+ { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
+ "Object.defineProperty(o, 'length', {get: () => 4});"
+ "Object.defineProperty(o, '3', {get: () => 'd'});"
+ "Array.prototype.reduceRight.call(o, (p, v) => p + v)"),
+ njs_str("dcba") },
+
{ njs_str("var a = ['1','2','3','4','5','6']; a.sort()"),
njs_str("1,2,3,4,5,6") },