#include <njs_main.h>
-#define njs_fast_object(_sz) ((_sz) <= NJS_ARRAY_FAST_OBJECT_LENGTH)
+#define njs_fast_object(_sz) ((_sz) <= NJS_ARRAY_FAST_OBJECT_LENGTH)
+
+
+#define njs_array_func(type) \
+ ((type << 1) | NJS_ARRAY_FUNC)
+
+
+#define njs_array_arg(type) \
+ ((type << 1) | NJS_ARRAY_ARG)
+
+
+#define njs_array_type(magic) (magic >> 1)
+#define njs_array_arg1(magic) (magic & 0x1)
+
+
+typedef enum {
+ NJS_ARRAY_EVERY = 0,
+ NJS_ARRAY_SOME,
+ NJS_ARRAY_INCLUDES,
+ NJS_ARRAY_INDEX_OF,
+ NJS_ARRAY_FOR_EACH,
+ NJS_ARRAY_FIND,
+ NJS_ARRAY_FIND_INDEX,
+ NJS_ARRAY_REDUCE,
+ NJS_ARRAY_FILTER,
+ NJS_ARRAY_MAP,
+} njs_array_iterator_fun_t;
+
+
+typedef enum {
+ NJS_ARRAY_LAST_INDEX_OF = 0,
+ NJS_ARRAY_REDUCE_RIGHT,
+} njs_array_reverse_iterator_fun_t;
+
+
+typedef enum {
+ NJS_ARRAY_FUNC = 0,
+ NJS_ARRAY_ARG
+} njs_array_iterator_arg_t;
typedef struct {
njs_inline njs_int_t
-njs_array_object_handler(njs_vm_t *vm, njs_array_iterator_handler_t handler,
- njs_array_iterator_args_t *args, njs_value_t *key, int64_t i)
+njs_is_concat_spreadable(njs_vm_t *vm, njs_value_t *value)
{
njs_int_t ret;
- njs_value_t prop, *entry;
+ njs_value_t retval;
- if (key != NULL) {
- ret = njs_value_property(vm, args->value, key, &prop);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
+ static const njs_value_t key =
+ njs_wellknown_symbol(NJS_SYMBOL_IS_CONCAT_SPREADABLE);
- } else {
- ret = njs_value_property_i64(vm, args->value, i, &prop);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
+ if (njs_slow_path(!njs_is_object(value))) {
+ return NJS_DECLINED;
}
- entry = (ret == NJS_OK) ? &prop : njs_value_arg(&njs_value_invalid);
-
- ret = handler(vm, args, entry, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
+ ret = njs_value_property(vm, value, njs_value_arg(&key), &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
return NJS_ERROR;
}
- return ret;
+ if (njs_is_defined(&retval)) {
+ return njs_bool(&retval) ? NJS_OK : NJS_DECLINED;
+ }
+
+ return njs_is_array(value) ? NJS_OK : NJS_DECLINED;
}
-njs_inline njs_int_t
-njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
- njs_array_iterator_handler_t handler)
+static njs_int_t
+njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
{
- double idx;
- int64_t length, i, from, to;
- njs_int_t ret;
- njs_array_t *array, *keys;
- njs_value_t *value, *entry, prop, character, string_obj;
- njs_object_t *object;
- const u_char *p, *end, *pos;
- njs_string_prop_t string_prop;
-
- value = args->value;
- from = args->from;
- to = args->to;
-
- if (njs_is_array(value)) {
- array = njs_array(value);
+ double idx;
+ int64_t k, len, length;
+ njs_int_t ret;
+ njs_uint_t i;
+ njs_value_t this, retval, *value, *e;
+ njs_array_t *array, *keys;
- for (; from < to; from++) {
- if (njs_slow_path(!array->object.fast_array)) {
- goto process_object;
- }
+ ret = njs_value_to_object(vm, &args[0]);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
- if (njs_fast_path(from < array->length
- && njs_is_valid(&array->start[from])))
- {
- ret = handler(vm, args, &array->start[from], from);
+ /* TODO: ArraySpeciesCreate(). */
- } else {
- entry = njs_value_arg(&njs_value_invalid);
- ret = njs_value_property_i64(vm, value, from, &prop);
- if (njs_slow_path(ret != NJS_DECLINED)) {
- if (ret == NJS_ERROR) {
- return NJS_ERROR;
- }
+ array = njs_array_alloc(vm, 0, 0, NJS_ARRAY_SPARE);
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
- entry = ∝
- }
+ njs_set_array(&this, array);
- ret = handler(vm, args, entry, from);
- }
+ len = 0;
+ length = 0;
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
+ for (i = 0; i < nargs; i++) {
+ e = njs_argument(args, i);
- return NJS_ERROR;
- }
+ ret = njs_is_concat_spreadable(vm, e);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return NJS_ERROR;
}
- return NJS_OK;
- }
-
- if (njs_is_string(value) || njs_is_object_string(value)) {
+ if (ret == NJS_OK) {
+ ret = njs_object_length(vm, e, &len);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
- if (njs_is_string(value)) {
- object = njs_object_value_alloc(vm, value, NJS_STRING);
- if (njs_slow_path(object == NULL)) {
+ if (njs_slow_path((length + len) > NJS_MAX_LENGTH)) {
+ njs_type_error(vm, "Invalid length");
return NJS_ERROR;
}
- njs_set_type_object(&string_obj, object, NJS_OBJECT_STRING);
+ if (njs_is_fast_array(&this) && njs_is_fast_array(e)
+ && (length + len) <= NJS_ARRAY_LARGE_OBJECT_LENGTH)
+ {
+ for (k = 0; k < len; k++, length++) {
+ value = &njs_array_start(e)[k];
- args->value = &string_obj;
- }
- else {
- value = njs_object_value(value);
- }
+ if (njs_slow_path(!njs_is_valid(value))) {
+ ret = njs_value_property_i64(vm, e, k, &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
- length = njs_string_prop(&string_prop, value);
+ if (ret == NJS_DECLINED) {
+ njs_set_invalid(&retval);
+ }
- p = string_prop.start;
- end = p + string_prop.size;
+ value = &retval;
+ }
- if ((size_t) length == string_prop.size) {
- /* Byte or ASCII string. */
+ ret = njs_array_add(vm, array, value);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+ }
- for (i = from; i < to; i++) {
- /* This cannot fail. */
- (void) njs_string_new(vm, &character, p + i, 1, 1);
+ continue;
+ }
- ret = handler(vm, args, &character, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
+ if (njs_fast_object(len)) {
+ for (k = 0; k < len; k++, length++) {
+ ret = njs_value_property_i64(vm, e, k, &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
}
- return NJS_ERROR;
+ if (ret != NJS_OK) {
+ continue;
+ }
+
+ ret = njs_value_property_i64_set(vm, &this, length,
+ &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
}
+
+ continue;
}
- } else {
- /* UTF-8 string. */
+ keys = njs_array_indices(vm, e);
+ if (njs_slow_path(keys == NULL)) {
+ return NJS_ERROR;
+ }
- for (i = from; i < to; i++) {
- pos = njs_utf8_next(p, end);
+ for (k = 0; k < keys->length; k++) {
+ ret = njs_value_property(vm, e, &keys->start[k], &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
- /* This cannot fail. */
- (void) njs_string_new(vm, &character, p, pos - p, 1);
+ idx = njs_string_to_index(&keys->start[k]) + length;
- ret = handler(vm, args, &character, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
+ if (ret == NJS_OK) {
+ ret = njs_value_property_i64_set(vm, &this, idx, &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ njs_array_destroy(vm, keys);
+ return ret;
}
-
- return NJS_ERROR;
}
-
- p = pos;
}
- }
- return NJS_OK;
- }
+ njs_array_destroy(vm, keys);
- if (!njs_is_object(value)) {
- return NJS_OK;
- }
+ length += len;
-process_object:
+ continue;
+ }
- if (!njs_fast_object(to - from)) {
- keys = njs_array_indices(vm, value);
- if (njs_slow_path(keys == NULL)) {
+ if (njs_slow_path((length + len) >= NJS_MAX_LENGTH)) {
+ njs_type_error(vm, "Invalid length");
return NJS_ERROR;
}
- for (i = 0; i < keys->length; i++) {
- idx = njs_string_to_index(&keys->start[i]);
-
- if (idx < from || idx >= to) {
- continue;
+ if (njs_is_fast_array(&this)) {
+ ret = njs_array_add(vm, array, e);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
- ret = njs_array_object_handler(vm, handler, args, &keys->start[i],
- idx);
- if (njs_slow_path(ret != NJS_OK)) {
- njs_array_destroy(vm, keys);
+ } else {
+ ret = njs_value_property_i64_set(vm, &this, length, e);
+ if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
}
- njs_array_destroy(vm, keys);
-
- return NJS_OK;
+ length++;
}
- for (i = from; i < to; i++) {
- ret = njs_array_object_handler(vm, handler, args, NULL, i);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ ret = njs_object_length_set(vm, &this, length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
}
+ vm->retval = this;
+
return NJS_OK;
}
-njs_inline njs_int_t
-njs_array_reverse_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
+static njs_int_t
+njs_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ int64_t i, length, start, end;
+ njs_int_t ret;
+ njs_array_t *array;
+ njs_value_t *this, *value;
+
+ this = njs_argument(args, 0);
+
+ ret = njs_value_to_object(vm, this);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ array = NULL;
+
+ if (njs_is_fast_array(this)) {
+ array = njs_array(this);
+ length = array->length;
+
+ } else {
+ ret = njs_object_length(vm, this, &length);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+ }
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ start = (start < 0) ? njs_max(length + start, 0) : njs_min(start, length);
+
+ if (njs_is_undefined(njs_arg(args, nargs, 3))) {
+ end = length;
+
+ } else {
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 3), &end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length);
+
+ value = njs_arg(args, nargs, 1);
+
+ if (array != NULL) {
+ for (i = start; i < end; i++) {
+ array->start[i] = *value;
+ }
+
+ vm->retval = *this;
+
+ return NJS_OK;
+ }
+
+ value = njs_arg(args, nargs, 1);
+
+ while (start < end) {
+ ret = njs_value_property_i64_set(vm, this, start++, value);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+ }
+
+ vm->retval = *this;
+
+ return NJS_OK;
+}
+
+
+njs_inline njs_int_t
+njs_array_iterator_call(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ const njs_value_t *entry, uint32_t n)
+{
+ njs_value_t arguments[3];
+
+ /* GC: array elt, array */
+
+ arguments[0] = *entry;
+ njs_set_number(&arguments[1], n);
+ arguments[2] = *args->value;
+
+ return njs_function_call(vm, args->function, args->argument, arguments, 3,
+ &vm->retval);
+}
+
+
+static njs_int_t
+njs_array_object_handler(njs_vm_t *vm, njs_array_iterator_handler_t handler,
+ njs_array_iterator_args_t *args, njs_value_t *key, int64_t i)
+{
+ njs_int_t ret;
+ njs_value_t prop, *entry;
+
+ if (key != NULL) {
+ ret = njs_value_property(vm, args->value, key, &prop);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ } else {
+ ret = njs_value_property_i64(vm, args->value, i, &prop);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+ }
+
+ entry = (ret == NJS_OK) ? &prop : njs_value_arg(&njs_value_invalid);
+
+ ret = handler(vm, args, entry, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret == NJS_DONE) {
+ return NJS_DONE;
+ }
+
+ return NJS_ERROR;
+ }
+
+ return ret;
+}
+
+
+njs_inline njs_int_t
+njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
njs_array_iterator_handler_t handler)
{
double idx;
- int64_t i, from, to, length;
+ int64_t length, i, from, to;
njs_int_t ret;
njs_array_t *array, *keys;
- njs_value_t *entry, *value, prop, character, string_obj;
+ njs_value_t *value, *entry, prop, character, string_obj;
njs_object_t *object;
const u_char *p, *end, *pos;
njs_string_prop_t string_prop;
if (njs_is_array(value)) {
array = njs_array(value);
- from += 1;
-
- while (from-- > to) {
+ for (; from < to; from++) {
if (njs_slow_path(!array->object.fast_array)) {
goto process_object;
}
}
if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
+ if (ret == NJS_DONE) {
+ return NJS_DONE;
}
return NJS_ERROR;
}
length = njs_string_prop(&string_prop, value);
- end = string_prop.start + string_prop.size;
+
+ p = string_prop.start;
+ end = p + string_prop.size;
if ((size_t) length == string_prop.size) {
/* Byte or ASCII string. */
- p = string_prop.start + from;
-
- i = from + 1;
-
- while (i-- > to) {
+ for (i = from; i < to; i++) {
/* This cannot fail. */
- (void) njs_string_new(vm, &character, p, 1, 1);
+ (void) njs_string_new(vm, &character, p + i, 1, 1);
ret = handler(vm, args, &character, i);
if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
+ if (ret == NJS_DONE) {
+ return NJS_DONE;
}
return NJS_ERROR;
}
-
- p--;
}
} else {
/* UTF-8 string. */
- p = njs_string_offset(string_prop.start, end, from);
- p = njs_utf8_next(p, end);
-
- i = from + 1;
-
- while (i-- > to) {
- pos = njs_utf8_prev(p);
+ for (i = from; i < to; i++) {
+ pos = njs_utf8_next(p, end);
/* This cannot fail. */
- (void) njs_string_new(vm, &character, pos, p - pos , 1);
+ (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;
+ if (ret == NJS_DONE) {
+ return NJS_DONE;
}
return NJS_ERROR;
process_object:
- if (!njs_fast_object(from - to)) {
+ if (!njs_fast_object(to - from)) {
keys = njs_array_indices(vm, value);
if (njs_slow_path(keys == NULL)) {
return NJS_ERROR;
}
- i = keys->length;
-
- while (i > 0) {
- idx = njs_string_to_index(&keys->start[--i]);
+ for (i = 0; i < keys->length; i++) {
+ idx = njs_string_to_index(&keys->start[i]);
- if (idx < to || idx > from) {
+ if (idx < from || idx >= to) {
continue;
}
return NJS_OK;
}
- i = from + 1;
-
- while (i-- > to) {
+ for (i = from; i < to; i++) {
ret = njs_array_object_handler(vm, handler, args, NULL, i);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
-njs_inline njs_int_t
-njs_is_concat_spreadable(njs_vm_t *vm, njs_value_t *value)
+static njs_int_t
+njs_array_handler_every(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, int64_t n)
{
- njs_int_t ret;
- njs_value_t retval;
+ njs_int_t ret;
- static const njs_value_t key =
- njs_wellknown_symbol(NJS_SYMBOL_IS_CONCAT_SPREADABLE);
+ if (njs_is_valid(entry)) {
+ ret = njs_array_iterator_call(vm, args, entry, n);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
- if (njs_slow_path(!njs_is_object(value))) {
- return NJS_DECLINED;
+ if (!njs_is_true(&vm->retval)) {
+ vm->retval = njs_value_false;
+ return NJS_DONE;
+ }
}
- ret = njs_value_property(vm, value, njs_value_arg(&key), &retval);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return NJS_ERROR;
- }
+ return NJS_OK;
+}
- if (njs_is_defined(&retval)) {
- return njs_bool(&retval) ? NJS_OK : NJS_DECLINED;
+
+static njs_int_t
+njs_array_handler_some(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, int64_t n)
+{
+ njs_int_t ret;
+
+ if (njs_is_valid(entry)) {
+ ret = njs_array_iterator_call(vm, args, entry, n);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_is_true(&vm->retval)) {
+ vm->retval = njs_value_true;
+ return NJS_DONE;
+ }
}
- return njs_is_array(value) ? NJS_OK : NJS_DECLINED;
+ 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)
+njs_array_handler_includes(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, int64_t n)
{
- double idx;
- int64_t k, len, length;
- njs_int_t ret;
- njs_uint_t i;
- njs_value_t this, retval, *value, *e;
- njs_array_t *array, *keys;
-
- ret = njs_value_to_object(vm, &args[0]);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
+ if (!njs_is_valid(entry)) {
+ entry = njs_value_arg(&njs_value_undefined);
}
- /* TODO: ArraySpeciesCreate(). */
+ if (njs_values_same_zero(args->argument, entry)) {
+ njs_set_true(&vm->retval);
- array = njs_array_alloc(vm, 0, 0, NJS_ARRAY_SPARE);
- if (njs_slow_path(array == NULL)) {
- return NJS_ERROR;
+ return NJS_DONE;
}
- njs_set_array(&this, array);
+ return NJS_OK;
+}
- len = 0;
- length = 0;
- for (i = 0; i < nargs; i++) {
- e = njs_argument(args, i);
+static njs_int_t
+njs_array_handler_index_of(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, int64_t n)
+{
+ if (njs_values_strict_equal(args->argument, entry)) {
+ njs_set_number(&vm->retval, n);
- ret = njs_is_concat_spreadable(vm, e);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return NJS_ERROR;
- }
-
- if (ret == NJS_OK) {
- ret = njs_object_length(vm, e, &len);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
-
- if (njs_slow_path((length + len) > NJS_MAX_LENGTH)) {
- njs_type_error(vm, "Invalid length");
- return NJS_ERROR;
- }
-
- if (njs_is_fast_array(&this) && njs_is_fast_array(e)
- && (length + len) <= NJS_ARRAY_LARGE_OBJECT_LENGTH)
- {
- for (k = 0; k < len; k++, length++) {
- value = &njs_array_start(e)[k];
-
- if (njs_slow_path(!njs_is_valid(value))) {
- ret = njs_value_property_i64(vm, e, k, &retval);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
-
- if (ret == NJS_DECLINED) {
- njs_set_invalid(&retval);
- }
-
- value = &retval;
- }
-
- ret = njs_array_add(vm, array, value);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- }
- }
-
- continue;
- }
-
- if (njs_fast_object(len)) {
- for (k = 0; k < len; k++, length++) {
- ret = njs_value_property_i64(vm, e, k, &retval);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
-
- if (ret != NJS_OK) {
- continue;
- }
-
- ret = njs_value_property_i64_set(vm, &this, length,
- &retval);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
- }
-
- continue;
- }
-
- keys = njs_array_indices(vm, e);
- if (njs_slow_path(keys == NULL)) {
- return NJS_ERROR;
- }
-
- for (k = 0; k < keys->length; k++) {
- ret = njs_value_property(vm, e, &keys->start[k], &retval);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
-
- idx = njs_string_to_index(&keys->start[k]) + length;
-
- if (ret == NJS_OK) {
- ret = njs_value_property_i64_set(vm, &this, idx, &retval);
- if (njs_slow_path(ret == NJS_ERROR)) {
- njs_array_destroy(vm, keys);
- return ret;
- }
- }
- }
-
- njs_array_destroy(vm, keys);
-
- length += len;
-
- continue;
- }
-
- if (njs_slow_path((length + len) >= NJS_MAX_LENGTH)) {
- njs_type_error(vm, "Invalid length");
- return NJS_ERROR;
- }
-
- if (njs_is_fast_array(&this)) {
- ret = njs_array_add(vm, array, e);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- } else {
- ret = njs_value_property_i64_set(vm, &this, length, e);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
- }
-
- length++;
- }
-
- ret = njs_object_length_set(vm, &this, length);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- }
-
- vm->retval = this;
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_array_handler_index_of(njs_vm_t *vm, njs_array_iterator_args_t *args,
- njs_value_t *entry, int64_t n)
-{
- if (njs_values_strict_equal(args->argument, entry)) {
- njs_set_number(&vm->retval, n);
-
- return 1;
+ return NJS_DONE;
}
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, length;
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
-
- iargs.value = njs_argument(args, 0);
-
- ret = njs_value_to_object(vm, iargs.value);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- iargs.argument = njs_arg(args, nargs, 1);
-
- ret = njs_value_length(vm, iargs.value, &length);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- if (length == 0 || from >= (int64_t) length) {
- goto not_found;
- }
-
- if (from < 0) {
- from = length + from;
-
- if (from < 0) {
- from = 0;
- }
- }
-
- iargs.from = from;
- iargs.to = length;
-
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_index_of);
- if (njs_fast_path(ret != NJS_OK)) {
- return (ret == NJS_DECLINED) ? NJS_OK : NJS_ERROR;
- }
-
-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, length;
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
-
- iargs.value = njs_argument(args, 0);
-
- ret = njs_value_to_object(vm, iargs.value);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- 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) {
- ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- } 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_OK)) {
- return (ret == NJS_DECLINED) ? NJS_OK : NJS_ERROR;
- }
-
-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, int64_t n)
-{
- if (!njs_is_valid(entry)) {
- entry = njs_value_arg(&njs_value_undefined);
- }
-
- if (njs_values_same_zero(args->argument, 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, length;
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
-
- iargs.value = njs_argument(args, 0);
-
- ret = njs_value_to_object(vm, iargs.value);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- 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;
- }
-
- ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- if (from < 0) {
- from += length;
-
- if (from < 0) {
- from = 0;
- }
- }
-
- iargs.from = from;
- iargs.to = length;
-
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_includes);
- if (njs_fast_path(ret != NJS_OK)) {
- return (ret == NJS_DECLINED) ? NJS_OK : NJS_ERROR;
- }
-
-not_found:
-
- njs_set_false(&vm->retval);
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- int64_t i, length, start, end;
- njs_int_t ret;
- njs_array_t *array;
- njs_value_t *this, *value;
-
- this = njs_argument(args, 0);
-
- ret = njs_value_to_object(vm, this);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- array = NULL;
-
- if (njs_is_fast_array(this)) {
- array = njs_array(this);
- length = array->length;
-
- } else {
- ret = njs_object_length(vm, this, &length);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
- }
-
- ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &start);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- start = (start < 0) ? njs_max(length + start, 0) : njs_min(start, length);
-
- if (njs_is_undefined(njs_arg(args, nargs, 3))) {
- end = length;
-
- } else {
- ret = njs_value_to_integer(vm, njs_arg(args, nargs, 3), &end);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
- }
-
- end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length);
-
- value = njs_arg(args, nargs, 1);
-
- if (array != NULL) {
- for (i = start; i < end; i++) {
- array->start[i] = *value;
- }
-
- vm->retval = *this;
-
- return NJS_OK;
- }
-
- value = njs_arg(args, nargs, 1);
-
- while (start < end) {
- ret = njs_value_property_i64_set(vm, this, start++, value);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
- }
-
- vm->retval = *this;
-
- return NJS_OK;
-}
-
-
-njs_inline njs_int_t
-njs_array_iterator_call(njs_vm_t *vm, njs_array_iterator_args_t *args,
- const njs_value_t *entry, uint32_t n)
-{
- njs_value_t arguments[3];
-
- /* GC: array elt, array */
-
- arguments[0] = *entry;
- njs_set_number(&arguments[1], n);
- arguments[2] = *args->value;
-
- return njs_function_call(vm, args->function, args->argument, arguments, 3,
- &vm->retval);
-}
-
-
-njs_inline njs_int_t
-njs_array_validate_args(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_array_iterator_args_t *iargs)
-{
- njs_int_t ret;
-
- iargs->value = njs_argument(args, 0);
-
- ret = njs_value_to_object(vm, iargs->value);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- ret = njs_value_length(vm, iargs->value, &iargs->to);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
- goto failed;
- }
-
- iargs->from = 0;
- iargs->function = njs_function(njs_argument(args, 1));
- iargs->argument = njs_arg(args, nargs, 2);
-
- return NJS_OK;
-
-failed:
-
- njs_type_error(vm, "unexpected iterator arguments");
-
- return NJS_ERROR;
-}
-
-
static njs_int_t
njs_array_handler_for_each(njs_vm_t *vm, njs_array_iterator_args_t *args,
njs_value_t *entry, int64_t n)
static njs_int_t
-njs_array_prototype_for_each(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
-
- ret = njs_array_validate_args(vm, args, nargs, &iargs);
- 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;
- }
-
- njs_set_undefined(&vm->retval);
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_array_handler_some(njs_vm_t *vm, njs_array_iterator_args_t *args,
+njs_array_handler_find(njs_vm_t *vm, njs_array_iterator_args_t *args,
njs_value_t *entry, int64_t n)
{
- njs_int_t ret;
+ njs_int_t ret;
+ njs_value_t copy;
if (njs_is_valid(entry)) {
- ret = njs_array_iterator_call(vm, args, entry, n);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- if (njs_is_true(&vm->retval)) {
- vm->retval = njs_value_true;
+ copy = *entry;
- return 1;
- }
+ } else {
+ njs_set_undefined(©);
}
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_array_prototype_some(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
-
- ret = njs_array_validate_args(vm, args, nargs, &iargs);
+ ret = njs_array_iterator_call(vm, args, ©, n);
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;
- }
+ if (njs_is_true(&vm->retval)) {
+ vm->retval = copy;
- if (ret != NJS_DECLINED) {
- vm->retval = njs_value_false;
+ return NJS_DONE;
}
return NJS_OK;
static njs_int_t
-njs_array_handler_every(njs_vm_t *vm, njs_array_iterator_args_t *args,
+njs_array_handler_find_index(njs_vm_t *vm, njs_array_iterator_args_t *args,
njs_value_t *entry, int64_t n)
{
- njs_int_t ret;
+ njs_int_t ret;
+ njs_value_t copy;
if (njs_is_valid(entry)) {
- ret = njs_array_iterator_call(vm, args, entry, n);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ copy = *entry;
- if (!njs_is_true(&vm->retval)) {
- vm->retval = njs_value_false;
+ } else {
+ njs_set_undefined(©);
+ }
- return 1;
- }
+ ret = njs_array_iterator_call(vm, args, ©, n);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_is_true(&vm->retval)) {
+ njs_set_number(&vm->retval, n);
+
+ return NJS_DONE;
}
return NJS_OK;
static njs_int_t
-njs_array_prototype_every(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
+njs_array_handler_reduce(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, int64_t n)
{
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
+ njs_int_t ret;
+ njs_value_t arguments[5];
- ret = njs_array_validate_args(vm, args, nargs, &iargs);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ if (njs_is_valid(entry)) {
+ if (!njs_is_valid(args->argument)) {
+ *(args->argument) = *entry;
+ return NJS_OK;
+ }
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_every);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
+ /* GC: array elt, array */
- if (ret != NJS_DECLINED) {
- vm->retval = njs_value_true;
+ njs_set_undefined(&arguments[0]);
+ arguments[1] = *args->argument;
+ arguments[2] = *entry;
+ njs_set_number(&arguments[3], n);
+ arguments[4] = *args->value;
+
+ ret = njs_function_apply(vm, args->function, arguments, 5,
+ args->argument);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
}
return NJS_OK;
}
if (njs_is_true(&vm->retval)) {
-
ret = njs_array_add(vm, args->array, ©);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
static njs_int_t
-njs_array_prototype_filter(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
+njs_array_handler_map(njs_vm_t *vm, njs_array_iterator_args_t *args,
+ njs_value_t *entry, int64_t n)
{
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
+ njs_int_t ret;
+ njs_array_t *retval;
+ njs_value_t this;
- ret = njs_array_validate_args(vm, args, nargs, &iargs);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ retval = args->array;
- iargs.array = njs_array_alloc(vm, 0, 0, NJS_ARRAY_SPARE);
- if (njs_slow_path(iargs.array == NULL)) {
- return NJS_ERROR;
+ if (retval->object.fast_array) {
+ njs_set_invalid(&retval->start[n]);
}
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_filter);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ if (njs_is_valid(entry)) {
+ ret = njs_array_iterator_call(vm, args, entry, n);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_is_valid(&vm->retval)) {
+ if (retval->object.fast_array) {
+ retval->start[n] = vm->retval;
+
+ } else {
+ njs_set_array(&this, retval);
- njs_set_array(&vm->retval, iargs.array);
+ ret = njs_value_property_i64_set(vm, &this, n, &vm->retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+ }
+ }
return NJS_OK;
}
static njs_int_t
-njs_array_handler_find(njs_vm_t *vm, njs_array_iterator_args_t *args,
- njs_value_t *entry, int64_t n)
+njs_array_prototype_iterator(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t magic)
{
- njs_int_t ret;
- njs_value_t copy;
+ int64_t i, length;
+ njs_int_t ret;
+ njs_array_t *array;
+ njs_value_t accumulator;
+ njs_array_iterator_args_t iargs;
+ njs_array_iterator_handler_t handler;
- if (njs_is_valid(entry)) {
- copy = *entry;
+ iargs.value = njs_argument(args, 0);
- } else {
- njs_set_undefined(©);
+ ret = njs_value_to_object(vm, iargs.value);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
- ret = njs_array_iterator_call(vm, args, ©, n);
+ ret = njs_value_length(vm, iargs.value, &iargs.to);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- if (njs_is_true(&vm->retval)) {
- vm->retval = copy;
+ iargs.from = 0;
+
+ if (njs_array_arg1(magic) == NJS_ARRAY_FUNC) {
+ if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
+ njs_type_error(vm, "callback argument is not callable");
+ return NJS_ERROR;
+ }
+
+ iargs.function = njs_function(njs_argument(args, 1));
+ iargs.argument = njs_arg(args, nargs, 2);
- return 1;
+ } else {
+ iargs.argument = njs_arg(args, nargs, 1);
}
- return NJS_OK;
-}
+ switch (njs_array_type(magic)) {
+ case NJS_ARRAY_EVERY:
+ handler = njs_array_handler_every;
+ break;
+ case NJS_ARRAY_SOME:
+ handler = njs_array_handler_some;
+ break;
-static njs_int_t
-njs_array_prototype_find(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
+ case NJS_ARRAY_INCLUDES:
+ case NJS_ARRAY_INDEX_OF:
+ switch (njs_array_type(magic)) {
+ case NJS_ARRAY_INCLUDES:
+ handler = njs_array_handler_includes;
- ret = njs_array_validate_args(vm, args, nargs, &iargs);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ if (iargs.to == 0) {
+ goto done;
+ }
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_find);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
+ break;
- if (ret != NJS_DECLINED) {
- vm->retval = njs_value_undefined;
- }
+ default:
+ handler = njs_array_handler_index_of;
+ }
- return NJS_OK;
-}
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &iargs.from);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ if (iargs.from < 0) {
+ iargs.from += iargs.to;
-static njs_int_t
-njs_array_handler_find_index(njs_vm_t *vm, njs_array_iterator_args_t *args,
- njs_value_t *entry, int64_t n)
-{
- njs_int_t ret;
- njs_value_t copy;
+ if (iargs.from < 0) {
+ iargs.from = 0;
+ }
+ }
- if (njs_is_valid(entry)) {
- copy = *entry;
+ break;
- } else {
- njs_set_undefined(©);
- }
+ case NJS_ARRAY_FOR_EACH:
+ handler = njs_array_handler_for_each;
+ break;
- ret = njs_array_iterator_call(vm, args, ©, n);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ case NJS_ARRAY_FIND:
+ handler = njs_array_handler_find;
+ break;
- if (njs_is_true(&vm->retval)) {
- njs_set_number(&vm->retval, n);
+ case NJS_ARRAY_FIND_INDEX:
+ handler = njs_array_handler_find_index;
+ break;
- return 1;
- }
+ case NJS_ARRAY_REDUCE:
+ handler = njs_array_handler_reduce;
- return NJS_OK;
-}
+ njs_set_invalid(&accumulator);
+ if (nargs > 2) {
+ accumulator = *iargs.argument;
+ }
-static njs_int_t
-njs_array_prototype_find_index(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
-{
- njs_int_t ret;
- njs_array_iterator_args_t iargs;
+ iargs.argument = &accumulator;
+ break;
- ret = njs_array_validate_args(vm, args, nargs, &iargs);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
+ case NJS_ARRAY_FILTER:
+ case NJS_ARRAY_MAP:
+ default:
+ if (njs_array_type(magic) == NJS_ARRAY_FILTER) {
+ length = 0;
+ handler = njs_array_handler_filter;
+
+ } else {
+ length = iargs.to;
+ handler = njs_array_handler_map;
+ }
+
+ array = njs_array_alloc(vm, 0, length, NJS_ARRAY_SPARE);
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if (array->object.fast_array) {
+ for (i = 0; i < length; i++) {
+ njs_set_invalid(&array->start[i]);
+ }
+ }
+
+ iargs.array = array;
+
+ break;
}
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_find_index);
+ ret = njs_array_iterator(vm, &iargs, handler);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
- if (ret != NJS_DECLINED) {
+ if (ret == NJS_DONE) {
+ return NJS_OK;
+ }
+
+done:
+
+ /* Default values. */
+
+ switch (njs_array_type(magic)) {
+ case NJS_ARRAY_EVERY:
+ vm->retval = njs_value_true;
+ break;
+
+ case NJS_ARRAY_SOME:
+ case NJS_ARRAY_INCLUDES:
+ vm->retval = njs_value_false;
+ break;
+
+ case NJS_ARRAY_INDEX_OF:
+ case NJS_ARRAY_FIND_INDEX:
njs_set_number(&vm->retval, -1);
+ break;
+
+ case NJS_ARRAY_FOR_EACH:
+ case NJS_ARRAY_FIND:
+ njs_set_undefined(&vm->retval);
+ break;
+
+ case NJS_ARRAY_REDUCE:
+ if (!njs_is_valid(&accumulator)) {
+ njs_type_error(vm, "Reduce of empty object with no initial value");
+ return NJS_ERROR;
+ }
+
+ vm->retval = accumulator;
+ break;
+
+ case NJS_ARRAY_FILTER:
+ case NJS_ARRAY_MAP:
+ default:
+ njs_set_array(&vm->retval, iargs.array);
}
return NJS_OK;
}
-static njs_int_t
-njs_array_handler_map(njs_vm_t *vm, njs_array_iterator_args_t *args,
- njs_value_t *entry, int64_t n)
+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 ret;
- njs_array_t *retval;
- njs_value_t this;
+ double idx;
+ int64_t i, from, to, length;
+ njs_int_t ret;
+ njs_array_t *array, *keys;
+ njs_value_t *entry, *value, prop, character, string_obj;
+ njs_object_t *object;
+ const u_char *p, *end, *pos;
+ njs_string_prop_t string_prop;
- retval = args->array;
+ value = args->value;
+ from = args->from;
+ to = args->to;
- if (retval->object.fast_array) {
- njs_set_invalid(&retval->start[n]);
- }
+ if (njs_is_array(value)) {
+ array = njs_array(value);
- if (njs_is_valid(entry)) {
- ret = njs_array_iterator_call(vm, args, entry, n);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
+ from += 1;
+
+ while (from-- > to) {
+ if (njs_slow_path(!array->object.fast_array)) {
+ goto process_object;
+ }
+
+ if (njs_fast_path(from < array->length
+ && njs_is_valid(&array->start[from])))
+ {
+ ret = handler(vm, args, &array->start[from], from);
+
+ } else {
+ entry = njs_value_arg(&njs_value_invalid);
+ ret = njs_value_property_i64(vm, value, from, &prop);
+ if (njs_slow_path(ret != NJS_DECLINED)) {
+ if (ret == NJS_ERROR) {
+ return NJS_ERROR;
+ }
+
+ entry = ∝
+ }
+
+ ret = handler(vm, args, entry, from);
+ }
+
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret == NJS_DONE) {
+ return NJS_DONE;
+ }
+
+ return NJS_ERROR;
+ }
}
- if (njs_is_valid(&vm->retval)) {
- if (retval->object.fast_array) {
- retval->start[n] = vm->retval;
+ 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;
+ }
- } else {
- njs_set_array(&this, retval);
+ njs_set_type_object(&string_obj, object, NJS_OBJECT_STRING);
- ret = njs_value_property_i64_set(vm, &this, n, &vm->retval);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
- }
+ args->value = &string_obj;
+ }
+ else {
+ value = njs_object_value(value);
}
- }
- return NJS_OK;
-}
+ length = njs_string_prop(&string_prop, value);
+ end = string_prop.start + string_prop.size;
+ if ((size_t) length == string_prop.size) {
+ /* Byte or ASCII string. */
-static njs_int_t
-njs_array_prototype_map(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- int64_t i, length;
- njs_int_t ret;
- njs_array_t *array;
- njs_value_t *this;
- njs_array_iterator_args_t iargs;
+ p = string_prop.start + from;
- this = njs_argument(args, 0);
+ i = from + 1;
- ret = njs_value_to_object(vm, this);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ while (i-- > to) {
+ /* This cannot fail. */
+ (void) njs_string_new(vm, &character, p, 1, 1);
- ret = njs_value_length(vm, this, &length);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ ret = handler(vm, args, &character, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret == NJS_DONE) {
+ return NJS_DONE;
+ }
- if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
- goto unexpected_args;
- }
+ return NJS_ERROR;
+ }
- iargs.array = njs_array_alloc(vm, 0, length, 0);
- if (njs_slow_path(iargs.array == NULL)) {
- return NJS_ERROR;
- }
+ p--;
+ }
- if (njs_slow_path(length == 0)) {
- goto done;
- }
+ } else {
+ /* UTF-8 string. */
- iargs.from = 0;
- iargs.to = length;
- iargs.value = this;
- iargs.function = njs_function(njs_argument(args, 1));
- iargs.argument = njs_arg(args, nargs, 2);
+ p = njs_string_offset(string_prop.start, end, from);
+ p = njs_utf8_next(p, end);
- if (iargs.array->object.fast_array) {
- array = iargs.array;
+ i = from + 1;
- for (i = 0; i < length; i++) {
- njs_set_invalid(&array->start[i]);
- }
- }
+ while (i-- > to) {
+ pos = njs_utf8_prev(p);
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_map);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ /* This cannot fail. */
+ (void) njs_string_new(vm, &character, pos, p - pos , 1);
-done:
+ ret = handler(vm, args, &character, i);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret == NJS_DONE) {
+ return NJS_DONE;
+ }
- njs_set_array(&vm->retval, iargs.array);
+ return NJS_ERROR;
+ }
- return NJS_OK;
+ p = pos;
+ }
+ }
-unexpected_args:
+ return NJS_OK;
+ }
- njs_type_error(vm, "unexpected iterator arguments");
+ if (!njs_is_object(value)) {
+ return NJS_OK;
+ }
- return NJS_ERROR;
-}
+process_object:
+ if (!njs_fast_object(from - to)) {
+ keys = njs_array_indices(vm, value);
+ if (njs_slow_path(keys == NULL)) {
+ return NJS_ERROR;
+ }
-njs_inline njs_int_t
-njs_array_iterator_reduce(njs_vm_t *vm, njs_array_iterator_args_t *args,
- njs_value_t *entry, int64_t n)
-{
- njs_value_t arguments[5];
+ i = keys->length;
- /* GC: array elt, array */
+ while (i > 0) {
+ idx = njs_string_to_index(&keys->start[--i]);
- njs_set_undefined(&arguments[0]);
- arguments[1] = *args->argument;
- arguments[2] = *entry;
- njs_set_number(&arguments[3], n);
- arguments[4] = *args->value;
+ if (idx < to || idx > from) {
+ continue;
+ }
- return njs_function_apply(vm, args->function, arguments, 5, args->argument);
-}
+ ret = njs_array_object_handler(vm, handler, args, &keys->start[i],
+ idx);
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_array_destroy(vm, keys);
+ return ret;
+ }
+ }
+ njs_array_destroy(vm, keys);
-static njs_int_t
-njs_array_handler_reduce(njs_vm_t *vm, njs_array_iterator_args_t *args,
- njs_value_t *entry, int64_t n)
-{
- njs_int_t ret;
+ return NJS_OK;
+ }
- if (njs_is_valid(entry)) {
- if (!njs_is_valid(args->argument)) {
- *(args->argument) = *entry;
- return NJS_OK;
- }
+ i = from + 1;
- ret = njs_array_iterator_reduce(vm, args, entry, n);
+ while (i-- > to) {
+ ret = njs_array_object_handler(vm, handler, args, NULL, i);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
static njs_int_t
-njs_array_prototype_reduce(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
+njs_array_prototype_reverse_iterator(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t type)
{
- njs_int_t ret;
- njs_value_t accumulator;
- njs_array_iterator_args_t iargs;
+ int64_t from, length;
+ njs_int_t ret;
+ njs_value_t accumulator;
+ njs_array_iterator_args_t iargs;
+ njs_array_iterator_handler_t handler;
+
+ iargs.value = njs_argument(args, 0);
- ret = njs_array_validate_args(vm, args, nargs, &iargs);
+ ret = njs_value_to_object(vm, iargs.value);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- njs_set_invalid(&accumulator);
-
- if (nargs > 2) {
- accumulator = *iargs.argument;
- }
-
- iargs.argument = &accumulator;
+ iargs.argument = njs_arg(args, nargs, 1);
- ret = njs_array_iterator(vm, &iargs, njs_array_handler_reduce);
+ ret = njs_value_length(vm, iargs.value, &length);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- if (!njs_is_valid(&accumulator)) {
- njs_type_error(vm, "Reduce of empty object with no initial value");
- return NJS_ERROR;
- }
+ switch (type) {
+ case NJS_ARRAY_LAST_INDEX_OF:
+ handler = njs_array_handler_index_of;
- vm->retval = accumulator;
+ if (length == 0) {
+ goto done;
+ }
- return NJS_OK;
-}
+ if (nargs > 2) {
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ } else {
+ from = length - 1;
+ }
-static njs_int_t
-njs_array_prototype_reduce_right(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
-{
- njs_int_t ret;
- njs_value_t accumulator;
- njs_array_iterator_args_t iargs;
+ if (from >= 0) {
+ from = njs_min(from, length - 1);
- iargs.value = njs_argument(args, 0);
+ } else if (from < 0) {
+ from += length;
+ }
- ret = njs_value_to_object(vm, iargs.value);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ break;
- ret = njs_value_length(vm, iargs.value, &iargs.from);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
+ case NJS_ARRAY_REDUCE_RIGHT:
+ default:
+ handler = njs_array_handler_reduce;
- if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
- goto unexpected_args;
- }
+ if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
+ njs_type_error(vm, "callback argument is not callable");
+ return NJS_ERROR;
+ }
- njs_set_invalid(&accumulator);
+ njs_set_invalid(&accumulator);
- iargs.to = 0;
- iargs.function = njs_function(njs_argument(args, 1));
- iargs.argument = &accumulator;
+ iargs.function = njs_function(njs_argument(args, 1));
+ iargs.argument = &accumulator;
- if (nargs > 2) {
- accumulator = *njs_argument(args, 2);
- }
+ if (nargs > 2) {
+ accumulator = *njs_argument(args, 2);
- if (iargs.from == 0) {
- if (nargs < 3) {
- goto failed;
+ } else if (length == 0) {
+ goto done;
}
- goto done;
+ from = length - 1;
+ break;
}
- iargs.from--;
+ iargs.from = from;
+ iargs.to = 0;
- ret = njs_array_reverse_iterator(vm, &iargs, njs_array_handler_reduce);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
+ ret = njs_array_reverse_iterator(vm, &iargs, handler);
+ if (njs_fast_path(ret == NJS_ERROR)) {
+ return NJS_ERROR;
}
- if (!njs_is_valid(&accumulator)) {
- goto failed;
+ if (ret == NJS_DONE) {
+ return NJS_OK;
}
done:
- vm->retval = accumulator;
-
- return NJS_OK;
-
-failed:
-
- njs_type_error(vm, "Reduce of empty object with no initial value");
-
- return NJS_ERROR;
+ switch (type) {
+ case NJS_ARRAY_LAST_INDEX_OF:
+ njs_set_number(&vm->retval, -1);
+ break;
-unexpected_args:
+ case NJS_ARRAY_REDUCE_RIGHT:
+ default:
+ if (!njs_is_valid(&accumulator)) {
+ njs_type_error(vm, "Reduce of empty object with no initial value");
+ return NJS_ERROR;
+ }
- njs_type_error(vm, "unexpected iterator arguments");
+ vm->retval = accumulator;
+ break;
+ }
- return NJS_ERROR;
+ return NJS_OK;
}
{
.type = NJS_PROPERTY,
- .name = njs_string("slice"),
- .value = njs_native_function(njs_array_prototype_slice, 2),
+ .name = njs_string("concat"),
+ .value = njs_native_function(njs_array_prototype_concat, 1),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("push"),
- .value = njs_native_function(njs_array_prototype_push, 1),
+ .name = njs_string("copyWithin"),
+ .value = njs_native_function(njs_array_prototype_copy_within, 2),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("pop"),
- .value = njs_native_function(njs_array_prototype_pop, 0),
+ .name = njs_string("every"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_func(NJS_ARRAY_EVERY)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("unshift"),
- .value = njs_native_function(njs_array_prototype_unshift, 1),
+ .name = njs_string("fill"),
+ .value = njs_native_function(njs_array_prototype_fill, 1),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("shift"),
- .value = njs_native_function(njs_array_prototype_shift, 0),
+ .name = njs_string("filter"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_func(NJS_ARRAY_FILTER)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("splice"),
- .value = njs_native_function(njs_array_prototype_splice, 2),
+ .name = njs_string("find"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_func(NJS_ARRAY_FIND)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("reverse"),
- .value = njs_native_function(njs_array_prototype_reverse, 0),
+ .name = njs_string("findIndex"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_func(NJS_ARRAY_FIND_INDEX)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("toString"),
- .value = njs_native_function(njs_array_prototype_to_string, 0),
+ .name = njs_string("forEach"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_func(NJS_ARRAY_FOR_EACH)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("join"),
- .value = njs_native_function(njs_array_prototype_join, 1),
+ .name = njs_string("includes"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_arg(NJS_ARRAY_INCLUDES)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("concat"),
- .value = njs_native_function(njs_array_prototype_concat, 1),
+ .name = njs_string("indexOf"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_arg(NJS_ARRAY_INDEX_OF)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("indexOf"),
- .value = njs_native_function(njs_array_prototype_index_of, 1),
+ .name = njs_string("join"),
+ .value = njs_native_function(njs_array_prototype_join, 1),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("lastIndexOf"),
- .value = njs_native_function(njs_array_prototype_last_index_of, 1),
+ .value = njs_native_function2(njs_array_prototype_reverse_iterator, 1,
+ NJS_ARRAY_LAST_INDEX_OF),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("includes"),
- .value = njs_native_function(njs_array_prototype_includes, 1),
+ .name = njs_string("map"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_func(NJS_ARRAY_MAP)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("forEach"),
- .value = njs_native_function(njs_array_prototype_for_each, 1),
+ .name = njs_string("pop"),
+ .value = njs_native_function(njs_array_prototype_pop, 0),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("some"),
- .value = njs_native_function(njs_array_prototype_some, 1),
+ .name = njs_string("push"),
+ .value = njs_native_function(njs_array_prototype_push, 1),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("every"),
- .value = njs_native_function(njs_array_prototype_every, 1),
+ .name = njs_string("reduce"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_func(NJS_ARRAY_REDUCE)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("fill"),
- .value = njs_native_function(njs_array_prototype_fill, 1),
+ .name = njs_string("reduceRight"),
+ .value = njs_native_function2(njs_array_prototype_reverse_iterator, 1,
+ NJS_ARRAY_REDUCE_RIGHT),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("filter"),
- .value = njs_native_function(njs_array_prototype_filter, 1),
+ .name = njs_string("reverse"),
+ .value = njs_native_function(njs_array_prototype_reverse, 0),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("find"),
- .value = njs_native_function(njs_array_prototype_find, 1),
+ .name = njs_string("shift"),
+ .value = njs_native_function(njs_array_prototype_shift, 0),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("findIndex"),
- .value = njs_native_function(njs_array_prototype_find_index, 1),
+ .name = njs_string("slice"),
+ .value = njs_native_function(njs_array_prototype_slice, 2),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("map"),
- .value = njs_native_function(njs_array_prototype_map, 1),
+ .name = njs_string("some"),
+ .value = njs_native_function2(njs_array_prototype_iterator, 1,
+ njs_array_func(NJS_ARRAY_SOME)),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("reduce"),
- .value = njs_native_function(njs_array_prototype_reduce, 1),
+ .name = njs_string("sort"),
+ .value = njs_native_function(njs_array_prototype_sort, 1),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("reduceRight"),
- .value = njs_native_function(njs_array_prototype_reduce_right, 1),
+ .name = njs_string("splice"),
+ .value = njs_native_function(njs_array_prototype_splice, 2),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("sort"),
- .value = njs_native_function(njs_array_prototype_sort, 1),
+ .name = njs_string("toString"),
+ .value = njs_native_function(njs_array_prototype_to_string, 0),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
- .name = njs_string("copyWithin"),
- .value = njs_native_function(njs_array_prototype_copy_within, 2),
+ .name = njs_string("unshift"),
+ .value = njs_native_function(njs_array_prototype_unshift, 1),
.writable = 1,
.configurable = 1,
},