]> git.kaiwu.me - njs.git/commitdiff
Fixed arrays expansion.
authorValentin Bartenev <vbart@nginx.com>
Wed, 8 May 2019 16:09:10 +0000 (19:09 +0300)
committerValentin Bartenev <vbart@nginx.com>
Wed, 8 May 2019 16:09:10 +0000 (19:09 +0300)
There were two problems with njs_array_expand():

 1. It checked that the requred size with the appended elements wasn't bigger
    then the array size and then did nothing.  If there were elements removed
    from the beggining (by shift() operation), then "size <= array->size" can
    be true even if there wasn't enought free space after the array.

 2. After allocating more space to prepend elements, it set array->size without
    counting those elements.

Probably, the original idea was to decrement array->size while removing
elements from the beginning, but it wasn't done right.  Even if so, the
new version of the function looks cleaner.

This closes #152 and closes #153 issues on Github.

njs/njs_array.c
njs/test/njs_unit_test.c

index 75ab47bda46da150d9f43df51ccdb18d3bf4c645..514035ec0e63529b726b27569cc663a2d5217726 100644 (file)
@@ -214,15 +214,19 @@ njs_ret_t
 njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend,
     uint32_t append)
 {
+    uint32_t     free_before, free_after;
     uint64_t     size;
     njs_value_t  *start, *old;
 
-    size = (uint64_t) append + array->length;
+    free_before = array->start - array->data;
+    free_after = array->size - array->length - free_before;
 
-    if (nxt_fast_path(size <= array->size && prepend == 0)) {
+    if (nxt_fast_path(free_before >= prepend && free_after >= append)) {
         return NXT_OK;
     }
 
+    size = (uint64_t) prepend + array->length + append;
+
     if (size < 16) {
         size *= 2;
 
@@ -230,12 +234,12 @@ njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend,
         size += size / 2;
     }
 
-    if (nxt_slow_path((prepend + size) > NJS_ARRAY_MAX_LENGTH)) {
+    if (nxt_slow_path(size > NJS_ARRAY_MAX_LENGTH)) {
         goto memory_error;
     }
 
     start = nxt_mp_align(vm->mem_pool, sizeof(njs_value_t),
-                         (prepend + size) * sizeof(njs_value_t));
+                         size * sizeof(njs_value_t));
     if (nxt_slow_path(start == NULL)) {
         goto memory_error;
     }
@@ -728,11 +732,9 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
         n = nargs - 1;
 
         if (n != 0) {
-            if ((intptr_t) n > (array->start - array->data)) {
-                ret = njs_array_expand(vm, array, n, 0);
-                if (nxt_slow_path(ret != NXT_OK)) {
-                    return ret;
-                }
+            ret = njs_array_expand(vm, array, n, 0);
+            if (nxt_slow_path(ret != NXT_OK)) {
+                return ret;
             }
 
             array->length += n;
index e4167cf19bc23bdb7da4bf3179a0f1a5f3a73dfa..91822550c95c5c67694a2e440adfda1ec46e3358 100644 (file)
@@ -3730,6 +3730,9 @@ static njs_unit_test_t  njs_test[] =
                  "len +' '+ a +' '+ a.shift()"),
       nxt_string("5 3,4,5,1,2 3") },
 
+    { nxt_string("var a=[0], n = 64; while(--n) {a.push(n); a.shift()}; a"),
+      nxt_string("1") },
+
     { nxt_string("var a = []; a.splice()"),
       nxt_string("") },