1
0
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:
Dmitry Stogov
2015-01-30 12:24:31 +03:00
parent 5aa9712b0a
commit cc4b7be41e
9 changed files with 254 additions and 196 deletions

View 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

View 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

View 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

View 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

View 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) {
}

View 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)

View File

@@ -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)));

View File

@@ -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"
}

View File

@@ -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"
}