From 319fddf5638c3d356c94cb5a36a05e7485b23467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Magalh=C3=A3es?= Date: Tue, 29 Jan 2019 00:08:10 +0000 Subject: [PATCH] Implement the negative_array_index RFC --- Zend/zend_hash.c | 16 ++++++---- ext/standard/array.c | 2 +- ext/standard/tests/array/bug67693.phpt | 4 +-- ext/standard/tests/array/negative_index.phpt | 31 ++++++++++++++++++++ 4 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 ext/standard/tests/array/negative_index.phpt diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index f95034a60ffc..05c938abc264 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -220,7 +220,7 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize ht->nNumUsed = 0; ht->nNumOfElements = 0; ht->nInternalPointer = 0; - ht->nNextFreeElement = 0; + ht->nNextFreeElement = ZEND_LONG_MIN; ht->pDestructor = pDestructor; ht->nTableSize = zend_hash_check_size(nSize); } @@ -935,6 +935,10 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, IS_CONSISTENT(ht); HT_ASSERT_RC1(ht); + if (h == ZEND_LONG_MIN && (flag & HASH_ADD_NEXT)) { + h = 0; + } + if (HT_FLAGS(ht) & HASH_FLAG_PACKED) { if (h < ht->nNumUsed) { p = ht->arData + h; @@ -998,8 +1002,8 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, p = ht->arData + idx; Z_NEXT(p->val) = HT_HASH(ht, nIndex); HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx); - if ((zend_long)h >= (zend_long)ht->nNextFreeElement) { - ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX; + if ((zend_long)h >= ht->nNextFreeElement) { + ht->nNextFreeElement = (zend_long)h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX; } add: ht->nNumOfElements++; @@ -1665,7 +1669,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht) } ht->nNumUsed = 0; ht->nNumOfElements = 0; - ht->nNextFreeElement = 0; + ht->nNextFreeElement = ZEND_LONG_MIN; ht->nInternalPointer = 0; } @@ -1704,7 +1708,7 @@ ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht) } ht->nNumUsed = 0; ht->nNumOfElements = 0; - ht->nNextFreeElement = 0; + ht->nNextFreeElement = ZEND_LONG_MIN; ht->nInternalPointer = 0; } @@ -2018,7 +2022,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) target->nTableMask = HT_MIN_MASK; target->nNumUsed = 0; target->nNumOfElements = 0; - target->nNextFreeElement = 0; + target->nNextFreeElement = ZEND_LONG_MIN; target->nInternalPointer = 0; target->nTableSize = HT_MIN_SIZE; HT_SET_DATA_ADDR(target, &uninitialized_bucket); diff --git a/ext/standard/array.c b/ext/standard/array.c index e8b0c64f3cd6..ba90bc8ecb0e 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -3228,7 +3228,7 @@ PHP_FUNCTION(array_pop) } ZVAL_COPY_DEREF(return_value, val); - if (!p->key && Z_ARRVAL_P(stack)->nNextFreeElement > 0 && p->h >= (zend_ulong)(Z_ARRVAL_P(stack)->nNextFreeElement - 1)) { + if (!p->key && (zend_long)p->h == (Z_ARRVAL_P(stack)->nNextFreeElement - 1)) { Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1; } diff --git a/ext/standard/tests/array/bug67693.phpt b/ext/standard/tests/array/bug67693.phpt index 516436c51138..c9aa2d86fab6 100644 --- a/ext/standard/tests/array/bug67693.phpt +++ b/ext/standard/tests/array/bug67693.phpt @@ -16,9 +16,9 @@ echo"\nDone"; ?> --EXPECT-- array(2) { - [0]=> + [-1]=> int(0) - [1]=> + [0]=> int(0) } diff --git a/ext/standard/tests/array/negative_index.phpt b/ext/standard/tests/array/negative_index.phpt new file mode 100644 index 000000000000..a9f442acbdbe --- /dev/null +++ b/ext/standard/tests/array/negative_index.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test arrays starting with negative indices +--FILE-- + true, true, true]; +$c = ["string" => true, -2 => true, true, true]; +unset($c["string"]); +$d[-2] = true; +$d[] = true; +$d[] = true; +$e = [-2 => false]; +array_pop($e); +$e[] = true; +$e[] = true; +$e[] = true; + +var_dump($a === $b && $b === $c && $c === $d && $d == $e); +var_dump($a); +?> +--EXPECT-- +bool(true) +array(3) { + [-2]=> + bool(true) + [-1]=> + bool(true) + [0]=> + bool(true) +}