Skip to content

Commit 1aa8719

Browse files
committed
Add zend_hash_reindex
The implementation differs from the original in array.c in that it rehashes the hashtable in the same loop. This is approximately two times faster (not counting the rare case of a purely associative array).
1 parent eaf44ec commit 1aa8719

File tree

3 files changed

+26
-21
lines changed

3 files changed

+26
-21
lines changed

Zend/zend_hash.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,16 +466,37 @@ ZEND_API int zend_hash_rehash(HashTable *ht)
466466
}
467467

468468
memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
469-
p = ht->pListHead;
470-
while (p != NULL) {
469+
for (p = ht->pListHead; p != NULL; p = p->pListNext) {
471470
nIndex = p->h & ht->nTableMask;
472471
CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
473472
ht->arBuckets[nIndex] = p;
474-
p = p->pListNext;
475473
}
476474
return SUCCESS;
477475
}
478476

477+
ZEND_API void zend_hash_reindex(HashTable *ht) {
478+
Bucket *p;
479+
uint nIndex;
480+
ulong offset = 0;
481+
482+
IS_CONSISTENT(ht);
483+
if (UNEXPECTED(ht->nNumOfElements == 0)) {
484+
return;
485+
}
486+
487+
memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
488+
for (p = ht->pListHead; p != NULL; p = p->pListNext) {
489+
if (p->nKeyLength == 0) {
490+
p->h = offset++;
491+
}
492+
493+
nIndex = p->h & ht->nTableMask;
494+
CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
495+
ht->arBuckets[nIndex] = p;
496+
}
497+
ht->nNextFreeElement = offset;
498+
}
499+
479500
ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag)
480501
{
481502
uint nIndex;

Zend/zend_hash.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ ZEND_API int zend_hash_minmax(const HashTable *ht, compare_func_t compar, int fl
227227
ZEND_API int zend_hash_num_elements(const HashTable *ht);
228228

229229
ZEND_API int zend_hash_rehash(HashTable *ht);
230+
ZEND_API void zend_hash_reindex(HashTable *ht);
230231

231232
/*
232233
* DJBX33A (Daniel J. Bernstein, Times 33 with Addition)

ext/standard/array.c

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,24 +1975,7 @@ static void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int off_the_end)
19751975

19761976
/* If we did a shift... re-index like it did before */
19771977
if (!off_the_end) {
1978-
unsigned int k = 0;
1979-
int should_rehash = 0;
1980-
Bucket *p = Z_ARRVAL_P(stack)->pListHead;
1981-
while (p != NULL) {
1982-
if (p->nKeyLength == 0) {
1983-
if (p->h != k) {
1984-
p->h = k++;
1985-
should_rehash = 1;
1986-
} else {
1987-
k++;
1988-
}
1989-
}
1990-
p = p->pListNext;
1991-
}
1992-
Z_ARRVAL_P(stack)->nNextFreeElement = k;
1993-
if (should_rehash) {
1994-
zend_hash_rehash(Z_ARRVAL_P(stack));
1995-
}
1978+
zend_hash_reindex(Z_ARRVAL_P(stack));
19961979
} else if (!key_len && index >= Z_ARRVAL_P(stack)->nNextFreeElement - 1) {
19971980
Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;
19981981
}

0 commit comments

Comments
 (0)