[njs] Fixed Array.prototype.reverse() according to the specification.

Dmitry Volyntsev xeioex at nginx.com
Tue May 26 18:36:21 UTC 2020


details:   https://hg.nginx.org/njs/rev/db77713e0536
branches:  
changeset: 1401:db77713e0536
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue May 26 16:35:11 2020 +0000
description:
Fixed Array.prototype.reverse() according to the specification.

diffstat:

 src/njs_array.c          |  104 +++++++++++++++++++++++++++++++++++++++-------
 src/test/njs_unit_test.c |   17 +++++++
 2 files changed, 104 insertions(+), 17 deletions(-)

diffs (160 lines):

diff -r b5f4b848c60f -r db77713e0536 src/njs_array.c
--- a/src/njs_array.c	Tue May 26 16:34:45 2020 +0000
+++ b/src/njs_array.c	Tue May 26 16:35:11 2020 +0000
@@ -1306,10 +1306,9 @@ static njs_int_t
 njs_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    int64_t      length;
-    njs_int_t    ret;
-    njs_uint_t   i, n;
-    njs_value_t  value, *this;
+    int64_t      length, l, h;
+    njs_int_t    ret, lret, hret;
+    njs_value_t  value, lvalue, hvalue, *this;
     njs_array_t  *array;
 
     this = njs_argument(args, 0);
@@ -1324,31 +1323,102 @@ njs_array_prototype_reverse(njs_vm_t *vm
         return ret;
     }
 
-    if (njs_slow_path(length == 0)) {
+    if (njs_slow_path(length < 2)) {
         vm->retval = *this;
         return NJS_OK;
     }
 
-    if (njs_slow_path(!njs_is_fast_array(this))) {
-        njs_internal_error(vm, "reverse() is not implemented yet for objects");
-        return NJS_ERROR;
-    }
-
     if (njs_is_fast_array(this)) {
         array = njs_array(this);
-        length = array->length;
-
-        if (length > 1) {
-            for (i = 0, n = length - 1; i < n; i++, n--) {
-                value = array->start[i];
-                array->start[i] = array->start[n];
-                array->start[n] = value;
+
+        for (l = 0, h = length - 1; l < h; l++, h--) {
+            if (njs_fast_path(njs_is_valid(&array->start[l]))) {
+                lvalue = array->start[l];
+                lret = NJS_OK;
+
+            } else {
+                lret = njs_value_property_i64(vm, this, l, &lvalue);
+                if (njs_slow_path(lret == NJS_ERROR)) {
+                    return NJS_ERROR;
+                }
+            }
+
+            if (njs_fast_path(njs_is_valid(&array->start[h]))) {
+                hvalue = array->start[h];
+                hret = NJS_OK;
+
+            } else {
+                hret = njs_value_property_i64(vm, this, h, &hvalue);
+                if (njs_slow_path(hret == NJS_ERROR)) {
+                    return NJS_ERROR;
+                }
+            }
+
+            if (lret == NJS_OK) {
+                array->start[h] = lvalue;
+
+                if (hret == NJS_OK) {
+                    array->start[l] = hvalue;
+
+                } else {
+                    array->start[h] = njs_value_invalid;
+                }
+
+            } else if (hret == NJS_OK) {
+                array->start[l] = hvalue;
+                array->start[h] = njs_value_invalid;
             }
         }
 
         njs_set_array(&vm->retval, array);
+        return NJS_OK;
     }
 
+    for (l = 0, h = length - 1; l < h; l++, h--) {
+        lret = njs_value_property_i64(vm, this, l, &lvalue);
+        if (njs_slow_path(lret == NJS_ERROR)) {
+            return NJS_ERROR;
+        }
+
+        hret = njs_value_property_i64(vm, this, h, &hvalue);
+        if (njs_slow_path(hret == NJS_ERROR)) {
+            return NJS_ERROR;
+        }
+
+        if (lret == NJS_OK) {
+            ret = njs_value_property_i64_set(vm, this, h, &lvalue);
+            if (njs_slow_path(ret == NJS_ERROR)) {
+                return NJS_ERROR;
+            }
+
+            if (hret == NJS_OK) {
+                ret = njs_value_property_i64_set(vm, this, l, &hvalue);
+                if (njs_slow_path(ret == NJS_ERROR)) {
+                    return NJS_ERROR;
+                }
+
+            } else {
+                ret = njs_value_property_i64_delete(vm, this, l, &value);
+                if (njs_slow_path(ret == NJS_ERROR)) {
+                    return NJS_ERROR;
+                }
+            }
+
+        } else if (hret == NJS_OK) {
+            ret = njs_value_property_i64_set(vm, this, l, &hvalue);
+            if (njs_slow_path(ret == NJS_ERROR)) {
+                return NJS_ERROR;
+            }
+
+            ret = njs_value_property_i64_delete(vm, this, h, &value);
+            if (njs_slow_path(ret == NJS_ERROR)) {
+                return NJS_ERROR;
+            }
+        }
+    }
+
+    vm->retval = *this;
+
     return NJS_OK;
 }
 
diff -r b5f4b848c60f -r db77713e0536 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Tue May 26 16:34:45 2020 +0000
+++ b/src/test/njs_unit_test.c	Tue May 26 16:35:11 2020 +0000
@@ -4509,6 +4509,23 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var o = {1:true, 2:'', length:-2}; Array.prototype.reverse.call(o) === o"),
       njs_str("true") },
 
+    { njs_str("["
+              " ['a','b','c'],"
+              " ['a','b','c','d'],"
+              " [,'b','c','d'],"
+              " ['a','b','c',],"
+              " [,'b','c',],"
+              "]"
+              ".map(v=>Object.defineProperty(v, 1, {value:v[1], enumerable:false}))"
+              ".map(v=>v.reverse().join(''))"),
+      njs_str("cba,dcba,dcb,cba,cb") },
+
+    { njs_str("Array.prototype[1] = 1; var x = [0]; x.length = 2; x.reverse(); x"),
+      njs_str("1,0") },
+
+    { njs_str("Array.prototype[0] = 0; var x = [,1]; x.reverse(); x"),
+      njs_str("1,0") },
+
     { njs_str("var a = [1,2,3,4]; a.indexOf()"),
       njs_str("-1") },
 


More information about the nginx-devel mailing list