mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Make internal function, operation on array passed by reference, to preserve foreach hash position
This commit is contained in:
19
Zend/tests/foreach_011.phpt
Normal file
19
Zend/tests/foreach_011.phpt
Normal file
@@ -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
|
||||
18
Zend/tests/foreach_012.phpt
Normal file
18
Zend/tests/foreach_012.phpt
Normal file
@@ -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
|
||||
17
Zend/tests/foreach_013.phpt
Normal file
17
Zend/tests/foreach_013.phpt
Normal file
@@ -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
|
||||
15
Zend/tests/foreach_014.phpt
Normal file
15
Zend/tests/foreach_014.phpt
Normal file
@@ -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
|
||||
18
Zend/tests/foreach_015.phpt
Normal file
18
Zend/tests/foreach_015.phpt
Normal file
@@ -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) {
|
||||
}
|
||||
18
Zend/tests/foreach_016.phpt
Normal file
18
Zend/tests/foreach_016.phpt
Normal file
@@ -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)
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user