Skip to content

Commit 319fddf

Browse files
committed
Implement the negative_array_index RFC
1 parent 81bca7f commit 319fddf

File tree

4 files changed

+44
-9
lines changed

4 files changed

+44
-9
lines changed

Zend/zend_hash.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize
220220
ht->nNumUsed = 0;
221221
ht->nNumOfElements = 0;
222222
ht->nInternalPointer = 0;
223-
ht->nNextFreeElement = 0;
223+
ht->nNextFreeElement = ZEND_LONG_MIN;
224224
ht->pDestructor = pDestructor;
225225
ht->nTableSize = zend_hash_check_size(nSize);
226226
}
@@ -935,6 +935,10 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht,
935935
IS_CONSISTENT(ht);
936936
HT_ASSERT_RC1(ht);
937937

938+
if (h == ZEND_LONG_MIN && (flag & HASH_ADD_NEXT)) {
939+
h = 0;
940+
}
941+
938942
if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
939943
if (h < ht->nNumUsed) {
940944
p = ht->arData + h;
@@ -998,8 +1002,8 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht,
9981002
p = ht->arData + idx;
9991003
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
10001004
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1001-
if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
1002-
ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
1005+
if ((zend_long)h >= ht->nNextFreeElement) {
1006+
ht->nNextFreeElement = (zend_long)h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
10031007
}
10041008
add:
10051009
ht->nNumOfElements++;
@@ -1665,7 +1669,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
16651669
}
16661670
ht->nNumUsed = 0;
16671671
ht->nNumOfElements = 0;
1668-
ht->nNextFreeElement = 0;
1672+
ht->nNextFreeElement = ZEND_LONG_MIN;
16691673
ht->nInternalPointer = 0;
16701674
}
16711675

@@ -1704,7 +1708,7 @@ ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
17041708
}
17051709
ht->nNumUsed = 0;
17061710
ht->nNumOfElements = 0;
1707-
ht->nNextFreeElement = 0;
1711+
ht->nNextFreeElement = ZEND_LONG_MIN;
17081712
ht->nInternalPointer = 0;
17091713
}
17101714

@@ -2018,7 +2022,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
20182022
target->nTableMask = HT_MIN_MASK;
20192023
target->nNumUsed = 0;
20202024
target->nNumOfElements = 0;
2021-
target->nNextFreeElement = 0;
2025+
target->nNextFreeElement = ZEND_LONG_MIN;
20222026
target->nInternalPointer = 0;
20232027
target->nTableSize = HT_MIN_SIZE;
20242028
HT_SET_DATA_ADDR(target, &uninitialized_bucket);

ext/standard/array.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -3228,7 +3228,7 @@ PHP_FUNCTION(array_pop)
32283228
}
32293229
ZVAL_COPY_DEREF(return_value, val);
32303230

3231-
if (!p->key && Z_ARRVAL_P(stack)->nNextFreeElement > 0 && p->h >= (zend_ulong)(Z_ARRVAL_P(stack)->nNextFreeElement - 1)) {
3231+
if (!p->key && (zend_long)p->h == (Z_ARRVAL_P(stack)->nNextFreeElement - 1)) {
32323232
Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;
32333233
}
32343234

ext/standard/tests/array/bug67693.phpt

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ echo"\nDone";
1616
?>
1717
--EXPECT--
1818
array(2) {
19-
[0]=>
19+
[-1]=>
2020
int(0)
21-
[1]=>
21+
[0]=>
2222
int(0)
2323
}
2424

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
Test arrays starting with negative indices
3+
--FILE--
4+
<?php
5+
6+
$a = array_fill(-2, 3, true);
7+
$b = [-2 => true, true, true];
8+
$c = ["string" => true, -2 => true, true, true];
9+
unset($c["string"]);
10+
$d[-2] = true;
11+
$d[] = true;
12+
$d[] = true;
13+
$e = [-2 => false];
14+
array_pop($e);
15+
$e[] = true;
16+
$e[] = true;
17+
$e[] = true;
18+
19+
var_dump($a === $b && $b === $c && $c === $d && $d == $e);
20+
var_dump($a);
21+
?>
22+
--EXPECT--
23+
bool(true)
24+
array(3) {
25+
[-2]=>
26+
bool(true)
27+
[-1]=>
28+
bool(true)
29+
[0]=>
30+
bool(true)
31+
}

0 commit comments

Comments
 (0)