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: 669 720 92.9 %
Date: 2014-04-18 Functions: 44 46 95.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2013 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             : 
      24             : #define CONNECT_TO_BUCKET_DLLIST(element, list_head)            \
      25             :         (element)->pNext = (list_head);                                                      \
      26             :         (element)->pLast = NULL;                                                             \
      27             :         if ((element)->pNext) {                                                                      \
      28             :                 (element)->pNext->pLast = (element);                              \
      29             :         }
      30             : 
      31             : #define CONNECT_TO_GLOBAL_DLLIST(element, ht)                           \
      32             :         (element)->pListLast = (ht)->pListTail;                                   \
      33             :         (ht)->pListTail = (element);                                                 \
      34             :         (element)->pListNext = NULL;                                                 \
      35             :         if ((element)->pListLast != NULL) {                                          \
      36             :                 (element)->pListLast->pListNext = (element);              \
      37             :         }                                                                                                               \
      38             :         if (!(ht)->pListHead) {                                                                      \
      39             :                 (ht)->pListHead = (element);                                         \
      40             :         }                                                                                                               \
      41             :         if ((ht)->pInternalPointer == NULL) {                                        \
      42             :                 (ht)->pInternalPointer = (element);                                  \
      43             :         }
      44             : 
      45             : #if ZEND_DEBUG
      46             : #define HT_OK                           0
      47             : #define HT_IS_DESTROYING        1
      48             : #define HT_DESTROYED            2
      49             : #define HT_CLEANING                     3
      50             : 
      51             : static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
      52             : {
      53             :         if (ht->inconsistent==HT_OK) {
      54             :                 return;
      55             :         }
      56             :         switch (ht->inconsistent) {
      57             :                 case HT_IS_DESTROYING:
      58             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
      59             :                         break;
      60             :                 case HT_DESTROYED:
      61             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
      62             :                         break;
      63             :                 case HT_CLEANING:
      64             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
      65             :                         break;
      66             :                 default:
      67             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is inconsistent", file, line, ht);
      68             :                         break;
      69             :         }
      70             :         zend_bailout();
      71             : }
      72             : #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
      73             : #define SET_INCONSISTENT(n) ht->inconsistent = n;
      74             : #else
      75             : #define IS_CONSISTENT(a)
      76             : #define SET_INCONSISTENT(n)
      77             : #endif
      78             : 
      79             : #define HASH_PROTECT_RECURSION(ht)                                                                                                              \
      80             :         if ((ht)->bApplyProtection) {                                                                                                                \
      81             :                 if ((ht)->nApplyCount++ >= 3) {                                                                                                   \
      82             :                         zend_error(E_ERROR, "Nesting level too deep - recursive dependency?");                \
      83             :                 }                                                                                                                                                               \
      84             :         }
      85             : 
      86             : 
      87             : #define HASH_UNPROTECT_RECURSION(ht)                                                                                                    \
      88             :         if ((ht)->bApplyProtection) {                                                                                                                \
      89             :                 (ht)->nApplyCount--;                                                                                                                 \
      90             :         }
      91             : 
      92             : 
      93             : #define ZEND_HASH_IF_FULL_DO_RESIZE(ht)                         \
      94             :         if ((ht)->nNumOfElements > (ht)->nTableSize) { \
      95             :                 zend_hash_do_resize(ht);                                        \
      96             :         }
      97             : 
      98             : static int zend_hash_do_resize(HashTable *ht);
      99             : 
     100      310916 : ZEND_API ulong zend_hash_func(const char *arKey, uint nKeyLength)
     101             : {
     102      310916 :         return zend_inline_hash_func(arKey, nKeyLength);
     103             : }
     104             : 
     105             : 
     106             : #define UPDATE_DATA(ht, p, pData, nDataSize)                                                                                    \
     107             :         if (nDataSize == sizeof(void*)) {                                                                                                       \
     108             :                 if ((p)->pData != &(p)->pDataPtr) {                                                                                           \
     109             :                         pefree_rel((p)->pData, (ht)->persistent);                                                                 \
     110             :                 }                                                                                                                                                               \
     111             :                 memcpy(&(p)->pDataPtr, pData, sizeof(void *));                                                                   \
     112             :                 (p)->pData = &(p)->pDataPtr;                                                                                                  \
     113             :         } else {                                                                                                                                                        \
     114             :                 if ((p)->pData == &(p)->pDataPtr) {                                                                                           \
     115             :                         (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent);                  \
     116             :                         (p)->pDataPtr=NULL;                                                                                                                  \
     117             :                 } else {                                                                                                                                                \
     118             :                         (p)->pData = (void *) perealloc_rel((p)->pData, nDataSize, (ht)->persistent);  \
     119             :                         /* (p)->pDataPtr is already NULL so no need to initialize it */                              \
     120             :                 }                                                                                                                                                               \
     121             :                 memcpy((p)->pData, pData, nDataSize);                                                                                        \
     122             :         }
     123             : 
     124             : #define INIT_DATA(ht, p, pData, nDataSize);                                                             \
     125             :         if (nDataSize == sizeof(void*)) {                                                                       \
     126             :                 memcpy(&(p)->pDataPtr, pData, sizeof(void *));                                   \
     127             :                 (p)->pData = &(p)->pDataPtr;                                                                  \
     128             :         } else {                                                                                                                        \
     129             :                 (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent);\
     130             :                 if (!(p)->pData) {                                                                                           \
     131             :                         pefree_rel(p, (ht)->persistent);                                                     \
     132             :                         return FAILURE;                                                                                         \
     133             :                 }                                                                                                                               \
     134             :                 memcpy((p)->pData, pData, nDataSize);                                                        \
     135             :                 (p)->pDataPtr=NULL;                                                                                          \
     136             :         }
     137             : 
     138             : 
     139             : 
     140    23468698 : ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
     141             : {
     142    23468698 :         uint i = 3;
     143             :         Bucket **tmp;
     144             : 
     145             :         SET_INCONSISTENT(HT_OK);
     146             : 
     147    23468698 :         if (nSize >= 0x80000000) {
     148             :                 /* prevent overflow */
     149           0 :                 ht->nTableSize = 0x80000000;
     150             :         } else {
     151    47789527 :                 while ((1U << i) < nSize) {
     152      852131 :                         i++;
     153             :                 }
     154    23468698 :                 ht->nTableSize = 1 << i;
     155             :         }
     156             : 
     157    23468698 :         ht->nTableMask = ht->nTableSize - 1;
     158    23468698 :         ht->pDestructor = pDestructor;
     159    23468698 :         ht->arBuckets = NULL;
     160    23468698 :         ht->pListHead = NULL;
     161    23468698 :         ht->pListTail = NULL;
     162    23468698 :         ht->nNumOfElements = 0;
     163    23468698 :         ht->nNextFreeElement = 0;
     164    23468698 :         ht->pInternalPointer = NULL;
     165    23468698 :         ht->persistent = persistent;
     166    23468698 :         ht->nApplyCount = 0;
     167    23468698 :         ht->bApplyProtection = 1;
     168             :         
     169             :         /* Uses ecalloc() so that Bucket* == NULL */
     170    23468698 :         if (persistent) {
     171    16402424 :                 tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *));
     172    16402424 :                 if (!tmp) {
     173           0 :                         return FAILURE;
     174             :                 }
     175    16402424 :                 ht->arBuckets = tmp;
     176             :         } else {
     177     7066274 :                 tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *));
     178     7066274 :                 if (tmp) {
     179     7066274 :                         ht->arBuckets = tmp;
     180             :                 }
     181             :         }
     182             :         
     183    23468698 :         return SUCCESS;
     184             : }
     185             : 
     186             : 
     187    15486902 : ZEND_API int _zend_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC)
     188             : {
     189    15486902 :         int retval = _zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent ZEND_FILE_LINE_CC);
     190             : 
     191    15486902 :         ht->bApplyProtection = bApplyProtection;
     192    15486902 :         return retval;
     193             : }
     194             : 
     195             : 
     196           0 : ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
     197             : {
     198           0 :         ht->bApplyProtection = bApplyProtection;
     199           0 : }
     200             : 
     201             : 
     202             : 
     203   153399813 : ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
     204             : {
     205             :         ulong h;
     206             :         uint nIndex;
     207             :         Bucket *p;
     208             : 
     209             :         IS_CONSISTENT(ht);
     210             : 
     211   153399813 :         if (nKeyLength <= 0) {
     212             : #if ZEND_DEBUG
     213             :                 ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
     214             : #endif
     215           0 :                 return FAILURE;
     216             :         }
     217             : 
     218   153399813 :         h = zend_inline_hash_func(arKey, nKeyLength);
     219   153399813 :         nIndex = h & ht->nTableMask;
     220             : 
     221   153399813 :         p = ht->arBuckets[nIndex];
     222   403711628 :         while (p != NULL) {
     223    97926755 :                 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
     224     1015201 :                         if (!memcmp(p->arKey, arKey, nKeyLength)) {
     225     1014753 :                                 if (flag & HASH_ADD) {
     226      253473 :                                         return FAILURE;
     227             :                                 }
     228      761280 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     229             : #if ZEND_DEBUG
     230             :                                 if (p->pData == pData) {
     231             :                                         ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
     232             :                                         HANDLE_UNBLOCK_INTERRUPTIONS();
     233             :                                         return FAILURE;
     234             :                                 }
     235             : #endif
     236      761280 :                                 if (ht->pDestructor) {
     237      722314 :                                         ht->pDestructor(p->pData);
     238             :                                 }
     239      761280 :                                 UPDATE_DATA(ht, p, pData, nDataSize);
     240      761280 :                                 if (pDest) {
     241      105194 :                                         *pDest = p->pData;
     242             :                                 }
     243      761280 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     244      761280 :                                 return SUCCESS;
     245             :                         }
     246             :                 }
     247    96912002 :                 p = p->pNext;
     248             :         }
     249             :         
     250   152385060 :         p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent);
     251   152385060 :         if (!p) {
     252           0 :                 return FAILURE;
     253             :         }
     254   152385060 :         memcpy(p->arKey, arKey, nKeyLength);
     255   152385060 :         p->nKeyLength = nKeyLength;
     256   152385060 :         INIT_DATA(ht, p, pData, nDataSize);
     257   152385060 :         p->h = h;
     258   152385060 :         CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
     259   152385060 :         if (pDest) {
     260    80533463 :                 *pDest = p->pData;
     261             :         }
     262             : 
     263   152385060 :         HANDLE_BLOCK_INTERRUPTIONS();
     264   152385060 :         CONNECT_TO_GLOBAL_DLLIST(p, ht);
     265   152385060 :         ht->arBuckets[nIndex] = p;
     266   152385060 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     267             : 
     268   152385060 :         ht->nNumOfElements++;
     269   152385060 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     270   152385060 :         return SUCCESS;
     271             : }
     272             : 
     273    35119784 : ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
     274             : {
     275             :         uint nIndex;
     276             :         Bucket *p;
     277             : 
     278             :         IS_CONSISTENT(ht);
     279             : 
     280    35119784 :         if (nKeyLength == 0) {
     281           0 :                 return zend_hash_index_update(ht, h, pData, nDataSize, pDest);
     282             :         }
     283             : 
     284    35119784 :         nIndex = h & ht->nTableMask;
     285             :         
     286    35119784 :         p = ht->arBuckets[nIndex];
     287    88997622 :         while (p != NULL) {
     288    18759198 :                 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
     289        1144 :                         if (!memcmp(p->arKey, arKey, nKeyLength)) {
     290        1144 :                                 if (flag & HASH_ADD) {
     291         643 :                                         return FAILURE;
     292             :                                 }
     293         501 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     294             : #if ZEND_DEBUG
     295             :                                 if (p->pData == pData) {
     296             :                                         ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
     297             :                                         HANDLE_UNBLOCK_INTERRUPTIONS();
     298             :                                         return FAILURE;
     299             :                                 }
     300             : #endif
     301         501 :                                 if (ht->pDestructor) {
     302         501 :                                         ht->pDestructor(p->pData);
     303             :                                 }
     304         501 :                                 UPDATE_DATA(ht, p, pData, nDataSize);
     305         501 :                                 if (pDest) {
     306         486 :                                         *pDest = p->pData;
     307             :                                 }
     308         501 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     309         501 :                                 return SUCCESS;
     310             :                         }
     311             :                 }
     312    18758054 :                 p = p->pNext;
     313             :         }
     314             :         
     315    35118640 :         p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent);
     316    35118640 :         if (!p) {
     317           0 :                 return FAILURE;
     318             :         }
     319             : 
     320    35118640 :         memcpy(p->arKey, arKey, nKeyLength);
     321    35118640 :         p->nKeyLength = nKeyLength;
     322    35118640 :         INIT_DATA(ht, p, pData, nDataSize);
     323    35118640 :         p->h = h;
     324             :         
     325    35118640 :         CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
     326             : 
     327    35118640 :         if (pDest) {
     328    35023978 :                 *pDest = p->pData;
     329             :         }
     330             : 
     331    35118640 :         HANDLE_BLOCK_INTERRUPTIONS();
     332    35118640 :         ht->arBuckets[nIndex] = p;
     333    35118640 :         CONNECT_TO_GLOBAL_DLLIST(p, ht);
     334    35118640 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     335             : 
     336    35118640 :         ht->nNumOfElements++;
     337    35118640 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     338    35118640 :         return SUCCESS;
     339             : }
     340             : 
     341             : 
     342       27751 : ZEND_API int zend_hash_add_empty_element(HashTable *ht, const char *arKey, uint nKeyLength)
     343             : {
     344       27751 :         void *dummy = (void *) 1;
     345             : 
     346       27751 :         return zend_hash_add(ht, arKey, nKeyLength, &dummy, sizeof(void *), NULL);
     347             : }
     348             : 
     349             : 
     350    11208673 : ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
     351             : {
     352             :         uint nIndex;
     353             :         Bucket *p;
     354             : 
     355             :         IS_CONSISTENT(ht);
     356             : 
     357    11208673 :         if (flag & HASH_NEXT_INSERT) {
     358     5275443 :                 h = ht->nNextFreeElement;
     359             :         }
     360    11208673 :         nIndex = h & ht->nTableMask;
     361             : 
     362    11208673 :         p = ht->arBuckets[nIndex];
     363    23254917 :         while (p != NULL) {
     364      841409 :                 if ((p->nKeyLength == 0) && (p->h == h)) {
     365        3838 :                         if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {
     366           3 :                                 return FAILURE;
     367             :                         }
     368        3835 :                         HANDLE_BLOCK_INTERRUPTIONS();
     369             : #if ZEND_DEBUG
     370             :                         if (p->pData == pData) {
     371             :                                 ZEND_PUTS("Fatal error in zend_hash_index_update: p->pData == pData\n");
     372             :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     373             :                                 return FAILURE;
     374             :                         }
     375             : #endif
     376        3835 :                         if (ht->pDestructor) {
     377        3835 :                                 ht->pDestructor(p->pData);
     378             :                         }
     379        3835 :                         UPDATE_DATA(ht, p, pData, nDataSize);
     380        3835 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     381        3835 :                         if ((long)h >= (long)ht->nNextFreeElement) {
     382           1 :                                 ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
     383             :                         }
     384        3835 :                         if (pDest) {
     385           3 :                                 *pDest = p->pData;
     386             :                         }
     387        3835 :                         return SUCCESS;
     388             :                 }
     389      837571 :                 p = p->pNext;
     390             :         }
     391    11204835 :         p = (Bucket *) pemalloc_rel(sizeof(Bucket) - 1, ht->persistent);
     392    11204835 :         if (!p) {
     393           0 :                 return FAILURE;
     394             :         }
     395    11204835 :         p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */
     396    11204835 :         p->h = h;
     397    11204835 :         INIT_DATA(ht, p, pData, nDataSize);
     398    11204835 :         if (pDest) {
     399     4897982 :                 *pDest = p->pData;
     400             :         }
     401             : 
     402    11204835 :         CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
     403             : 
     404    11204835 :         HANDLE_BLOCK_INTERRUPTIONS();
     405    11204835 :         ht->arBuckets[nIndex] = p;
     406    11204835 :         CONNECT_TO_GLOBAL_DLLIST(p, ht);
     407    11204835 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     408             : 
     409    11204835 :         if ((long)h >= (long)ht->nNextFreeElement) {
     410     9693326 :                 ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
     411             :         }
     412    11204835 :         ht->nNumOfElements++;
     413    11204835 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);
     414    11204835 :         return SUCCESS;
     415             : }
     416             : 
     417             : 
     418     5499065 : static int zend_hash_do_resize(HashTable *ht)
     419             : {
     420             :         Bucket **t;
     421             : 
     422             :         IS_CONSISTENT(ht);
     423             : 
     424     5499065 :         if ((ht->nTableSize << 1) > 0) {    /* Let's double the table size */
     425     5499065 :                 t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent);
     426     5499065 :                 if (t) {
     427     5499065 :                         HANDLE_BLOCK_INTERRUPTIONS();
     428     5499065 :                         ht->arBuckets = t;
     429     5499065 :                         ht->nTableSize = (ht->nTableSize << 1);
     430     5499065 :                         ht->nTableMask = ht->nTableSize - 1;
     431     5499065 :                         zend_hash_rehash(ht);
     432     5499065 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     433     5499065 :                         return SUCCESS;
     434             :                 }
     435           0 :                 return FAILURE;
     436             :         }
     437           0 :         return SUCCESS;
     438             : }
     439             : 
     440     5589548 : ZEND_API int zend_hash_rehash(HashTable *ht)
     441             : {
     442             :         Bucket *p;
     443             :         uint nIndex;
     444             : 
     445             :         IS_CONSISTENT(ht);
     446             : 
     447     5589548 :         memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
     448     5589548 :         p = ht->pListHead;
     449   259309893 :         while (p != NULL) {
     450   248130797 :                 nIndex = p->h & ht->nTableMask;
     451   248130797 :                 CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
     452   248130797 :                 ht->arBuckets[nIndex] = p;
     453   248130797 :                 p = p->pListNext;
     454             :         }
     455     5589548 :         return SUCCESS;
     456             : }
     457             : 
     458    46518056 : ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag)
     459             : {
     460             :         uint nIndex;
     461             :         Bucket *p;
     462             : 
     463             :         IS_CONSISTENT(ht);
     464             : 
     465    46518056 :         if (flag == HASH_DEL_KEY) {
     466    45576926 :                 h = zend_inline_hash_func(arKey, nKeyLength);
     467             :         }
     468    46518056 :         nIndex = h & ht->nTableMask;
     469             : 
     470    46518056 :         p = ht->arBuckets[nIndex];
     471    96506352 :         while (p != NULL) {
     472   187356113 :                 if ((p->h == h) 
     473    46198593 :                          && (p->nKeyLength == nKeyLength)
     474    46198593 :                          && ((p->nKeyLength == 0) /* Numeric index (short circuits the memcmp() check) */
     475    45290140 :                                  || !memcmp(p->arKey, arKey, nKeyLength))) { /* String index */
     476    46198547 :                         HANDLE_BLOCK_INTERRUPTIONS();
     477    46198547 :                         if (p == ht->arBuckets[nIndex]) {
     478    43000292 :                                 ht->arBuckets[nIndex] = p->pNext;
     479             :                         } else {
     480     3198255 :                                 p->pLast->pNext = p->pNext;
     481             :                         }
     482    46198547 :                         if (p->pNext) {
     483     8440075 :                                 p->pNext->pLast = p->pLast;
     484             :                         }
     485    46198547 :                         if (p->pListLast != NULL) {
     486    44807597 :                                 p->pListLast->pListNext = p->pListNext;
     487             :                         } else { 
     488             :                                 /* Deleting the head of the list */
     489     1390950 :                                 ht->pListHead = p->pListNext;
     490             :                         }
     491    46198547 :                         if (p->pListNext != NULL) {
     492    45441261 :                                 p->pListNext->pListLast = p->pListLast;
     493             :                         } else {
     494      757286 :                                 ht->pListTail = p->pListLast;
     495             :                         }
     496    46198547 :                         if (ht->pInternalPointer == p) {
     497     1390885 :                                 ht->pInternalPointer = p->pListNext;
     498             :                         }
     499    46198547 :                         if (ht->pDestructor) {
     500    45500532 :                                 ht->pDestructor(p->pData);
     501             :                         }
     502    46198546 :                         if (p->pData != &p->pDataPtr) {
     503    45184045 :                                 pefree(p->pData, ht->persistent);
     504             :                         }
     505    46198546 :                         pefree(p, ht->persistent);
     506    46198546 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     507    46198546 :                         ht->nNumOfElements--;
     508    46198546 :                         return SUCCESS;
     509             :                 }
     510     3470240 :                 p = p->pNext;
     511             :         }
     512      319509 :         return FAILURE;
     513             : }
     514             : 
     515             : 
     516    23421166 : ZEND_API void zend_hash_destroy(HashTable *ht)
     517             : {
     518             :         Bucket *p, *q;
     519             : 
     520             :         IS_CONSISTENT(ht);
     521             : 
     522             :         SET_INCONSISTENT(HT_IS_DESTROYING);
     523             : 
     524    23421166 :         p = ht->pListHead;
     525   191477802 :         while (p != NULL) {
     526   144635472 :                 q = p;
     527   144635472 :                 p = p->pListNext;
     528   144635472 :                 if (ht->pDestructor) {
     529   126697454 :                         ht->pDestructor(q->pData);
     530             :                 }
     531   144635470 :                 if (q->pData != &q->pDataPtr) {
     532   105711473 :                         pefree(q->pData, ht->persistent);
     533             :                 }
     534   144635470 :                 pefree(q, ht->persistent);
     535             :         }
     536    23421164 :         pefree(ht->arBuckets, ht->persistent);
     537             : 
     538             :         SET_INCONSISTENT(HT_DESTROYED);
     539    23421164 : }
     540             : 
     541             : 
     542      105213 : ZEND_API void zend_hash_clean(HashTable *ht)
     543             : {
     544             :         Bucket *p, *q;
     545             : 
     546             :         IS_CONSISTENT(ht);
     547             : 
     548      105213 :         p = ht->pListHead;
     549             : 
     550      105213 :         memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *));
     551      105213 :         ht->pListHead = NULL;
     552      105213 :         ht->pListTail = NULL;
     553      105213 :         ht->nNumOfElements = 0;
     554      105213 :         ht->nNextFreeElement = 0;
     555      105213 :         ht->pInternalPointer = NULL;
     556             : 
     557     1456646 :         while (p != NULL) {
     558     1246220 :                 q = p;
     559     1246220 :                 p = p->pListNext;
     560     1246220 :                 if (ht->pDestructor) {
     561     1225202 :                         ht->pDestructor(q->pData);
     562             :                 }
     563     1246220 :                 if (q->pData != &q->pDataPtr) {
     564           0 :                         pefree(q->pData, ht->persistent);
     565             :                 }
     566     1246220 :                 pefree(q, ht->persistent);
     567             :         }
     568      105213 : }
     569             : 
     570             : /* This function is used by the various apply() functions.
     571             :  * It deletes the passed bucket, and returns the address of the
     572             :  * next bucket.  The hash *may* be altered during that time, the
     573             :  * returned value will still be valid.
     574             :  */
     575     6961030 : static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p)
     576             : {
     577             :         Bucket *retval;
     578             : 
     579     6961030 :         HANDLE_BLOCK_INTERRUPTIONS();
     580     6961030 :         if (p->pLast) {
     581      255410 :                 p->pLast->pNext = p->pNext;
     582             :         } else {
     583             :                 uint nIndex;
     584             : 
     585     6705620 :                 nIndex = p->h & ht->nTableMask;
     586     6705620 :                 ht->arBuckets[nIndex] = p->pNext;
     587             :         }
     588     6961030 :         if (p->pNext) {
     589     1278204 :                 p->pNext->pLast = p->pLast;
     590             :         } else {
     591             :                 /* Nothing to do as this list doesn't have a tail */
     592             :         }
     593             : 
     594     6961030 :         if (p->pListLast != NULL) {
     595     5108352 :                 p->pListLast->pListNext = p->pListNext;
     596             :         } else { 
     597             :                 /* Deleting the head of the list */
     598     1852678 :                 ht->pListHead = p->pListNext;
     599             :         }
     600     6961030 :         if (p->pListNext != NULL) {
     601     4898142 :                 p->pListNext->pListLast = p->pListLast;
     602             :         } else {
     603     2062888 :                 ht->pListTail = p->pListLast;
     604             :         }
     605     6961030 :         if (ht->pInternalPointer == p) {
     606     1852673 :                 ht->pInternalPointer = p->pListNext;
     607             :         }
     608     6961030 :         ht->nNumOfElements--;
     609     6961030 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     610             : 
     611     6961030 :         if (ht->pDestructor) {
     612     1935233 :                 ht->pDestructor(p->pData);
     613             :         }
     614     6961030 :         if (p->pData != &p->pDataPtr) {
     615     6551696 :                 pefree(p->pData, ht->persistent);
     616             :         }
     617     6961030 :         retval = p->pListNext;
     618     6961030 :         pefree(p, ht->persistent);
     619             : 
     620     6961030 :         return retval;
     621             : }
     622             : 
     623             : 
     624           0 : ZEND_API void zend_hash_graceful_destroy(HashTable *ht)
     625             : {
     626             :         Bucket *p;
     627             : 
     628             :         IS_CONSISTENT(ht);
     629             : 
     630           0 :         p = ht->pListHead;
     631           0 :         while (p != NULL) {
     632           0 :                 p = zend_hash_apply_deleter(ht, p);
     633             :         }
     634           0 :         pefree(ht->arBuckets, ht->persistent);
     635             : 
     636             :         SET_INCONSISTENT(HT_DESTROYED);
     637           0 : }
     638             : 
     639       77598 : ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht)
     640             : {
     641             :         Bucket *p;
     642             : 
     643             :         IS_CONSISTENT(ht);
     644             : 
     645       77598 :         p = ht->pListTail;
     646     1985895 :         while (p != NULL) {
     647     1830699 :                 zend_hash_apply_deleter(ht, p);
     648     1830699 :                 p = ht->pListTail;
     649             :         }
     650             : 
     651       77598 :         pefree(ht->arBuckets, ht->persistent);
     652             : 
     653             :         SET_INCONSISTENT(HT_DESTROYED);
     654       77598 : }
     655             : 
     656             : /* This is used to recurse elements and selectively delete certain entries 
     657             :  * from a hashtable. apply_func() receives the data and decides if the entry 
     658             :  * should be deleted or recursion should be stopped. The following three 
     659             :  * return codes are possible:
     660             :  * ZEND_HASH_APPLY_KEEP   - continue
     661             :  * ZEND_HASH_APPLY_STOP   - stop iteration
     662             :  * ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former
     663             :  */
     664             : 
     665      435044 : ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
     666             : {
     667             :         Bucket *p;
     668             : 
     669             :         IS_CONSISTENT(ht);
     670             : 
     671      435044 :         HASH_PROTECT_RECURSION(ht);
     672      435044 :         p = ht->pListHead;
     673     9080757 :         while (p != NULL) {
     674     8210671 :                 int result = apply_func(p->pData TSRMLS_CC);
     675             :                 
     676     8210669 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
     677       24077 :                         p = zend_hash_apply_deleter(ht, p);
     678             :                 } else {
     679     8186592 :                         p = p->pListNext;
     680             :                 }
     681     8210669 :                 if (result & ZEND_HASH_APPLY_STOP) {
     682           0 :                         break;
     683             :                 }
     684             :         }
     685      435042 :         HASH_UNPROTECT_RECURSION(ht);
     686      435042 : }
     687             : 
     688             : 
     689      681279 : ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument TSRMLS_DC)
     690             : {
     691             :         Bucket *p;
     692             : 
     693             :         IS_CONSISTENT(ht);
     694             : 
     695      681279 :         HASH_PROTECT_RECURSION(ht);
     696      681279 :         p = ht->pListHead;
     697   109371471 :         while (p != NULL) {
     698   108013221 :                 int result = apply_func(p->pData, argument TSRMLS_CC);
     699             :                 
     700   108013211 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
     701     5005905 :                         p = zend_hash_apply_deleter(ht, p);
     702             :                 } else {
     703   103007306 :                         p = p->pListNext;
     704             :                 }
     705   108013211 :                 if (result & ZEND_HASH_APPLY_STOP) {
     706        4298 :                         break;
     707             :                 }
     708             :         }
     709      681269 :         HASH_UNPROTECT_RECURSION(ht);
     710      681269 : }
     711             : 
     712             : 
     713     1266657 : ZEND_API void zend_hash_apply_with_arguments(HashTable *ht TSRMLS_DC, apply_func_args_t apply_func, int num_args, ...)
     714             : {
     715             :         Bucket *p;
     716             :         va_list args;
     717             :         zend_hash_key hash_key;
     718             : 
     719             :         IS_CONSISTENT(ht);
     720             : 
     721     1266657 :         HASH_PROTECT_RECURSION(ht);
     722             : 
     723     1266655 :         p = ht->pListHead;
     724     2761202 :         while (p != NULL) {
     725             :                 int result;
     726      227900 :                 va_start(args, num_args);
     727      227900 :                 hash_key.arKey = p->arKey;
     728      227900 :                 hash_key.nKeyLength = p->nKeyLength;
     729      227900 :                 hash_key.h = p->h;
     730      227900 :                 result = apply_func(p->pData TSRMLS_CC, num_args, args, &hash_key);
     731             : 
     732      227892 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
     733           0 :                         p = zend_hash_apply_deleter(ht, p);
     734             :                 } else {
     735      227892 :                         p = p->pListNext;
     736             :                 }
     737      227892 :                 if (result & ZEND_HASH_APPLY_STOP) {
     738           0 :                         va_end(args);
     739           0 :                         break;
     740             :                 }
     741      227892 :                 va_end(args);
     742             :         }
     743             : 
     744     1266647 :         HASH_UNPROTECT_RECURSION(ht);
     745     1266647 : }
     746             : 
     747             : 
     748      140015 : ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
     749             : {
     750             :         Bucket *p, *q;
     751             : 
     752             :         IS_CONSISTENT(ht);
     753             : 
     754      140015 :         HASH_PROTECT_RECURSION(ht);
     755      140015 :         p = ht->pListTail;
     756     2319059 :         while (p != NULL) {
     757     2135839 :                 int result = apply_func(p->pData TSRMLS_CC);
     758             : 
     759     2135839 :                 q = p;
     760     2135839 :                 p = p->pListLast;
     761     2135839 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
     762      100349 :                         zend_hash_apply_deleter(ht, q);
     763             :                 }
     764     2135839 :                 if (result & ZEND_HASH_APPLY_STOP) {
     765       96810 :                         break;
     766             :                 }
     767             :         }
     768      140015 :         HASH_UNPROTECT_RECURSION(ht);
     769      140015 : }
     770             : 
     771             : 
     772     2373404 : ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size)
     773             : {
     774             :         Bucket *p;
     775             :         void *new_entry;
     776             :         zend_bool setTargetPointer;
     777             : 
     778             :         IS_CONSISTENT(source);
     779             :         IS_CONSISTENT(target);
     780             : 
     781     2373404 :         setTargetPointer = !target->pInternalPointer;
     782     2373404 :         p = source->pListHead;
     783     9645809 :         while (p) {
     784     4899001 :                 if (setTargetPointer && source->pInternalPointer == p) {
     785      874139 :                         target->pInternalPointer = NULL;
     786             :                 }
     787     4899001 :                 if (p->nKeyLength) {
     788     1854330 :                         zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &new_entry);
     789             :                 } else {
     790     3044671 :                         zend_hash_index_update(target, p->h, p->pData, size, &new_entry);
     791             :                 }
     792     4899001 :                 if (pCopyConstructor) {
     793     4887028 :                         pCopyConstructor(new_entry);
     794             :                 }
     795     4899001 :                 p = p->pListNext;
     796             :         }
     797     2373404 :         if (!target->pInternalPointer) {
     798     1499016 :                 target->pInternalPointer = target->pListHead;
     799             :         }
     800     2373404 : }
     801             : 
     802             : 
     803     2654075 : ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite ZEND_FILE_LINE_DC)
     804             : {
     805             :         Bucket *p;
     806             :         void *t;
     807     2654075 :         int mode = (overwrite?HASH_UPDATE:HASH_ADD);
     808             : 
     809             :         IS_CONSISTENT(source);
     810             :         IS_CONSISTENT(target);
     811             : 
     812     2654075 :         p = source->pListHead;
     813    12527277 :         while (p) {
     814     7219127 :                 if (p->nKeyLength>0) {
     815     7219111 :                         if (_zend_hash_quick_add_or_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t, mode ZEND_FILE_LINE_RELAY_CC)==SUCCESS && pCopyConstructor) {
     816     4394686 :                                 pCopyConstructor(t);
     817             :                         }
     818             :                 } else {
     819          16 :                         if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h)) && zend_hash_index_update(target, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
     820           6 :                                 pCopyConstructor(t);
     821             :                         }
     822             :                 }
     823     7219127 :                 p = p->pListNext;
     824             :         }
     825     2654075 :         target->pInternalPointer = target->pListHead;
     826     2654075 : }
     827             : 
     828             : 
     829    29616528 : static zend_bool zend_hash_replace_checker_wrapper(HashTable *target, void *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func)
     830             : {
     831             :         zend_hash_key hash_key;
     832             : 
     833    29616528 :         hash_key.arKey = p->arKey;
     834    29616528 :         hash_key.nKeyLength = p->nKeyLength;
     835    29616528 :         hash_key.h = p->h;
     836    29616528 :         return merge_checker_func(target, source_data, &hash_key, pParam);
     837             : }
     838             : 
     839             : 
     840     4801490 : ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, uint size, merge_checker_func_t pMergeSource, void *pParam)
     841             : {
     842             :         Bucket *p;
     843             :         void *t;
     844             : 
     845             :         IS_CONSISTENT(source);
     846             :         IS_CONSISTENT(target);
     847             : 
     848     4801490 :         p = source->pListHead;
     849    39219466 :         while (p) {
     850    29616528 :                 if (zend_hash_replace_checker_wrapper(target, p->pData, p, pParam, pMergeSource)) {
     851    23000068 :                         if (zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
     852    23000068 :                                 pCopyConstructor(t);
     853             :                         }
     854             :                 }
     855    29616486 :                 p = p->pListNext;
     856             :         }
     857     4801448 :         target->pInternalPointer = target->pListHead;
     858     4801448 : }
     859             : 
     860             : 
     861     2049220 : ZEND_API ulong zend_get_hash_value(const char *arKey, uint nKeyLength)
     862             : {
     863     2049220 :         return zend_inline_hash_func(arKey, nKeyLength);
     864             : }
     865             : 
     866             : 
     867             : /* Returns SUCCESS if found and FAILURE if not. The pointer to the
     868             :  * data is returned in pData. The reason is that there's no reason
     869             :  * someone using the hash table might not want to have NULL data
     870             :  */
     871    20496893 : ZEND_API int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData)
     872             : {
     873             :         ulong h;
     874             :         uint nIndex;
     875             :         Bucket *p;
     876             : 
     877             :         IS_CONSISTENT(ht);
     878             : 
     879    20496893 :         h = zend_inline_hash_func(arKey, nKeyLength);
     880    20496893 :         nIndex = h & ht->nTableMask;
     881             : 
     882    20496893 :         p = ht->arBuckets[nIndex];
     883    49998447 :         while (p != NULL) {
     884    21407605 :                 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
     885    12403708 :                         if (!memcmp(p->arKey, arKey, nKeyLength)) {
     886    12402944 :                                 *pData = p->pData;
     887    12402944 :                                 return SUCCESS;
     888             :                         }
     889             :                 }
     890     9004661 :                 p = p->pNext;
     891             :         }
     892     8093949 :         return FAILURE;
     893             : }
     894             : 
     895             : 
     896    50425571 : ZEND_API int zend_hash_quick_find(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void **pData)
     897             : {
     898             :         uint nIndex;
     899             :         Bucket *p;
     900             : 
     901    50425571 :         if (nKeyLength==0) {
     902           0 :                 return zend_hash_index_find(ht, h, pData);
     903             :         }
     904             : 
     905             :         IS_CONSISTENT(ht);
     906             : 
     907    50425571 :         nIndex = h & ht->nTableMask;
     908             : 
     909    50425571 :         p = ht->arBuckets[nIndex];
     910   120534269 :         while (p != NULL) {
     911    44383552 :                 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
     912    24700425 :                         if (!memcmp(p->arKey, arKey, nKeyLength)) {
     913    24700425 :                                 *pData = p->pData;
     914    24700425 :                                 return SUCCESS;
     915             :                         }
     916             :                 }
     917    19683127 :                 p = p->pNext;
     918             :         }
     919    25725146 :         return FAILURE;
     920             : }
     921             : 
     922             : 
     923     1051844 : ZEND_API int zend_hash_exists(const HashTable *ht, const char *arKey, uint nKeyLength)
     924             : {
     925             :         ulong h;
     926             :         uint nIndex;
     927             :         Bucket *p;
     928             : 
     929             :         IS_CONSISTENT(ht);
     930             : 
     931     1051844 :         h = zend_inline_hash_func(arKey, nKeyLength);
     932     1051844 :         nIndex = h & ht->nTableMask;
     933             : 
     934     1051844 :         p = ht->arBuckets[nIndex];
     935     2286528 :         while (p != NULL) {
     936      512242 :                 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
     937      329402 :                         if (!memcmp(p->arKey, arKey, nKeyLength)) {
     938      329402 :                                 return 1;
     939             :                         }
     940             :                 }
     941      182840 :                 p = p->pNext;
     942             :         }
     943      722442 :         return 0;
     944             : }
     945             : 
     946             : 
     947         994 : ZEND_API int zend_hash_quick_exists(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h)
     948             : {
     949             :         uint nIndex;
     950             :         Bucket *p;
     951             : 
     952         994 :         if (nKeyLength==0) {
     953           0 :                 return zend_hash_index_exists(ht, h);
     954             :         }
     955             : 
     956             :         IS_CONSISTENT(ht);
     957             : 
     958         994 :         nIndex = h & ht->nTableMask;
     959             : 
     960         994 :         p = ht->arBuckets[nIndex];
     961        2066 :         while (p != NULL) {
     962         497 :                 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
     963         419 :                         if (!memcmp(p->arKey, arKey, nKeyLength)) {
     964         419 :                                 return 1;
     965             :                         }
     966             :                 }
     967          78 :                 p = p->pNext;
     968             :         }
     969         575 :         return 0;
     970             : 
     971             : }
     972             : 
     973             : 
     974    20162363 : ZEND_API int zend_hash_index_find(const HashTable *ht, ulong h, void **pData)
     975             : {
     976             :         uint nIndex;
     977             :         Bucket *p;
     978             : 
     979             :         IS_CONSISTENT(ht);
     980             : 
     981    20162363 :         nIndex = h & ht->nTableMask;
     982             : 
     983    20162363 :         p = ht->arBuckets[nIndex];
     984    41988164 :         while (p != NULL) {
     985    18739652 :                 if ((p->h == h) && (p->nKeyLength == 0)) {
     986    17076214 :                         *pData = p->pData;
     987    17076214 :                         return SUCCESS;
     988             :                 }
     989     1663438 :                 p = p->pNext;
     990             :         }
     991     3086149 :         return FAILURE;
     992             : }
     993             : 
     994             : 
     995     1450959 : ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h)
     996             : {
     997             :         uint nIndex;
     998             :         Bucket *p;
     999             : 
    1000             :         IS_CONSISTENT(ht);
    1001             : 
    1002     1450959 :         nIndex = h & ht->nTableMask;
    1003             : 
    1004     1450959 :         p = ht->arBuckets[nIndex];
    1005     3462826 :         while (p != NULL) {
    1006      831904 :                 if ((p->h == h) && (p->nKeyLength == 0)) {
    1007      270996 :                         return 1;
    1008             :                 }
    1009      560908 :                 p = p->pNext;
    1010             :         }
    1011     1179963 :         return 0;
    1012             : }
    1013             : 
    1014             : 
    1015     5686520 : ZEND_API int zend_hash_num_elements(const HashTable *ht)
    1016             : {
    1017             :         IS_CONSISTENT(ht);
    1018             : 
    1019     5686520 :         return ht->nNumOfElements;
    1020             : }
    1021             : 
    1022             : 
    1023     2035122 : ZEND_API int zend_hash_get_pointer(const HashTable *ht, HashPointer *ptr)
    1024             : {
    1025     2035122 :         ptr->pos = ht->pInternalPointer;
    1026     2035122 :         if (ht->pInternalPointer) {
    1027     1972989 :                 ptr->h = ht->pInternalPointer->h;
    1028     1972989 :                 return 1;
    1029             :         } else {
    1030       62133 :                 ptr->h = 0;
    1031       62133 :                 return 0;
    1032             :         }
    1033             : }
    1034             : 
    1035     2029765 : ZEND_API int zend_hash_set_pointer(HashTable *ht, const HashPointer *ptr)
    1036             : {
    1037     2029765 :         if (ptr->pos == NULL) {
    1038       61765 :                 ht->pInternalPointer = NULL;
    1039     1968000 :         } else if (ht->pInternalPointer != ptr->pos) {
    1040             :                 Bucket *p;
    1041             : 
    1042             :                 IS_CONSISTENT(ht);
    1043          69 :                 p = ht->arBuckets[ptr->h & ht->nTableMask];
    1044         186 :                 while (p != NULL) {
    1045          58 :                         if (p == ptr->pos) {
    1046          10 :                                 ht->pInternalPointer = p;
    1047          10 :                                 return 1;
    1048             :                         }
    1049          48 :                         p = p->pNext;
    1050             :                 }
    1051          59 :                 return 0;
    1052             :         }
    1053     2029696 :         return 1;
    1054             : }
    1055             : 
    1056     3262083 : ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
    1057             : {
    1058             :         IS_CONSISTENT(ht);
    1059             : 
    1060     3262083 :         if (pos)
    1061      330341 :                 *pos = ht->pListHead;
    1062             :         else
    1063     2931742 :                 ht->pInternalPointer = ht->pListHead;
    1064     3262083 : }
    1065             : 
    1066             : 
    1067             : /* This function will be extremely optimized by remembering 
    1068             :  * the end of the list
    1069             :  */
    1070         273 : ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
    1071             : {
    1072             :         IS_CONSISTENT(ht);
    1073             : 
    1074         273 :         if (pos)
    1075         157 :                 *pos = ht->pListTail;
    1076             :         else
    1077         116 :                 ht->pInternalPointer = ht->pListTail;
    1078         273 : }
    1079             : 
    1080             : 
    1081    12015149 : ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
    1082             : {
    1083    12015149 :         HashPosition *current = pos ? pos : &ht->pInternalPointer;
    1084             : 
    1085             :         IS_CONSISTENT(ht);
    1086             : 
    1087    12015149 :         if (*current) {
    1088    12015124 :                 *current = (*current)->pListNext;
    1089    12015124 :                 return SUCCESS;
    1090             :         } else
    1091          25 :                 return FAILURE;
    1092             : }
    1093             : 
    1094         531 : ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
    1095             : {
    1096         531 :         HashPosition *current = pos ? pos : &ht->pInternalPointer;
    1097             : 
    1098             :         IS_CONSISTENT(ht);
    1099             : 
    1100         531 :         if (*current) {
    1101         529 :                 *current = (*current)->pListLast;
    1102         529 :                 return SUCCESS;
    1103             :         } else
    1104           2 :                 return FAILURE;
    1105             : }
    1106             : 
    1107             : 
    1108             : /* This function should be made binary safe  */
    1109     3614554 : ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, uint *str_length, ulong *num_index, zend_bool duplicate, HashPosition *pos)
    1110             : {
    1111             :         Bucket *p;
    1112             : 
    1113     3614554 :         p = pos ? (*pos) : ht->pInternalPointer;
    1114             : 
    1115             :         IS_CONSISTENT(ht);
    1116             : 
    1117     3614554 :         if (p) {
    1118     3538451 :                 if (p->nKeyLength) {
    1119     3299064 :                         if (duplicate) {
    1120     1435158 :                                 *str_index = estrndup(p->arKey, p->nKeyLength - 1);
    1121             :                         } else {
    1122     1863906 :                                 *str_index = p->arKey;
    1123             :                         }
    1124     3299064 :                         if (str_length) {
    1125     3287102 :                                 *str_length = p->nKeyLength;
    1126             :                         }
    1127     3299064 :                         return HASH_KEY_IS_STRING;
    1128             :                 } else {
    1129      239387 :                         *num_index = p->h;
    1130      239387 :                         return HASH_KEY_IS_LONG;
    1131             :                 }
    1132             :         }
    1133       76103 :         return HASH_KEY_NON_EXISTANT;
    1134             : }
    1135             : 
    1136             : 
    1137      121367 : ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
    1138             : {
    1139             :         Bucket *p;
    1140             : 
    1141      121367 :         p = pos ? (*pos) : ht->pInternalPointer;
    1142             : 
    1143             :         IS_CONSISTENT(ht);
    1144             : 
    1145      121367 :         if (p) {
    1146      106127 :                 if (p->nKeyLength) {
    1147       70601 :                         return HASH_KEY_IS_STRING;
    1148             :                 } else {
    1149       35526 :                         return HASH_KEY_IS_LONG;
    1150             :                 }
    1151             :         }
    1152       15240 :         return HASH_KEY_NON_EXISTANT;
    1153             : }
    1154             : 
    1155             : 
    1156    14441594 : ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos)
    1157             : {
    1158             :         Bucket *p;
    1159             : 
    1160    14441594 :         p = pos ? (*pos) : ht->pInternalPointer;
    1161             : 
    1162             :         IS_CONSISTENT(ht);
    1163             : 
    1164    14441594 :         if (p) {
    1165    12005039 :                 *pData = p->pData;
    1166    12005039 :                 return SUCCESS;
    1167             :         } else {
    1168     2436555 :                 return FAILURE;
    1169             :         }
    1170             : }
    1171             : 
    1172             : /* This function changes key of current element without changing elements'
    1173             :  * order. If element with target key already exists, it will be deleted first.
    1174             :  */
    1175          93 : ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const char *str_index, uint str_length, ulong num_index, int mode, HashPosition *pos)
    1176             : {
    1177             :         Bucket *p, *q;
    1178             : 
    1179          93 :         p = pos ? (*pos) : ht->pInternalPointer;
    1180             : 
    1181             :         IS_CONSISTENT(ht);
    1182             : 
    1183          93 :         if (p) {
    1184          93 :                 if (key_type == HASH_KEY_IS_LONG) {
    1185          54 :                         str_length = 0;
    1186          54 :                         if (!p->nKeyLength && p->h == num_index) {
    1187           0 :                                 return SUCCESS;
    1188             :                         }
    1189             : 
    1190          54 :                         q = ht->arBuckets[num_index & ht->nTableMask];
    1191         113 :                         while (q != NULL) {
    1192           9 :                                 if (!q->nKeyLength && q->h == num_index) {
    1193           4 :                                         break;
    1194             :                                 }
    1195           5 :                                 q = q->pNext;
    1196             :                         }
    1197          39 :                 } else if (key_type == HASH_KEY_IS_STRING) {
    1198             :                         ulong h;
    1199             : 
    1200          52 :                         if (p->nKeyLength == str_length &&
    1201          13 :                             memcmp(p->arKey, str_index, str_length) == 0) {
    1202           0 :                                 return SUCCESS;
    1203             :                         }
    1204             : 
    1205          39 :                         h = zend_inline_hash_func(str_index, str_length);
    1206          39 :                         q = ht->arBuckets[h & ht->nTableMask];
    1207             : 
    1208          85 :                         while (q != NULL) {
    1209          15 :                                 if (q->h == h && q->nKeyLength == str_length && 
    1210           4 :                                            memcmp(q->arKey, str_index, str_length) == 0) {
    1211           4 :                                         break;
    1212             :                                 }
    1213           7 :                                 q = q->pNext;
    1214             :                         }
    1215             :                 } else {
    1216           0 :                         return FAILURE;
    1217             :                 }
    1218             : 
    1219          93 :                 HANDLE_BLOCK_INTERRUPTIONS();
    1220             : 
    1221          93 :                 if (q) {
    1222           8 :                         if (mode != HASH_UPDATE_KEY_ANYWAY) {
    1223           8 :                                 Bucket *r = p->pListLast;
    1224           8 :                                 int found = HASH_UPDATE_KEY_IF_BEFORE;
    1225             :                                                 
    1226          16 :                                 while (r) {
    1227           6 :                                         if (r == q) {
    1228           6 :                                                 found = HASH_UPDATE_KEY_IF_AFTER;
    1229           6 :                                                 break;
    1230             :                                         }
    1231           0 :                                         r = r->pListLast;
    1232             :                                 }
    1233           8 :                                 if (mode & found) {
    1234             :                                         /* delete current bucket */
    1235           2 :                                         if (p == ht->arBuckets[p->h & ht->nTableMask]) {
    1236           2 :                                                 ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
    1237             :                                         } else {
    1238           0 :                                                 p->pLast->pNext = p->pNext;
    1239             :                                         }
    1240           2 :                                         if (p->pNext) {
    1241           0 :                                                 p->pNext->pLast = p->pLast;
    1242             :                                         }
    1243           2 :                                         if (p->pListLast != NULL) {
    1244           0 :                                                 p->pListLast->pListNext = p->pListNext;
    1245             :                                         } else { 
    1246             :                                                 /* Deleting the head of the list */
    1247           2 :                                                 ht->pListHead = p->pListNext;
    1248             :                                         }
    1249           2 :                                         if (p->pListNext != NULL) {
    1250           2 :                                                 p->pListNext->pListLast = p->pListLast;
    1251             :                                         } else {
    1252           0 :                                                 ht->pListTail = p->pListLast;
    1253             :                                         }
    1254           2 :                                         if (ht->pInternalPointer == p) {
    1255           2 :                                                 ht->pInternalPointer = p->pListNext;
    1256             :                                         }
    1257           2 :                                         if (ht->pDestructor) {
    1258           2 :                                                 ht->pDestructor(p->pData);
    1259             :                                         }
    1260           2 :                                         if (p->pData != &p->pDataPtr) {
    1261           0 :                                                 pefree(p->pData, ht->persistent);
    1262             :                                         }
    1263           2 :                                         pefree(p, ht->persistent);
    1264           2 :                                         ht->nNumOfElements--;
    1265           2 :                                         HANDLE_UNBLOCK_INTERRUPTIONS();
    1266           2 :                                         return FAILURE;
    1267             :                                 }
    1268             :                         }
    1269             :                         /* delete another bucket with the same key */
    1270           6 :                         if (q == ht->arBuckets[q->h & ht->nTableMask]) {
    1271           5 :                                 ht->arBuckets[q->h & ht->nTableMask] = q->pNext;
    1272             :                         } else {
    1273           1 :                                 q->pLast->pNext = q->pNext;
    1274             :                         }
    1275           6 :                         if (q->pNext) {
    1276           0 :                                 q->pNext->pLast = q->pLast;
    1277             :                         }
    1278           6 :                         if (q->pListLast != NULL) {
    1279           1 :                                 q->pListLast->pListNext = q->pListNext;
    1280             :                         } else { 
    1281             :                                 /* Deleting the head of the list */
    1282           5 :                                 ht->pListHead = q->pListNext;
    1283             :                         }
    1284           6 :                         if (q->pListNext != NULL) {
    1285           6 :                                 q->pListNext->pListLast = q->pListLast;
    1286             :                         } else {
    1287           0 :                                 ht->pListTail = q->pListLast;
    1288             :                         }
    1289           6 :                         if (ht->pInternalPointer == q) {
    1290           0 :                                 ht->pInternalPointer = q->pListNext;
    1291             :                         }
    1292           6 :                         if (ht->pDestructor) {
    1293           6 :                                 ht->pDestructor(q->pData);
    1294             :                         }
    1295           6 :                         if (q->pData != &q->pDataPtr) {
    1296           0 :                                 pefree(q->pData, ht->persistent);
    1297             :                         }
    1298           6 :                         pefree(q, ht->persistent);
    1299           6 :                         ht->nNumOfElements--;
    1300             :                 }
    1301             : 
    1302          91 :                 if (p->pNext) {
    1303           2 :                         p->pNext->pLast = p->pLast;
    1304             :                 }
    1305          91 :                 if (p->pLast) {
    1306           4 :                         p->pLast->pNext = p->pNext;
    1307             :                 } else {
    1308          87 :                         ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
    1309             :                 }
    1310             : 
    1311          91 :                 if (p->nKeyLength != str_length) {
    1312          78 :                         Bucket *q = (Bucket *) pemalloc(sizeof(Bucket) - 1 + str_length, ht->persistent);
    1313             : 
    1314          78 :                         q->nKeyLength = str_length;
    1315          78 :                         if (p->pData == &p->pDataPtr) {
    1316          78 :                                 q->pData = &q->pDataPtr;
    1317             :                         } else {
    1318           0 :                                 q->pData = p->pData;
    1319             :                         }
    1320          78 :                         q->pDataPtr = p->pDataPtr;
    1321          78 :                         q->pListNext = p->pListNext;
    1322          78 :                         q->pListLast = p->pListLast;
    1323          78 :                         if (q->pListNext) {
    1324          12 :                                 p->pListNext->pListLast = q;
    1325             :                         } else {
    1326          66 :                                 ht->pListTail = q;
    1327             :                         }
    1328          78 :                         if (q->pListLast) {
    1329           8 :                                 p->pListLast->pListNext = q;
    1330             :                         } else {
    1331          70 :                                 ht->pListHead = q;
    1332             :                         }
    1333          78 :                         if (ht->pInternalPointer == p) {
    1334          78 :                                 ht->pInternalPointer = q;
    1335             :                         }
    1336          78 :                         if (pos) {
    1337           0 :                                 *pos = q;
    1338             :                         }
    1339          78 :                         pefree(p, ht->persistent);
    1340          78 :                         p = q;
    1341             :                 }
    1342             : 
    1343          91 :                 if (key_type == HASH_KEY_IS_LONG) {
    1344          53 :                         p->h = num_index;
    1345             :                 } else {
    1346          38 :                         memcpy(p->arKey, str_index, str_length);
    1347          38 :                         p->h = zend_inline_hash_func(str_index, str_length);
    1348             :                 }
    1349             : 
    1350          91 :                 CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[p->h & ht->nTableMask]);
    1351          91 :                 ht->arBuckets[p->h & ht->nTableMask] = p;
    1352          91 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
    1353             : 
    1354          91 :                 return SUCCESS;
    1355             :         } else {
    1356           0 :                 return FAILURE;
    1357             :         }
    1358             : }
    1359             : 
    1360       20924 : ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
    1361             :                                                         compare_func_t compar, int renumber TSRMLS_DC)
    1362             : {
    1363             :         Bucket **arTmp;
    1364             :         Bucket *p;
    1365             :         int i, j;
    1366             : 
    1367             :         IS_CONSISTENT(ht);
    1368             : 
    1369       20924 :         if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */
    1370         276 :                 return SUCCESS;
    1371             :         }
    1372       20648 :         arTmp = (Bucket **) pemalloc(ht->nNumOfElements * sizeof(Bucket *), ht->persistent);
    1373       20648 :         if (!arTmp) {
    1374           0 :                 return FAILURE;
    1375             :         }
    1376       20648 :         p = ht->pListHead;
    1377       20648 :         i = 0;
    1378     1544974 :         while (p) {
    1379     1503678 :                 arTmp[i] = p;
    1380     1503678 :                 p = p->pListNext;
    1381     1503678 :                 i++;
    1382             :         }
    1383             : 
    1384       20648 :         (*sort_func)((void *) arTmp, i, sizeof(Bucket *), compar TSRMLS_CC);
    1385             : 
    1386       20647 :         HANDLE_BLOCK_INTERRUPTIONS();
    1387       20647 :         ht->pListHead = arTmp[0];
    1388       20647 :         ht->pListTail = NULL;
    1389       20647 :         ht->pInternalPointer = ht->pListHead;
    1390             : 
    1391       20647 :         arTmp[0]->pListLast = NULL;
    1392       20647 :         if (i > 1) {
    1393       20638 :                 arTmp[0]->pListNext = arTmp[1];
    1394     1483029 :                 for (j = 1; j < i-1; j++) {
    1395     1462391 :                         arTmp[j]->pListLast = arTmp[j-1];
    1396     1462391 :                         arTmp[j]->pListNext = arTmp[j+1];
    1397             :                 }
    1398       20638 :                 arTmp[j]->pListLast = arTmp[j-1];
    1399       20638 :                 arTmp[j]->pListNext = NULL;
    1400             :         } else {
    1401           9 :                 arTmp[0]->pListNext = NULL;
    1402             :         }
    1403       20647 :         ht->pListTail = arTmp[i-1];
    1404             : 
    1405       20647 :         pefree(arTmp, ht->persistent);
    1406       20647 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1407             : 
    1408       20647 :         if (renumber) {
    1409         280 :                 p = ht->pListHead;
    1410         280 :                 i=0;
    1411       14392 :                 while (p != NULL) {
    1412       13832 :                         p->nKeyLength = 0;
    1413       13832 :                         p->h = i++;
    1414       13832 :                         p = p->pListNext;
    1415             :                 }
    1416         280 :                 ht->nNextFreeElement = i;
    1417         280 :                 zend_hash_rehash(ht);
    1418             :         }
    1419       20647 :         return SUCCESS;
    1420             : }
    1421             : 
    1422             : 
    1423        1339 : ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC)
    1424             : {
    1425        1339 :         Bucket *p1, *p2 = NULL;
    1426             :         int result;
    1427             :         void *pData2;
    1428             : 
    1429             :         IS_CONSISTENT(ht1);
    1430             :         IS_CONSISTENT(ht2);
    1431             : 
    1432        1339 :         HASH_PROTECT_RECURSION(ht1); 
    1433        1339 :         HASH_PROTECT_RECURSION(ht2); 
    1434             : 
    1435        1339 :         result = ht1->nNumOfElements - ht2->nNumOfElements;
    1436        1339 :         if (result!=0) {
    1437         570 :                 HASH_UNPROTECT_RECURSION(ht1); 
    1438         570 :                 HASH_UNPROTECT_RECURSION(ht2); 
    1439         570 :                 return result;
    1440             :         }
    1441             : 
    1442         769 :         p1 = ht1->pListHead;
    1443         769 :         if (ordered) {
    1444          66 :                 p2 = ht2->pListHead;
    1445             :         }
    1446             : 
    1447        4979 :         while (p1) {
    1448        3779 :                 if (ordered && !p2) {
    1449           0 :                         HASH_UNPROTECT_RECURSION(ht1); 
    1450           0 :                         HASH_UNPROTECT_RECURSION(ht2); 
    1451           0 :                         return 1; /* That's not supposed to happen */
    1452             :                 }
    1453        3779 :                 if (ordered) {
    1454        1531 :                         if (p1->nKeyLength==0 && p2->nKeyLength==0) { /* numeric indices */
    1455         380 :                                 result = p1->h - p2->h;
    1456         380 :                                 if (result!=0) {
    1457           1 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1458           1 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1459           1 :                                         return result;
    1460             :                                 }
    1461             :                         } else { /* string indices */
    1462         772 :                                 result = p1->nKeyLength - p2->nKeyLength;
    1463         772 :                                 if (result!=0) {
    1464           0 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1465           0 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1466           0 :                                         return result;
    1467             :                                 }
    1468         772 :                                 result = memcmp(p1->arKey, p2->arKey, p1->nKeyLength);
    1469         772 :                                 if (result!=0) {
    1470           0 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1471           0 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1472           0 :                                         return result;
    1473             :                                 }
    1474             :                         }
    1475        1151 :                         pData2 = p2->pData;
    1476             :                 } else {
    1477        2627 :                         if (p1->nKeyLength==0) { /* numeric index */
    1478         222 :                                 if (zend_hash_index_find(ht2, p1->h, &pData2)==FAILURE) {
    1479           4 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1480           4 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1481           4 :                                         return 1;
    1482             :                                 }
    1483             :                         } else { /* string index */
    1484        2405 :                                 if (zend_hash_quick_find(ht2, p1->arKey, p1->nKeyLength, p1->h, &pData2)==FAILURE) {
    1485          22 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1486          22 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1487          22 :                                         return 1;
    1488             :                                 }
    1489             :                         }
    1490             :                 }
    1491        3752 :                 result = compar(p1->pData, pData2 TSRMLS_CC);
    1492        3752 :                 if (result!=0) {
    1493         311 :                         HASH_UNPROTECT_RECURSION(ht1); 
    1494         311 :                         HASH_UNPROTECT_RECURSION(ht2); 
    1495         311 :                         return result;
    1496             :                 }
    1497        3441 :                 p1 = p1->pListNext;
    1498        3441 :                 if (ordered) {
    1499        1147 :                         p2 = p2->pListNext;
    1500             :                 }
    1501             :         }
    1502             :         
    1503         431 :         HASH_UNPROTECT_RECURSION(ht1); 
    1504         431 :         HASH_UNPROTECT_RECURSION(ht2); 
    1505         431 :         return 0;
    1506             : }
    1507             : 
    1508             : 
    1509          82 : ZEND_API int zend_hash_minmax(const HashTable *ht, compare_func_t compar, int flag, void **pData TSRMLS_DC)
    1510             : {
    1511             :         Bucket *p, *res;
    1512             : 
    1513             :         IS_CONSISTENT(ht);
    1514             : 
    1515          82 :         if (ht->nNumOfElements == 0 ) {
    1516           4 :                 *pData=NULL;
    1517           4 :                 return FAILURE;
    1518             :         }
    1519             : 
    1520          78 :         res = p = ht->pListHead;
    1521         376 :         while ((p = p->pListNext)) {
    1522         220 :                 if (flag) {
    1523         168 :                         if (compar(&res, &p TSRMLS_CC) < 0) { /* max */
    1524          20 :                                 res = p;
    1525             :                         }
    1526             :                 } else {
    1527          52 :                         if (compar(&res, &p TSRMLS_CC) > 0) { /* min */
    1528           6 :                                 res = p;
    1529             :                         }
    1530             :                 }
    1531             :         }
    1532          78 :         *pData = res->pData;
    1533          78 :         return SUCCESS;
    1534             : }
    1535             : 
    1536      627450 : ZEND_API ulong zend_hash_next_free_element(const HashTable *ht)
    1537             : {
    1538             :         IS_CONSISTENT(ht);
    1539             : 
    1540      627450 :         return ht->nNextFreeElement;
    1541             : 
    1542             : }
    1543             : 
    1544             : 
    1545             : #if ZEND_DEBUG
    1546             : void zend_hash_display_pListTail(const HashTable *ht)
    1547             : {
    1548             :         Bucket *p;
    1549             : 
    1550             :         p = ht->pListTail;
    1551             :         while (p != NULL) {
    1552             :                 zend_output_debug_string(0, "pListTail has key %s\n", p->arKey);
    1553             :                 p = p->pListLast;
    1554             :         }
    1555             : }
    1556             : 
    1557             : void zend_hash_display(const HashTable *ht)
    1558             : {
    1559             :         Bucket *p;
    1560             :         uint i;
    1561             : 
    1562             :         for (i = 0; i < ht->nTableSize; i++) {
    1563             :                 p = ht->arBuckets[i];
    1564             :                 while (p != NULL) {
    1565             :                         zend_output_debug_string(0, "%s <==> 0x%lX\n", p->arKey, p->h);
    1566             :                         p = p->pNext;
    1567             :                 }
    1568             :         }
    1569             : 
    1570             :         p = ht->pListTail;
    1571             :         while (p != NULL) {
    1572             :                 zend_output_debug_string(0, "%s <==> 0x%lX\n", p->arKey, p->h);
    1573             :                 p = p->pListLast;
    1574             :         }
    1575             : }
    1576             : #endif
    1577             : 
    1578             : /*
    1579             :  * Local variables:
    1580             :  * tab-width: 4
    1581             :  * c-basic-offset: 4
    1582             :  * indent-tabs-mode: t
    1583             :  * End:
    1584             :  */

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:22 +0000 (6 days ago)

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