diff options
Diffstat (limited to 'Zend/zend_hash.c')
-rw-r--r-- | Zend/zend_hash.c | 193 |
1 files changed, 129 insertions, 64 deletions
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index b6666ecc63..0609d707f5 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -20,6 +20,7 @@ /* $Id$ */ #include "zend.h" +#include "zend_globals.h" #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ (element)->pNext = (list_head); \ @@ -135,12 +136,18 @@ ZEND_API ulong zend_hash_func(const char *arKey, uint nKeyLength) (p)->pDataPtr=NULL; \ } - +#define CHECK_INIT(ht) do { \ + if (UNEXPECTED((ht)->nTableMask == 0)) { \ + (ht)->arBuckets = (Bucket **) pecalloc((ht)->nTableSize, sizeof(Bucket *), (ht)->persistent); \ + (ht)->nTableMask = (ht)->nTableSize - 1; \ + } \ +} while (0) + +static const Bucket *uninitialized_bucket = NULL; ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) { uint i = 3; - Bucket **tmp; SET_INCONSISTENT(HT_OK); @@ -154,9 +161,9 @@ ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunctio ht->nTableSize = 1 << i; } - ht->nTableMask = ht->nTableSize - 1; + ht->nTableMask = 0; /* 0 means that ht->arBuckets is uninitialized */ ht->pDestructor = pDestructor; - ht->arBuckets = NULL; + ht->arBuckets = (Bucket**)&uninitialized_bucket; ht->pListHead = NULL; ht->pListTail = NULL; ht->nNumOfElements = 0; @@ -165,21 +172,6 @@ ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunctio ht->persistent = persistent; ht->nApplyCount = 0; ht->bApplyProtection = 1; - - /* Uses ecalloc() so that Bucket* == NULL */ - if (persistent) { - tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *)); - if (!tmp) { - return FAILURE; - } - ht->arBuckets = tmp; - } else { - tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *)); - if (tmp) { - ht->arBuckets = tmp; - } - } - return SUCCESS; } @@ -205,6 +197,9 @@ ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKe ulong h; uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -215,13 +210,15 @@ ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKe return FAILURE; } + CHECK_INIT(ht); + h = zend_inline_hash_func(arKey, nKeyLength); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { if (flag & HASH_ADD) { return FAILURE; } @@ -242,16 +239,24 @@ ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKe } HANDLE_UNBLOCK_INTERRUPTIONS(); return SUCCESS; - } } p = p->pNext; } - p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); - if (!p) { - return FAILURE; + if (IS_INTERNED(arKey)) { + p = (Bucket *) pemalloc(sizeof(Bucket), ht->persistent); + if (!p) { + return FAILURE; + } + p->arKey = arKey; + } else { + p = (Bucket *) pemalloc(sizeof(Bucket) + nKeyLength, ht->persistent); + if (!p) { + return FAILURE; + } + p->arKey = (const char*)(p + 1); + memcpy((char*)p->arKey, arKey, nKeyLength); } - memcpy(p->arKey, arKey, nKeyLength); p->nKeyLength = nKeyLength; INIT_DATA(ht, p, pData, nDataSize); p->h = h; @@ -274,6 +279,9 @@ ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, ui { uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -281,12 +289,13 @@ ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, ui return zend_hash_index_update(ht, h, pData, nDataSize, pDest); } + CHECK_INIT(ht); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { if (flag & HASH_ADD) { return FAILURE; } @@ -307,17 +316,25 @@ ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, ui } HANDLE_UNBLOCK_INTERRUPTIONS(); return SUCCESS; - } } p = p->pNext; } - p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); - if (!p) { - return FAILURE; + if (IS_INTERNED(arKey)) { + p = (Bucket *) pemalloc(sizeof(Bucket), ht->persistent); + if (!p) { + return FAILURE; + } + p->arKey = arKey; + } else { + p = (Bucket *) pemalloc(sizeof(Bucket) + nKeyLength, ht->persistent); + if (!p) { + return FAILURE; + } + p->arKey = (const char*)(p + 1); + memcpy((char*)p->arKey, arKey, nKeyLength); } - memcpy(p->arKey, arKey, nKeyLength); p->nKeyLength = nKeyLength; INIT_DATA(ht, p, pData, nDataSize); p->h = h; @@ -351,8 +368,12 @@ ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void { uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); + CHECK_INIT(ht); if (flag & HASH_NEXT_INSERT) { h = ht->nNextFreeElement; @@ -388,10 +409,11 @@ ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void } p = p->pNext; } - p = (Bucket *) pemalloc_rel(sizeof(Bucket) - 1, ht->persistent); + p = (Bucket *) pemalloc_rel(sizeof(Bucket), ht->persistent); if (!p) { return FAILURE; } + p->arKey = NULL; p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */ p->h = h; INIT_DATA(ht, p, pData, nDataSize); @@ -418,6 +440,9 @@ ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void static int zend_hash_do_resize(HashTable *ht) { Bucket **t; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -443,6 +468,9 @@ ZEND_API int zend_hash_rehash(HashTable *ht) uint nIndex; IS_CONSISTENT(ht); + if (UNEXPECTED(ht->nNumOfElements == 0)) { + return SUCCESS; + } memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *)); p = ht->pListHead; @@ -459,6 +487,9 @@ ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint n { uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -533,7 +564,9 @@ ZEND_API void zend_hash_destroy(HashTable *ht) } pefree(q, ht->persistent); } - pefree(ht->arBuckets, ht->persistent); + if (ht->nTableMask) { + pefree(ht->arBuckets, ht->persistent); + } SET_INCONSISTENT(HT_DESTROYED); } @@ -547,7 +580,9 @@ ZEND_API void zend_hash_clean(HashTable *ht) p = ht->pListHead; - memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *)); + if (ht->nTableMask) { + memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *)); + } ht->pListHead = NULL; ht->pListTail = NULL; ht->nNumOfElements = 0; @@ -575,6 +610,9 @@ ZEND_API void zend_hash_clean(HashTable *ht) static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p) { Bucket *retval; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif HANDLE_BLOCK_INTERRUPTIONS(); if (p->pLast) { @@ -631,7 +669,9 @@ ZEND_API void zend_hash_graceful_destroy(HashTable *ht) while (p != NULL) { p = zend_hash_apply_deleter(ht, p); } - pefree(ht->arBuckets, ht->persistent); + if (ht->nTableMask) { + pefree(ht->arBuckets, ht->persistent); + } SET_INCONSISTENT(HT_DESTROYED); } @@ -648,7 +688,9 @@ ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht) p = ht->pListTail; } - pefree(ht->arBuckets, ht->persistent); + if (ht->nTableMask) { + pefree(ht->arBuckets, ht->persistent); + } SET_INCONSISTENT(HT_DESTROYED); } @@ -881,11 +923,10 @@ ZEND_API int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLen p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { *pData = p->pData; return SUCCESS; - } } p = p->pNext; } @@ -908,11 +949,10 @@ ZEND_API int zend_hash_quick_find(const HashTable *ht, const char *arKey, uint n p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { *pData = p->pData; return SUCCESS; - } } p = p->pNext; } @@ -933,10 +973,9 @@ ZEND_API int zend_hash_exists(const HashTable *ht, const char *arKey, uint nKeyL p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { return 1; - } } p = p->pNext; } @@ -959,10 +998,9 @@ ZEND_API int zend_hash_quick_exists(const HashTable *ht, const char *arKey, uint p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { return 1; - } } p = p->pNext; } @@ -1119,7 +1157,7 @@ ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, if (duplicate) { *str_index = estrndup(p->arKey, p->nKeyLength - 1); } else { - *str_index = p->arKey; + *str_index = (char*)p->arKey; } if (str_length) { *str_length = p->nKeyLength; @@ -1175,6 +1213,10 @@ ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosi ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const char *str_index, uint str_length, ulong num_index, int mode, HashPosition *pos) { Bucket *p, *q; + ulong h; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif p = pos ? (*pos) : ht->pInternalPointer; @@ -1195,19 +1237,25 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const q = q->pNext; } } else if (key_type == HASH_KEY_IS_STRING) { - ulong h; + if (IS_INTERNED(str_index)) { + h = INTERNED_HASH(str_index); + } else { + h = zend_inline_hash_func(str_index, str_length); + } - if (p->nKeyLength == str_length && - memcmp(p->arKey, str_index, str_length) == 0) { + if (p->arKey == str_index || + (p->nKeyLength == str_length && + p->h == h && + memcmp(p->arKey, str_index, str_length) == 0)) { return SUCCESS; } - h = zend_inline_hash_func(str_index, str_length); q = ht->arBuckets[h & ht->nTableMask]; while (q != NULL) { - if (q->h == h && q->nKeyLength == str_length && - memcmp(q->arKey, str_index, str_length) == 0) { + if (q->arKey == str_index || + (q->h == h && q->nKeyLength == str_length && + memcmp(q->arKey, str_index, str_length) == 0)) { break; } q = q->pNext; @@ -1222,7 +1270,7 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const if (mode != HASH_UPDATE_KEY_ANYWAY) { Bucket *r = p->pListLast; int found = HASH_UPDATE_KEY_IF_BEFORE; - + while (r) { if (r == q) { found = HASH_UPDATE_KEY_IF_AFTER; @@ -1242,7 +1290,7 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const } if (p->pListLast != NULL) { p->pListLast->pListNext = p->pListNext; - } else { + } else { /* Deleting the head of the list */ ht->pListHead = p->pListNext; } @@ -1277,7 +1325,7 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const } if (q->pListLast != NULL) { q->pListLast->pListNext = q->pListNext; - } else { + } else { /* Deleting the head of the list */ ht->pListHead = q->pListNext; } @@ -1308,8 +1356,15 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const ht->arBuckets[p->h & ht->nTableMask] = p->pNext; } - if (p->nKeyLength != str_length) { - Bucket *q = (Bucket *) pemalloc(sizeof(Bucket) - 1 + str_length, ht->persistent); + if ((IS_INTERNED(p->arKey) != IS_INTERNED(str_index)) || + (!IS_INTERNED(p->arKey) && p->nKeyLength != str_length)) { + Bucket *q; + + if (IS_INTERNED(str_index)) { + q = (Bucket *) pemalloc(sizeof(Bucket), ht->persistent); + } else { + q = (Bucket *) pemalloc(sizeof(Bucket) + str_length, ht->persistent); + } q->nKeyLength = str_length; if (p->pData == &p->pDataPtr) { @@ -1343,8 +1398,14 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const if (key_type == HASH_KEY_IS_LONG) { p->h = num_index; } else { - memcpy(p->arKey, str_index, str_length); - p->h = zend_inline_hash_func(str_index, str_length); + p->h = h; + p->nKeyLength = str_length; + if (IS_INTERNED(str_index)) { + p->arKey = str_index; + } else { + p->arKey = (const char*)(p+1); + memcpy((char*)p->arKey, str_index, str_length); + } } CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[p->h & ht->nTableMask]); @@ -1559,6 +1620,10 @@ void zend_hash_display(const HashTable *ht) Bucket *p; uint i; + if (UNEXPECTED(ht->nNumOfElements == 0)) { + zend_output_debug_string(0, "The hash is empty"); + return; + } for (i = 0; i < ht->nTableSize; i++) { p = ht->arBuckets[i]; while (p != NULL) { |