Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [PATCH] zrealloc on array+=( )



Hello,
I revisited the patch, tested with debug prints, added test cases that
stress things out. No code changes.

Thought to test how Bash (3.2) performs on appends:

# fun() { local -a arr; i=5001; while (( -- i )); do arr+=( "The
appended test string of medium length" ); done; }
# time  fun
real     0m0.221s
user 0m0.214s
sys 0m0.004s

So it's 200 ms.  The same test with no-zrealloc-Zsh is 2.94 s. With the
patch it's 116 ms (using time tool, typeset -F SECONDS reveals it's 4
ms). So this can be a motivation to apply the patch. We can leverage the
fact that operating system has size of the array and can extend it, and
this way beat Bash. Of course, the real deal here is to be able to do
data processing, e.g. log gathering, etc.

-- 
  Sebastian Gniazdowski
  psprint3@xxxxxxxxxxxx
diff --git a/Src/params.c b/Src/params.c
index 19cbb1c..8942fef 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2723,24 +2723,57 @@ setarrvalue(Value v, char **val)
 		*p++ = *r++;
 	    }
 	} else {
-	    p = new = (char **) zalloc(sizeof(char *)
-				       * (post_assignment_length + 1));
-
-	    for (i = 0; i < v->start; i++)
-		*p++ = i < pre_assignment_length ? ztrdup(*q++) : ztrdup("");
-	    for (r = val; *r;) {
-		/* Give away ownership of the string */
-		*p++ = *r++;
-	    }
-	    if (v->end < pre_assignment_length)
-		for (q = old + v->end; *q;)
-		    *p++ = ztrdup(*q++);
-	    *p = NULL;
+            /* arr+=( ... )
+             * arr[${#arr}+x,...]=( ... ) */
+            if (post_assignment_length > pre_assignment_length &&
+                    pre_assignment_length <= v->start &&
+                    pre_assignment_length > 0 &&
+                    v->pm->gsu.a->setfn == arrsetfn)
+            {
+                p = new = (char **) zrealloc(old, sizeof(char *)
+                                           * (post_assignment_length + 1));
+
+                p += pre_assignment_length; /* after old elements */
+
+                /* Consider 1 < 0, case for a=( 1 ); a[1,..] =
+                 *          1 < 1, case for a=( 1 ); a[2,..] = */
+                if (pre_assignment_length < v->start) {
+                    for (i = pre_assignment_length; i < v->start; i++) {
+                        *p++ = ztrdup("");
+                    }
+                }
+
+                for (r = val; *r;) {
+                    /* Give away ownership of the string */
+                    *p++ = *r++;
+                }
+
+                /* v->end doesn't matter:
+                 * a=( 1 2 ); a[4,100]=( a b ); echo "${(q@)a}"
+                 * 1 2 '' a b */
+                *p = NULL;
+
+                v->pm->u.arr = NULL;
+                v->pm->gsu.a->setfn(v->pm, new);
+            } else {
+                p = new = (char **) zalloc(sizeof(char *)
+                                           * (post_assignment_length + 1));
+                for (i = 0; i < v->start; i++)
+                    *p++ = i < pre_assignment_length ? ztrdup(*q++) : ztrdup("");
+                for (r = val; *r;) {
+                    /* Give away ownership of the string */
+                    *p++ = *r++;
+                }
+                if (v->end < pre_assignment_length)
+                    for (q = old + v->end; *q;)
+                        *p++ = ztrdup(*q++);
+                *p = NULL;
+
+                v->pm->gsu.a->setfn(v->pm, new);
+            }
 
 	    DPUTS2(p - new != post_assignment_length, "setarrvalue: wrong allocation: %d 1= %lu",
 		   post_assignment_length, (unsigned long)(p - new));
-
-	    v->pm->gsu.a->setfn(v->pm, new);
 	}
 
         /* Ownership of all strings has been
diff --git a/Test/A06assign.ztst b/Test/A06assign.ztst
index bf39aee..fd2b417 100644
--- a/Test/A06assign.ztst
+++ b/Test/A06assign.ztst
@@ -133,6 +133,72 @@
 >1 2 42 43 44 5
 >1 2 42 100 99 5
 
+# (subsection: append to array)
+
+ array=( )
+ array[5,6]=( 1 2 3 )
+ print $array
+ print "${(q@)array}"
+0:Append to empty array by range
+>1 2 3
+>'' '' '' '' 1 2 3
+
+ array=( a )
+ array[5,6]=( 1 2 3 )
+ print $array
+ print "${(q@)array}"
+0:Append to 1-element array by range
+>a 1 2 3
+>a '' '' '' 1 2 3
+
+ array=( a b )
+ array[5,6]=( 1 2 3 )
+ print $array
+ print "${(q@)array}"
+0:Append to 2-element array by range
+>a b 1 2 3
+>a b '' '' 1 2 3
+
+ array=( a b )
+ array[5,5]=( 1 2 3 )
+ print $array
+ print "${(q@)array}"
+0:Append to 2-element array by [a,a] range
+>a b 1 2 3
+>a b '' '' 1 2 3
+
+ array=( a b c d )
+ array[5,6]=( 1 2 3 )
+ print $array
+ print "${(q@)array}"
+0:Append array by range, continuously
+>a b c d 1 2 3
+>a b c d 1 2 3
+
+ array=( a b c d )
+ array[5,5]=( 1 2 3 )
+ print $array
+ print "${(q@)array}"
+0:Append array by [a,a] range, continuously
+>a b c d 1 2 3
+>a b c d 1 2 3
+
+ array=( )
+ array+=( 1 2 3 )
+ print $array
+ print "${(q@)array}"
+0:Append empty array via +=
+>1 2 3
+>1 2 3
+
+ array=( a )
+ array+=( 1 2 3 )
+ print $array
+ print "${(q@)array}"
+0:Append 1-element array via +=
+>a 1 2 3
+>a 1 2 3
+
 # tests of var+=scalar
 
  s+=foo


Messages sorted by: Reverse Date, Date, Thread, Author