dmitry                                   Tue, 20 Apr 2010 10:49:22 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=298202

Log:
Added an optimization which saves memory and emalloc/efree calls for empty 
HashTables

Changed paths:
    U   php/php-src/trunk/NEWS
    U   php/php-src/trunk/Zend/zend_hash.c

Modified: php/php-src/trunk/NEWS
===================================================================
--- php/php-src/trunk/NEWS      2010-04-20 10:44:19 UTC (rev 298201)
+++ php/php-src/trunk/NEWS      2010-04-20 10:49:22 UTC (rev 298202)
@@ -4,6 +4,8 @@
 - Upgraded bundled sqlite to version 3.6.23.1. (Ilia)
 - Upgraded bundled PCRE to version 8.02. (Ilia)

+- Added an optimization which saves memory and emalloc/efree calls for empty
+  HashTables (Stas, Dmitry)
 - Added Tokyo Cabinet abstract DB support to ext/dba. (Michael Maclean)
 - Added Jenkins's one-at-a-time hash support to ext/hash. (Martin Jansen)
 - Added FNV-1 hash support to ext/hash. (Michael Maclean)

Modified: php/php-src/trunk/Zend/zend_hash.c
===================================================================
--- php/php-src/trunk/Zend/zend_hash.c  2010-04-20 10:44:19 UTC (rev 298201)
+++ php/php-src/trunk/Zend/zend_hash.c  2010-04-20 10:49:22 UTC (rev 298202)
@@ -132,12 +132,18 @@
                (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 @@
                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 @@
        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 @@
                return FAILURE;
        }

+       CHECK_INIT(ht);
+
        h = zend_inline_hash_func(arKey, nKeyLength);
        nIndex = h & ht->nTableMask;

@@ -278,6 +271,7 @@
                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 @@
        Bucket *p;

        IS_CONSISTENT(ht);
+       CHECK_INIT(ht);

        if (flag & HASH_NEXT_INSERT) {
                h = ht->nNextFreeElement;
@@ -440,6 +435,9 @@
        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 @@
                }
                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 @@
                }
                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 @@
        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 @@
                p = ht->pListTail;
        }

-       pefree(ht->arBuckets, ht->persistent);
+       if (ht->nTableMask) {
+               pefree(ht->arBuckets, ht->persistent);
+       }

        SET_INCONSISTENT(HT_DESTROYED);
 }
@@ -1177,6 +1183,7 @@
        p = pos ? (*pos) : ht->pInternalPointer;

        IS_CONSISTENT(ht);
+       CHECK_INIT(ht);

        if (p) {
                if (key_type == HASH_KEY_IS_LONG) {
@@ -1533,6 +1540,10 @@
        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) {

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to