summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Src/params.c50
2 files changed, 38 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 6206f1f07..3bb1c6c5d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2016-12-28  Sebastian Gniazdowski  <psprint@fastmail.com>
+
+	* 40231: Src/params.c: Optimise setarrvalue().
+
 2016-12-28  Daniel Shahaf  <d.s@daniel.shahaf.name>
 
 	* 40232: configure.ac: Remove SH_USE_BSD_ECHO autoconf test.
diff --git a/Src/params.c b/Src/params.c
index c64d7486b..5b93cafe2 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2708,24 +2708,40 @@ setarrvalue(Value v, char **val)
 	    post_assignment_length += pre_assignment_length - v->end;
 	}
 
-	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;
+	if (pre_assignment_length == post_assignment_length
+	    && v->pm->gsu.a->setfn == arrsetfn
+	    /* ... and isn't something that arrsetfn() treats specially */
+	    && 0 == (v->pm->node.flags & (PM_SPECIAL|PM_UNIQUE))
+	    && NULL == v->pm->ename)
+	{
+	    /* v->start is 0-based */
+	    p = old + v->start;
+	    for (r = val; *r;) {
+		/* Free previous string */
+		zsfree(*p);
+		/* Give away ownership of the string */
+		*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;
 
-	DPUTS2(p - new != post_assignment_length, "setarrvalue: wrong allocation: %d 1= %lu",
-	       post_assignment_length, (unsigned long)(p - 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);
+	    v->pm->gsu.a->setfn(v->pm, new);
+	}
 
         /* Ownership of all strings has been
          * given away, can plainly free */
@@ -3485,6 +3501,8 @@ arrsetfn(Param pm, char **x)
     /* Arrays tied to colon-arrays may need to fix the environment */
     if (pm->ename && x)
 	arrfixenv(pm->ename, x);
+    /* If you extend this function, update the list of conditions in
+     * setarrvalue(). */
 }
 
 /* Function to get value of an association parameter */