]> git.kaiwu.me - njs.git/commitdiff
Introduced njs_array_copy_within().
authorDmitry Volyntsev <xeioex@nginx.com>
Wed, 3 Jun 2020 18:40:09 +0000 (18:40 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Wed, 3 Jun 2020 18:40:09 +0000 (18:40 +0000)
src/njs_array.c
src/test/njs_unit_test.c

index d4ac54921c4c330186d215a4d62cc33d9145ad38..519eba939a2f2912292c2639dddb6f0d66b233d2 100644 (file)
@@ -250,6 +250,60 @@ done:
 }
 
 
+static njs_int_t
+njs_array_copy_within(njs_vm_t *vm, njs_value_t *array, int64_t to_pos,
+    int64_t from_pos, int64_t count, njs_bool_t forward)
+{
+    int64_t      i, from, to;
+    njs_int_t    ret;
+    njs_array_t  *arr;
+    njs_value_t  value;
+
+    if (njs_fast_path(njs_is_fast_array(array) && count > 0)) {
+        arr = njs_array(array);
+
+        memmove(&arr->start[to_pos], &arr->start[from_pos],
+                count * sizeof(njs_value_t));
+
+        return NJS_OK;
+    }
+
+    if (!forward) {
+        from_pos += count - 1;
+        to_pos += count - 1;
+    }
+
+    for (i = 0; i < count; i++) {
+        if (forward) {
+            from = from_pos + i;
+            to = to_pos + i;
+
+        } else {
+            from = from_pos - i;
+            to = to_pos - i;
+        }
+
+        ret = njs_value_property_i64(vm, array, from, &value);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return NJS_ERROR;
+        }
+
+        if (ret == NJS_OK) {
+            ret = njs_value_property_i64_set(vm, array, to, &value);
+
+        } else {
+            ret = njs_value_property_i64_delete(vm, array, to, NULL);
+        }
+
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return NJS_ERROR;
+        }
+    }
+
+    return NJS_OK;
+}
+
+
 njs_int_t
 njs_array_add(njs_vm_t *vm, njs_array_t *array, njs_value_t *value)
 {
@@ -3423,11 +3477,9 @@ 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      length, count, to, from, end;
     njs_int_t    ret;
-    njs_array_t  *array;
-    njs_value_t  *this, *value, prop;
+    njs_value_t  *this, *value;
 
     this = njs_argument(args, 0);
 
@@ -3471,53 +3523,10 @@ njs_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args,
 
     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_fast_path(njs_is_fast_array(this))) {
-        array = njs_array(this);
-
-        while (count-- > 0) {
-            array->start[to] = array->start[from];
-
-            from = from + direction;
-            to = to + direction;
-        }
-
-        return NJS_OK;
-    }
-
-    while (count-- > 0) {
-        ret = njs_value_property_i64(vm, this, from, &prop);
-
-        if (ret == NJS_OK) {
-            ret = njs_value_property_i64_set(vm, this, to, &prop);
-
-        } else {
-            if (njs_slow_path(ret == NJS_ERROR)) {
-                return ret;
-            }
-
-            ret = njs_value_property_i64_delete(vm, this, to, NULL);
-        }
-
-        if (njs_slow_path(ret == NJS_ERROR)) {
-            return ret;
-        }
-
-        from = from + direction;
-        to = to + direction;
-    }
-
-    return NJS_OK;
+    return njs_array_copy_within(vm, this, to, from, count,
+                                 !(from < to && to < from + count));
 }
 
 
index 30487b10f9f8fba3bf9649f46542daadcec6c01a..25a527c7c513b6d314dc128888ab19181483aa55 100644 (file)
@@ -4165,6 +4165,9 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("[0, 1, , , 1].copyWithin(0, 1, 4)"),
       njs_str("1,,,,1") },
 
+    { njs_str("[0, 1, 2, 3].copyWithin(0, 1, -10)"),
+      njs_str("0,1,2,3") },
+
     { njs_str("var o = [0, 1, , , 1].copyWithin(0, 1, 4); typeof o"),
       njs_str("object") },
 
@@ -4184,6 +4187,10 @@ static njs_unit_test_t  njs_test[] =
               "Object.keys(obj) + '|' + Object.values(obj)"),
       njs_str("length,1,2,3,4,5,0|5,a,b,c,d,e,c") },
 
+    { njs_str("var o = {length:1}; Object.defineProperty(o, '0', {get:()=>{throw Error('Oops')}});"
+              "Array.prototype.copyWithin.call(o, 0, 0)"),
+      njs_str("Error: Oops") },
+
     { njs_str("Array.prototype.slice(1)"),
       njs_str("") },