summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@php.net>2010-04-20 10:49:22 (GMT)
committerDmitry Stogov <dmitry@php.net>2010-04-20 10:49:22 (GMT)
commitea53dc5af6a216b46a84944ee870c5ce18dcfe90 (patch)
treeeb43592a149955127cd41c55191c3b698f64ad6d /Zend
parentc373e5efdc29bd7449c631485782721e28eb22a0 (diff)
downloadphp-ea53dc5af6a216b46a84944ee870c5ce18dcfe90.tar.gz
Added an optimization which saves memory and emalloc/efree calls for empty HashTables
Diffstat (limited to 'Zend')
-rw-r--r--Zend/zend_hash.c57
1 files changed, 34 insertions, 23 deletions
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c
index d8b4087..69b6bdc 100644
--- a/Zend/zend_hash.c
+++ b/Zend/zend_hash.c
@@ -132,12 +132,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)->nTableMask = (ht)->nTableSize - 1; \
+ (ht)->arBuckets = (Bucket **) pecalloc((ht)->nTableSize, sizeof(Bucket *), (ht)->persistent); \
+ } \
+} 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);
@@ -151,9 +157,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;
@@ -162,21 +168,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;
}
@@ -212,6 +203,8 @@ 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;
@@ -278,6 +271,7 @@ 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];
@@ -350,6 +344,7 @@ ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void
Bucket *p;
IS_CONSISTENT(ht);
+ CHECK_INIT(ht);
if (flag & HASH_NEXT_INSERT) {
h = ht->nNextFreeElement;
@@ -440,6 +435,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;
@@ -530,7 +528,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);
}
@@ -556,7 +556,9 @@ ZEND_API void zend_hash_clean(HashTable *ht)
}
pefree(q, ht->persistent);
}
- 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;
@@ -630,7 +632,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);
}
@@ -647,7 +651,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);
}
@@ -1177,6 +1183,7 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const
p = pos ? (*pos) : ht->pInternalPointer;
IS_CONSISTENT(ht);
+ CHECK_INIT(ht);
if (p) {
if (key_type == HASH_KEY_IS_LONG) {
@@ -1533,6 +1540,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) {