.nNumUsed = 0,
.nNumOfElements = 0,
.nTableSize = HT_MIN_SIZE,
- .nInternalPointer = HT_INVALID_IDX,
+ .nInternalPointer = 0,
.nNextFreeElement = 0,
.pDestructor = ZVAL_PTR_DTOR
};
HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
ht->nNumUsed = 0;
ht->nNumOfElements = 0;
- ht->nInternalPointer = HT_INVALID_IDX;
+ ht->nInternalPointer = 0;
ht->nNextFreeElement = 0;
ht->pDestructor = pDestructor;
ht->nTableSize = zend_hash_check_size(nSize);
}
/* }}} */
+static zend_always_inline HashPosition _zend_hash_get_first_pos(const HashTable *ht)
+{
+ HashPosition pos = 0;
+
+ while (pos < ht->nNumUsed && Z_ISUNDEF(ht->arData[pos].val)) {
+ pos++;
+ }
+ return pos;
+}
+
+static zend_always_inline HashPosition _zend_hash_get_current_pos(const HashTable *ht)
+{
+ HashPosition pos = ht->nInternalPointer;
+
+ if (pos == 0) {
+ pos = _zend_hash_get_first_pos(ht);
+ }
+ return pos;
+}
+
+ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht)
+{
+ return _zend_hash_get_current_pos(ht);
+}
+
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
{
HashTableIterator *iter = EG(ht_iterators);
HashTableIterator *iter = EG(ht_iterators) + idx;
ZEND_ASSERT(idx != (uint32_t)-1);
- if (iter->pos == HT_INVALID_IDX) {
- return HT_INVALID_IDX;
- } else if (UNEXPECTED(iter->ht != ht)) {
+ if (UNEXPECTED(iter->ht != ht)) {
if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
&& EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
HT_DEC_ITERATORS_COUNT(iter->ht);
HT_INC_ITERATORS_COUNT(ht);
}
iter->ht = ht;
- iter->pos = ht->nInternalPointer;
+ iter->pos = _zend_hash_get_current_pos(ht);
}
return iter->pos;
}
HashTableIterator *iter = EG(ht_iterators) + idx;
ZEND_ASSERT(idx != (uint32_t)-1);
- if (iter->pos == HT_INVALID_IDX) {
- return HT_INVALID_IDX;
- } else if (UNEXPECTED(iter->ht != ht)) {
+ if (UNEXPECTED(iter->ht != ht)) {
if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
&& EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
HT_DEC_ITERATORS_COUNT(iter->ht);
HT_INC_ITERATORS_COUNT(ht);
}
iter->ht = ht;
- iter->pos = ht->nInternalPointer;
+ iter->pos = _zend_hash_get_current_pos(ht);
}
return iter->pos;
}
{
HashTableIterator *iter = EG(ht_iterators);
HashTableIterator *end = iter + EG(ht_iterators_used);
- HashPosition res = HT_INVALID_IDX;
+ HashPosition res = ht->nNumUsed;
while (iter != end) {
if (iter->ht == ht) {
}
}
+ZEND_API void ZEND_FASTCALL zend_hash_iterators_advance(HashTable *ht, HashPosition step)
+{
+ HashTableIterator *iter = EG(ht_iterators);
+ HashTableIterator *end = iter + EG(ht_iterators_used);
+
+ while (iter != end) {
+ if (iter->ht == ht) {
+ iter->pos += step;
+ }
+ iter++;
+ }
+}
+
static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key, zend_bool known_hash)
{
zend_ulong h;
add_to_hash:
idx = ht->nNumUsed++;
ht->nNumOfElements++;
- if (ht->nInternalPointer == HT_INVALID_IDX) {
- ht->nInternalPointer = idx;
- }
- zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
arData = ht->arData;
p = arData + idx;
p->key = key;
add_to_hash:
idx = ht->nNumUsed++;
ht->nNumOfElements++;
- if (ht->nInternalPointer == HT_INVALID_IDX) {
- ht->nInternalPointer = idx;
- }
- zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
p = ht->arData + idx;
p->key = key = zend_string_init(str, len, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
p->h = ZSTR_H(key) = h;
ht->nNumUsed = h + 1;
}
ht->nNumOfElements++;
- if (ht->nInternalPointer == HT_INVALID_IDX) {
- ht->nInternalPointer = h;
- }
- zend_hash_iterators_update(ht, HT_INVALID_IDX, h);
if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
}
add_to_hash:
idx = ht->nNumUsed++;
ht->nNumOfElements++;
- if (ht->nInternalPointer == HT_INVALID_IDX) {
- ht->nInternalPointer = idx;
- }
- zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
}
while (1) {
new_idx++;
if (new_idx >= ht->nNumUsed) {
- new_idx = HT_INVALID_IDX;
break;
} else if (Z_TYPE(ht->arData[new_idx].val) != IS_UNDEF) {
break;
ht->nNumUsed = 0;
ht->nNumOfElements = 0;
ht->nNextFreeElement = 0;
- ht->nInternalPointer = HT_INVALID_IDX;
+ ht->nInternalPointer = 0;
}
ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
ht->nNumUsed = 0;
ht->nNumOfElements = 0;
ht->nNextFreeElement = 0;
- ht->nInternalPointer = HT_INVALID_IDX;
+ ht->nInternalPointer = 0;
}
ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht)
uint32_t idx;
Bucket *p;
zval *new_entry, *data;
- zend_bool setTargetPointer;
IS_CONSISTENT(source);
IS_CONSISTENT(target);
HT_ASSERT_RC1(target);
- setTargetPointer = (target->nInternalPointer == HT_INVALID_IDX);
for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx;
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
- if (setTargetPointer && source->nInternalPointer == idx) {
- target->nInternalPointer = HT_INVALID_IDX;
- }
/* INDIRECT element may point to UNDEF-ined slots */
data = &p->val;
if (Z_TYPE_P(data) == IS_INDIRECT) {
pCopyConstructor(new_entry);
}
}
- if (target->nInternalPointer == HT_INVALID_IDX && target->nNumOfElements > 0) {
- idx = 0;
- while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
- idx++;
- }
- target->nInternalPointer = idx;
- }
}
target->nNumUsed = 0;
target->nNumOfElements = 0;
target->nNextFreeElement = 0;
- target->nInternalPointer = HT_INVALID_IDX;
+ target->nInternalPointer = 0;
HT_SET_DATA_ADDR(target, &uninitialized_bucket);
} else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) {
HT_FLAGS(target) = HT_FLAGS(source);
HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
target->nInternalPointer = source->nInternalPointer;
memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source));
- if (target->nInternalPointer == HT_INVALID_IDX) {
- idx = 0;
- while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
- idx++;
- }
- target->nInternalPointer = idx;
- }
} else if (HT_FLAGS(source) & HASH_FLAG_PACKED) {
HT_FLAGS(target) = HT_FLAGS(source);
target->nTableMask = HT_MIN_MASK;
target->nNumOfElements = source->nNumOfElements;
target->nNextFreeElement = source->nNextFreeElement;
HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
- target->nInternalPointer = source->nInternalPointer;
+ target->nInternalPointer =
+ (source->nInternalPointer < source->nNumUsed) ?
+ source->nInternalPointer : 0;
+
HT_HASH_RESET_PACKED(target);
if (HT_IS_WITHOUT_HOLES(target)) {
} else {
zend_array_dup_packed_elements(source, target, 1);
}
- if (target->nInternalPointer == HT_INVALID_IDX) {
- idx = 0;
- while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
- idx++;
- }
- target->nInternalPointer = idx;
- }
} else {
HT_FLAGS(target) = HT_FLAGS(source);
target->nTableMask = source->nTableMask;
target->nNextFreeElement = source->nNextFreeElement;
- target->nInternalPointer = source->nInternalPointer;
+ target->nInternalPointer =
+ (source->nInternalPointer < source->nNumUsed) ?
+ source->nInternalPointer : 0;
HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
HT_HASH_RESET(target);
}
target->nNumUsed = idx;
target->nNumOfElements = idx;
- if (target->nInternalPointer == HT_INVALID_IDX) {
- target->nInternalPointer = 0;
- }
}
return target;
}
}
}
}
- if (target->nNumOfElements > 0) {
- idx = 0;
- while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
- idx++;
- }
- target->nInternalPointer = idx;
- }
}
}
}
}
- if (target->nNumOfElements > 0) {
- idx = 0;
- while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
- idx++;
- }
- target->nInternalPointer = idx;
- }
}
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
{
- uint32_t idx;
-
IS_CONSISTENT(ht);
HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
-
- for (idx = 0; idx < ht->nNumUsed; idx++) {
- if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
- *pos = idx;
- return;
- }
- }
- *pos = HT_INVALID_IDX;
+ *pos = _zend_hash_get_first_pos(ht);
}
return;
}
}
- *pos = HT_INVALID_IDX;
+ *pos = ht->nNumUsed;
}
IS_CONSISTENT(ht);
HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
- if (idx != HT_INVALID_IDX) {
+ if (idx < ht->nNumUsed) {
+ if (idx == 0) {
+ idx = _zend_hash_get_first_pos(ht);
+ if (idx >= ht->nNumUsed) {
+ *pos = idx;
+ return SUCCESS;
+ }
+ }
while (1) {
idx++;
if (idx >= ht->nNumUsed) {
- *pos = HT_INVALID_IDX;
+ *pos = ht->nNumUsed;
return SUCCESS;
}
if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
}
}
} else {
- return FAILURE;
+ return FAILURE;
}
}
IS_CONSISTENT(ht);
HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
- if (idx != HT_INVALID_IDX) {
+ if (idx < ht->nNumUsed) {
while (idx > 0) {
idx--;
if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
return SUCCESS;
}
}
- *pos = HT_INVALID_IDX;
+ *pos = ht->nNumUsed;
return SUCCESS;
} else {
return FAILURE;
Bucket *p;
IS_CONSISTENT(ht);
- if (idx != HT_INVALID_IDX) {
+ if (idx < ht->nNumUsed) {
+ if (idx == 0) {
+ idx = _zend_hash_get_first_pos(ht);
+ if (idx >= ht->nNumUsed) {
+ return HASH_KEY_NON_EXISTENT;
+ }
+ }
p = ht->arData + idx;
if (p->key) {
*str_index = p->key;
Bucket *p;
IS_CONSISTENT(ht);
- if (idx == HT_INVALID_IDX) {
+ if (idx >= ht->nNumUsed) {
ZVAL_NULL(key);
} else {
+ if (idx == 0) {
+ idx = _zend_hash_get_first_pos(ht);
+ if (idx >= ht->nNumUsed) {
+ ZVAL_NULL(key);
+ return;
+ }
+ }
p = ht->arData + idx;
if (p->key) {
ZVAL_STR_COPY(key, p->key);
Bucket *p;
IS_CONSISTENT(ht);
- if (idx != HT_INVALID_IDX) {
+ if (idx < ht->nNumUsed) {
+ if (idx == 0) {
+ idx = _zend_hash_get_first_pos(ht);
+ if (idx >= ht->nNumUsed) {
+ return HASH_KEY_NON_EXISTENT;
+ }
+ }
p = ht->arData + idx;
if (p->key) {
return HASH_KEY_IS_STRING;
Bucket *p;
IS_CONSISTENT(ht);
- if (idx != HT_INVALID_IDX) {
+ if (idx < ht->nNumUsed) {
+ if (idx == 0) {
+ idx = _zend_hash_get_first_pos(ht);
+ if (idx >= ht->nNumUsed) {
+ return NULL;
+ }
+ }
p = ht->arData + idx;
return &p->val;
} else {
zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
Z_ARRVAL_P(return_value)->nNumUsed = (uint32_t)(start_key + num);
Z_ARRVAL_P(return_value)->nNumOfElements = (uint32_t)num;
- Z_ARRVAL_P(return_value)->nInternalPointer = (uint32_t)start_key;
Z_ARRVAL_P(return_value)->nNextFreeElement = (zend_long)(start_key + num);
if (Z_REFCOUNTED_P(val)) {
Z_TRY_ADDREF(args[i]);
zend_hash_next_index_insert_new(&new_hash, &args[i]);
}
- if (EXPECTED(!HT_HAS_ITERATORS(Z_ARRVAL_P(stack)))) {
- 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;
- uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 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);
- }
- old_idx = (Bucket*)value - Z_ARRVAL_P(stack)->arData;
- if (old_idx == iter_pos) {
- zend_hash_iterators_update(Z_ARRVAL_P(stack), old_idx, new_idx);
- iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
- }
- new_idx++;
- } ZEND_HASH_FOREACH_END();
+ 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(HT_HAS_ITERATORS(Z_ARRVAL_P(stack)))) {
+ zend_hash_iterators_advance(Z_ARRVAL_P(stack), argc);
+ HT_SET_ITERATORS_COUNT(&new_hash, HT_ITERATORS_COUNT(Z_ARRVAL_P(stack)));
+ HT_SET_ITERATORS_COUNT(Z_ARRVAL_P(stack), 0);
}
/* replace HashTable data */
- HT_SET_ITERATORS_COUNT(Z_ARRVAL_P(stack), 0);
Z_ARRVAL_P(stack)->pDestructor = NULL;
zend_hash_destroy(Z_ARRVAL_P(stack));