]> git.kaiwu.me - njs.git/commitdiff
Added remaining methods for %TypedArray%.prototype.
authorDmitry Volyntsev <xeioex@nginx.com>
Fri, 21 Aug 2020 13:07:48 +0000 (13:07 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Fri, 21 Aug 2020 13:07:48 +0000 (13:07 +0000)
The following methods were added:
every(), filter(), find(), findIndex(), forEach(), includes(),
indexOf(), lastIndexOf(), map(), reduce(), reduceRight(), reverse(),
some().

src/njs_typed_array.c
src/njs_utils.c
src/njs_utils.h
src/test/njs_unit_test.c

index cf4543cbabbf72de0468a28557176ae87b032e0f..8f55d34cc6a51ab808c89422086ede68bcaaebe0 100644 (file)
@@ -8,6 +8,17 @@
 #include <njs_main.h>
 
 
+typedef enum {
+    NJS_ARRAY_EVERY = 0,
+    NJS_ARRAY_FOR_EACH,
+    NJS_ARRAY_SOME,
+    NJS_ARRAY_FIND,
+    NJS_ARRAY_FIND_INDEX,
+    NJS_ARRAY_FILTER,
+    NJS_ARRAY_MAP,
+} njs_array_iterator_fun_t;
+
+
 njs_typed_array_t *
 njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_object_type_t type)
@@ -826,6 +837,558 @@ njs_typed_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args,
 }
 
 
+static njs_int_t
+njs_typed_array_prototype_iterator(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t type)
+{
+    double             val;
+    int64_t            i, length;
+    njs_int_t          ret;
+    njs_arr_t          results;
+    njs_value_t        *this, *this_arg, *r;
+    njs_value_t        arguments[4], retval;
+    njs_function_t     *function;
+    njs_typed_array_t  *array, *dst;
+
+    this = njs_argument(args, 0);
+    if (njs_slow_path(!njs_is_typed_array(this))) {
+        njs_type_error(vm, "this is not a typed array");
+        return NJS_ERROR;
+    }
+
+    dst = NULL;
+    array = njs_typed_array(this);
+    length = njs_typed_array_length(array);
+
+    if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
+        njs_type_error(vm, "callback argument is not callable");
+        return NJS_ERROR;
+    }
+
+    function = njs_function(njs_argument(args, 1));
+    this_arg = njs_arg(args, nargs, 2);
+
+    results.separate = 0;
+    results.pointer = 0;
+
+    switch (type) {
+    case NJS_ARRAY_MAP:
+        njs_set_number(&arguments[0], length);
+        ret = njs_typed_array_species_create(vm, this, njs_value_arg(arguments),
+                                             1, &retval);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return NJS_ERROR;
+        }
+
+        dst = njs_typed_array(&retval);
+        break;
+
+    case NJS_ARRAY_FILTER:
+        r = njs_arr_init(vm->mem_pool, &results, NULL, 4, sizeof(njs_value_t));
+        if (njs_slow_path(r == NULL)) {
+            return NJS_ERROR;
+        }
+
+    default:
+        break;
+    }
+
+    for (i = 0; i < length; i++) {
+        val = njs_typed_array_get(array, i);
+
+        arguments[0] = *this_arg;
+        njs_set_number(&arguments[1], val);
+        njs_set_number(&arguments[2], i);
+        njs_set_typed_array(&arguments[3], array);
+
+        ret = njs_function_apply(vm, function, arguments, 4, &vm->retval);
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto exception;
+        }
+
+        switch (type) {
+        case NJS_ARRAY_EVERY:
+            if (!njs_is_true(&vm->retval)) {
+                vm->retval = njs_value_false;
+                goto done;
+            }
+
+            break;
+
+        case NJS_ARRAY_FOR_EACH:
+            break;
+
+        case NJS_ARRAY_SOME:
+        case NJS_ARRAY_FIND:
+        case NJS_ARRAY_FIND_INDEX:
+            if (!njs_is_true(&vm->retval)) {
+                continue;
+            }
+
+            switch (type) {
+            case NJS_ARRAY_SOME:
+                vm->retval = njs_value_true;
+                break;
+
+            case NJS_ARRAY_FIND:
+                njs_set_number(&vm->retval, val);
+                break;
+
+            default:
+                njs_set_number(&vm->retval, i);
+                break;
+            }
+
+            goto done;
+
+        case NJS_ARRAY_MAP:
+            ret = njs_typed_array_set_value(vm, dst, i, &vm->retval);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto exception;
+            }
+
+            break;
+
+        default:
+            /* NJS_ARRAY_FILTER. */
+
+            if (!njs_is_true(&vm->retval)) {
+                continue;
+            }
+
+            r = njs_arr_add(&results);
+            if (njs_slow_path(r == NULL)) {
+                goto exception;
+            }
+
+            njs_set_number(r, val);
+        }
+    }
+
+    /* Default values. */
+
+    switch (type) {
+    case NJS_ARRAY_EVERY:
+        vm->retval = njs_value_true;
+        break;
+
+    case NJS_ARRAY_SOME:
+        vm->retval = njs_value_false;
+        break;
+
+    case NJS_ARRAY_FOR_EACH:
+    case NJS_ARRAY_FIND:
+        njs_set_undefined(&vm->retval);
+        break;
+
+    case NJS_ARRAY_FIND_INDEX:
+        njs_set_number(&vm->retval, -1);
+        break;
+
+    case NJS_ARRAY_MAP:
+    case NJS_ARRAY_FILTER:
+    default:
+        if (type == NJS_ARRAY_FILTER) {
+            njs_set_number(&arguments[0], results.items);
+            ret = njs_typed_array_species_create(vm, this,
+                                                 njs_value_arg(arguments),
+                                                 1, &retval);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto exception;
+            }
+
+            dst = njs_typed_array(&retval);
+
+            i = 0;
+
+            while (i < results.items) {
+                r = njs_arr_item(&results, i);
+                ret = njs_typed_array_set_value(vm, dst, i++, r);
+                if (njs_slow_path(ret != NJS_OK)) {
+                    goto exception;
+                }
+            }
+        }
+
+        njs_set_typed_array(&vm->retval, dst);
+        break;
+    }
+
+done:
+
+    ret = NJS_OK;
+
+exception:
+
+    njs_arr_destroy(&results);
+
+    return ret;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_index_of(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t type)
+{
+    double              v;
+    int64_t             i, i64, from, to, index, increment, offset, length;
+    njs_int_t           ret, integer;
+    njs_value_t         *this;
+    const float         *f32;
+    const double        *f64;
+    const uint8_t       *u8;
+    const uint16_t      *u16;
+    const uint32_t      *u32;
+    njs_typed_array_t   *array;
+    njs_array_buffer_t  *buffer;
+
+    this = njs_argument(args, 0);
+    if (njs_slow_path(!njs_is_typed_array(this))) {
+        njs_type_error(vm, "this is not a typed array");
+        return NJS_ERROR;
+    }
+
+    index = -1;
+    array = njs_typed_array(this);
+    length = njs_typed_array_length(array);
+
+    if (!njs_is_number(njs_arg(args, nargs, 1)) || length == 0) {
+        goto done;
+    }
+
+    if (type & 2) {
+        /* lastIndexOf(). */
+
+        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;
+        }
+
+        to = -1;
+        increment = -1;
+
+        if (from <= to) {
+            goto done;
+        }
+
+    } else {
+        /* indexOf(), includes(). */
+
+        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;
+            }
+        }
+
+        to = length;
+        increment = 1;
+
+        if (from >= to) {
+            goto done;
+        }
+    }
+
+    v = njs_number(njs_argument(args, 1));
+
+    i64 = v;
+    integer = (v == i64);
+
+    buffer = array->buffer;
+    offset = array->offset;
+
+    switch (array->type) {
+    case NJS_OBJ_TYPE_INT8_ARRAY:
+        if (integer && ((int8_t) i64 == i64)) {
+            goto search8;
+        }
+
+        break;
+
+    case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
+    case NJS_OBJ_TYPE_UINT8_ARRAY:
+        if (integer && ((uint8_t) i64 == i64)) {
+search8:
+            u8 = &buffer->u.u8[0];
+            for (i = from; i != to; i += increment) {
+                if (u8[offset + i] == (uint8_t) i64) {
+                    index = i;
+                    break;
+                }
+            }
+        }
+
+        break;
+
+    case NJS_OBJ_TYPE_INT16_ARRAY:
+        if (integer && ((int16_t) i64 == i64)) {
+            goto search16;
+        }
+
+        break;
+
+    case NJS_OBJ_TYPE_UINT16_ARRAY:
+        if (integer && ((uint16_t) i64 == i64)) {
+search16:
+            u16 = &buffer->u.u16[0];
+            for (i = from; i != to; i += increment) {
+                if (u16[offset + i] == (uint16_t) i64) {
+                    index = i;
+                    break;
+                }
+            }
+        }
+
+        break;
+
+    case NJS_OBJ_TYPE_INT32_ARRAY:
+        if (integer && ((int32_t) i64 == i64)) {
+            goto search32;
+        }
+
+        break;
+
+    case NJS_OBJ_TYPE_UINT32_ARRAY:
+        if (integer && ((uint32_t) i64 == i64)) {
+search32:
+            u32 = &buffer->u.u32[0];
+            for (i = from; i != to; i += increment) {
+                if (u32[offset + i] == (uint32_t) i64) {
+                    index = i;
+                    break;
+                }
+            }
+        }
+
+        break;
+
+    case NJS_OBJ_TYPE_FLOAT32_ARRAY:
+        f32 = &buffer->u.f32[0];
+
+        if (((float) v == v)) {
+            for (i = from; i != to; i += increment) {
+                if (f32[offset + i] == (float) v) {
+                    index = i;
+                    break;
+                }
+            }
+
+        } else if ((type & 1) && isnan(v)) {
+            /* includes() handles NaN. */
+
+            for (i = from; i != to; i += increment) {
+                if (isnan(f32[offset + i])) {
+                    index = i;
+                    break;
+                }
+            }
+        }
+
+        break;
+
+    default:
+
+        /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
+
+        f64 = &buffer->u.f64[0];
+
+        if ((type & 1) && isnan(v)) {
+            /* includes() handles NaN. */
+
+            for (i = from; i != to; i += increment) {
+                if (isnan(f64[offset + i])) {
+                    index = i;
+                    break;
+                }
+            }
+
+        } else {
+            for (i = from; i != to; i += increment) {
+                if (f64[offset + i] == v) {
+                    index = i;
+                    break;
+                }
+            }
+        }
+    }
+
+done:
+
+    /* Default values. */
+
+    if (type & 1) {
+        njs_set_boolean(&vm->retval, index != -1);
+
+    } else {
+        njs_set_number(&vm->retval, index);
+    }
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_reduce(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t right)
+{
+    int64_t            i, from, to, increment, length;
+    njs_int_t          ret;
+    njs_value_t        *this, accumulator;
+    njs_value_t        arguments[5];
+    njs_function_t     *function;
+    njs_typed_array_t  *array;
+
+    this = njs_argument(args, 0);
+    if (njs_slow_path(!njs_is_typed_array(this))) {
+        njs_type_error(vm, "this is not a typed array");
+        return NJS_ERROR;
+    }
+
+    array = njs_typed_array(this);
+    length = njs_typed_array_length(array);
+
+    if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
+        njs_type_error(vm, "callback argument is not callable");
+        return NJS_ERROR;
+    }
+
+    function = njs_function(njs_argument(args, 1));
+
+    if (length == 0 && nargs <= 2) {
+        njs_type_error(vm, "Reduce of empty object with no initial value");
+        return NJS_ERROR;
+    }
+
+    if (right) {
+        from = length - 1;
+        to = -1;
+        increment = -1;
+
+    } else {
+        from = 0;
+        to = length;
+        increment = 1;
+    }
+
+    if (nargs > 2) {
+        accumulator = *njs_argument(args, 2);
+
+    } else {
+        njs_set_number(&accumulator, njs_typed_array_get(array, from));
+        from += increment;
+    }
+
+    for (i = from; i != to; i += increment) {
+        njs_set_undefined(&arguments[0]);
+        arguments[1] = accumulator;
+        njs_set_number(&arguments[2], njs_typed_array_get(array, i));
+        njs_set_number(&arguments[3], i);
+        njs_set_typed_array(&arguments[4], array);
+
+        ret =  njs_function_apply(vm, function, arguments, 5, &accumulator);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+    }
+
+    vm->retval = accumulator;
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t unused)
+{
+    double              *f64;
+    uint8_t             *u8;
+    int64_t             i, length;
+    uint16_t            *u16;
+    uint32_t            *u32;
+    njs_value_t         *this;
+    njs_typed_array_t   *array;
+    njs_array_buffer_t  *buffer;
+
+    this = njs_argument(args, 0);
+    if (njs_slow_path(!njs_is_typed_array(this))) {
+        njs_type_error(vm, "this is not a typed array");
+        return NJS_ERROR;
+    }
+
+    array = njs_typed_array(this);
+    length = njs_typed_array_length(array);
+
+    buffer = array->buffer;
+
+    switch (array->type) {
+    case NJS_OBJ_TYPE_UINT8_ARRAY:
+    case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
+    case NJS_OBJ_TYPE_INT8_ARRAY:
+        u8 = &buffer->u.u8[array->offset];
+
+        for (i = 0; i < length / 2; i++) {
+            njs_swap_u8(&u8[i], &u8[length - i - 1], 0);
+        }
+
+        break;
+
+    case NJS_OBJ_TYPE_INT16_ARRAY:
+    case NJS_OBJ_TYPE_UINT16_ARRAY:
+        u16 = &buffer->u.u16[array->offset];
+
+        for (i = 0; i < length / 2; i++) {
+            njs_swap_u16(&u16[i], &u16[length - i - 1], 0);
+        }
+
+        break;
+
+    case NJS_OBJ_TYPE_INT32_ARRAY:
+    case NJS_OBJ_TYPE_UINT32_ARRAY:
+    case NJS_OBJ_TYPE_FLOAT32_ARRAY:
+        u32 = &buffer->u.u32[array->offset];
+
+        for (i = 0; i < length / 2; i++) {
+            njs_swap_u32(&u32[i], &u32[length - i - 1], 0);
+        }
+
+        break;
+
+    default:
+
+        /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
+
+        f64 = &buffer->u.f64[array->offset];
+
+        for (i = 0; i < length / 2; i++) {
+            njs_swap_u64(&f64[i], &f64[length - i - 1], 0);
+        }
+    }
+
+    njs_set_typed_array(&vm->retval, array);
+
+    return NJS_OK;
+}
+
+
 static int
 njs_typed_array_compare_i8(const void *a, const void *b, void *c)
 {
@@ -1367,48 +1930,69 @@ static const njs_object_prop_t  njs_typed_array_prototype_properties[] =
 
     {
         .type = NJS_PROPERTY,
-        .name = njs_string("set"),
-        .value = njs_native_function(njs_typed_array_prototype_set, 2),
+        .name = njs_string("copyWithin"),
+        .value = njs_native_function(njs_typed_array_prototype_copy_within, 2),
         .writable = 1,
         .configurable = 1,
     },
 
     {
         .type = NJS_PROPERTY,
-        .name = njs_string("slice"),
-        .value = njs_native_function2(njs_typed_array_prototype_slice, 2, 1),
+        .name = njs_string("every"),
+        .value = njs_native_function2(njs_typed_array_prototype_iterator, 1,
+                                      NJS_ARRAY_EVERY),
         .writable = 1,
         .configurable = 1,
     },
 
     {
         .type = NJS_PROPERTY,
-        .name = njs_string("subarray"),
-        .value = njs_native_function2(njs_typed_array_prototype_slice, 2, 0),
+        .name = njs_string("filter"),
+        .value = njs_native_function2(njs_typed_array_prototype_iterator, 1,
+                                      NJS_ARRAY_FILTER),
         .writable = 1,
         .configurable = 1,
     },
 
     {
         .type = NJS_PROPERTY,
-        .name = njs_string("sort"),
-        .value = njs_native_function(njs_typed_array_prototype_sort, 1),
+        .name = njs_string("find"),
+        .value = njs_native_function2(njs_typed_array_prototype_iterator, 1,
+                                      NJS_ARRAY_FIND),
         .writable = 1,
         .configurable = 1,
     },
 
     {
         .type = NJS_PROPERTY,
-        .name = njs_string("copyWithin"),
-        .value = njs_native_function(njs_typed_array_prototype_copy_within, 2),
+        .name = njs_string("findIndex"),
+        .value = njs_native_function2(njs_typed_array_prototype_iterator, 1,
+                                      NJS_ARRAY_FIND_INDEX),
         .writable = 1,
         .configurable = 1,
     },
 
     {
         .type = NJS_PROPERTY,
-        .name = njs_string("fill"),
-        .value = njs_native_function(njs_typed_array_prototype_fill, 1),
+        .name = njs_string("forEach"),
+        .value = njs_native_function2(njs_typed_array_prototype_iterator, 1,
+                                      NJS_ARRAY_FOR_EACH),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("includes"),
+        .value = njs_native_function2(njs_typed_array_prototype_index_of, 1, 1),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("indexOf"),
+        .value = njs_native_function2(njs_typed_array_prototype_index_of, 1, 0),
         .writable = 1,
         .configurable = 1,
     },
@@ -1421,6 +2005,96 @@ static const njs_object_prop_t  njs_typed_array_prototype_properties[] =
         .configurable = 1,
     },
 
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("fill"),
+        .value = njs_native_function(njs_typed_array_prototype_fill, 1),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("lastIndexOf"),
+        .value = njs_native_function2(njs_typed_array_prototype_index_of, 1, 2),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("map"),
+        .value = njs_native_function2(njs_typed_array_prototype_iterator, 1,
+                                      NJS_ARRAY_MAP),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("reduce"),
+        .value = njs_native_function2(njs_typed_array_prototype_reduce, 1, 0),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("reduceRight"),
+        .value = njs_native_function2(njs_typed_array_prototype_reduce, 1, 1),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("reverse"),
+        .value = njs_native_function(njs_typed_array_prototype_reverse, 0),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("set"),
+        .value = njs_native_function(njs_typed_array_prototype_set, 2),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("slice"),
+        .value = njs_native_function2(njs_typed_array_prototype_slice, 2, 1),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("some"),
+        .value = njs_native_function2(njs_typed_array_prototype_iterator, 1,
+                                      NJS_ARRAY_SOME),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("sort"),
+        .value = njs_native_function(njs_typed_array_prototype_sort, 1),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("subarray"),
+        .value = njs_native_function2(njs_typed_array_prototype_slice, 2, 0),
+        .writable = 1,
+        .configurable = 1,
+    },
+
     {
         .type = NJS_PROPERTY,
         .name = njs_string("toString"),
index c58cf34292a578ffb91d6ecf927a886fc0cae883..2a921ff64a04b93f16863c179a1275b42d0e1ba5 100644 (file)
 typedef void (*njs_swap_t) (void *a, void *b, size_t size);
 
 
-njs_inline void
-njs_swap_u8(void *a, void *b, size_t size)
-{
-    uint8_t  u, *au, *bu;
-
-    au = (uint8_t *) a;
-    bu = (uint8_t *) b;
-
-    u = au[0];
-    au[0] = bu[0];
-    bu[0] = u;
-}
-
-
-njs_inline void
-njs_swap_u16(void *a, void *b, size_t size)
-{
-    uint16_t  u, *au, *bu;
-
-    au = (uint16_t *) a;
-    bu = (uint16_t *) b;
-
-    u = au[0];
-    au[0] = bu[0];
-    bu[0] = u;
-}
-
-
-njs_inline void
-njs_swap_u32(void *a, void *b, size_t size)
-{
-    uint32_t  u, *au, *bu;
-
-    au = (uint32_t *) a;
-    bu = (uint32_t *) b;
-
-    u = au[0];
-    au[0] = bu[0];
-    bu[0] = u;
-}
-
-
-njs_inline void
-njs_swap_u64(void *a, void *b, size_t size)
-{
-    uint64_t  u, *au, *bu;
-
-    au = (uint64_t *) a;
-    bu = (uint64_t *) b;
-
-    u = au[0];
-    au[0] = bu[0];
-    bu[0] = u;
-}
-
-
 njs_inline void
 njs_swap_u128(void *a, void *b, size_t size)
 {
index 30207887b13befeff2a31b89e491f4773f1ea710..1ba7462aff90edbfc73dcc4d312697aed7956602 100644 (file)
@@ -15,4 +15,61 @@ void njs_qsort(void *base, size_t n, size_t size, njs_sort_cmp_t cmp,
 
 const char *njs_errno_string(int errnum);
 
+
+njs_inline void
+njs_swap_u8(void *a, void *b, size_t size)
+{
+    uint8_t  u, *au, *bu;
+
+    au = (uint8_t *) a;
+    bu = (uint8_t *) b;
+
+    u = au[0];
+    au[0] = bu[0];
+    bu[0] = u;
+}
+
+
+njs_inline void
+njs_swap_u16(void *a, void *b, size_t size)
+{
+    uint16_t  u, *au, *bu;
+
+    au = (uint16_t *) a;
+    bu = (uint16_t *) b;
+
+    u = au[0];
+    au[0] = bu[0];
+    bu[0] = u;
+}
+
+
+njs_inline void
+njs_swap_u32(void *a, void *b, size_t size)
+{
+    uint32_t  u, *au, *bu;
+
+    au = (uint32_t *) a;
+    bu = (uint32_t *) b;
+
+    u = au[0];
+    au[0] = bu[0];
+    bu[0] = u;
+}
+
+
+njs_inline void
+njs_swap_u64(void *a, void *b, size_t size)
+{
+    uint64_t  u, *au, *bu;
+
+    au = (uint64_t *) a;
+    bu = (uint64_t *) b;
+
+    u = au[0];
+    au[0] = bu[0];
+    bu[0] = u;
+}
+
+
 #endif /* _NJS_UTILS_H_INCLUDED_ */
index 3f7f0412fd54984ad03750c2858ee70746a19689..f8ed01a9b00c77c7eb664fd4d01d08edac324e36 100644 (file)
@@ -5895,6 +5895,312 @@ static njs_unit_test_t  njs_test[] =
               "           return a.toString() === '4,5,3,4,5'})"),
       njs_str("true") },
 
+    { njs_str("Uint8Array.prototype.every.call(1)"),
+      njs_str("TypeError: this is not a typed array") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([1,2,3])).every(e=>e>0) === true})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([1,2,3])).every(function(e) {"
+              "              if (this != undefined) {throw 'Oops';}"
+              "              return e > 0}) === true})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([1,2,3])).every(function(e) {"
+              "              if (this != 'QQ') {throw 'Oops';}"
+              "              return e > 0}, 'QQ') === true})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([1,2,3])).every(e=>e>1) === false})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.every(e=>e<4)})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var collect = []; (new v([42,43])).forEach(e=>collect.push(e)); "
+              "           return collect.join('|') === '42|43'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([7,10,3,8,5])).filter(q=>q%2).join('|') === '7|3|5'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,7,10,3,8,5,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 5);"
+              "           return a.filter(q=>q%2).join('|') === '7|3|5'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.find(e=>e>2) === 3})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.find(e=>e===255) === undefined})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.findIndex(e=>e>2) === 2})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.findIndex(e=>e===255) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([1,2,3])).some(e=>e==2)})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.some(e=>e==255)})"),
+      njs_str("false") },
+
+    { njs_str("Uint8Array.prototype.includes.call(1)"),
+      njs_str("TypeError: this is not a typed array") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v()).includes(0, {valueOf(){throw 'Oops'}}) === false})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([0,1,2,3])).includes(2) === true})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([0,1,2,3])).includes(2,3) === false})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = new v(5);"
+              "           return a.includes(0, 4) === true "
+              "                  && a.includes(0, 5) === false;})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([0,1,2,3])).includes(-0) === true})"),
+      njs_str("true") },
+
+    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([42, 43, NaN, 41])).includes(NaN) === true})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,0,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.includes(255) === false})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v()).indexOf(0, {valueOf(){throw 'Oops'}}) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1])).indexOf(2) === 1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1])).indexOf(2,2) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1])).indexOf(2,Infinity) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1])).indexOf(2,-Infinity) === 1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([42, 43, NaN, 41])).indexOf(NaN) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1])).indexOf(257) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1])).indexOf(2.00001) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1,0])).indexOf(-0) === 3})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = new v(5);"
+              "           return a.indexOf(0, 4) === 4"
+              "                  && a.indexOf(0, 5) === -1;})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,0,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.indexOf(255) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1,2])).lastIndexOf(2) === 3})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1,2])).lastIndexOf(4) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([42, 43])).lastIndexOf(42,0) === 0})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([42, 43, 43, 41])).lastIndexOf(43,Infinity) === 2})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([42, 43, 43, 41])).lastIndexOf(43,-Infinity) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([42, 43, NaN, 41])).lastIndexOf(NaN) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,0,2,3,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.lastIndexOf(255) === -1})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{return (new v([3,2,1])).map(q=>2*q).join('|') === '6|4|2'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var orig = new v([255,255,6,4,2,255]);"
+              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
+              "           return a.map(q=>q/2).join('|') === '3|2|1'})"),
+      njs_str("true") },
+
+    { njs_str("Uint8Array.prototype.reduce.call(1)"),
+      njs_str("TypeError: this is not a typed array") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ try { (new v([])).reduce((p, q) => p + q) } "
+              "            catch (e) { return e.name == 'TypeError'} })"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([])).reduce((p, q) => p + q, 10) == 10})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([7])).reduce((p, q) => p + q) == 7})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([7])).reduce((p, q) => p + q, 10) == 17})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([1,2,3])).reduce((p, q) => p + q) == 6})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([1,2,3])).reduce((p, q) => p + q, 10) == 16})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([1,2,3])).reduce((p, q) => p + q, '') == '123'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([3,2,1])).reduce((p, q, i) => { "
+              "             if (q + i != 3) {throw 'Oops'}; "
+              "             return p + q;}) == 6})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ var a = new v([3,2,1]); "
+              "            return a.reduce((p, q, _, o) => { "
+              "                 if (a != o) {throw 'Oops'};  "
+              "                 return p + q;}) == 6})"),
+      njs_str("true") },
+
+    { njs_str("var a = [3,2,1]; a.reduce((p, v, _, o) => { if (a != o) {throw 'Oops'};return p + v})"),
+      njs_str("6") },
+
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ try { (new v([])).reduceRight((p, q) => p + q) } "
+              "            catch (e) { return e.name == 'TypeError'} })"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([])).reduceRight((p, q) => p + q, 10) == 10})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([7])).reduceRight((p, q) => p + q) == 7})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([7])).reduceRight((p, q) => p + q, 10) == 17})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([1,2,3])).reduceRight((p, q) => p + q) == 6})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([1,2,3])).reduceRight((p, q) => p + q, 10) == 16})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([1,2,3])).reduceRight((p, q) => p + q, '') == '321'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([3,2,1])).reduceRight((p, q, i) => { "
+              "             if (q + i != 3) {throw 'Oops'}; "
+              "             return p + q;}) == 6})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ var a = new v([3,2,1]); "
+              "            return a.reduceRight((p, q, _, o) => { "
+              "                 if (a != o) {throw 'Oops'};  "
+              "                 return p + q;}) == 6})"),
+      njs_str("true") },
+
+    { njs_str("var a = [3,2,1]; a.reduceRight((p, v, _, o) => { if (a != o) {throw 'Oops'};return p + v})"),
+      njs_str("6") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([1,2,3])).reverse().join('|') == '3|2|1'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ return (new v([1,2,3,4])).reverse().join('|') == '4|3|2|1'})"),
+      njs_str("true") },
+
+    { njs_str("Uint8Array.prototype.sort.call(1)"),
+      njs_str("TypeError: this is not a typed array") },
+
     { njs_str(NJS_TYPED_ARRAY_LIST
               ".every(v=>{var a = new v([]); a.sort(); "
               "           return a.toString() === ''})"),
@@ -6164,45 +6470,42 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("Array.prototype.map.call({0:9, length:2**16}, val=>val<10).length"),
       njs_str("65536") },
 
-    { njs_str("var a = [];"
-                 "a.reduce(function(p, v, i, a) { return p + v })"),
+    { njs_str("[].reduce((p, v) => p + v)"),
       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("[].reduce((p, v) => p + v, 10)"),
       njs_str("10") },
 
-    { njs_str("var a = [,,];"
-                 "a.reduce(function(p, v, i, a) { return p + v })"),
+    { njs_str("[,,].reduce((p, v) => p + v)"),
       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("[,,].reduce((p, v) => p + v, 10)"),
       njs_str("10") },
 
-    { njs_str("var a = [1];"
-                 "a.reduce(function(p, v, i, a) { return p + v })"),
+    { njs_str("[1].reduce((p, v) => p + v)"),
       njs_str("1") },
 
-    { njs_str("var a = [1];"
-                 "a.reduce(function(p, v, i, a) { return p + v }, 10)"),
+    { njs_str("[1].reduce((p, v) => p + v, 10)"),
       njs_str("11") },
 
-    { njs_str("var a = [1,2,3];"
-                 "a.reduce(function(p, v, i, a) { return p + v })"),
+    { njs_str("[1,2,3].reduce((p, v) => p + v)"),
       njs_str("6") },
 
-    { njs_str("var a = [1,2,3];"
-                 "a.reduce(function(p, v, i, a) { return p + v }, 10)"),
+    { njs_str("[1,2,3].reduce((p, v) => p + v, 10)"),
       njs_str("16") },
 
-    { njs_str("[[0, 1], [2, 3], [4, 5]].reduce(function(a, b)"
-                 "                         { return a.concat(b) }, [])"),
+    { njs_str("[3,2,1].reduce((p, v, i) => { if (v + i != 3) {throw 'Oops'};return p + v})"),
+      njs_str("6") },
+
+    { njs_str("var a = [3,2,1]; a.reduce((p, v, _, o) => { if (a != o) {throw 'Oops'};return p + v})"),
+      njs_str("6") },
+
+    { njs_str("[[0, 1], [2, 3], [4, 5]].reduce((a, b) => a.concat(b), [])"),
       njs_str("0,1,2,3,4,5") },
 
     { njs_str("var o = {0: 'a', 1: 'b', 2: 'c', 'length': { valueOf() { return 3 }}};"
-                 "var reducer = (a, b) => a + b;"
-                 "var a = Array.prototype.reduce.call(o, reducer); a"),
+              "var reducer = (a, b) => a + b;"
+              "var a = Array.prototype.reduce.call(o, reducer); a"),
       njs_str("abc") },
 
     { njs_str("function reducer(a, b, i, arr) {"
@@ -6224,46 +6527,38 @@ static njs_unit_test_t  njs_test[] =
               "var r = Array.prototype.reduce.call(o, (a, b) => a + b); r"),
       njs_str("abcd") },
 
-    { njs_str("var a = [];"
-                 "a.reduceRight(function(p, v, i, a) { return p + v })"),
+    { njs_str("[].reduceRight((p, v) => p + v)"),
       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("[].reduceRight((p, v) => p + v, 10)"),
       njs_str("10") },
 
-    { njs_str("var a = [,,];"
-                 "a.reduceRight(function(p, v, i, a) { return p + v })"),
+    { njs_str("[,,].reduceRight((p, v) => p + v)"),
       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("[,,].reduceRight((p, v) => p + v, 10)"),
       njs_str("10") },
 
-    { njs_str("var a = [1];"
-                 "a.reduceRight(function(p, v, i, a) { return p + v })"),
+    { njs_str("[1].reduceRight((p, v) => p + v)"),
       njs_str("1") },
 
-    { njs_str("var a = [1];"
-                 "a.reduceRight(function(p, v, i, a) { return p + v }, 10)"),
+    { njs_str("[1].reduceRight((p, v) => p + v, 10)"),
       njs_str("11") },
 
-    { njs_str("var a = [1,2,3];"
-                 "a.reduceRight(function(p, v, i, a) { return p + v })"),
+    { njs_str("[1,2,3].reduceRight((p, v) => p + v)"),
       njs_str("6") },
 
-    { njs_str("var a = [1,2,3];"
-                 "a.reduceRight(function(p, v, i, a) { return p + v }, 10)"),
+    { njs_str("[1,2,3].reduceRight((p, v) => p + v, 10)"),
       njs_str("16") },
 
+    { njs_str("[3,2,1].reduceRight((p, v, i) => { if (v + i != 3) {throw 'Oops'};return p + v})"),
+      njs_str("6") },
+
     { njs_str("var a = [1,2,3];"
-                 "a.reduceRight(function(p, v, i, a)"
-                 "              { a.shift(); return p + v })"),
+              "a.reduceRight(function(p, v, _, a) { a.shift(); return p + v })"),
       njs_str("7") },
-
     { njs_str("var a = [1,2,3];"
-                 "a.reduceRight(function(p, v, i, a)"
-                 "              { a.shift(); return p + v }, 10)"),
+              "a.reduceRight(function(p, v, _, a) { a.shift(); return p + v }, 10)"),
       njs_str("19") },
 
     { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"