mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Make array_splice() to preserve foreach hash position
This commit is contained in:
111
Zend/tests/foreach_017.phpt
Normal file
111
Zend/tests/foreach_017.phpt
Normal file
@@ -0,0 +1,111 @@
|
||||
--TEST--
|
||||
array_unshift() function precerve foreach by reference iterator pointer
|
||||
--FILE--
|
||||
<?php
|
||||
/* remove before */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 3) {
|
||||
$done = 1;
|
||||
array_splice($a, 1, 2);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
/* remove after */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 0) {
|
||||
$done = 1;
|
||||
array_splice($a, 2, 2);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
/* remove current */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 2) {
|
||||
$done = 1;
|
||||
array_splice($a, 1, 3);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
$replacement = ['x', 'y', 'z'];
|
||||
|
||||
/* replace before */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if ($done && $v == 3) {
|
||||
$done = 1;
|
||||
array_splice($a, 1, 2, $replacement);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
/* replace after */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 0) {
|
||||
$done = 1;
|
||||
array_splice($a, 2, 2, $replacement);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
/* replace current */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 2) {
|
||||
$done = 1;
|
||||
array_splice($a, 1, 3, $replacement);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
2
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
x
|
||||
y
|
||||
z
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
2
|
||||
4
|
||||
@@ -354,21 +354,6 @@ ZEND_API void zend_hash_iterators_update(HashTable *ht, HashPosition from, HashP
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void zend_hash_iterators_reset(HashTable *ht)
|
||||
{
|
||||
if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_used);
|
||||
|
||||
while (iter != end) {
|
||||
if (iter->ht == ht) {
|
||||
iter->pos = ht->nInternalPointer;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
|
||||
{
|
||||
zend_ulong h;
|
||||
|
||||
@@ -230,7 +230,6 @@ ZEND_API uint32_t zend_hash_iterator_add(HashTable *ht);
|
||||
ZEND_API HashPosition zend_hash_iterator_pos(uint32_t idx, HashTable *ht);
|
||||
ZEND_API void zend_hash_iterator_del(uint32_t idx);
|
||||
ZEND_API void zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to);
|
||||
ZEND_API void zend_hash_iterators_reset(HashTable *ht);
|
||||
|
||||
|
||||
END_EXTERN_C()
|
||||
|
||||
@@ -1989,7 +1989,6 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
for (pos = 0, idx = 0; pos < offset && idx < in_hash->nNumUsed; idx++) {
|
||||
p = in_hash->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
pos++;
|
||||
/* Get entry and increase reference count */
|
||||
entry = &p->val;
|
||||
|
||||
@@ -1999,6 +1998,10 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
} else {
|
||||
zend_hash_add_new(&out_hash, p->key, entry);
|
||||
}
|
||||
if (idx != pos) {
|
||||
zend_hash_iterators_update(in_hash, idx, pos);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
/* If hash for removed entries exists, go until offset+length and copy the entries to it */
|
||||
@@ -2024,10 +2027,12 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
}
|
||||
}
|
||||
} else { /* otherwise just skip those entries */
|
||||
for ( ; pos < offset + length && idx < in_hash->nNumUsed; idx++) {
|
||||
int pos2 = pos;
|
||||
|
||||
for ( ; pos2 < offset + length && idx < in_hash->nNumUsed; idx++) {
|
||||
p = in_hash->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
pos++;
|
||||
pos2++;
|
||||
if (p->key == NULL) {
|
||||
zend_hash_index_del(in_hash, p->h);
|
||||
} else {
|
||||
@@ -2045,6 +2050,7 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
ZEND_HASH_FOREACH_VAL_IND(replace, entry) {
|
||||
if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
|
||||
zend_hash_next_index_insert_new(&out_hash, entry);
|
||||
pos++;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
@@ -2058,13 +2064,28 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
} else {
|
||||
zend_hash_add_new(&out_hash, p->key, entry);
|
||||
}
|
||||
if (idx != pos) {
|
||||
zend_hash_iterators_update(in_hash, idx, pos);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
zend_hash_internal_pointer_reset(&out_hash);
|
||||
|
||||
/* replace HashTable data */
|
||||
in_hash->u.v.nIteratorsCount = 0;
|
||||
in_hash->pDestructor = NULL;
|
||||
zend_hash_destroy(in_hash);
|
||||
*in_hash = out_hash;
|
||||
|
||||
in_hash->u.v.flags = out_hash.u.v.flags;
|
||||
in_hash->nTableSize = out_hash.nTableSize;
|
||||
in_hash->nTableMask = out_hash.nTableMask;
|
||||
in_hash->nNumUsed = out_hash.nNumUsed;
|
||||
in_hash->nNumOfElements = out_hash.nNumOfElements;
|
||||
in_hash->nNextFreeElement = out_hash.nNextFreeElement;
|
||||
in_hash->arData = out_hash.arData;
|
||||
in_hash->arHash = out_hash.arHash;
|
||||
in_hash->pDestructor = out_hash.pDestructor;
|
||||
|
||||
zend_hash_internal_pointer_reset(in_hash);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user