PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - Zend - zend_hash.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 819 924 88.6 %
Date: 2014-10-30 Functions: 57 65 87.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 2.00 of the Zend license,     |
       8             :    | that is bundled with this package in the file LICENSE, and is        | 
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.zend.com/license/2_00.txt.                                |
      11             :    | If you did not receive a copy of the Zend license and are unable to  |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@zend.com so we can mail you a copy immediately.              |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : #include "zend.h"
      23             : #include "zend_globals.h"
      24             : 
      25             : #if ZEND_DEBUG
      26             : /*
      27             : #define HASH_MASK_CONSISTENCY   0x60
      28             : */
      29             : #define HT_OK                                   0x00
      30             : #define HT_IS_DESTROYING                0x20
      31             : #define HT_DESTROYED                    0x40
      32             : #define HT_CLEANING                             0x60
      33             : 
      34             : static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
      35             : {
      36             :         if ((ht->u.flags & HASH_MASK_CONSISTENCY) == HT_OK) {
      37             :                 return;
      38             :         }
      39             :         switch ((ht->u.flags & HASH_MASK_CONSISTENCY)) {
      40             :                 case HT_IS_DESTROYING:
      41             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
      42             :                         break;
      43             :                 case HT_DESTROYED:
      44             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
      45             :                         break;
      46             :                 case HT_CLEANING:
      47             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
      48             :                         break;
      49             :                 default:
      50             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is inconsistent", file, line, ht);
      51             :                         break;
      52             :         }
      53             :         zend_bailout();
      54             : }
      55             : #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
      56             : #define SET_INCONSISTENT(n) do { \
      57             :                 (ht)->u.flags |= n; \
      58             :         } while (0)
      59             : #else
      60             : #define IS_CONSISTENT(a)
      61             : #define SET_INCONSISTENT(n)
      62             : #endif
      63             : 
      64             : #define HASH_PROTECT_RECURSION(ht)                                                                                                              \
      65             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      66             :                 if ((ht)->u.flags >= (3 << 8)) {                                                                                            \
      67             :                         zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");\
      68             :                 }                                                                                                                                                               \
      69             :                 ZEND_HASH_INC_APPLY_COUNT(ht);                                                                                                  \
      70             :         }
      71             : 
      72             : #define HASH_UNPROTECT_RECURSION(ht)                                                                                                    \
      73             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      74             :                 ZEND_HASH_DEC_APPLY_COUNT(ht);                                                                                                  \
      75             :         }
      76             : 
      77             : #define ZEND_HASH_IF_FULL_DO_RESIZE(ht)                         \
      78             :         if ((ht)->nNumUsed >= (ht)->nTableSize) {              \
      79             :                 zend_hash_do_resize(ht);                                        \
      80             :         }
      81             : 
      82             : static void zend_hash_do_resize(HashTable *ht);
      83             : 
      84             : #define CHECK_INIT(ht, packed) do {                                                                                             \
      85             :         if (UNEXPECTED((ht)->nTableMask == 0)) {                                                     \
      86             :                 if (packed) { \
      87             :                         (ht)->arData = (Bucket *) safe_pemalloc((ht)->nTableSize, sizeof(Bucket), 0, (ht)->u.flags & HASH_FLAG_PERSISTENT);        \
      88             :                         (ht)->u.flags |= HASH_FLAG_PACKED; \
      89             :                 } else { \
      90             :                         (ht)->arData = (Bucket *) safe_pemalloc((ht)->nTableSize, sizeof(Bucket) + sizeof(uint32_t), 0, (ht)->u.flags & HASH_FLAG_PERSISTENT);     \
      91             :                         (ht)->arHash = (uint32_t*)((ht)->arData + (ht)->nTableSize);   \
      92             :                         memset((ht)->arHash, INVALID_IDX, (ht)->nTableSize * sizeof(uint32_t));   \
      93             :                 } \
      94             :                 (ht)->nTableMask = (ht)->nTableSize - 1;                                          \
      95             :         }                                                                                                                                       \
      96             : } while (0)
      97             :  
      98             : static const uint32_t uninitialized_bucket = {INVALID_IDX};
      99             : 
     100    16671467 : ZEND_API void _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
     101             : {
     102             :         /* Use big enough power of 2 */
     103             : #ifdef PHP_WIN32
     104             :         if (nSize <= 8) {
     105             :                 ht->nTableSize = 8;
     106             :         } else if (nSize >= 0x80000000) {
     107             :                 /* prevent overflow */
     108             :                 ht->nTableSize = 0x80000000;
     109             :         } else {
     110             :                 ht->nTableSize = 1U << __lzcnt(nSize);
     111             :                 if (ht->nTableSize < nSize) {
     112             :                         ht->nTableSize <<= 1;
     113             :                 }
     114             :         }
     115             : #else
     116             :         /* size should be between 8 and 0x80000000 */
     117    16671467 :         nSize = (nSize <= 8 ? 8 : (nSize >= 0x80000000 ? 0x80000000 : nSize));
     118             : # if defined(__GNUC__)
     119    16671467 :         ht->nTableSize =  0x2 << (__builtin_clz(nSize - 1) ^ 0x1f);
     120             : # else
     121             :         nSize -= 1;
     122             :         nSize |= (nSize >> 1);
     123             :         nSize |= (nSize >> 2);
     124             :         nSize |= (nSize >> 4);
     125             :         nSize |= (nSize >> 8);
     126             :         nSize |= (nSize >> 16);
     127             :         ht->nTableSize = nSize + 1;
     128             : # endif
     129             : #endif
     130             : 
     131    16671467 :         ht->nTableMask = 0;  /* 0 means that ht->arBuckets is uninitialized */
     132    16671467 :         ht->nNumUsed = 0;
     133    16671467 :         ht->nNumOfElements = 0;
     134    16671467 :         ht->nNextFreeElement = 0;
     135    16671467 :         ht->arData = NULL;
     136    16671467 :         ht->arHash = (uint32_t*)&uninitialized_bucket;
     137    16671467 :         ht->pDestructor = pDestructor;
     138    16671467 :         ht->nInternalPointer = INVALID_IDX;
     139    16671467 :         ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION;
     140    16671467 : }
     141             : 
     142       36941 : static void zend_hash_packed_grow(HashTable *ht)
     143             : {
     144       36941 :         HANDLE_BLOCK_INTERRUPTIONS();
     145       36941 :         ht->arData = (Bucket *) safe_perealloc(ht->arData, (ht->nTableSize << 1), sizeof(Bucket), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
     146       36941 :         ht->nTableSize = (ht->nTableSize << 1);
     147       36941 :         ht->nTableMask = ht->nTableSize - 1;
     148       36941 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     149       36941 : }
     150             : 
     151       69386 : ZEND_API void zend_hash_real_init(HashTable *ht, zend_bool packed)
     152             : {
     153             :         IS_CONSISTENT(ht);
     154             : 
     155       69386 :         CHECK_INIT(ht, packed);
     156       69386 : }
     157             : 
     158       25950 : ZEND_API void zend_hash_packed_to_hash(HashTable *ht)
     159             : {
     160       25950 :         HANDLE_BLOCK_INTERRUPTIONS();
     161       25950 :         ht->u.flags &= ~HASH_FLAG_PACKED;
     162       25950 :         ht->arData = (Bucket *) safe_perealloc(ht->arData, ht->nTableSize, sizeof(Bucket) + sizeof(uint32_t), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
     163       25950 :         ht->arHash = (uint32_t*)(ht->arData + ht->nTableSize);
     164       25950 :         zend_hash_rehash(ht);
     165       25950 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     166       25950 : }
     167             : 
     168          15 : ZEND_API void zend_hash_to_packed(HashTable *ht)
     169             : {
     170          15 :         HANDLE_BLOCK_INTERRUPTIONS();
     171          15 :         ht->u.flags |= HASH_FLAG_PACKED;
     172          15 :         ht->arData = erealloc(ht->arData, ht->nTableSize * sizeof(Bucket));
     173          15 :         ht->arHash = (uint32_t*)&uninitialized_bucket;
     174          15 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     175          15 : }
     176             : 
     177    11111518 : ZEND_API void _zend_hash_init_ex(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC)
     178             : {
     179    11111518 :         _zend_hash_init(ht, nSize, pDestructor, persistent ZEND_FILE_LINE_CC);
     180    11111518 :         if (!bApplyProtection) {
     181    11111518 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     182             :         }
     183    11111518 : }
     184             : 
     185             : 
     186           0 : ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
     187             : {
     188           0 :         if (bApplyProtection) {
     189           0 :                 ht->u.flags |= HASH_FLAG_APPLY_PROTECTION;
     190             :         } else {
     191           0 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     192             :         }
     193           0 : }
     194             : 
     195             : static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
     196             : {
     197             :         zend_ulong h;
     198             :         uint32_t nIndex;
     199             :         uint32_t idx;
     200             :         Bucket *p;
     201             : 
     202   272003040 :         h = zend_string_hash_val(key);
     203   272003040 :         nIndex = h & ht->nTableMask;
     204   272003040 :         idx = ht->arHash[nIndex];
     205   418996554 :         while (idx != INVALID_IDX) {
     206   160850872 :                 p = ht->arData + idx;
     207   328813420 :                 if ((p->key == key) || /* check for the the same interned string */
     208   152234154 :                         (p->h == h &&
     209     5242798 :                          p->key &&
     210     5242798 :                          p->key->len == key->len &&
     211     5242798 :                          memcmp(p->key->val, key->val, key->len) == 0)) {
     212    13857358 :                         return p;
     213             :                 }
     214   146993514 :                 idx = Z_NEXT(p->val);
     215             :         }
     216   258145682 :         return NULL;
     217             : }
     218             : 
     219             : static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, const char *str, size_t len, zend_ulong h)
     220             : {
     221             :         uint32_t nIndex;
     222             :         uint32_t idx;
     223             :         Bucket *p;
     224             : 
     225     3434044 :         nIndex = h & ht->nTableMask;
     226     3434044 :         idx = ht->arHash[nIndex];
     227     4240608 :         while (idx != INVALID_IDX) {
     228             :                 ZEND_ASSERT(idx < ht->nTableSize);
     229     3349799 :                 p = ht->arData + idx;
     230    10979555 :                 if ((p->h == h) 
     231             :                          && p->key
     232     5086504 :                          && (p->key->len == len)
     233     2543252 :                          && !memcmp(p->key->val, str, len)) {
     234     2543235 :                         return p;
     235             :                 }
     236      806564 :                 idx = Z_NEXT(p->val);
     237             :         }
     238      890809 :         return NULL;
     239             : }
     240             : 
     241             : static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_ulong h)
     242             : {
     243             :         uint32_t nIndex;
     244             :         uint32_t idx;
     245             :         Bucket *p;
     246             : 
     247     4081838 :         nIndex = h & ht->nTableMask;
     248     4081838 :         idx = ht->arHash[nIndex];
     249     5405386 :         while (idx != INVALID_IDX) {
     250             :                 ZEND_ASSERT(idx < ht->nTableSize);
     251     2317660 :                 p = ht->arData + idx;
     252     2317660 :                 if (p->h == h && !p->key) {
     253      994112 :                         return p;
     254             :                 }
     255     1323548 :                 idx = Z_NEXT(p->val);
     256             :         }
     257     3087726 :         return NULL;
     258             : }
     259             : 
     260             : static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     261             : {
     262             :         zend_ulong h;
     263             :         uint32_t nIndex;
     264             :         uint32_t idx;
     265             :         Bucket *p;
     266             : #ifdef ZEND_SIGNALS
     267             :         TSRMLS_FETCH();
     268             : #endif
     269             : 
     270             :         IS_CONSISTENT(ht);
     271             : 
     272   249841403 :         CHECK_INIT(ht, 0);
     273   249841403 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     274       24931 :                 zend_hash_packed_to_hash(ht);
     275             :         }
     276             : 
     277   249841403 :         h = zend_string_hash_val(key);
     278             : 
     279   249841403 :         if ((flag & HASH_ADD_NEW) == 0) {
     280   220704632 :                 p = zend_hash_find_bucket(ht, key);
     281             : 
     282   220704632 :                 if (p) {
     283             :                         zval *data;
     284             : 
     285     1017759 :                         if (flag & HASH_ADD) {
     286      255322 :                                 return NULL;
     287             :                         }
     288             :                         ZEND_ASSERT(&p->val != pData);
     289      762437 :                         data = &p->val;
     290      817390 :                         if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
     291         254 :                                 data = Z_INDIRECT_P(data);
     292             :                         }
     293      762437 :                         HANDLE_BLOCK_INTERRUPTIONS();
     294      762437 :                         if (ht->pDestructor) {
     295      721219 :                                 ht->pDestructor(data);
     296             :                         }
     297      762437 :                         ZVAL_COPY_VALUE(data, pData);
     298      762437 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     299      762437 :                         return data;
     300             :                 }
     301             :         }
     302             :         
     303   248823644 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     304             : 
     305   248823644 :         HANDLE_BLOCK_INTERRUPTIONS();
     306   248823644 :         idx = ht->nNumUsed++;
     307   248823644 :         ht->nNumOfElements++;
     308   248823644 :         if (ht->nInternalPointer == INVALID_IDX) {
     309     6810513 :                 ht->nInternalPointer = idx;
     310             :         }
     311   248823644 :         p = ht->arData + idx; 
     312   248823644 :         p->h = h;
     313   248823644 :         p->key = key;
     314             :         zend_string_addref(key);
     315   248823644 :         ZVAL_COPY_VALUE(&p->val, pData);
     316   248823644 :         nIndex = h & ht->nTableMask;
     317   248823644 :         Z_NEXT(p->val) = ht->arHash[nIndex];
     318   248823644 :         ht->arHash[nIndex] = idx;
     319   248823644 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     320             : 
     321   248823644 :         return &p->val;
     322             : }
     323             : 
     324     2983257 : ZEND_API zval *_zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     325             : {
     326     2983257 :         return _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_RELAY_CC);
     327             : }
     328             : 
     329   138365186 : ZEND_API zval *_zend_hash_add(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     330             : {
     331   138365186 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     332             : }
     333             : 
     334    52925830 : ZEND_API zval *_zend_hash_update(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     335             : {
     336    52925830 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     337             : }
     338             : 
     339        1133 : ZEND_API zval *_zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     340             : {
     341        1133 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_RELAY_CC);
     342             : }
     343             : 
     344    29133957 : ZEND_API zval *_zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     345             : {
     346    29133957 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     347             : }
     348             : 
     349           0 : ZEND_API zval *_zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     350             : {
     351           0 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     352           0 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_CC);
     353             :         zend_string_release(key);
     354           0 :         return ret;
     355             : }
     356             : 
     357    12578123 : ZEND_API zval *_zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     358             : {
     359    25156246 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     360    12578123 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_CC);
     361             :         zend_string_release(key);
     362    12578123 :         return ret;
     363             : }
     364             : 
     365     1270767 : ZEND_API zval *_zend_hash_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     366             : {
     367     2541534 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     368     1270767 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_CC);
     369             :         zend_string_release(key);
     370     1270767 :         return ret;
     371             : }
     372             : 
     373    12580336 : ZEND_API zval *_zend_hash_str_add(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     374             : {
     375    25160672 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     376    12580336 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_CC);
     377             :         zend_string_release(key);
     378    12580336 :         return ret;
     379             : }
     380             : 
     381        2814 : ZEND_API zval *_zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     382             : {
     383        5628 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     384        2814 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_CC);
     385             :         zend_string_release(key);
     386        2814 :         return ret;
     387             : }
     388             : 
     389           0 : ZEND_API zval *zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h)
     390             : {
     391             :         
     392             :         zval dummy;
     393             : 
     394           0 :         ZVAL_NULL(&dummy);
     395           0 :         return zend_hash_index_add(ht, h, &dummy);
     396             : }
     397             : 
     398         222 : ZEND_API zval *zend_hash_add_empty_element(HashTable *ht, zend_string *key)
     399             : {
     400             :         
     401             :         zval dummy;
     402             : 
     403         222 :         ZVAL_NULL(&dummy);
     404         222 :         return zend_hash_add(ht, key, &dummy);
     405             : }
     406             : 
     407      512338 : ZEND_API zval *zend_hash_str_add_empty_element(HashTable *ht, const char *str, size_t len)
     408             : {
     409             :         
     410             :         zval dummy;
     411             : 
     412      512338 :         ZVAL_NULL(&dummy);
     413      512338 :         return zend_hash_str_add(ht, str, len, &dummy);
     414             : }
     415             : 
     416             : static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     417             : {
     418             :         uint32_t nIndex;
     419             :         uint32_t idx;
     420             :         Bucket *p;
     421             : #ifdef ZEND_SIGNALS
     422             :         TSRMLS_FETCH();
     423             : #endif
     424             : 
     425             :         IS_CONSISTENT(ht);
     426     7534726 :         CHECK_INIT(ht, h < ht->nTableSize);
     427             : 
     428     7534726 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     429     5550688 :                 if (h < ht->nNumUsed) {
     430        3799 :                         p = ht->arData + h;
     431        7598 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
     432        3643 :                                 if (flag & HASH_ADD) {
     433          24 :                                         return NULL;
     434             :                                 }
     435        3619 :                                 if (ht->pDestructor) {
     436        3619 :                                         ht->pDestructor(&p->val);
     437             :                                 }
     438        3619 :                                 ZVAL_COPY_VALUE(&p->val, pData);
     439        3619 :                                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     440           0 :                                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     441             :                                 }
     442        3619 :                                 return &p->val;
     443             :                         } else { /* we have to keep the order :( */
     444             :                                 goto convert_to_hash;
     445             :                         }
     446     5546889 :                 } else if (EXPECTED(h < ht->nTableSize)) {
     447     5509346 :                         p = ht->arData + h;
     448       75011 :                 } else if (h < ht->nTableSize * 2 &&
     449       37468 :                                    ht->nTableSize - ht->nNumOfElements < ht->nTableSize / 2) {
     450       36941 :                         zend_hash_packed_grow(ht);
     451       36941 :                         p = ht->arData + h;
     452             :                 } else {
     453             :                         goto convert_to_hash;
     454             :                 }
     455             : 
     456     5546287 :                 HANDLE_BLOCK_INTERRUPTIONS();
     457             :                 /* incremental initialization of empty Buckets */
     458     5546287 :                 if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) == (HASH_ADD_NEW|HASH_ADD_NEXT)) {
     459      451994 :                         ht->nNumUsed = h + 1;
     460     5094293 :                 } else if (h >= ht->nNumUsed) {
     461     5094293 :                         if (h > ht->nNumUsed) {
     462      892763 :                                 Bucket *q = ht->arData + ht->nNumUsed;
     463     1790164 :                                 while (q != p) {
     464      897401 :                                         ZVAL_UNDEF(&q->val);
     465      897401 :                                         q++;
     466             :                                 }
     467             :                         }
     468     5094293 :                         ht->nNumUsed = h + 1;
     469             :                 }
     470     5546287 :                 ht->nNumOfElements++;
     471     5546287 :                 if (ht->nInternalPointer == INVALID_IDX) {
     472     1901503 :                         ht->nInternalPointer = h;
     473             :                 }
     474     5546287 :                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     475     5546275 :                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     476             :                 }
     477     5546287 :                 p->h = h;
     478     5546287 :                 p->key = NULL;
     479     5546287 :                 ZVAL_COPY_VALUE(&p->val, pData);
     480     5546287 :                 Z_NEXT(p->val) = INVALID_IDX;
     481             : 
     482     5546287 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     483             : 
     484     5546287 :                 return &p->val;
     485             : 
     486             : convert_to_hash:
     487         758 :                 zend_hash_packed_to_hash(ht);
     488             :         }
     489             : 
     490     1984796 :         if ((flag & HASH_ADD_NEW) == 0) {
     491     1428531 :                 p = zend_hash_index_find_bucket(ht, h);
     492     1428531 :                 if (p) {
     493       10251 :                         if (flag & HASH_ADD) {
     494           5 :                                 return NULL;
     495             :                         }
     496             :                         ZEND_ASSERT(&p->val != pData);
     497       10246 :                         HANDLE_BLOCK_INTERRUPTIONS();
     498       10246 :                         if (ht->pDestructor) {
     499       10201 :                                 ht->pDestructor(&p->val);
     500             :                         }
     501       10246 :                         ZVAL_COPY_VALUE(&p->val, pData);
     502       10246 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     503       10246 :                         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     504           1 :                                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     505             :                         }
     506       10246 :                         return &p->val;
     507             :                 }
     508             :         }
     509             : 
     510     1974545 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     511             : 
     512     1974545 :         HANDLE_BLOCK_INTERRUPTIONS();
     513     1974545 :         idx = ht->nNumUsed++;
     514     1974545 :         ht->nNumOfElements++;
     515     1974545 :         if (ht->nInternalPointer == INVALID_IDX) {
     516      167835 :                 ht->nInternalPointer = idx;
     517             :         }
     518     1974545 :         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     519      615626 :                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     520             :         }
     521     1974545 :         p = ht->arData + idx;
     522     1974545 :         p->h = h;
     523     1974545 :         p->key = NULL;
     524     1974545 :         nIndex = h & ht->nTableMask;
     525     1974545 :         ZVAL_COPY_VALUE(&p->val, pData);
     526     1974545 :         Z_NEXT(p->val) = ht->arHash[nIndex];
     527     1974545 :         ht->arHash[nIndex] = idx;
     528     1974545 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     529             : 
     530     1974545 :         return &p->val;
     531             : }
     532             : 
     533           0 : ZEND_API zval *_zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     534             : {
     535           0 :         return _zend_hash_index_add_or_update_i(ht, h, pData, flag ZEND_FILE_LINE_RELAY_CC);
     536             : }
     537             : 
     538         100 : ZEND_API zval *_zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     539             : {
     540         100 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     541             : }
     542             : 
     543      911174 : ZEND_API zval *_zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     544             : {
     545      911174 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD | HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     546             : }
     547             : 
     548     2362300 : ZEND_API zval *_zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     549             : {
     550     2362300 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     551             : }
     552             : 
     553     3808894 : ZEND_API zval *_zend_hash_next_index_insert(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     554             : {
     555     7617788 :         return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT ZEND_FILE_LINE_RELAY_CC);
     556             : }
     557             : 
     558      452258 : ZEND_API zval *_zend_hash_next_index_insert_new(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     559             : {
     560      904516 :         return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT ZEND_FILE_LINE_RELAY_CC);
     561             : }
     562             : 
     563     6257010 : static void zend_hash_do_resize(HashTable *ht)
     564             : {
     565             : #ifdef ZEND_SIGNALS
     566             :         TSRMLS_FETCH();
     567             : #endif
     568             : 
     569             :         IS_CONSISTENT(ht);
     570             : 
     571     6257010 :         if (ht->nNumUsed < ht->nNumOfElements) {
     572           0 :                 HANDLE_BLOCK_INTERRUPTIONS();
     573           0 :                 zend_hash_rehash(ht);
     574           0 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     575     6257010 :         } else if ((ht->nTableSize << 1) > 0) {     /* Let's double the table size */
     576     6257010 :                 HANDLE_BLOCK_INTERRUPTIONS();
     577     6257010 :                 ht->arData = (Bucket *) safe_perealloc(ht->arData, (ht->nTableSize << 1), sizeof(Bucket) + sizeof(uint32_t), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
     578     6257010 :                 ht->arHash = (uint32_t*)(ht->arData + (ht->nTableSize << 1));
     579     6257010 :                 ht->nTableSize = (ht->nTableSize << 1);
     580     6257010 :                 ht->nTableMask = ht->nTableSize - 1;
     581     6257010 :                 zend_hash_rehash(ht);
     582     6257010 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     583             :         }
     584     6257010 : }
     585             : 
     586     6365540 : ZEND_API int zend_hash_rehash(HashTable *ht)
     587             : {
     588             :         Bucket *p;
     589             :         uint32_t nIndex, i, j;
     590             : 
     591             :         IS_CONSISTENT(ht);
     592             : 
     593     6365540 :         if (UNEXPECTED(ht->nNumOfElements == 0)) {
     594           3 :                 if (ht->nTableMask) {
     595           0 :                         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
     596             :                 }
     597           3 :                 return SUCCESS;
     598             :         }
     599             : 
     600     6365537 :         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
     601   396180314 :         for (i = 0, j = 0; i < ht->nNumUsed; i++) {
     602   389814777 :                 p = ht->arData + i;
     603   779629554 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     604   389759423 :                 if (i != j) {
     605      126802 :                         ht->arData[j] = ht->arData[i];
     606      126802 :                         if (ht->nInternalPointer == i) {
     607         948 :                                 ht->nInternalPointer = j;
     608             :                         }
     609             :                 }
     610   389759423 :                 nIndex = ht->arData[j].h & ht->nTableMask;
     611   389759423 :                 Z_NEXT(ht->arData[j].val) = ht->arHash[nIndex];
     612   389759423 :                 ht->arHash[nIndex] = j;
     613   389759423 :                 j++;
     614             :         }
     615     6365537 :         ht->nNumUsed = j;
     616     6365537 :         return SUCCESS;
     617             : }
     618             : 
     619             : static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx, Bucket *p, Bucket *prev)
     620             : {
     621    53263251 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     622    53158704 :                 if (prev) {
     623     2965213 :                         Z_NEXT(prev->val) = Z_NEXT(p->val);
     624             :                 } else {
     625    50193491 :                         ht->arHash[p->h & ht->nTableMask] = Z_NEXT(p->val);
     626             :                 }
     627             :         }
     628    53263251 :         if (ht->nNumUsed - 1 == idx) {
     629             :                 do {
     630     3669848 :                         ht->nNumUsed--;
     631     7170423 :                 } while (ht->nNumUsed > 0 && (Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF));
     632             :         }
     633    53263251 :         ht->nNumOfElements--;
     634    53263251 :         if (ht->nInternalPointer == idx) {
     635             :                 while (1) {
     636    47346108 :                         idx++;
     637    47346108 :                         if (idx >= ht->nNumUsed) {
     638      169264 :                                 ht->nInternalPointer = INVALID_IDX;
     639             :                                 break;
     640    94353688 :                         } else if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
     641     2999321 :                                 ht->nInternalPointer = idx;
     642             :                                 break;
     643             :                         }
     644             :                 }
     645             :         }
     646    53263251 :         if (p->key) {
     647    52994492 :                 zend_string_release(p->key);
     648             :         }
     649    53263251 :         if (ht->pDestructor) {
     650             :                 zval tmp;
     651    52477459 :                 ZVAL_COPY_VALUE(&tmp, &p->val);
     652    52477459 :                 ZVAL_UNDEF(&p->val);
     653    52477459 :                 ht->pDestructor(&tmp);
     654             :         } else {
     655      785792 :                 ZVAL_UNDEF(&p->val);
     656             :         }
     657             : }
     658             : 
     659             : static zend_always_inline void _zend_hash_del_el(HashTable *ht, uint32_t idx, Bucket *p)
     660             : {
     661     7360380 :         Bucket *prev = NULL;
     662             : 
     663     7360380 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     664     7348242 :                 uint32_t nIndex = p->h & ht->nTableMask;
     665     7348242 :                 uint32_t i = ht->arHash[nIndex];
     666             : 
     667     7348242 :                 if (i != idx) {
     668      311930 :                         prev = ht->arData + i;
     669      353437 :                         while (Z_NEXT(prev->val) != idx) {
     670       41507 :                                 i = Z_NEXT(prev->val);
     671       41507 :                                 prev = ht->arData + i;
     672             :                         }
     673             :                 }
     674             :         }
     675             : 
     676             :         _zend_hash_del_el_ex(ht, idx, p, prev);
     677             : }
     678             : 
     679    45793352 : ZEND_API int zend_hash_del(HashTable *ht, zend_string *key)
     680             : {
     681             :         zend_ulong h;
     682             :         uint32_t nIndex;
     683             :         uint32_t idx;
     684             :         Bucket *p;
     685    45793352 :         Bucket *prev = NULL;
     686             : #ifdef ZEND_SIGNALS
     687             :         TSRMLS_FETCH();
     688             : #endif
     689             : 
     690             :         IS_CONSISTENT(ht);
     691             : 
     692    45793352 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     693           7 :                 return FAILURE;
     694             :         }
     695             : 
     696    45793345 :         h = zend_string_hash_val(key);
     697    45793345 :         nIndex = h & ht->nTableMask;
     698             : 
     699    45793345 :         idx = ht->arHash[nIndex];
     700    94379779 :         while (idx != INVALID_IDX) {
     701    47763204 :                 p = ht->arData + idx;
     702   230318283 :                 if ((p->key == key) ||
     703    47733552 :                         (p->h == h &&
     704    44940509 :                      p->key &&
     705    44940509 :                      p->key->len == key->len &&
     706    44940509 :                      memcmp(p->key->val, key->val, key->len) == 0)) {
     707    44970115 :                         HANDLE_BLOCK_INTERRUPTIONS();
     708             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
     709    44970115 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     710    44970115 :                         return SUCCESS;
     711             :                 }
     712     2793089 :                 prev = p;
     713     2793089 :                 idx = Z_NEXT(p->val);
     714             :         }
     715      823230 :         return FAILURE;
     716             : }
     717             : 
     718         383 : ZEND_API int zend_hash_del_ind(HashTable *ht, zend_string *key)
     719             : {
     720             :         zend_ulong h;
     721             :         uint32_t nIndex;
     722             :         uint32_t idx;
     723             :         Bucket *p;
     724         383 :         Bucket *prev = NULL;
     725             : #ifdef ZEND_SIGNALS
     726             :         TSRMLS_FETCH();
     727             : #endif
     728             : 
     729             :         IS_CONSISTENT(ht);
     730             : 
     731         383 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     732           0 :                 return FAILURE;
     733             :         }
     734             : 
     735         383 :         h = zend_string_hash_val(key);
     736         383 :         nIndex = h & ht->nTableMask;
     737             : 
     738         383 :         idx = ht->arHash[nIndex];
     739         775 :         while (idx != INVALID_IDX) {
     740         210 :                 p = ht->arData + idx;
     741         907 :                 if ((p->key == key) ||
     742         181 :                         (p->h == h &&
     743         172 :                      p->key &&
     744         172 :                      p->key->len == key->len &&
     745         172 :                      memcmp(p->key->val, key->val, key->len) == 0)) {
     746         402 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
     747          14 :                                 zval *data = Z_INDIRECT(p->val);
     748             : 
     749          14 :                                 if (Z_TYPE_P(data) == IS_UNDEF) {
     750           0 :                                         return FAILURE;
     751             :                                 } else {
     752          14 :                                         if (ht->pDestructor) {
     753          14 :                                                 ht->pDestructor(data);
     754             :                                         }
     755          14 :                                         ZVAL_UNDEF(data);
     756             :                                 }
     757             :                         } else {
     758         187 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     759             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
     760         187 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     761             :                         }
     762         201 :                         return SUCCESS;
     763             :                 }
     764           9 :                 prev = p;
     765           9 :                 idx = Z_NEXT(p->val);
     766             :         }
     767         182 :         return FAILURE;
     768             : }
     769             : 
     770      720824 : ZEND_API int zend_hash_str_del(HashTable *ht, const char *str, size_t len)
     771             : {
     772             :         zend_ulong h;
     773             :         uint32_t nIndex;
     774             :         uint32_t idx;
     775             :         Bucket *p;
     776      720824 :         Bucket *prev = NULL;
     777             : #ifdef ZEND_SIGNALS
     778             :         TSRMLS_FETCH();
     779             : #endif
     780             : 
     781             :         IS_CONSISTENT(ht);
     782             : 
     783      720824 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     784           0 :                 return FAILURE;
     785             :         }
     786             : 
     787      720824 :         h = zend_inline_hash_func(str, len);
     788      720824 :         nIndex = h & ht->nTableMask;
     789             : 
     790      720824 :         idx = ht->arHash[nIndex];
     791     1482997 :         while (idx != INVALID_IDX) {
     792      738824 :                 p = ht->arData + idx;
     793     2831249 :                 if ((p->h == h) 
     794             :                          && p->key
     795     1394950 :                          && (p->key->len == len)
     796      697475 :                          && !memcmp(p->key->val, str, len)) {
     797     1394950 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
     798           0 :                                 zval *data = Z_INDIRECT(p->val);
     799             : 
     800           0 :                                 if (Z_TYPE_P(data) == IS_UNDEF) {
     801           0 :                                         return FAILURE;
     802             :                                 } else {
     803           0 :                                         if (ht->pDestructor) {
     804           0 :                                                 ht->pDestructor(data);
     805             :                                         }
     806           0 :                                         ZVAL_UNDEF(data);
     807             :                                 }
     808             :                         } else {
     809      697475 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     810             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
     811      697475 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     812             :                         }
     813      697475 :                         return SUCCESS;
     814             :                 }
     815       41349 :                 prev = p;
     816       41349 :                 idx = Z_NEXT(p->val);
     817             :         }
     818       23349 :         return FAILURE;
     819             : }
     820             : 
     821           0 : ZEND_API int zend_hash_str_del_ind(HashTable *ht, const char *str, size_t len)
     822             : {
     823             :         zend_ulong h;
     824             :         uint32_t nIndex;
     825             :         uint32_t idx;
     826             :         Bucket *p;
     827           0 :         Bucket *prev = NULL;
     828             : #ifdef ZEND_SIGNALS
     829             :         TSRMLS_FETCH();
     830             : #endif
     831             : 
     832             :         IS_CONSISTENT(ht);
     833             : 
     834           0 :         h = zend_inline_hash_func(str, len);
     835           0 :         nIndex = h & ht->nTableMask;
     836             : 
     837           0 :         idx = ht->arHash[nIndex];
     838           0 :         while (idx != INVALID_IDX) {
     839           0 :                 p = ht->arData + idx;
     840           0 :                 if ((p->h == h) 
     841             :                          && p->key
     842           0 :                          && (p->key->len == len)
     843           0 :                          && !memcmp(p->key->val, str, len)) {
     844           0 :                         HANDLE_BLOCK_INTERRUPTIONS();
     845             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
     846           0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     847           0 :                         return SUCCESS;
     848             :                 }
     849           0 :                 prev = p;
     850           0 :                 idx = Z_NEXT(p->val);
     851             :         }
     852           0 :         return FAILURE;
     853             : }
     854             : 
     855      241776 : ZEND_API int zend_hash_index_del(HashTable *ht, zend_ulong h)
     856             : {
     857             :         uint32_t nIndex;
     858             :         uint32_t idx;
     859             :         Bucket *p;
     860      241776 :         Bucket *prev = NULL;
     861             : #ifdef ZEND_SIGNALS
     862             :         TSRMLS_FETCH();
     863             : #endif
     864             : 
     865             :         IS_CONSISTENT(ht);
     866             : 
     867      241776 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     868       97893 :                 if (h < ht->nNumUsed) {
     869       92416 :                         p = ht->arData + h;
     870      184832 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
     871       92409 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     872       92409 :                                 _zend_hash_del_el_ex(ht, h, p, NULL);
     873       92409 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     874       92409 :                                 return SUCCESS;
     875             :                         }
     876             :                 }
     877        5484 :                 return FAILURE;
     878             :         }
     879      143883 :         nIndex = h & ht->nTableMask;
     880             : 
     881      143883 :         idx = ht->arHash[nIndex];
     882      287913 :         while (idx != INVALID_IDX) {
     883      142832 :                 p = ht->arData + idx;
     884      142832 :                 if ((p->h == h) && (p->key == NULL)) {
     885      142685 :                         HANDLE_BLOCK_INTERRUPTIONS();
     886             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
     887      142685 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     888      142685 :                         return SUCCESS;
     889             :                 }
     890         147 :                 prev = p;
     891         147 :                 idx = Z_NEXT(p->val);
     892             :         }
     893        1198 :         return FAILURE;
     894             : }
     895             : 
     896    17889086 : ZEND_API void zend_hash_destroy(HashTable *ht)
     897             : {
     898             :         Bucket *p, *end;
     899             : 
     900             :         IS_CONSISTENT(ht);
     901             : 
     902    17889086 :         if (ht->nNumUsed) {
     903     9758738 :                 p = ht->arData;
     904     9758738 :                 end = p + ht->nNumUsed;
     905     9758738 :                 if (ht->pDestructor) {
     906             :                         SET_INCONSISTENT(HT_IS_DESTROYING);
     907             : 
     908     9466910 :                         if (ht->u.flags & HASH_FLAG_PACKED) {
     909             :                                 do {
     910    19290480 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
     911     7909622 :                                                 ht->pDestructor(&p->val);
     912             :                                         }
     913     9645237 :                                 } while (++p != end);
     914             :                         } else {
     915             :                                 do {
     916   644888014 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
     917   272980158 :                                                 ht->pDestructor(&p->val);
     918   272980158 :                                                 if (EXPECTED(p->key)) {
     919   272384073 :                                                         zend_string_release(p->key);
     920             :                                                 }
     921             :                                         }
     922   322444007 :                                 } while (++p != end);
     923             :                         }
     924             :                 
     925             :                         SET_INCONSISTENT(HT_DESTROYED);
     926             :                 } else {
     927      291828 :                         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     928             :                                 do {
     929    21115932 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
     930    10476134 :                                                 if (EXPECTED(p->key)) {
     931     9224038 :                                                         zend_string_release(p->key);
     932             :                                                 }
     933             :                                         }
     934    10557966 :                                 } while (++p != end);
     935             :                         }
     936             :                 }
     937     8130348 :         } else if (EXPECTED(!ht->nTableMask)) {
     938     8060911 :                 return;
     939             :         }
     940     9828172 :         pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
     941             : }
     942             : 
     943             : 
     944      137763 : ZEND_API void zend_hash_clean(HashTable *ht)
     945             : {
     946             :         uint32_t idx;
     947             :         Bucket *p;
     948             : 
     949             :         IS_CONSISTENT(ht);
     950             : 
     951     2159060 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
     952     2021297 :                 p = ht->arData + idx;
     953     4042594 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     954     2021293 :                 if (ht->pDestructor) {
     955     1990931 :                         ht->pDestructor(&p->val);
     956             :                 }
     957     2021293 :                 if (p->key) {
     958     2018466 :                         zend_string_release(p->key);
     959             :                 }
     960             :         }
     961      137763 :         ht->nNumUsed = 0;
     962      137763 :         ht->nNumOfElements = 0;
     963      137763 :         ht->nNextFreeElement = 0;
     964      137763 :         ht->nInternalPointer = INVALID_IDX;
     965      137763 :         if (ht->nTableMask) {
     966       96429 :                 if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     967       96419 :                         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));       
     968             :                 }
     969             :         }
     970      137763 : }
     971             : 
     972             : /* This function is used by the various apply() functions.
     973             :  * It deletes the passed bucket, and returns the address of the
     974             :  * next bucket.  The hash *may* be altered during that time, the
     975             :  * returned value will still be valid.
     976             :  */
     977     7360380 : static void zend_hash_apply_deleter(HashTable *ht, uint32_t idx, Bucket *p)
     978             : {
     979             : #ifdef ZEND_SIGNALS
     980             :         TSRMLS_FETCH();
     981             : #endif
     982             : 
     983     7360380 :         HANDLE_BLOCK_INTERRUPTIONS();
     984             :         _zend_hash_del_el(ht, idx, p);
     985     7360380 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     986     7360380 : }
     987             : 
     988             : 
     989           0 : ZEND_API void zend_hash_graceful_destroy(HashTable *ht)
     990             : {
     991             :         uint32_t idx;
     992             :         Bucket *p;
     993             : 
     994             :         IS_CONSISTENT(ht);
     995             : 
     996           0 :         for (idx = 0; idx < ht->nNumUsed; idx++) {                
     997           0 :                 p = ht->arData + idx;
     998           0 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     999           0 :                 zend_hash_apply_deleter(ht, idx, p);
    1000             :         }
    1001           0 :         if (ht->nTableMask) {
    1002           0 :                 pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
    1003             :         }
    1004             : 
    1005             :         SET_INCONSISTENT(HT_DESTROYED);
    1006           0 : }
    1007             : 
    1008       81868 : ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht)
    1009             : {
    1010             :         uint32_t idx;
    1011             :         Bucket *p;
    1012             : 
    1013             :         IS_CONSISTENT(ht);
    1014             : 
    1015       81868 :         idx = ht->nNumUsed;
    1016     1914746 :         while (idx > 0) {
    1017     1751010 :                 idx--;
    1018     1751010 :                 p = ht->arData + idx;
    1019     3502020 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1020     1705660 :                 zend_hash_apply_deleter(ht, idx, p);
    1021             :         }
    1022             : 
    1023       81868 :         if (ht->nTableMask) {
    1024       62235 :                 pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
    1025             :         }
    1026             : 
    1027             :         SET_INCONSISTENT(HT_DESTROYED);
    1028       81868 : }
    1029             : 
    1030             : /* This is used to recurse elements and selectively delete certain entries 
    1031             :  * from a hashtable. apply_func() receives the data and decides if the entry 
    1032             :  * should be deleted or recursion should be stopped. The following three 
    1033             :  * return codes are possible:
    1034             :  * ZEND_HASH_APPLY_KEEP   - continue
    1035             :  * ZEND_HASH_APPLY_STOP   - stop iteration
    1036             :  * ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former
    1037             :  */
    1038             : 
    1039       91413 : ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
    1040             : {
    1041             :         uint32_t idx;
    1042             :         Bucket *p;
    1043             :         int result;
    1044             : 
    1045             :         IS_CONSISTENT(ht);
    1046             : 
    1047       91413 :         HASH_PROTECT_RECURSION(ht);
    1048     1691687 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1049     1600276 :                 p = ht->arData + idx;
    1050     3200552 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1051             :                 
    1052     1600261 :                 result = apply_func(&p->val TSRMLS_CC);
    1053             :                 
    1054     1600259 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1055      107232 :                         zend_hash_apply_deleter(ht, idx, p);
    1056             :                 }
    1057     1600259 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1058           0 :                         break;
    1059             :                 }
    1060             :         }
    1061       91411 :         HASH_UNPROTECT_RECURSION(ht);
    1062       91411 : }
    1063             : 
    1064             : 
    1065      644796 : ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument TSRMLS_DC)
    1066             : {
    1067             :     uint32_t idx;
    1068             :         Bucket *p;
    1069             :         int result;
    1070             : 
    1071             :         IS_CONSISTENT(ht);
    1072             : 
    1073      644796 :         HASH_PROTECT_RECURSION(ht);
    1074   188847667 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1075   188207023 :                 p = ht->arData + idx;
    1076   376414046 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1077             : 
    1078   148070830 :                 result = apply_func(&p->val, argument TSRMLS_CC);
    1079             :                 
    1080   148070830 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1081     5445233 :                         zend_hash_apply_deleter(ht, idx, p);
    1082             :                 }
    1083   148070830 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1084        4152 :                         break;
    1085             :                 }
    1086             :         }
    1087      644796 :         HASH_UNPROTECT_RECURSION(ht);
    1088      644796 : }
    1089             : 
    1090             : 
    1091         715 : ZEND_API void zend_hash_apply_with_arguments(HashTable *ht TSRMLS_DC, apply_func_args_t apply_func, int num_args, ...)
    1092             : {
    1093             :         uint32_t idx;
    1094             :         Bucket *p;
    1095             :         va_list args;
    1096             :         zend_hash_key hash_key;
    1097             :         int result;
    1098             : 
    1099             :         IS_CONSISTENT(ht);
    1100             : 
    1101         715 :         HASH_PROTECT_RECURSION(ht);
    1102             : 
    1103     1100069 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1104     1099354 :                 p = ht->arData + idx;
    1105     2198708 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1106     1099265 :                 va_start(args, num_args);
    1107     1099265 :                 hash_key.h = p->h;
    1108     1099265 :                 hash_key.key = p->key;
    1109             : 
    1110     1099265 :                 result = apply_func(&p->val TSRMLS_CC, num_args, args, &hash_key);
    1111             : 
    1112     1099265 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1113          24 :                         zend_hash_apply_deleter(ht, idx, p);
    1114             :                 }
    1115     1099265 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1116           0 :                         va_end(args);
    1117           0 :                         break;
    1118             :                 }
    1119     1099265 :                 va_end(args);
    1120             :         }
    1121             : 
    1122         715 :         HASH_UNPROTECT_RECURSION(ht);
    1123         715 : }
    1124             : 
    1125             : 
    1126      106781 : ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
    1127             : {
    1128             :         uint32_t idx;
    1129             :         Bucket *p;
    1130             :         int result;
    1131             : 
    1132             :         IS_CONSISTENT(ht);
    1133             : 
    1134      106781 :         HASH_PROTECT_RECURSION(ht);
    1135      106781 :         idx = ht->nNumUsed;
    1136      716038 :         while (idx > 0) {
    1137      563724 :                 idx--;
    1138      563724 :                 p = ht->arData + idx;
    1139     1127448 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1140             :                 
    1141      510263 :                 result = apply_func(&p->val TSRMLS_CC);
    1142             : 
    1143      510263 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1144      102231 :                         zend_hash_apply_deleter(ht, idx, p);
    1145             :                 }
    1146      510263 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1147       61248 :                         break;
    1148             :                 }
    1149             :         }
    1150      106781 :         HASH_UNPROTECT_RECURSION(ht);
    1151      106781 : }
    1152             : 
    1153             : 
    1154         463 : ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor)
    1155             : {
    1156             :     uint32_t idx;
    1157             :         Bucket *p;
    1158             :         zval *new_entry, *data;
    1159             :         zend_bool setTargetPointer;
    1160             : 
    1161             :         IS_CONSISTENT(source);
    1162             :         IS_CONSISTENT(target);
    1163             : 
    1164         463 :         setTargetPointer = (target->nInternalPointer == INVALID_IDX);
    1165       11854 :         for (idx = 0; idx < source->nNumUsed; idx++) {            
    1166       11391 :                 p = source->arData + idx;
    1167       22782 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1168             : 
    1169       11391 :                 if (setTargetPointer && source->nInternalPointer == idx) {
    1170         312 :                         target->nInternalPointer = INVALID_IDX;
    1171             :                 }
    1172             :                 /* INDIRECT element may point to UNDEF-ined slots */
    1173       11391 :                 data = &p->val;
    1174       11391 :                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1175          96 :                         data = Z_INDIRECT_P(data);
    1176          96 :                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1177           0 :                                 continue;
    1178             :                         }
    1179             :                 }
    1180       11391 :                 if (p->key) {
    1181       11302 :                         new_entry = zend_hash_update(target, p->key, data);
    1182             :                 } else {
    1183          89 :                         new_entry = zend_hash_index_update(target, p->h, data);
    1184             :                 }
    1185       11391 :                 if (pCopyConstructor) {
    1186         411 :                         pCopyConstructor(new_entry);
    1187             :                 }
    1188             :         }
    1189         463 :         if (target->nInternalPointer == INVALID_IDX && target->nNumOfElements > 0) {
    1190           0 :                 idx = 0;
    1191           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1192           0 :                         idx++;
    1193             :                 }
    1194           0 :                 target->nInternalPointer = idx;
    1195             :         }
    1196         463 : }
    1197             : 
    1198             : 
    1199     1290458 : ZEND_API void zend_array_dup(HashTable *target, HashTable *source)
    1200             : {
    1201             :     uint32_t idx, target_idx;
    1202             :         uint32_t nIndex;
    1203             :         Bucket *p, *q;
    1204             :         zval *data;
    1205             : 
    1206             :         IS_CONSISTENT(source);
    1207             :         
    1208     1290458 :         target->nTableMask = source->nTableMask;
    1209     1290458 :         target->nTableSize = source->nTableSize;
    1210     1290458 :         target->pDestructor = source->pDestructor;
    1211     1290458 :         target->nInternalPointer = INVALID_IDX;
    1212     1290458 :         target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1213             : 
    1214     1290458 :         target_idx = 0;
    1215     1290458 :         if (target->nTableMask) {
    1216     1129801 :                 if (target->u.flags & HASH_FLAG_PACKED) {
    1217     1072766 :                         target->nNumUsed = source->nNumUsed;
    1218     1072766 :                         target->nNumOfElements = source->nNumOfElements;
    1219     1072766 :                         target->nNextFreeElement = source->nNextFreeElement;
    1220     1072766 :                         target->arData = (Bucket *) safe_pemalloc(target->nTableSize, sizeof(Bucket), 0, 0);
    1221     1072766 :                         target->arHash = (uint32_t*)&uninitialized_bucket;
    1222     1072766 :                         target->nInternalPointer = source->nInternalPointer;
    1223             : 
    1224     4437917 :                         for (idx = 0; idx < source->nNumUsed; idx++) {            
    1225     3365151 :                                 p = source->arData + idx;
    1226     3365151 :                                 q = target->arData + idx;
    1227     6730302 :                                 if (Z_TYPE(p->val) == IS_UNDEF) {
    1228      846090 :                                         ZVAL_UNDEF(&q->val);
    1229      846090 :                                         continue;
    1230             :                                 }
    1231             :                                 /* INDIRECT element may point to UNDEF-ined slots */
    1232     2519061 :                                 data = &p->val;
    1233     2519061 :                                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1234           0 :                                         data = Z_INDIRECT_P(data);
    1235           0 :                                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1236           0 :                                                 ZVAL_UNDEF(&q->val);
    1237           0 :                                                 continue;
    1238             :                                         }
    1239             :                                 }
    1240             : 
    1241     2519061 :                                 q->h = p->h;
    1242     2519061 :                                 q->key = NULL;
    1243     2519061 :                                 if (Z_OPT_REFCOUNTED_P(data)) {
    1244     2388029 :                                         if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
    1245           1 :                                                 ZVAL_COPY(&q->val, Z_REFVAL_P(data));
    1246             :                                         } else {
    1247     2388006 :                                                 ZVAL_COPY(&q->val, data);
    1248             :                                         }
    1249             :                                 } else {
    1250      131054 :                                         ZVAL_COPY_VALUE(&q->val, data);
    1251             :                                 }
    1252             :                         }
    1253     2145532 :                         if (target->nNumOfElements > 0 &&
    1254     1072766 :                             target->nInternalPointer == INVALID_IDX) {
    1255          41 :                                 idx = 0;
    1256         145 :                                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1257          11 :                                         idx++;
    1258             :                                 }
    1259          41 :                                 target->nInternalPointer = idx;
    1260             :                         }
    1261             :                 } else {
    1262       57035 :                         target->nNextFreeElement = source->nNextFreeElement;
    1263       57035 :                         target->arData = (Bucket *) safe_pemalloc(target->nTableSize, sizeof(Bucket) + sizeof(uint32_t), 0, 0);
    1264       57035 :                         target->arHash = (uint32_t*)(target->arData + target->nTableSize);
    1265       57035 :                         memset(target->arHash, INVALID_IDX, target->nTableSize * sizeof(uint32_t));
    1266             : 
    1267      771843 :                         for (idx = 0; idx < source->nNumUsed; idx++) {            
    1268      714808 :                                 p = source->arData + idx;
    1269     1429616 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1270             :                                 /* INDIRECT element may point to UNDEF-ined slots */
    1271      714804 :                                 data = &p->val;
    1272      714804 :                                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1273       29525 :                                         data = Z_INDIRECT_P(data);
    1274       29525 :                                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1275        5178 :                                                 continue;
    1276             :                                         }
    1277             :                                 }
    1278             : 
    1279      709626 :                                 if (source->nInternalPointer == idx) {
    1280       44046 :                                         target->nInternalPointer = target_idx;
    1281             :                                 }
    1282             : 
    1283      709626 :                                 q = target->arData + target_idx;
    1284      709626 :                                 q->h = p->h;
    1285      709626 :                                 q->key = p->key;
    1286      709626 :                                 if (q->key) {
    1287      703987 :                                         zend_string_addref(q->key);
    1288             :                                 }
    1289      709626 :                                 nIndex = q->h & target->nTableMask;
    1290      709626 :                                 Z_NEXT(q->val) = target->arHash[nIndex];
    1291      709626 :                                 target->arHash[nIndex] = target_idx;
    1292      709626 :                                 if (Z_OPT_REFCOUNTED_P(data)) {
    1293      632911 :                                         if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
    1294          97 :                                                 ZVAL_COPY(&q->val, Z_REFVAL_P(data));
    1295             :                                         } else {
    1296      632171 :                                                 ZVAL_COPY(&q->val, data);
    1297             :                                         }
    1298             :                                 } else {
    1299       77358 :                                         ZVAL_COPY_VALUE(&q->val, data);
    1300             :                                 }
    1301      709626 :                                 target_idx++;
    1302             :                         }
    1303       57035 :                         target->nNumUsed = target_idx;
    1304       57035 :                         target->nNumOfElements = target_idx;
    1305      114051 :                         if (target->nNumOfElements > 0 &&
    1306       57016 :                             target->nInternalPointer == INVALID_IDX) {
    1307       12970 :                                 target->nInternalPointer = 0;
    1308             :                         }
    1309             :                 }
    1310             :         } else {
    1311      160657 :                 target->nNumUsed = 0;
    1312      160657 :                 target->nNumOfElements = 0;
    1313      160657 :                 target->nNextFreeElement = 0;
    1314      160657 :                 target->arData = NULL;
    1315      160657 :                 target->arHash = (uint32_t*)&uninitialized_bucket;
    1316             :         }
    1317     1290458 : }
    1318             : 
    1319             : 
    1320      183884 : ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, zend_bool overwrite ZEND_FILE_LINE_DC)
    1321             : {
    1322             :     uint32_t idx;
    1323             :         Bucket *p;
    1324             :         zval *t;
    1325      183884 :         uint32_t mode = (overwrite?HASH_UPDATE:HASH_ADD);
    1326             : 
    1327             :         IS_CONSISTENT(source);
    1328             :         IS_CONSISTENT(target);
    1329             : 
    1330     3167157 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1331     2983273 :                 p = source->arData + idx;
    1332     5966546 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1333     2983273 :                 if (p->key) {
    1334     2983257 :                         t = _zend_hash_add_or_update(target, p->key, &p->val, mode ZEND_FILE_LINE_RELAY_CC);
    1335     2983257 :                         if (t && pCopyConstructor) {
    1336     2982675 :                                 pCopyConstructor(t);
    1337             :                         }
    1338             :                 } else {
    1339          16 :                         if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h))) {
    1340           6 :                                 t = zend_hash_index_update(target, p->h, &p->val);
    1341           6 :                                 if (t && pCopyConstructor) {
    1342           6 :                                         pCopyConstructor(t);
    1343             :                                 }
    1344             :                         }
    1345             :                 }
    1346             :         }
    1347      183884 :         if (target->nNumOfElements > 0) {
    1348      183882 :                 idx = 0;
    1349      551646 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1350           0 :                         idx++;
    1351             :                 }
    1352      183882 :                 target->nInternalPointer = idx;
    1353             :         }
    1354      183884 : }
    1355             : 
    1356             : 
    1357           0 : static zend_bool zend_hash_replace_checker_wrapper(HashTable *target, zval *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func)
    1358             : {
    1359             :         zend_hash_key hash_key;
    1360             : 
    1361           0 :         hash_key.h = p->h;
    1362           0 :         hash_key.key = p->key;
    1363           0 :         return merge_checker_func(target, source_data, &hash_key, pParam);
    1364             : }
    1365             : 
    1366             : 
    1367           0 : ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam)
    1368             : {
    1369             :         uint32_t idx;
    1370             :         Bucket *p;
    1371             :         zval *t;
    1372             : 
    1373             :         IS_CONSISTENT(source);
    1374             :         IS_CONSISTENT(target);
    1375             : 
    1376           0 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1377           0 :                 p = source->arData + idx;
    1378           0 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1379           0 :                 if (zend_hash_replace_checker_wrapper(target, &p->val, p, pParam, pMergeSource)) {
    1380           0 :                         t = zend_hash_update(target, p->key, &p->val);
    1381           0 :                         if (t && pCopyConstructor) {
    1382           0 :                                 pCopyConstructor(t);
    1383             :                         }
    1384             :                 }
    1385             :         }
    1386           0 :         if (target->nNumOfElements > 0) {
    1387           0 :                 idx = 0;
    1388           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1389           0 :                         idx++;
    1390             :                 }
    1391           0 :                 target->nInternalPointer = idx;
    1392             :         }
    1393           0 : }
    1394             : 
    1395             : 
    1396             : /* Returns SUCCESS if found and FAILURE if not. The pointer to the
    1397             :  * data is returned in pData. The reason is that there's no reason
    1398             :  * someone using the hash table might not want to have NULL data
    1399             :  */
    1400    50746960 : ZEND_API zval *zend_hash_find(const HashTable *ht, zend_string *key)
    1401             : {
    1402             :         Bucket *p;
    1403             : 
    1404             :         IS_CONSISTENT(ht);
    1405             : 
    1406    50746960 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1407         747 :                 return NULL;
    1408             :         }
    1409             : 
    1410    50746213 :         p = zend_hash_find_bucket(ht, key);
    1411    50746213 :         return p ? &p->val : NULL;
    1412             : }
    1413             : 
    1414     2585259 : ZEND_API zval *zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
    1415             : {
    1416             :         zend_ulong h;
    1417             :         Bucket *p;
    1418             : 
    1419             :         IS_CONSISTENT(ht);
    1420             : 
    1421     2585259 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1422         171 :                 return NULL;
    1423             :         }
    1424             : 
    1425     2585088 :         h = zend_inline_hash_func(str, len);
    1426     2585088 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1427     2585088 :         return p ? &p->val : NULL;
    1428             : }
    1429             : 
    1430      552250 : ZEND_API zend_bool zend_hash_exists(const HashTable *ht, zend_string *key)
    1431             : {
    1432             :         Bucket *p;
    1433             : 
    1434             :         IS_CONSISTENT(ht);
    1435             : 
    1436      552250 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1437          55 :                 return 0;
    1438             :         }
    1439             : 
    1440      552195 :         p = zend_hash_find_bucket(ht, key);
    1441      552195 :         return p ? 1 : 0;
    1442             : }
    1443             : 
    1444      848956 : ZEND_API zend_bool zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
    1445             : {
    1446             :         zend_ulong h;
    1447             :         Bucket *p;
    1448             : 
    1449             :         IS_CONSISTENT(ht);
    1450             : 
    1451      848956 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1452           0 :                 return 0;
    1453             :         }
    1454             : 
    1455      848956 :         h = zend_inline_hash_func(str, len);
    1456      848956 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1457      848956 :         return p ? 1 : 0;
    1458             : }
    1459             : 
    1460     6109683 : ZEND_API zval *zend_hash_index_find(const HashTable *ht, zend_ulong h)
    1461             : {
    1462             :         Bucket *p;
    1463             : 
    1464             :         IS_CONSISTENT(ht);
    1465             : 
    1466     6109683 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1467     4967990 :                 if (h < ht->nNumUsed) {
    1468     4716568 :                         p = ht->arData + h;
    1469     9433136 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
    1470     4716064 :                                 return &p->val;
    1471             :                         }
    1472             :                 }
    1473      251926 :                 return NULL;
    1474             :         }
    1475             : 
    1476     1141693 :         p = zend_hash_index_find_bucket(ht, h);
    1477     1141693 :         return p ? &p->val : NULL;
    1478             : }
    1479             : 
    1480             : 
    1481     1511670 : ZEND_API zend_bool zend_hash_index_exists(const HashTable *ht, zend_ulong h)
    1482             : {
    1483             :         Bucket *p;
    1484             : 
    1485             :         IS_CONSISTENT(ht);
    1486             : 
    1487     1511670 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1488          56 :                 if (h < ht->nNumUsed) {
    1489         102 :                         if (Z_TYPE(ht->arData[h].val) != IS_UNDEF) {
    1490          50 :                                 return 1;
    1491             :                         }
    1492             :                 }
    1493           6 :                 return 0;
    1494             :         }
    1495             : 
    1496     1511614 :         p = zend_hash_index_find_bucket(ht, h);
    1497     1511614 :         return p ? 1 : 0;
    1498             : }
    1499             : 
    1500             : 
    1501       21616 : ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
    1502             : {
    1503             :     uint32_t idx;
    1504             :         
    1505             :         IS_CONSISTENT(ht);
    1506       22105 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1507       42496 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1508       20759 :                         *pos = idx;
    1509       20759 :                         return;
    1510             :                 }
    1511             :         }
    1512         857 :         *pos = INVALID_IDX;
    1513             : }
    1514             : 
    1515             : 
    1516             : /* This function will be extremely optimized by remembering 
    1517             :  * the end of the list
    1518             :  */
    1519          47 : ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
    1520             : {
    1521             :         uint32_t idx;
    1522             :         
    1523             :         IS_CONSISTENT(ht);
    1524             : 
    1525          47 :         idx = ht->nNumUsed;
    1526          94 :         while (idx > 0) {
    1527          45 :                 idx--;
    1528          90 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1529          45 :                         *pos = idx;
    1530          45 :                         return;
    1531             :                 }
    1532             :         }
    1533           2 :         *pos = INVALID_IDX;
    1534             : }
    1535             : 
    1536             : 
    1537       81462 : ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
    1538             : {
    1539       81462 :         uint32_t idx = *pos;
    1540             : 
    1541             :         IS_CONSISTENT(ht);
    1542             : 
    1543       81462 :         if (idx != INVALID_IDX) {
    1544             :                 while (1) {
    1545       81514 :                         idx++;
    1546       81514 :                         if (idx >= ht->nNumUsed) {
    1547       17055 :                                 *pos = INVALID_IDX;
    1548       17055 :                                 return SUCCESS;
    1549             :                         }
    1550      128918 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1551       64383 :                                 *pos = idx;
    1552       64383 :                                 return SUCCESS;
    1553             :                         }
    1554          76 :                 }
    1555             :         } else {
    1556          24 :                 return FAILURE;
    1557             :         }
    1558             : }
    1559             : 
    1560          21 : ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
    1561             : {
    1562          21 :         uint32_t idx = *pos;
    1563             : 
    1564             :         IS_CONSISTENT(ht);
    1565             : 
    1566          21 :         if (idx != INVALID_IDX) {
    1567          38 :                 while (idx > 0) {
    1568          14 :                         idx--;
    1569          28 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1570          14 :                                 *pos = idx;
    1571          14 :                                 return SUCCESS;
    1572             :                         }
    1573             :                 }
    1574           5 :                 *pos = INVALID_IDX;
    1575           5 :                 return SUCCESS;
    1576             :         } else {
    1577           2 :                 return FAILURE;
    1578             :         }
    1579             : }
    1580             : 
    1581             : 
    1582             : /* This function should be made binary safe  */
    1583       23187 : ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, zend_bool duplicate, HashPosition *pos)
    1584             : {
    1585       23187 :         uint32_t idx = *pos;
    1586             :         Bucket *p;
    1587             : 
    1588             :         IS_CONSISTENT(ht);
    1589       23187 :         if (idx != INVALID_IDX) {
    1590       22266 :                 p = ht->arData + idx;
    1591       22266 :                 if (p->key) {
    1592       20786 :                         if (duplicate) {
    1593           0 :                                 *str_index = zend_string_copy(p->key);
    1594             :                         } else {
    1595       20786 :                                 *str_index = p->key;
    1596             :                         }
    1597       20786 :                         return HASH_KEY_IS_STRING;
    1598             :                 } else {
    1599        1480 :                         *num_index = p->h;
    1600        1480 :                         return HASH_KEY_IS_LONG;
    1601             :                 }
    1602             :         }
    1603         921 :         return HASH_KEY_NON_EXISTENT;
    1604             : }
    1605             : 
    1606        3512 : ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos)
    1607             : {
    1608        3512 :         uint32_t idx = *pos;
    1609             :         Bucket *p;
    1610             : 
    1611             :         IS_CONSISTENT(ht);
    1612        3512 :         if (idx == INVALID_IDX) {
    1613          54 :                 ZVAL_NULL(key);
    1614             :         } else {
    1615        3458 :                 p = ht->arData + idx;
    1616        3458 :                 if (p->key) {
    1617         669 :                         ZVAL_STR_COPY(key, p->key);
    1618             :                 } else {
    1619        2789 :                         ZVAL_LONG(key, p->h);
    1620             :                 }
    1621             :         }
    1622        3512 : }
    1623             : 
    1624       68692 : ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
    1625             : {
    1626       68692 :     uint32_t idx = *pos;
    1627             :         Bucket *p;
    1628             : 
    1629             :         IS_CONSISTENT(ht);
    1630       68692 :         if (idx != INVALID_IDX) {
    1631       53529 :                 p = ht->arData + idx;
    1632       53529 :                 if (p->key) {
    1633       51003 :                         return HASH_KEY_IS_STRING;
    1634             :                 } else {
    1635        2526 :                         return HASH_KEY_IS_LONG;
    1636             :                 }
    1637             :         }
    1638       15163 :         return HASH_KEY_NON_EXISTENT;
    1639             : }
    1640             : 
    1641             : 
    1642       74786 : ZEND_API zval *zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
    1643             : {
    1644       74786 :         uint32_t idx = *pos;
    1645             :         Bucket *p;
    1646             : 
    1647             :         IS_CONSISTENT(ht);
    1648       74786 :         if (idx != INVALID_IDX) {
    1649       73623 :                 p = ht->arData + idx;
    1650       73623 :                 return &p->val;
    1651             :         } else {
    1652        1163 :                 return NULL;
    1653             :         }
    1654             : }
    1655             : 
    1656       22128 : ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
    1657             :                                                         compare_func_t compar, zend_bool renumber TSRMLS_DC)
    1658             : {
    1659             :         Bucket *p;
    1660             :         uint32_t i, j;
    1661             : 
    1662             :         IS_CONSISTENT(ht);
    1663             : 
    1664       22128 :         if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */
    1665         288 :                 return SUCCESS;
    1666             :         }
    1667             : 
    1668       21840 :         if (ht->nNumUsed == ht->nNumOfElements) {
    1669       21730 :                 i = ht->nNumUsed;
    1670             :         } else {
    1671         787 :                 for (j = 0, i = 0; j < ht->nNumUsed; j++) {
    1672         677 :                         p = ht->arData + j;
    1673        1354 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1674         520 :                         if (i != j) {
    1675         504 :                                 ht->arData[i] = *p;
    1676             :                         }
    1677         520 :                         i++;
    1678             :                 }
    1679             :         }
    1680             : 
    1681       21840 :         (*sort_func)((void *) ht->arData, i, sizeof(Bucket), compar TSRMLS_CC);
    1682             : 
    1683       21839 :         HANDLE_BLOCK_INTERRUPTIONS();
    1684       21839 :         ht->nNumUsed = i;
    1685       21839 :         ht->nInternalPointer = 0;
    1686             : 
    1687       21839 :         if (renumber) {
    1688       15272 :                 for (j = 0; j < i; j++) {
    1689       14983 :                         p = ht->arData + j;
    1690       14983 :                         p->h = j;
    1691       14983 :                         if (p->key) {
    1692         288 :                                 zend_string_release(p->key);
    1693         288 :                                 p->key = NULL;
    1694             :                         }
    1695             :                 }
    1696             :         }
    1697       21839 :         if (renumber) {
    1698         289 :                 ht->nNextFreeElement = i;
    1699             :         }
    1700       21839 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1701         502 :                 if (!renumber) {
    1702         261 :                         zend_hash_packed_to_hash(ht);
    1703             :                 }
    1704             :         } else {
    1705       21337 :                 if (renumber) {
    1706          48 :                         ht->u.flags |= HASH_FLAG_PACKED;
    1707          48 :                         ht->arData = erealloc(ht->arData, ht->nTableSize * sizeof(Bucket));
    1708          48 :                         ht->arHash = (uint32_t*)&uninitialized_bucket;
    1709             :                 } else {
    1710       21289 :                         zend_hash_rehash(ht);
    1711             :                 }
    1712             :         }
    1713             : 
    1714       21839 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1715             : 
    1716       21839 :         return SUCCESS;
    1717             : }
    1718             : 
    1719             : 
    1720        1099 : ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC)
    1721             : {
    1722             :         uint32_t idx1, idx2;
    1723        1099 :         Bucket *p1, *p2 = NULL;
    1724             :         int result;
    1725             :         zval *pData1, *pData2;
    1726             : 
    1727             :         IS_CONSISTENT(ht1);
    1728             :         IS_CONSISTENT(ht2);
    1729             : 
    1730        1099 :         HASH_PROTECT_RECURSION(ht1); 
    1731        1099 :         HASH_PROTECT_RECURSION(ht2); 
    1732             : 
    1733        1099 :         result = ht1->nNumOfElements - ht2->nNumOfElements;
    1734        1099 :         if (result!=0) {
    1735         531 :                 HASH_UNPROTECT_RECURSION(ht1); 
    1736         531 :                 HASH_UNPROTECT_RECURSION(ht2); 
    1737         531 :                 return result;
    1738             :         }
    1739             : 
    1740        3904 :         for (idx1 = 0, idx2 = 0; idx1 < ht1->nNumUsed; idx1++) {
    1741        3510 :                 p1 = ht1->arData + idx1;
    1742        7020 :                 if (Z_TYPE(p1->val) == IS_UNDEF) continue;
    1743             : 
    1744        3497 :                 if (ordered) {
    1745             :                         while (1) {
    1746        1134 :                                 p2 = ht2->arData + idx2;
    1747        1134 :                                 if (idx2 == ht2->nNumUsed) {
    1748           0 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1749           0 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1750           0 :                                         return 1; /* That's not supposed to happen */
    1751             :                                 }
    1752        2268 :                                 if (Z_TYPE(p2->val) != IS_UNDEF) break;
    1753           1 :                                 idx2++;
    1754           1 :                         }                                               
    1755        1500 :                         if (p1->key == NULL && p2->key == NULL) { /* numeric indices */
    1756         368 :                                 result = p1->h - p2->h;
    1757         368 :                                 if (result != 0) {
    1758           1 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1759           1 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1760           1 :                                         return result;
    1761             :                                 }
    1762             :                         } else { /* string indices */
    1763         765 :                                 size_t len0 = (p1->key ? p1->key->len : 0);
    1764         765 :                                 size_t len1 = (p2->key ? p2->key->len : 0);
    1765         765 :                                 if (len0 != len1) {
    1766           0 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1767           0 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1768           0 :                                         return len0 > len1 ? 1 : -1;
    1769             :                                 }
    1770         765 :                                 result = memcmp(p1->key->val, p2->key->val, p1->key->len);
    1771         765 :                                 if (result != 0) {
    1772           0 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1773           0 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1774           0 :                                         return result;
    1775             :                                 }
    1776             :                         }
    1777        1132 :                         pData2 = &p2->val;
    1778             :                 } else {
    1779        2364 :                         if (p1->key == NULL) { /* numeric index */
    1780         219 :                                 pData2 = zend_hash_index_find(ht2, p1->h);
    1781         219 :                                 if (pData2 == NULL) {
    1782           4 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1783           4 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1784           4 :                                         return 1;
    1785             :                                 }
    1786             :                         } else { /* string index */
    1787        2145 :                                 pData2 = zend_hash_find(ht2, p1->key);
    1788        2145 :                                 if (pData2 == NULL) {
    1789          24 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1790          24 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1791          24 :                                         return 1;
    1792             :                                 }
    1793             :                         }
    1794             :                 }
    1795        3468 :                 pData1 = &p1->val;
    1796        3468 :                 if (Z_TYPE_P(pData1) == IS_INDIRECT) {
    1797         118 :                         pData1 = Z_INDIRECT_P(pData1);
    1798             :                 }
    1799        3468 :                 if (Z_TYPE_P(pData2) == IS_INDIRECT) {
    1800         118 :                         pData2 = Z_INDIRECT_P(pData2);
    1801             :                 }
    1802        3468 :                 if (Z_TYPE_P(pData1) == IS_UNDEF) {
    1803           0 :                         if (Z_TYPE_P(pData2) != IS_UNDEF) {
    1804           0 :                                 return -1;
    1805             :                         }
    1806        3468 :                 } else if (Z_TYPE_P(pData2) == IS_UNDEF) {
    1807           0 :                         return 1;
    1808             :                 } else {
    1809        3468 :                         result = compar(pData1, pData2 TSRMLS_CC);
    1810             :                 }
    1811        3468 :                 if (result != 0) {
    1812         145 :                         HASH_UNPROTECT_RECURSION(ht1); 
    1813         145 :                         HASH_UNPROTECT_RECURSION(ht2); 
    1814         145 :                         return result;
    1815             :                 }
    1816        3323 :                 if (ordered) {
    1817        1128 :                         idx2++;
    1818             :                 }
    1819             :         }
    1820             :         
    1821         394 :         HASH_UNPROTECT_RECURSION(ht1); 
    1822         394 :         HASH_UNPROTECT_RECURSION(ht2); 
    1823         394 :         return 0;
    1824             : }
    1825             : 
    1826             : 
    1827          82 : ZEND_API zval *zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag TSRMLS_DC)
    1828             : {
    1829             :         uint32_t idx;
    1830             :         Bucket *p, *res;
    1831             : 
    1832             :         IS_CONSISTENT(ht);
    1833             : 
    1834          82 :         if (ht->nNumOfElements == 0 ) {
    1835           4 :                 return NULL;
    1836             :         }
    1837             : 
    1838          78 :         idx = 0;
    1839             :         while (1) {
    1840          78 :                 if (idx == ht->nNumUsed) {
    1841           0 :                         return NULL;
    1842             :                 }
    1843         156 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) break;
    1844           0 :                 idx++;
    1845           0 :         }
    1846          78 :         res = ht->arData + idx;
    1847         376 :         for (; idx < ht->nNumUsed; idx++) {
    1848         298 :                 p = ht->arData + idx;
    1849         596 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1850             :                 
    1851         298 :                 if (flag) {
    1852         229 :                         if (compar(res, p TSRMLS_CC) < 0) { /* max */
    1853          20 :                                 res = p;
    1854             :                         }
    1855             :                 } else {
    1856          69 :                         if (compar(res, p TSRMLS_CC) > 0) { /* min */
    1857           6 :                                 res = p;
    1858             :                         }
    1859             :                 }
    1860             :         }
    1861          78 :         return &res->val;
    1862             : }
    1863             : 
    1864      382442 : ZEND_API int _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx)
    1865             : {
    1866      382442 :         register const char *tmp = key;
    1867             :         const char *end;
    1868             : 
    1869      382442 :         if (*tmp > '9') {
    1870           0 :                 return 0;
    1871      382442 :         } else if (*tmp < '0') {
    1872          59 :                 if (*tmp != '-') {
    1873           0 :                         return 0;
    1874             :                 }
    1875          59 :                 tmp++;
    1876          59 :                 if (*tmp > '9' || *tmp < '0') {
    1877           0 :                         return 0;
    1878             :                 }
    1879             :         }
    1880             : 
    1881             :         /* possibly a numeric index */
    1882      382442 :         end = key + length;
    1883             : 
    1884     1127184 :         if ((*end != '\0') /* not a null terminated string */
    1885      382442 :          || (*tmp == '0' && length > 1) /* numbers with leading zeros */
    1886      362300 :          || (end - tmp > MAX_LENGTH_OF_LONG - 1) /* number too long */
    1887             :          || (SIZEOF_ZEND_LONG == 4 &&
    1888             :              end - tmp == MAX_LENGTH_OF_LONG - 1 &&
    1889             :              *tmp > '2')) { /* overflow */
    1890       20169 :                 return 0;
    1891             :         }
    1892      362273 :         *idx = (*tmp - '0');
    1893             :         while (1) {
    1894     1442833 :                 ++tmp;
    1895     1442833 :                 if (tmp == end) {
    1896      362010 :                         if (*key == '-') {
    1897          28 :                                 if (*idx-1 > ZEND_LONG_MAX) { /* overflow */
    1898           0 :                                         return 0;
    1899             :                                 }
    1900          28 :                                 *idx = 0 - *idx;
    1901      361982 :                         } else if (*idx > ZEND_LONG_MAX) { /* overflow */
    1902           0 :                                 return 0;
    1903             :                         }
    1904      362010 :                         return 1;
    1905             :                 }
    1906     2161383 :                 if (*tmp <= '9' && *tmp >= '0') {
    1907     1080560 :                         *idx = (*idx * 10) + (*tmp - '0');
    1908             :                 } else {
    1909         263 :                         return 0;
    1910             :                 }
    1911     1080560 :         }
    1912             : }
    1913             : 
    1914             : /*
    1915             :  * Local variables:
    1916             :  * tab-width: 4
    1917             :  * c-basic-offset: 4
    1918             :  * indent-tabs-mode: t
    1919             :  * End:
    1920             :  */

Generated by: LCOV version 1.10

Generated at Thu, 30 Oct 2014 07:41:27 +0000 (30 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.