com php-src: Make internal function, operation on array passed by reference, to preserve foreach hash position: Zend/tests/foreac h_011.phpt Zend/tests/foreach_012.phpt Zend/tests/foreach_013.phpt Zend/tests/foreach_ 014.phpt Zend/tests/foreach_015.phpt Zend /tests/foreach_016.phpt ext/standard/array.c te sts/lang/foreachLoop.013.phpt tests/lang/foreachLoo p.015.phpt

[email protected] (Rasmus Lerdorf)
Newsgroups php.cvs
Message-ID <[email protected]>
Commit:    cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e
Author:    Dmitry Stogov <[email protected]>         Fri, 30 Jan 2015 12:24:31 +0300
Parents:   5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1
Branches:  dstogov-foreach

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e

Log:
Make internal function, operation on array passed by reference, to preserve foreach hash position

Changed paths:
  A  Zend/tests/foreach_011.phpt
  A  Zend/tests/foreach_012.phpt
  A  Zend/tests/foreach_013.phpt
  A  Zend/tests/foreach_014.phpt
  A  Zend/tests/foreach_015.phpt
  A  Zend/tests/foreach_016.phpt
  M  ext/standard/array.c
  M  tests/lang/foreachLoop.013.phpt
  M  tests/lang/foreachLoop.015.phpt
diff_cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e.txt (text/plain, 14.1 KB)
diff --git a/Zend/tests/foreach_011.phpt b/Zend/tests/foreach_011.phpt
new file mode 100644
index 0000000..e91426f
--- /dev/null
+++ b/Zend/tests/foreach_011.phpt
@@ -0,0 +1,19 @@
+--TEST--
+sort() functions precerve foreach by reference iterator pointer
+--FILE--
+<?php
+$a = [1,2,3,4,5,0];
+foreach($a as &$v) {
+	echo "$v\n";
+	if ($v == 3) {
+		rsort($a);
+	}
+}
+?>
+--EXPECT--
+1
+2
+3
+2
+1
+0
diff --git a/Zend/tests/foreach_012.phpt b/Zend/tests/foreach_012.phpt
new file mode 100644
index 0000000..5e5538c
--- /dev/null
+++ b/Zend/tests/foreach_012.phpt
@@ -0,0 +1,18 @@
+--TEST--
+array_walk() function precerve foreach by reference iterator pointer
+--FILE--
+<?php
+$a = [1,2,3,4,5];
+foreach($a as &$v) {
+	echo "$v\n";
+	if ($v == 3) {
+		array_walk($a, function (&$x) {$x+=10;});
+	}
+}
+?>
+--EXPECT--
+1
+2
+3
+14
+15
\ No newline at end of file
diff --git a/Zend/tests/foreach_013.phpt b/Zend/tests/foreach_013.phpt
new file mode 100644
index 0000000..cfbb3d7
--- /dev/null
+++ b/Zend/tests/foreach_013.phpt
@@ -0,0 +1,17 @@
+--TEST--
+array_push() function precerve foreach by reference iterator pointer
+--FILE--
+<?php
+$a = [1,2,3];
+foreach($a as &$v) {
+	echo "$v\n";
+	if ($v == 3) {
+		array_push($a, 4);
+	}
+}
+?>
+--EXPECT--
+1
+2
+3
+4
diff --git a/Zend/tests/foreach_014.phpt b/Zend/tests/foreach_014.phpt
new file mode 100644
index 0000000..8d0ac58
--- /dev/null
+++ b/Zend/tests/foreach_014.phpt
@@ -0,0 +1,15 @@
+--TEST--
+array_pop() function precerve foreach by reference iterator pointer
+--FILE--
+<?php
+$a = [1,2,3];
+foreach($a as &$v) {
+	echo "$v\n";
+	if ($v == 2) {
+		array_pop($a);
+	}
+}
+?>
+--EXPECT--
+1
+2
diff --git a/Zend/tests/foreach_015.phpt b/Zend/tests/foreach_015.phpt
new file mode 100644
index 0000000..adc8085
--- /dev/null
+++ b/Zend/tests/foreach_015.phpt
@@ -0,0 +1,18 @@
+--TEST--
+array_shift() function precerve foreach by reference iterator pointer
+--FILE--
+<?php
+$a = [1,2,3,4];
+foreach($a as &$v) {
+	echo "$v\n";
+	array_shift($a);
+}
+var_dump($a);
+?>
+--EXPECT--
+1
+2
+3
+4
+array(0) {
+}
\ No newline at end of file
diff --git a/Zend/tests/foreach_016.phpt b/Zend/tests/foreach_016.phpt
new file mode 100644
index 0000000..423c8dd
--- /dev/null
+++ b/Zend/tests/foreach_016.phpt
@@ -0,0 +1,18 @@
+--TEST--
+array_unshift() function precerve foreach by reference iterator pointer
+--FILE--
+<?php
+$a = [1,2,3];
+foreach($a as &$v) {
+	echo "$v\n";
+	if ($v == 2) {
+		array_unshift($a, 0, 0, 0, 0, 0, 0, 0, 0);
+	}
+}
+var_dump(count($a));
+?>
+--EXPECT--
+1
+2
+3
+int(11)
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 49c6cd0..526c921 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -1877,26 +1877,49 @@ static void php_array_data_shuffle(zval *array) /* {{{ */
 	hash = Z_ARRVAL_P(array);
 	n_left = n_elems;
 
-	if (hash->nNumUsed != hash->nNumOfElements) {
-		for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
-			p = hash->arData + idx;
-			if (Z_TYPE(p->val) == IS_UNDEF) continue;
-			if (j != idx) {
-				hash->arData[j] = *p;
+	if (EXPECTED(hash->u.v.nIteratorsCount == 0)) {
+		if (hash->nNumUsed != hash->nNumOfElements) {
+			for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
+				p = hash->arData + idx;
+				if (Z_TYPE(p->val) == IS_UNDEF) continue;
+				if (j != idx) {
+					hash->arData[j] = *p;
+				}
+				j++;
 			}
-			j++;
 		}
-	}
-	while (--n_left) {
-		rnd_idx = php_rand();
-		RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
-		if (rnd_idx != n_left) {
-			temp = hash->arData[n_left];
-			hash->arData[n_left] = hash->arData[rnd_idx];
-			hash->arData[rnd_idx] = temp;
+		while (--n_left) {
+			rnd_idx = php_rand();
+			RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
+			if (rnd_idx != n_left) {
+				temp = hash->arData[n_left];
+				hash->arData[n_left] = hash->arData[rnd_idx];
+				hash->arData[rnd_idx] = temp;
+			}
+		}
+	} else {
+		if (hash->nNumUsed != hash->nNumOfElements) {
+			for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
+				p = hash->arData + idx;
+				if (Z_TYPE(p->val) == IS_UNDEF) continue;
+				if (j != idx) {
+					hash->arData[j] = *p;
+					zend_hash_iterators_update(hash, idx, j);
+				}
+				j++;
+			}
+		}
+		while (--n_left) {
+			rnd_idx = php_rand();
+			RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
+			if (rnd_idx != n_left) {
+				temp = hash->arData[n_left];
+				hash->arData[n_left] = hash->arData[rnd_idx];
+				hash->arData[rnd_idx] = temp;
+				zend_hash_iterators_update(hash, rnd_idx, n_left);
+			}
 		}
 	}
-
 	HANDLE_BLOCK_INTERRUPTIONS();
 	hash->nNumUsed = n_elems;
 	hash->nInternalPointer = 0;
@@ -2194,18 +2217,33 @@ PHP_FUNCTION(array_shift)
 	if (Z_ARRVAL_P(stack)->u.flags & HASH_FLAG_PACKED) {
 		uint32_t k = 0;
 
-		for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
-			p = Z_ARRVAL_P(stack)->arData + idx;
-			if (Z_TYPE(p->val) == IS_UNDEF) continue;
-			if (idx != k) {
-				Bucket *q = Z_ARRVAL_P(stack)->arData + k;
-				q->h = k;
-				q->key = NULL;
-				ZVAL_COPY_VALUE(&q->val, &p->val);
-				ZVAL_UNDEF(&p->val);
-				zend_hash_iterators_update(Z_ARRVAL_P(stack), idx, k);
+		if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
+			for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
+				p = Z_ARRVAL_P(stack)->arData + idx;
+				if (Z_TYPE(p->val) == IS_UNDEF) continue;
+				if (idx != k) {
+					Bucket *q = Z_ARRVAL_P(stack)->arData + k;
+					q->h = k;
+					q->key = NULL;
+					ZVAL_COPY_VALUE(&q->val, &p->val);
+					ZVAL_UNDEF(&p->val);
+				}
+				k++;
+			}
+		} else {
+			for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
+				p = Z_ARRVAL_P(stack)->arData + idx;
+				if (Z_TYPE(p->val) == IS_UNDEF) continue;
+				if (idx != k) {
+					Bucket *q = Z_ARRVAL_P(stack)->arData + k;
+					q->h = k;
+					q->key = NULL;
+					ZVAL_COPY_VALUE(&q->val, &p->val);
+					ZVAL_UNDEF(&p->val);
+					zend_hash_iterators_update(Z_ARRVAL_P(stack), idx, k);
+				}
+				k++;
 			}
-			k++;
 		}
 		Z_ARRVAL_P(stack)->nNumUsed = k;
 		Z_ARRVAL_P(stack)->nNextFreeElement = k;
@@ -2258,21 +2296,46 @@ PHP_FUNCTION(array_unshift)
 		}
 		zend_hash_next_index_insert_new(&new_hash, &args[i]);
 	}
-	ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
-		if (key) {
-			zend_hash_add_new(&new_hash, key, value);
-		} else {
-			zend_hash_next_index_insert_new(&new_hash, value);
-		}
-	} ZEND_HASH_FOREACH_END();
+	if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
+		ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
+			if (key) {
+				zend_hash_add_new(&new_hash, key, value);
+			} else {
+				zend_hash_next_index_insert_new(&new_hash, value);
+			}
+		} ZEND_HASH_FOREACH_END();
+	} else {
+		uint32_t old_idx;
+		uint32_t new_idx = i;
 
-	new_hash.u.v.nIteratorsCount = Z_ARRVAL_P(stack)->u.v.nIteratorsCount;
+		ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
+			if (key) {
+				zend_hash_add_new(&new_hash, key, value);
+			} else {
+				zend_hash_next_index_insert_new(&new_hash, value);
+			}
+			old_idx = (Bucket*)value - Z_ARRVAL_P(stack)->arData;
+			zend_hash_iterators_update(Z_ARRVAL_P(stack), old_idx, new_idx);
+			new_idx++;
+		} ZEND_HASH_FOREACH_END();
+	}
+
+	/* replace HashTable data */
 	Z_ARRVAL_P(stack)->u.v.nIteratorsCount = 0;
 	Z_ARRVAL_P(stack)->pDestructor = NULL;
 	zend_hash_destroy(Z_ARRVAL_P(stack));
-	*Z_ARRVAL_P(stack) = new_hash;
+
+	Z_ARRVAL_P(stack)->u.v.flags         = new_hash.u.v.flags;
+	Z_ARRVAL_P(stack)->nTableSize        = new_hash.nTableSize;
+	Z_ARRVAL_P(stack)->nTableMask        = new_hash.nTableMask;
+	Z_ARRVAL_P(stack)->nNumUsed          = new_hash.nNumUsed;
+	Z_ARRVAL_P(stack)->nNumOfElements    = new_hash.nNumOfElements;
+	Z_ARRVAL_P(stack)->nNextFreeElement  = new_hash.nNextFreeElement;
+	Z_ARRVAL_P(stack)->arData            = new_hash.arData;
+	Z_ARRVAL_P(stack)->arHash            = new_hash.arHash;
+	Z_ARRVAL_P(stack)->pDestructor       = new_hash.pDestructor;
+	
 	zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
-	zend_hash_iterators_reset(Z_ARRVAL_P(stack));
 
 	/* Clean up and return the number of elements in the stack */
 	RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
diff --git a/tests/lang/foreachLoop.013.phpt b/tests/lang/foreachLoop.013.phpt
index 10f43f3..ea72815 100644
--- a/tests/lang/foreachLoop.013.phpt
+++ b/tests/lang/foreachLoop.013.phpt
@@ -445,28 +445,12 @@ array(1) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=0; $v=new.0
-     iteration 2:  $k=0; $v=new.1
-     iteration 3:  $k=0; $v=new.2
-     iteration 4:  $k=0; $v=new.3
-     iteration 5:  $k=0; $v=new.4
-  ** Stuck in a loop! **
 --> State of array after loop:
-array(7) {
+array(2) {
   [0]=>
-  string(5) "new.5"
-  [1]=>
-  &string(5) "new.4"
-  [2]=>
-  string(5) "new.3"
-  [3]=>
-  string(5) "new.2"
-  [4]=>
-  string(5) "new.1"
-  [5]=>
   string(5) "new.0"
-  [6]=>
-  string(3) "v.0"
+  [1]=>
+  &string(3) "v.0"
 }
 
 ---( Array with 2 element(s): )---
@@ -479,30 +463,17 @@ array(2) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=0; $v=new.0
-     iteration 2:  $k=0; $v=new.1
-     iteration 3:  $k=0; $v=new.2
-     iteration 4:  $k=0; $v=new.3
-     iteration 5:  $k=0; $v=new.4
-  ** Stuck in a loop! **
+     iteration 1:  $k=2; $v=v.1
 --> State of array after loop:
-array(8) {
+array(4) {
   [0]=>
-  string(5) "new.5"
-  [1]=>
-  &string(5) "new.4"
-  [2]=>
-  string(5) "new.3"
-  [3]=>
-  string(5) "new.2"
-  [4]=>
   string(5) "new.1"
-  [5]=>
+  [1]=>
   string(5) "new.0"
-  [6]=>
+  [2]=>
   string(3) "v.0"
-  [7]=>
-  string(3) "v.1"
+  [3]=>
+  &string(3) "v.1"
 }
 
 ---( Array with 3 element(s): )---
@@ -517,32 +488,19 @@ array(3) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=0; $v=new.0
-     iteration 2:  $k=0; $v=new.1
-     iteration 3:  $k=0; $v=new.2
-     iteration 4:  $k=0; $v=new.3
-     iteration 5:  $k=0; $v=new.4
-  ** Stuck in a loop! **
+     iteration 1:  $k=3; $v=v.2
 --> State of array after loop:
-array(9) {
+array(5) {
   [0]=>
-  string(5) "new.5"
-  [1]=>
-  &string(5) "new.4"
-  [2]=>
-  string(5) "new.3"
-  [3]=>
-  string(5) "new.2"
-  [4]=>
   string(5) "new.1"
-  [5]=>
+  [1]=>
   string(5) "new.0"
-  [6]=>
+  [2]=>
   string(3) "v.0"
-  [7]=>
+  [3]=>
   string(3) "v.1"
-  [8]=>
-  string(3) "v.2"
+  [4]=>
+  &string(3) "v.2"
 }
 
 ---( Array with 4 element(s): )---
@@ -559,32 +517,19 @@ array(4) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=0; $v=new.0
-     iteration 2:  $k=0; $v=new.1
-     iteration 3:  $k=0; $v=new.2
-     iteration 4:  $k=0; $v=new.3
-     iteration 5:  $k=0; $v=new.4
-  ** Stuck in a loop! **
+     iteration 1:  $k=4; $v=v.3
 --> State of array after loop:
-array(10) {
+array(6) {
   [0]=>
-  string(5) "new.5"
-  [1]=>
-  &string(5) "new.4"
-  [2]=>
-  string(5) "new.3"
-  [3]=>
-  string(5) "new.2"
-  [4]=>
   string(5) "new.1"
-  [5]=>
+  [1]=>
   string(5) "new.0"
-  [6]=>
+  [2]=>
   string(3) "v.0"
-  [7]=>
+  [3]=>
   string(3) "v.1"
-  [8]=>
+  [4]=>
   string(3) "v.2"
-  [9]=>
-  string(3) "v.3"
+  [5]=>
+  &string(3) "v.3"
 }
diff --git a/tests/lang/foreachLoop.015.phpt b/tests/lang/foreachLoop.015.phpt
index a56249e..a4ee09d 100644
--- a/tests/lang/foreachLoop.015.phpt
+++ b/tests/lang/foreachLoop.015.phpt
@@ -447,28 +447,12 @@ array(1) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=0; $v=new.0
-     iteration 2:  $k=0; $v=new.1
-     iteration 3:  $k=0; $v=new.2
-     iteration 4:  $k=0; $v=new.3
-     iteration 5:  $k=0; $v=new.4
-  ** Stuck in a loop! **
 --> State of array after loop:
-array(7) {
+array(2) {
   [0]=>
-  string(5) "new.5"
-  [1]=>
-  &string(5) "new.4"
-  [2]=>
-  string(5) "new.3"
-  [3]=>
-  string(5) "new.2"
-  [4]=>
-  string(5) "new.1"
-  [5]=>
   string(5) "new.0"
-  [6]=>
-  string(3) "v.0"
+  [1]=>
+  &string(3) "v.0"
 }
 
 ---( Array with 2 element(s): )---
@@ -481,30 +465,17 @@ array(2) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=0; $v=new.0
-     iteration 2:  $k=0; $v=new.1
-     iteration 3:  $k=0; $v=new.2
-     iteration 4:  $k=0; $v=new.3
-     iteration 5:  $k=0; $v=new.4
-  ** Stuck in a loop! **
+     iteration 1:  $k=2; $v=v.1
 --> State of array after loop:
-array(8) {
+array(4) {
   [0]=>
-  string(5) "new.5"
-  [1]=>
-  &string(5) "new.4"
-  [2]=>
-  string(5) "new.3"
-  [3]=>
-  string(5) "new.2"
-  [4]=>
   string(5) "new.1"
-  [5]=>
+  [1]=>
   string(5) "new.0"
-  [6]=>
+  [2]=>
   string(3) "v.0"
-  [7]=>
-  string(3) "v.1"
+  [3]=>
+  &string(3) "v.1"
 }
 
 ---( Array with 3 element(s): )---
@@ -519,32 +490,19 @@ array(3) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=0; $v=new.0
-     iteration 2:  $k=0; $v=new.1
-     iteration 3:  $k=0; $v=new.2
-     iteration 4:  $k=0; $v=new.3
-     iteration 5:  $k=0; $v=new.4
-  ** Stuck in a loop! **
+     iteration 1:  $k=3; $v=v.2
 --> State of array after loop:
-array(9) {
+array(5) {
   [0]=>
-  string(5) "new.5"
-  [1]=>
-  &string(5) "new.4"
-  [2]=>
-  string(5) "new.3"
-  [3]=>
-  string(5) "new.2"
-  [4]=>
   string(5) "new.1"
-  [5]=>
+  [1]=>
   string(5) "new.0"
-  [6]=>
+  [2]=>
   string(3) "v.0"
-  [7]=>
+  [3]=>
   string(3) "v.1"
-  [8]=>
-  string(3) "v.2"
+  [4]=>
+  &string(3) "v.2"
 }
 
 ---( Array with 4 element(s): )---
@@ -561,32 +519,19 @@ array(4) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=0; $v=new.0
-     iteration 2:  $k=0; $v=new.1
-     iteration 3:  $k=0; $v=new.2
-     iteration 4:  $k=0; $v=new.3
-     iteration 5:  $k=0; $v=new.4
-  ** Stuck in a loop! **
+     iteration 1:  $k=4; $v=v.3
 --> State of array after loop:
-array(10) {
+array(6) {
   [0]=>
-  string(5) "new.5"
-  [1]=>
-  &string(5) "new.4"
-  [2]=>
-  string(5) "new.3"
-  [3]=>
-  string(5) "new.2"
-  [4]=>
   string(5) "new.1"
-  [5]=>
+  [1]=>
   string(5) "new.0"
-  [6]=>
+  [2]=>
   string(3) "v.0"
-  [7]=>
+  [3]=>
   string(3) "v.1"
-  [8]=>
+  [4]=>
   string(3) "v.2"
-  [9]=>
-  string(3) "v.3"
+  [5]=>
+  &string(3) "v.3"
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.