[njs] Added implementation of Array.prototype.copyWithin().

Alexander Borisov alexander.borisov at nginx.com
Tue Nov 5 17:25:34 UTC 2019


details:   https://hg.nginx.org/njs/rev/ea588c413548
branches:  
changeset: 1221:ea588c413548
user:      Alexander Borisov <alexander.borisov at nginx.com>
date:      Tue Nov 05 20:24:48 2019 +0300
description:
Added implementation of Array.prototype.copyWithin().

diffstat:

 src/njs_array.c          |  122 +++++++++++++++++++++++++++++++++++++++++++++++
 src/test/njs_unit_test.c |   34 +++++++++++++
 2 files changed, 156 insertions(+), 0 deletions(-)

diffs (183 lines):

diff -r fc6aa7e27d57 -r ea588c413548 src/njs_array.c
--- a/src/njs_array.c	Sat Oct 12 16:23:25 2019 +0300
+++ b/src/njs_array.c	Tue Nov 05 20:24:48 2019 +0300
@@ -2770,6 +2770,120 @@ start:
 }
 
 
+static njs_int_t
+njs_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t unused)
+{
+    int8_t       direction;
+    int64_t      count, to, from, end;
+    uint32_t     length;
+    njs_int_t    ret;
+    njs_array_t  *array;
+    njs_value_t  *this, *value, from_key, to_key, prop;
+
+    this = njs_arg(args, nargs, 0);
+
+    ret = njs_value_to_object(vm, this);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    ret = njs_value_length(vm, this, &length);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &to);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    to = (to < 0) ? njs_max(length + to, 0) : njs_min(to, length);
+
+    ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    from = (from < 0) ? njs_max(length + from, 0) : njs_min(from, length);
+
+    value = njs_arg(args, nargs, 3);
+
+    if (njs_is_undefined(value)) {
+        end = length;
+
+    } else {
+        ret = njs_value_to_integer(vm, value, &end);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+    }
+
+    end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length);
+
+    count = njs_min(end - from, length - to);
+
+    if (from < to && from + count) {
+        direction = -1;
+        from = from + count - 1;
+        to = to + count - 1;
+
+    } else {
+        direction = 1;
+    }
+
+    njs_vm_retval_set(vm, this);
+
+    if (njs_is_array(this)) {
+        if (njs_slow_path(!njs_object_hash_is_empty(this))) {
+            goto process_object;
+        }
+
+        array = njs_array(this);
+
+        while (count-- > 0) {
+            array->start[to] = array->start[from];
+
+            from = from + direction;
+            to = to + direction;
+        }
+
+        return NJS_OK;
+    }
+
+process_object:
+
+    while (count-- > 0) {
+        /* FIXME: largest index is 2**53-1. */
+
+        njs_uint32_to_string(&from_key, (uint32_t) from);
+        njs_uint32_to_string(&to_key, (uint32_t) to);
+
+        ret = njs_value_property(vm, this, &from_key, &prop);
+
+        if (ret == NJS_OK) {
+            ret = njs_value_property_set(vm, this, &to_key, &prop);
+
+        } else {
+            if (njs_slow_path(ret == NJS_ERROR)) {
+                return ret;
+            }
+
+            ret = njs_value_property_delete(vm, this, &to_key, NULL);
+        }
+
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
+
+        from = from + direction;
+        to = to + direction;
+    }
+
+    return NJS_OK;
+}
+
+
 static const njs_object_prop_t  njs_array_prototype_properties[] =
 {
     {
@@ -2982,6 +3096,14 @@ static const njs_object_prop_t  njs_arra
         .writable = 1,
         .configurable = 1,
     },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("copyWithin"),
+        .value = njs_native_function(njs_array_prototype_copy_within, 2),
+        .writable = 1,
+        .configurable = 1,
+    },
 };
 
 
diff -r fc6aa7e27d57 -r ea588c413548 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Sat Oct 12 16:23:25 2019 +0300
+++ b/src/test/njs_unit_test.c	Tue Nov 05 20:24:48 2019 +0300
@@ -4019,6 +4019,40 @@ static njs_unit_test_t  njs_test[] =
               "Object.defineProperty(a, 'length', {writable:true})"),
       njs_str("TypeError: Cannot redefine property: \"length\"") },
 
+    { njs_str("[1, 2, 3, 4, 5].copyWithin(0, 3)"),
+      njs_str("4,5,3,4,5") },
+
+    { njs_str("[1, 2, 3, 4, 5].copyWithin(0, 3, 4)"),
+      njs_str("4,2,3,4,5") },
+
+    { njs_str("[1, 2, 3, 4, 5].copyWithin(0, -2, -1)"),
+      njs_str("4,2,3,4,5") },
+
+    { njs_str("[1, 2, 3, 4, 5].copyWithin(100, 200, 500)"),
+      njs_str("1,2,3,4,5") },
+
+    { njs_str("[0, 1, , , 1].copyWithin(0, 1, 4)"),
+      njs_str("1,,,,1") },
+
+    { njs_str("var o = [0, 1, , , 1].copyWithin(0, 1, 4); typeof o"),
+      njs_str("object") },
+
+    { njs_str("[].copyWithin.call({length: 5, 3: 1}, 0, 3)"),
+      njs_str("[object Object]") },
+
+    { njs_str("var o = [1, 2, 3, 4]; Object.defineProperties(o, { 5: {value: 'abc'}});"
+              "[].copyWithin.call(o, 0, 3, 4);"),
+      njs_str("4,2,3,4,,abc") },
+
+    { njs_str("var obj = {length: 5, 3: 1}; [].copyWithin.call(obj, 0, 3);"
+              "Object.keys(obj)"),
+      njs_str("length,3,0") },
+
+    { njs_str("var obj = {length: 5, 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'};"
+              "[].copyWithin.call(obj, 0, -2, -1);"
+              "Object.keys(obj) + '|' + Object.values(obj)"),
+      njs_str("length,1,2,3,4,5,0|5,a,b,c,d,e,c") },
+
     { njs_str("Array.prototype.slice(1)"),
       njs_str("") },
 


More information about the nginx-devel mailing list