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

Array slices that don't exist [was Optimization of getarrvalue()]



On Nov 24,  8:49pm, Jun T. wrote:
}
} % a=(one two)
} and see what is returned by
} % nargs "${(@)a[i,j]}"
} 
} For i >= 4 or i <= -3 it returns 1 if j >= i,
} while for i=3 (=$#a+1) it returns 0 always.

Hmm.

Internally the array $a is stored as a[0]="one" a[1]="two" a[2]=NULL so
when we look at $a[i,j] we decrement i but not j to look at the internal
elements starting with a[i-1] and ending before (not including) a[j].

This means that if $i = $#a we're always going to take the branch that
now has the comment

        /* Copy to a point before the end of the source array:
         * arrdup_max will copy at most v->end - v->start elements,
         * starting from v->start element. Original code said:
	 *  s[v->end - v->start] = NULL

with v->start pointing at the NULL terminator of the internal array, so
we return an empty array.

If $i > $#a then we take the arrlen_lt(s, v->start) branch and always
return a single element.

So the question is ... is the following more consistent?

for i in 1 2 3 4; do
 for j in 1 2 3 4 5; do
  print -n "$i $j = "
  nargs "${(@)a[i,j]}"
 done
done

5.2       |  5.3 **
----------+----------
1 1 => 1  |  1 1 => 1
1 2 => 2  |  1 2 => 2
1 3 => 2  |  1 3 => 2
1 4 => 2  |  1 4 => 2
1 5 => 2  |  1 5 => 2
2 1 => 0  |  2 1 => 0
2 2 => 1  |  2 2 => 1
2 3 => 1  |  2 3 => 1
2 4 => 1  |  2 4 => 1
2 5 => 1  |  2 5 => 1
3 1 => 0  |  3 1 => 0
3 2 => 0  |  3 2 => 0
3 3 => 0  |  3 3 => 0
3 4 => 0  |  3 4 => 1   **
3 5 => 0  |  3 5 => 1   **
4 1 => 0  |  4 1 => 0
4 2 => 0  |  4 2 => 0
4 3 => 0  |  4 3 => 0
4 4 => 1  |  4 4 => 0   **
4 5 => 1  |  4 5 => 1

This means you have to slice more than one non-existent element to
get an empty string; a slice of one such element is an empty array.

All "make check" tests still pass with that behavior though I'm not
certain that all completions would work identically.

Code looks like this:

diff --git a/Src/params.c b/Src/params.c
index 45f398a..aa8b196 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2299,9 +2299,16 @@ getarrvalue(Value v)
     if (v->end <= v->start) {
 	s = arrdup_max(nular, 0);
     }
-    else if (arrlen_lt(s, v->start) || v->start < 0) {
+    else if (v->start < 0) {
 	s = arrdup_max(nular, 1);
-    } else {
+    }
+    else if (arrlen_le(s, v->start)) {
+	/* Handle $ary[i,i] consistently for any $i > $#ary
+	 * and $ary[i,j] consistently for any $j > $i > $#ary
+	 */
+	s = arrdup_max(nular, v->end - (v->start + 1));
+    }
+    else {
         /* Copy to a point before the end of the source array:
          * arrdup_max will copy at most v->end - v->start elements,
          * starting from v->start element. Original code said:



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