Back to index

php5  5.3.10
Defines | Functions
zend_hash.c File Reference
#include "zend.h"

Go to the source code of this file.

Defines

#define CONNECT_TO_BUCKET_DLLIST(element, list_head)
#define CONNECT_TO_GLOBAL_DLLIST(element, ht)
#define IS_CONSISTENT(a)
#define SET_INCONSISTENT(n)
#define HASH_PROTECT_RECURSION(ht)
#define HASH_UNPROTECT_RECURSION(ht)
#define ZEND_HASH_IF_FULL_DO_RESIZE(ht)
#define UPDATE_DATA(ht, p, pData, nDataSize)
#define INIT_DATA(ht, p, pData, nDataSize)

Functions

static int zend_hash_do_resize (HashTable *ht)
ZEND_API ulong zend_hash_func (const char *arKey, uint nKeyLength)
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)
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)
ZEND_API void zend_hash_set_apply_protection (HashTable *ht, zend_bool bApplyProtection)
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)
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)
ZEND_API int zend_hash_add_empty_element (HashTable *ht, const char *arKey, uint nKeyLength)
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)
ZEND_API int zend_hash_rehash (HashTable *ht)
ZEND_API int zend_hash_del_key_or_index (HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag)
ZEND_API void zend_hash_destroy (HashTable *ht)
ZEND_API void zend_hash_clean (HashTable *ht)
static Bucketzend_hash_apply_deleter (HashTable *ht, Bucket *p)
ZEND_API void zend_hash_graceful_destroy (HashTable *ht)
ZEND_API void zend_hash_graceful_reverse_destroy (HashTable *ht)
ZEND_API void zend_hash_apply (HashTable *ht, apply_func_t apply_func TSRMLS_DC)
ZEND_API void zend_hash_apply_with_argument (HashTable *ht, apply_func_arg_t apply_func, void *argument TSRMLS_DC)
ZEND_API void zend_hash_apply_with_arguments (HashTable *ht TSRMLS_DC, apply_func_args_t apply_func, int num_args,...)
ZEND_API void zend_hash_reverse_apply (HashTable *ht, apply_func_t apply_func TSRMLS_DC)
ZEND_API void zend_hash_copy (HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size)
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)
static zend_bool zend_hash_replace_checker_wrapper (HashTable *target, void *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func)
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)
ZEND_API ulong zend_get_hash_value (const char *arKey, uint nKeyLength)
ZEND_API int zend_hash_find (const HashTable *ht, const char *arKey, uint nKeyLength, void **pData)
ZEND_API int zend_hash_quick_find (const HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void **pData)
ZEND_API int zend_hash_exists (const HashTable *ht, const char *arKey, uint nKeyLength)
ZEND_API int zend_hash_quick_exists (const HashTable *ht, const char *arKey, uint nKeyLength, ulong h)
ZEND_API int zend_hash_index_find (const HashTable *ht, ulong h, void **pData)
ZEND_API int zend_hash_index_exists (const HashTable *ht, ulong h)
ZEND_API int zend_hash_num_elements (const HashTable *ht)
ZEND_API int zend_hash_get_pointer (const HashTable *ht, HashPointer *ptr)
ZEND_API int zend_hash_set_pointer (HashTable *ht, const HashPointer *ptr)
ZEND_API void zend_hash_internal_pointer_reset_ex (HashTable *ht, HashPosition *pos)
ZEND_API void zend_hash_internal_pointer_end_ex (HashTable *ht, HashPosition *pos)
ZEND_API int zend_hash_move_forward_ex (HashTable *ht, HashPosition *pos)
ZEND_API int zend_hash_move_backwards_ex (HashTable *ht, HashPosition *pos)
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)
ZEND_API int zend_hash_get_current_key_type_ex (HashTable *ht, HashPosition *pos)
ZEND_API int zend_hash_get_current_data_ex (HashTable *ht, void **pData, HashPosition *pos)
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)
ZEND_API int zend_hash_sort (HashTable *ht, sort_func_t sort_func, compare_func_t compar, int renumber TSRMLS_DC)
ZEND_API int zend_hash_compare (HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC)
ZEND_API int zend_hash_minmax (const HashTable *ht, compare_func_t compar, int flag, void **pData TSRMLS_DC)
ZEND_API ulong zend_hash_next_free_element (const HashTable *ht)

Define Documentation

#define CONNECT_TO_BUCKET_DLLIST (   element,
  list_head 
)
Value:
(element)->pNext = (list_head);                                              \
       (element)->pLast = NULL;                                                     \
       if ((element)->pNext) {                                                             \
              (element)->pNext->pLast = (element);                           \
       }

Definition at line 24 of file zend_hash.c.

#define CONNECT_TO_GLOBAL_DLLIST (   element,
  ht 
)
Value:
(element)->pListLast = (ht)->pListTail;                               \
       (ht)->pListTail = (element);                                                 \
       (element)->pListNext = NULL;                                                 \
       if ((element)->pListLast != NULL) {                                          \
              (element)->pListLast->pListNext = (element);            \
       }                                                                                                 \
       if (!(ht)->pListHead) {                                                             \
              (ht)->pListHead = (element);                                          \
       }                                                                                                 \
       if ((ht)->pInternalPointer == NULL) {                                 \
              (ht)->pInternalPointer = (element);                                   \
       }

Definition at line 31 of file zend_hash.c.

#define HASH_PROTECT_RECURSION (   ht)
Value:
if ((ht)->bApplyProtection) {                                                                                                 \
              if ((ht)->nApplyCount++ >= 3) {                                                                                        \
                     zend_error(E_ERROR, "Nesting level too deep - recursive dependency?");              \
              }                                                                                                                                           \
       }

Definition at line 79 of file zend_hash.c.

#define HASH_UNPROTECT_RECURSION (   ht)
Value:
if ((ht)->bApplyProtection) {                                                                                                 \
              (ht)->nApplyCount--;                                                                                                   \
       }

Definition at line 87 of file zend_hash.c.

#define INIT_DATA (   ht,
  p,
  pData,
  nDataSize 
)
Value:
;                                                       \
       if (nDataSize == sizeof(void*)) {                                                          \
              memcpy(&(p)->pDataPtr, pData, sizeof(void *));                               \
              (p)->pData = &(p)->pDataPtr;                                                               \
       } else {                                                                                                        \
              (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent);\
              if (!(p)->pData) {                                                                                \
                     pefree_rel(p, (ht)->persistent);                                             \
                     return FAILURE;                                                                                   \
              }                                                                                                               \
              memcpy((p)->pData, pData, nDataSize);                                               \
              (p)->pDataPtr=NULL;                                                                               \
       }

Definition at line 124 of file zend_hash.c.

#define IS_CONSISTENT (   a)

Definition at line 75 of file zend_hash.c.

#define SET_INCONSISTENT (   n)

Definition at line 76 of file zend_hash.c.

#define UPDATE_DATA (   ht,
  p,
  pData,
  nDataSize 
)
Value:
if (nDataSize == sizeof(void*)) {                                                                                      \
              if ((p)->pData != &(p)->pDataPtr) {                                                                                    \
                     pefree_rel((p)->pData, (ht)->persistent);                                                         \
              }                                                                                                                                           \
              memcpy(&(p)->pDataPtr, pData, sizeof(void *));                                                           \
              (p)->pData = &(p)->pDataPtr;                                                                                           \
       } else {                                                                                                                                    \
              if ((p)->pData == &(p)->pDataPtr) {                                                                                    \
                     (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent);                    \
                     (p)->pDataPtr=NULL;                                                                                                    \
              } else {                                                                                                                             \
                     (p)->pData = (void *) perealloc_rel((p)->pData, nDataSize, (ht)->persistent);       \
                     /* (p)->pDataPtr is already NULL so no need to initialize it */                            \
              }                                                                                                                                           \
              memcpy((p)->pData, pData, nDataSize);                                                                           \
       }

Definition at line 106 of file zend_hash.c.

#define ZEND_HASH_IF_FULL_DO_RESIZE (   ht)
Value:
if ((ht)->nNumOfElements > (ht)->nTableSize) {   \
              zend_hash_do_resize(ht);                                \
       }

Definition at line 93 of file zend_hash.c.


Function Documentation

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 
)

Definition at line 203 of file zend_hash.c.

{
       ulong h;
       uint nIndex;
       Bucket *p;

       IS_CONSISTENT(ht);

       if (nKeyLength <= 0) {
#if ZEND_DEBUG
              ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
#endif
              return FAILURE;
       }

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

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
                     if (!memcmp(p->arKey, arKey, nKeyLength)) {
                            if (flag & HASH_ADD) {
                                   return FAILURE;
                            }
                            HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
                            if (p->pData == pData) {
                                   ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
                                   HANDLE_UNBLOCK_INTERRUPTIONS();
                                   return FAILURE;
                            }
#endif
                            if (ht->pDestructor) {
                                   ht->pDestructor(p->pData);
                            }
                            UPDATE_DATA(ht, p, pData, nDataSize);
                            if (pDest) {
                                   *pDest = p->pData;
                            }
                            HANDLE_UNBLOCK_INTERRUPTIONS();
                            return SUCCESS;
                     }
              }
              p = p->pNext;
       }
       
       p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent);
       if (!p) {
              return FAILURE;
       }
       memcpy(p->arKey, arKey, nKeyLength);
       p->nKeyLength = nKeyLength;
       INIT_DATA(ht, p, pData, nDataSize);
       p->h = h;
       CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
       if (pDest) {
              *pDest = p->pData;
       }

       HANDLE_BLOCK_INTERRUPTIONS();
       CONNECT_TO_GLOBAL_DLLIST(p, ht);
       ht->arBuckets[nIndex] = p;
       HANDLE_UNBLOCK_INTERRUPTIONS();

       ht->nNumOfElements++;
       ZEND_HASH_IF_FULL_DO_RESIZE(ht);          /* If the Hash table is full, resize it */
       return SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 
)

Definition at line 350 of file zend_hash.c.

{
       uint nIndex;
       Bucket *p;

       IS_CONSISTENT(ht);

       if (flag & HASH_NEXT_INSERT) {
              h = ht->nNextFreeElement;
       }
       nIndex = h & ht->nTableMask;

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->nKeyLength == 0) && (p->h == h)) {
                     if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {
                            return FAILURE;
                     }
                     HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
                     if (p->pData == pData) {
                            ZEND_PUTS("Fatal error in zend_hash_index_update: p->pData == pData\n");
                            HANDLE_UNBLOCK_INTERRUPTIONS();
                            return FAILURE;
                     }
#endif
                     if (ht->pDestructor) {
                            ht->pDestructor(p->pData);
                     }
                     UPDATE_DATA(ht, p, pData, nDataSize);
                     HANDLE_UNBLOCK_INTERRUPTIONS();
                     if ((long)h >= (long)ht->nNextFreeElement) {
                            ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
                     }
                     if (pDest) {
                            *pDest = p->pData;
                     }
                     return SUCCESS;
              }
              p = p->pNext;
       }
       p = (Bucket *) pemalloc_rel(sizeof(Bucket) - 1, ht->persistent);
       if (!p) {
              return FAILURE;
       }
       p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */
       p->h = h;
       INIT_DATA(ht, p, pData, nDataSize);
       if (pDest) {
              *pDest = p->pData;
       }

       CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);

       HANDLE_BLOCK_INTERRUPTIONS();
       ht->arBuckets[nIndex] = p;
       CONNECT_TO_GLOBAL_DLLIST(p, ht);
       HANDLE_UNBLOCK_INTERRUPTIONS();

       if ((long)h >= (long)ht->nNextFreeElement) {
              ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
       }
       ht->nNumOfElements++;
       ZEND_HASH_IF_FULL_DO_RESIZE(ht);
       return SUCCESS;
}

Here is the caller graph for this function:

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 
)

Definition at line 140 of file zend_hash.c.

{
       uint i = 3;
       Bucket **tmp;

       SET_INCONSISTENT(HT_OK);

       if (nSize >= 0x80000000) {
              /* prevent overflow */
              ht->nTableSize = 0x80000000;
       } else {
              while ((1U << i) < nSize) {
                     i++;
              }
              ht->nTableSize = 1 << i;
       }

       ht->nTableMask = ht->nTableSize - 1;
       ht->pDestructor = pDestructor;
       ht->arBuckets = NULL;
       ht->pListHead = NULL;
       ht->pListTail = NULL;
       ht->nNumOfElements = 0;
       ht->nNextFreeElement = 0;
       ht->pInternalPointer = NULL;
       ht->persistent = persistent;
       ht->nApplyCount = 0;
       ht->bApplyProtection = 1;
       
       /* Uses ecalloc() so that Bucket* == NULL */
       if (persistent) {
              tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *));
              if (!tmp) {
                     return FAILURE;
              }
              ht->arBuckets = tmp;
       } else {
              tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *));
              if (tmp) {
                     ht->arBuckets = tmp;
              }
       }
       
       return SUCCESS;
}

Here is the caller graph for this function:

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 
)

Definition at line 187 of file zend_hash.c.

{
       int retval = _zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent ZEND_FILE_LINE_CC);

       ht->bApplyProtection = bApplyProtection;
       return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 
)

Definition at line 803 of file zend_hash.c.

{
       Bucket *p;
       void *t;
       int mode = (overwrite?HASH_UPDATE:HASH_ADD);

       IS_CONSISTENT(source);
       IS_CONSISTENT(target);

       p = source->pListHead;
       while (p) {
              if (p->nKeyLength>0) {
                     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) {
                            pCopyConstructor(t);
                     }
              } else {
                     if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h)) && zend_hash_index_update(target, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
                            pCopyConstructor(t);
                     }
              }
              p = p->pListNext;
       }
       target->pInternalPointer = target->pListHead;
}

Here is the call graph for this function:

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 
)

Definition at line 273 of file zend_hash.c.

{
       uint nIndex;
       Bucket *p;

       IS_CONSISTENT(ht);

       if (nKeyLength == 0) {
              return zend_hash_index_update(ht, h, pData, nDataSize, pDest);
       }

       nIndex = h & ht->nTableMask;
       
       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
                     if (!memcmp(p->arKey, arKey, nKeyLength)) {
                            if (flag & HASH_ADD) {
                                   return FAILURE;
                            }
                            HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
                            if (p->pData == pData) {
                                   ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
                                   HANDLE_UNBLOCK_INTERRUPTIONS();
                                   return FAILURE;
                            }
#endif
                            if (ht->pDestructor) {
                                   ht->pDestructor(p->pData);
                            }
                            UPDATE_DATA(ht, p, pData, nDataSize);
                            if (pDest) {
                                   *pDest = p->pData;
                            }
                            HANDLE_UNBLOCK_INTERRUPTIONS();
                            return SUCCESS;
                     }
              }
              p = p->pNext;
       }
       
       p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent);
       if (!p) {
              return FAILURE;
       }

       memcpy(p->arKey, arKey, nKeyLength);
       p->nKeyLength = nKeyLength;
       INIT_DATA(ht, p, pData, nDataSize);
       p->h = h;
       
       CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);

       if (pDest) {
              *pDest = p->pData;
       }

       HANDLE_BLOCK_INTERRUPTIONS();
       ht->arBuckets[nIndex] = p;
       CONNECT_TO_GLOBAL_DLLIST(p, ht);
       HANDLE_UNBLOCK_INTERRUPTIONS();

       ht->nNumOfElements++;
       ZEND_HASH_IF_FULL_DO_RESIZE(ht);          /* If the Hash table is full, resize it */
       return SUCCESS;
}

Here is the caller graph for this function:

ZEND_API ulong zend_get_hash_value ( const char *  arKey,
uint  nKeyLength 
)

Definition at line 861 of file zend_hash.c.

{
       return zend_inline_hash_func(arKey, nKeyLength);
}

Here is the call graph for this function:

Here is the caller graph for this function:

ZEND_API int zend_hash_add_empty_element ( HashTable ht,
const char *  arKey,
uint  nKeyLength 
)

Definition at line 342 of file zend_hash.c.

{
       void *dummy = (void *) 1;

       return zend_hash_add(ht, arKey, nKeyLength, &dummy, sizeof(void *), NULL);
}

Here is the caller graph for this function:

ZEND_API void zend_hash_apply ( HashTable ht,
apply_func_t apply_func  TSRMLS_DC 
)

Definition at line 665 of file zend_hash.c.

{
       Bucket *p;

       IS_CONSISTENT(ht);

       HASH_PROTECT_RECURSION(ht);
       p = ht->pListHead;
       while (p != NULL) {
              int result = apply_func(p->pData TSRMLS_CC);
              
              if (result & ZEND_HASH_APPLY_REMOVE) {
                     p = zend_hash_apply_deleter(ht, p);
              } else {
                     p = p->pListNext;
              }
              if (result & ZEND_HASH_APPLY_STOP) {
                     break;
              }
       }
       HASH_UNPROTECT_RECURSION(ht);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static Bucket* zend_hash_apply_deleter ( HashTable ht,
Bucket p 
) [static]

Definition at line 575 of file zend_hash.c.

{
       Bucket *retval;

       HANDLE_BLOCK_INTERRUPTIONS();
       if (p->pLast) {
              p->pLast->pNext = p->pNext;
       } else {
              uint nIndex;

              nIndex = p->h & ht->nTableMask;
              ht->arBuckets[nIndex] = p->pNext;
       }
       if (p->pNext) {
              p->pNext->pLast = p->pLast;
       } else {
              /* Nothing to do as this list doesn't have a tail */
       }

       if (p->pListLast != NULL) {
              p->pListLast->pListNext = p->pListNext;
       } else { 
              /* Deleting the head of the list */
              ht->pListHead = p->pListNext;
       }
       if (p->pListNext != NULL) {
              p->pListNext->pListLast = p->pListLast;
       } else {
              ht->pListTail = p->pListLast;
       }
       if (ht->pInternalPointer == p) {
              ht->pInternalPointer = p->pListNext;
       }
       ht->nNumOfElements--;
       HANDLE_UNBLOCK_INTERRUPTIONS();

       if (ht->pDestructor) {
              ht->pDestructor(p->pData);
       }
       if (p->pData != &p->pDataPtr) {
              pefree(p->pData, ht->persistent);
       }
       retval = p->pListNext;
       pefree(p, ht->persistent);

       return retval;
}

Here is the caller graph for this function:

ZEND_API void zend_hash_apply_with_argument ( HashTable ht,
apply_func_arg_t  apply_func,
void *argument  TSRMLS_DC 
)

Definition at line 689 of file zend_hash.c.

{
       Bucket *p;

       IS_CONSISTENT(ht);

       HASH_PROTECT_RECURSION(ht);
       p = ht->pListHead;
       while (p != NULL) {
              int result = apply_func(p->pData, argument TSRMLS_CC);
              
              if (result & ZEND_HASH_APPLY_REMOVE) {
                     p = zend_hash_apply_deleter(ht, p);
              } else {
                     p = p->pListNext;
              }
              if (result & ZEND_HASH_APPLY_STOP) {
                     break;
              }
       }
       HASH_UNPROTECT_RECURSION(ht);
}

Here is the call graph for this function:

Here is the caller graph for this function:

ZEND_API void zend_hash_apply_with_arguments ( HashTable *ht  TSRMLS_DC,
apply_func_args_t  apply_func,
int  num_args,
  ... 
)

Definition at line 713 of file zend_hash.c.

{
       Bucket *p;
       va_list args;
       zend_hash_key hash_key;

       IS_CONSISTENT(ht);

       HASH_PROTECT_RECURSION(ht);

       p = ht->pListHead;
       while (p != NULL) {
              int result;
              va_start(args, num_args);
              hash_key.arKey = p->arKey;
              hash_key.nKeyLength = p->nKeyLength;
              hash_key.h = p->h;
              result = apply_func(p->pData TSRMLS_CC, num_args, args, &hash_key);

              if (result & ZEND_HASH_APPLY_REMOVE) {
                     p = zend_hash_apply_deleter(ht, p);
              } else {
                     p = p->pListNext;
              }
              if (result & ZEND_HASH_APPLY_STOP) {
                     va_end(args);
                     break;
              }
              va_end(args);
       }

       HASH_UNPROTECT_RECURSION(ht);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 542 of file zend_hash.c.

{
       Bucket *p, *q;

       IS_CONSISTENT(ht);

       p = ht->pListHead;

       memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *));
       ht->pListHead = NULL;
       ht->pListTail = NULL;
       ht->nNumOfElements = 0;
       ht->nNextFreeElement = 0;
       ht->pInternalPointer = NULL;

       while (p != NULL) {
              q = p;
              p = p->pListNext;
              if (ht->pDestructor) {
                     ht->pDestructor(q->pData);
              }
              if (q->pData != &q->pDataPtr) {
                     pefree(q->pData, ht->persistent);
              }
              pefree(q, ht->persistent);
       }
}

Here is the caller graph for this function:

ZEND_API int zend_hash_compare ( HashTable ht1,
HashTable ht2,
compare_func_t  compar,
zend_bool ordered  TSRMLS_DC 
)

Definition at line 1423 of file zend_hash.c.

{
       Bucket *p1, *p2 = NULL;
       int result;
       void *pData2;

       IS_CONSISTENT(ht1);
       IS_CONSISTENT(ht2);

       HASH_PROTECT_RECURSION(ht1); 
       HASH_PROTECT_RECURSION(ht2); 

       result = ht1->nNumOfElements - ht2->nNumOfElements;
       if (result!=0) {
              HASH_UNPROTECT_RECURSION(ht1); 
              HASH_UNPROTECT_RECURSION(ht2); 
              return result;
       }

       p1 = ht1->pListHead;
       if (ordered) {
              p2 = ht2->pListHead;
       }

       while (p1) {
              if (ordered && !p2) {
                     HASH_UNPROTECT_RECURSION(ht1); 
                     HASH_UNPROTECT_RECURSION(ht2); 
                     return 1; /* That's not supposed to happen */
              }
              if (ordered) {
                     if (p1->nKeyLength==0 && p2->nKeyLength==0) { /* numeric indices */
                            result = p1->h - p2->h;
                            if (result!=0) {
                                   HASH_UNPROTECT_RECURSION(ht1); 
                                   HASH_UNPROTECT_RECURSION(ht2); 
                                   return result;
                            }
                     } else { /* string indices */
                            result = p1->nKeyLength - p2->nKeyLength;
                            if (result!=0) {
                                   HASH_UNPROTECT_RECURSION(ht1); 
                                   HASH_UNPROTECT_RECURSION(ht2); 
                                   return result;
                            }
                            result = memcmp(p1->arKey, p2->arKey, p1->nKeyLength);
                            if (result!=0) {
                                   HASH_UNPROTECT_RECURSION(ht1); 
                                   HASH_UNPROTECT_RECURSION(ht2); 
                                   return result;
                            }
                     }
                     pData2 = p2->pData;
              } else {
                     if (p1->nKeyLength==0) { /* numeric index */
                            if (zend_hash_index_find(ht2, p1->h, &pData2)==FAILURE) {
                                   HASH_UNPROTECT_RECURSION(ht1); 
                                   HASH_UNPROTECT_RECURSION(ht2); 
                                   return 1;
                            }
                     } else { /* string index */
                            if (zend_hash_quick_find(ht2, p1->arKey, p1->nKeyLength, p1->h, &pData2)==FAILURE) {
                                   HASH_UNPROTECT_RECURSION(ht1); 
                                   HASH_UNPROTECT_RECURSION(ht2); 
                                   return 1;
                            }
                     }
              }
              result = compar(p1->pData, pData2 TSRMLS_CC);
              if (result!=0) {
                     HASH_UNPROTECT_RECURSION(ht1); 
                     HASH_UNPROTECT_RECURSION(ht2); 
                     return result;
              }
              p1 = p1->pListNext;
              if (ordered) {
                     p2 = p2->pListNext;
              }
       }
       
       HASH_UNPROTECT_RECURSION(ht1); 
       HASH_UNPROTECT_RECURSION(ht2); 
       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

ZEND_API void zend_hash_copy ( HashTable target,
HashTable source,
copy_ctor_func_t  pCopyConstructor,
void *  tmp,
uint  size 
)

Definition at line 772 of file zend_hash.c.

{
       Bucket *p;
       void *new_entry;
       zend_bool setTargetPointer;

       IS_CONSISTENT(source);
       IS_CONSISTENT(target);

       setTargetPointer = !target->pInternalPointer;
       p = source->pListHead;
       while (p) {
              if (setTargetPointer && source->pInternalPointer == p) {
                     target->pInternalPointer = NULL;
              }
              if (p->nKeyLength) {
                     zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &new_entry);
              } else {
                     zend_hash_index_update(target, p->h, p->pData, size, &new_entry);
              }
              if (pCopyConstructor) {
                     pCopyConstructor(new_entry);
              }
              p = p->pListNext;
       }
       if (!target->pInternalPointer) {
              target->pInternalPointer = target->pListHead;
       }
}
ZEND_API int zend_hash_del_key_or_index ( HashTable ht,
const char *  arKey,
uint  nKeyLength,
ulong  h,
int  flag 
)

Definition at line 458 of file zend_hash.c.

{
       uint nIndex;
       Bucket *p;

       IS_CONSISTENT(ht);

       if (flag == HASH_DEL_KEY) {
              h = zend_inline_hash_func(arKey, nKeyLength);
       }
       nIndex = h & ht->nTableMask;

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) 
                      && (p->nKeyLength == nKeyLength)
                      && ((p->nKeyLength == 0) /* Numeric index (short circuits the memcmp() check) */
                             || !memcmp(p->arKey, arKey, nKeyLength))) { /* String index */
                     HANDLE_BLOCK_INTERRUPTIONS();
                     if (p == ht->arBuckets[nIndex]) {
                            ht->arBuckets[nIndex] = p->pNext;
                     } else {
                            p->pLast->pNext = p->pNext;
                     }
                     if (p->pNext) {
                            p->pNext->pLast = p->pLast;
                     }
                     if (p->pListLast != NULL) {
                            p->pListLast->pListNext = p->pListNext;
                     } else { 
                            /* Deleting the head of the list */
                            ht->pListHead = p->pListNext;
                     }
                     if (p->pListNext != NULL) {
                            p->pListNext->pListLast = p->pListLast;
                     } else {
                            ht->pListTail = p->pListLast;
                     }
                     if (ht->pInternalPointer == p) {
                            ht->pInternalPointer = p->pListNext;
                     }
                     if (ht->pDestructor) {
                            ht->pDestructor(p->pData);
                     }
                     if (p->pData != &p->pDataPtr) {
                            pefree(p->pData, ht->persistent);
                     }
                     pefree(p, ht->persistent);
                     HANDLE_UNBLOCK_INTERRUPTIONS();
                     ht->nNumOfElements--;
                     return SUCCESS;
              }
              p = p->pNext;
       }
       return FAILURE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 516 of file zend_hash.c.

{
       Bucket *p, *q;

       IS_CONSISTENT(ht);

       SET_INCONSISTENT(HT_IS_DESTROYING);

       p = ht->pListHead;
       while (p != NULL) {
              q = p;
              p = p->pListNext;
              if (ht->pDestructor) {
                     ht->pDestructor(q->pData);
              }
              if (q->pData != &q->pDataPtr) {
                     pefree(q->pData, ht->persistent);
              }
              pefree(q, ht->persistent);
       }
       pefree(ht->arBuckets, ht->persistent);

       SET_INCONSISTENT(HT_DESTROYED);
}
static int zend_hash_do_resize ( HashTable ht) [static]

Definition at line 418 of file zend_hash.c.

{
       Bucket **t;

       IS_CONSISTENT(ht);

       if ((ht->nTableSize << 1) > 0) {   /* Let's double the table size */
              t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent);
              if (t) {
                     HANDLE_BLOCK_INTERRUPTIONS();
                     ht->arBuckets = t;
                     ht->nTableSize = (ht->nTableSize << 1);
                     ht->nTableMask = ht->nTableSize - 1;
                     zend_hash_rehash(ht);
                     HANDLE_UNBLOCK_INTERRUPTIONS();
                     return SUCCESS;
              }
              return FAILURE;
       }
       return SUCCESS;
}

Here is the call graph for this function:

ZEND_API int zend_hash_exists ( const HashTable ht,
const char *  arKey,
uint  nKeyLength 
)

Definition at line 923 of file zend_hash.c.

{
       ulong h;
       uint nIndex;
       Bucket *p;

       IS_CONSISTENT(ht);

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

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
                     if (!memcmp(p->arKey, arKey, nKeyLength)) {
                            return 1;
                     }
              }
              p = p->pNext;
       }
       return 0;
}

Here is the call graph for this function:

ZEND_API int zend_hash_find ( const HashTable ht,
const char *  arKey,
uint  nKeyLength,
void **  pData 
)

Definition at line 871 of file zend_hash.c.

{
       ulong h;
       uint nIndex;
       Bucket *p;

       IS_CONSISTENT(ht);

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

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
                     if (!memcmp(p->arKey, arKey, nKeyLength)) {
                            *pData = p->pData;
                            return SUCCESS;
                     }
              }
              p = p->pNext;
       }
       return FAILURE;
}

Here is the call graph for this function:

ZEND_API ulong zend_hash_func ( const char *  arKey,
uint  nKeyLength 
)

Definition at line 100 of file zend_hash.c.

{
       return zend_inline_hash_func(arKey, nKeyLength);
}

Here is the call graph for this function:

Here is the caller graph for this function:

ZEND_API int zend_hash_get_current_data_ex ( HashTable ht,
void **  pData,
HashPosition pos 
)

Definition at line 1156 of file zend_hash.c.

{
       Bucket *p;

       p = pos ? (*pos) : ht->pInternalPointer;

       IS_CONSISTENT(ht);

       if (p) {
              *pData = p->pData;
              return SUCCESS;
       } else {
              return FAILURE;
       }
}
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 
)

Definition at line 1109 of file zend_hash.c.

{
       Bucket *p;

       p = pos ? (*pos) : ht->pInternalPointer;

       IS_CONSISTENT(ht);

       if (p) {
              if (p->nKeyLength) {
                     if (duplicate) {
                            *str_index = estrndup(p->arKey, p->nKeyLength - 1);
                     } else {
                            *str_index = p->arKey;
                     }
                     if (str_length) {
                            *str_length = p->nKeyLength;
                     }
                     return HASH_KEY_IS_STRING;
              } else {
                     *num_index = p->h;
                     return HASH_KEY_IS_LONG;
              }
       }
       return HASH_KEY_NON_EXISTANT;
}

Definition at line 1137 of file zend_hash.c.

{
       Bucket *p;

       p = pos ? (*pos) : ht->pInternalPointer;

       IS_CONSISTENT(ht);

       if (p) {
              if (p->nKeyLength) {
                     return HASH_KEY_IS_STRING;
              } else {
                     return HASH_KEY_IS_LONG;
              }
       }
       return HASH_KEY_NON_EXISTANT;
}

Definition at line 1023 of file zend_hash.c.

{
       ptr->pos = ht->pInternalPointer;
       if (ht->pInternalPointer) {
              ptr->h = ht->pInternalPointer->h;
              return 1;
       } else {
              ptr->h = 0;
              return 0;
       }
}

Here is the caller graph for this function:

Definition at line 624 of file zend_hash.c.

{
       Bucket *p;

       IS_CONSISTENT(ht);

       p = ht->pListHead;
       while (p != NULL) {
              p = zend_hash_apply_deleter(ht, p);
       }
       pefree(ht->arBuckets, ht->persistent);

       SET_INCONSISTENT(HT_DESTROYED);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 639 of file zend_hash.c.

{
       Bucket *p;

       IS_CONSISTENT(ht);

       p = ht->pListTail;
       while (p != NULL) {
              zend_hash_apply_deleter(ht, p);
              p = ht->pListTail;
       }

       pefree(ht->arBuckets, ht->persistent);

       SET_INCONSISTENT(HT_DESTROYED);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 995 of file zend_hash.c.

{
       uint nIndex;
       Bucket *p;

       IS_CONSISTENT(ht);

       nIndex = h & ht->nTableMask;

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) && (p->nKeyLength == 0)) {
                     return 1;
              }
              p = p->pNext;
       }
       return 0;
}

Here is the caller graph for this function:

ZEND_API int zend_hash_index_find ( const HashTable ht,
ulong  h,
void **  pData 
)

Definition at line 974 of file zend_hash.c.

{
       uint nIndex;
       Bucket *p;

       IS_CONSISTENT(ht);

       nIndex = h & ht->nTableMask;

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) && (p->nKeyLength == 0)) {
                     *pData = p->pData;
                     return SUCCESS;
              }
              p = p->pNext;
       }
       return FAILURE;
}

Definition at line 1070 of file zend_hash.c.

{
       IS_CONSISTENT(ht);

       if (pos)
              *pos = ht->pListTail;
       else
              ht->pInternalPointer = ht->pListTail;
}

Here is the caller graph for this function:

Definition at line 1056 of file zend_hash.c.

{
       IS_CONSISTENT(ht);

       if (pos)
              *pos = ht->pListHead;
       else
              ht->pInternalPointer = ht->pListHead;
}
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 
)

Definition at line 840 of file zend_hash.c.

{
       Bucket *p;
       void *t;

       IS_CONSISTENT(source);
       IS_CONSISTENT(target);

       p = source->pListHead;
       while (p) {
              if (zend_hash_replace_checker_wrapper(target, p->pData, p, pParam, pMergeSource)) {
                     if (zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
                            pCopyConstructor(t);
                     }
              }
              p = p->pListNext;
       }
       target->pInternalPointer = target->pListHead;
}

Here is the call graph for this function:

Here is the caller graph for this function:

ZEND_API int zend_hash_minmax ( const HashTable ht,
compare_func_t  compar,
int  flag,
void **pData  TSRMLS_DC 
)

Definition at line 1509 of file zend_hash.c.

{
       Bucket *p, *res;

       IS_CONSISTENT(ht);

       if (ht->nNumOfElements == 0 ) {
              *pData=NULL;
              return FAILURE;
       }

       res = p = ht->pListHead;
       while ((p = p->pListNext)) {
              if (flag) {
                     if (compar(&res, &p TSRMLS_CC) < 0) { /* max */
                            res = p;
                     }
              } else {
                     if (compar(&res, &p TSRMLS_CC) > 0) { /* min */
                            res = p;
                     }
              }
       }
       *pData = res->pData;
       return SUCCESS;
}

Here is the caller graph for this function:

Definition at line 1094 of file zend_hash.c.

{
       HashPosition *current = pos ? pos : &ht->pInternalPointer;

       IS_CONSISTENT(ht);

       if (*current) {
              *current = (*current)->pListLast;
              return SUCCESS;
       } else
              return FAILURE;
}

Here is the caller graph for this function:

Definition at line 1081 of file zend_hash.c.

{
       HashPosition *current = pos ? pos : &ht->pInternalPointer;

       IS_CONSISTENT(ht);

       if (*current) {
              *current = (*current)->pListNext;
              return SUCCESS;
       } else
              return FAILURE;
}

Definition at line 1536 of file zend_hash.c.

{
       IS_CONSISTENT(ht);

       return ht->nNextFreeElement;

}

Here is the caller graph for this function:

Definition at line 1015 of file zend_hash.c.

{
       IS_CONSISTENT(ht);

       return ht->nNumOfElements;
}
ZEND_API int zend_hash_quick_exists ( const HashTable ht,
const char *  arKey,
uint  nKeyLength,
ulong  h 
)

Definition at line 947 of file zend_hash.c.

{
       uint nIndex;
       Bucket *p;

       if (nKeyLength==0) {
              return zend_hash_index_exists(ht, h);
       }

       IS_CONSISTENT(ht);

       nIndex = h & ht->nTableMask;

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
                     if (!memcmp(p->arKey, arKey, nKeyLength)) {
                            return 1;
                     }
              }
              p = p->pNext;
       }
       return 0;

}

Here is the call graph for this function:

Here is the caller graph for this function:

ZEND_API int zend_hash_quick_find ( const HashTable ht,
const char *  arKey,
uint  nKeyLength,
ulong  h,
void **  pData 
)

Definition at line 896 of file zend_hash.c.

{
       uint nIndex;
       Bucket *p;

       if (nKeyLength==0) {
              return zend_hash_index_find(ht, h, pData);
       }

       IS_CONSISTENT(ht);

       nIndex = h & ht->nTableMask;

       p = ht->arBuckets[nIndex];
       while (p != NULL) {
              if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
                     if (!memcmp(p->arKey, arKey, nKeyLength)) {
                            *pData = p->pData;
                            return SUCCESS;
                     }
              }
              p = p->pNext;
       }
       return FAILURE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 440 of file zend_hash.c.

{
       Bucket *p;
       uint nIndex;

       IS_CONSISTENT(ht);

       memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
       p = ht->pListHead;
       while (p != NULL) {
              nIndex = p->h & ht->nTableMask;
              CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
              ht->arBuckets[nIndex] = p;
              p = p->pListNext;
       }
       return SUCCESS;
}

Here is the caller graph for this function:

static zend_bool zend_hash_replace_checker_wrapper ( HashTable target,
void *  source_data,
Bucket p,
void *  pParam,
merge_checker_func_t  merge_checker_func 
) [static]

Definition at line 829 of file zend_hash.c.

{
       zend_hash_key hash_key;

       hash_key.arKey = p->arKey;
       hash_key.nKeyLength = p->nKeyLength;
       hash_key.h = p->h;
       return merge_checker_func(target, source_data, &hash_key, pParam);
}

Here is the caller graph for this function:

ZEND_API void zend_hash_reverse_apply ( HashTable ht,
apply_func_t apply_func  TSRMLS_DC 
)

Definition at line 748 of file zend_hash.c.

{
       Bucket *p, *q;

       IS_CONSISTENT(ht);

       HASH_PROTECT_RECURSION(ht);
       p = ht->pListTail;
       while (p != NULL) {
              int result = apply_func(p->pData TSRMLS_CC);

              q = p;
              p = p->pListLast;
              if (result & ZEND_HASH_APPLY_REMOVE) {
                     zend_hash_apply_deleter(ht, q);
              }
              if (result & ZEND_HASH_APPLY_STOP) {
                     break;
              }
       }
       HASH_UNPROTECT_RECURSION(ht);
}

Here is the call graph for this function:

Here is the caller graph for this function:

ZEND_API void zend_hash_set_apply_protection ( HashTable ht,
zend_bool  bApplyProtection 
)

Definition at line 196 of file zend_hash.c.

{
       ht->bApplyProtection = bApplyProtection;
}

Definition at line 1035 of file zend_hash.c.

{
       if (ptr->pos == NULL) {
              ht->pInternalPointer = NULL;
       } else if (ht->pInternalPointer != ptr->pos) {
              Bucket *p;

              IS_CONSISTENT(ht);
              p = ht->arBuckets[ptr->h & ht->nTableMask];
              while (p != NULL) {
                     if (p == ptr->pos) {
                            ht->pInternalPointer = p;
                            return 1;
                     }
                     p = p->pNext;
              }
              return 0;
       }
       return 1;
}

Here is the caller graph for this function:

ZEND_API int zend_hash_sort ( HashTable ht,
sort_func_t  sort_func,
compare_func_t  compar,
int renumber  TSRMLS_DC 
)

Definition at line 1360 of file zend_hash.c.

{
       Bucket **arTmp;
       Bucket *p;
       int i, j;

       IS_CONSISTENT(ht);

       if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */
              return SUCCESS;
       }
       arTmp = (Bucket **) pemalloc(ht->nNumOfElements * sizeof(Bucket *), ht->persistent);
       if (!arTmp) {
              return FAILURE;
       }
       p = ht->pListHead;
       i = 0;
       while (p) {
              arTmp[i] = p;
              p = p->pListNext;
              i++;
       }

       (*sort_func)((void *) arTmp, i, sizeof(Bucket *), compar TSRMLS_CC);

       HANDLE_BLOCK_INTERRUPTIONS();
       ht->pListHead = arTmp[0];
       ht->pListTail = NULL;
       ht->pInternalPointer = ht->pListHead;

       arTmp[0]->pListLast = NULL;
       if (i > 1) {
              arTmp[0]->pListNext = arTmp[1];
              for (j = 1; j < i-1; j++) {
                     arTmp[j]->pListLast = arTmp[j-1];
                     arTmp[j]->pListNext = arTmp[j+1];
              }
              arTmp[j]->pListLast = arTmp[j-1];
              arTmp[j]->pListNext = NULL;
       } else {
              arTmp[0]->pListNext = NULL;
       }
       ht->pListTail = arTmp[i-1];

       pefree(arTmp, ht->persistent);
       HANDLE_UNBLOCK_INTERRUPTIONS();

       if (renumber) {
              p = ht->pListHead;
              i=0;
              while (p != NULL) {
                     p->nKeyLength = 0;
                     p->h = i++;
                     p = p->pListNext;
              }
              ht->nNextFreeElement = i;
              zend_hash_rehash(ht);
       }
       return SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 
)

Definition at line 1175 of file zend_hash.c.

{
       Bucket *p, *q;

       p = pos ? (*pos) : ht->pInternalPointer;

       IS_CONSISTENT(ht);

       if (p) {
              if (key_type == HASH_KEY_IS_LONG) {
                     str_length = 0;
                     if (!p->nKeyLength && p->h == num_index) {
                            return SUCCESS;
                     }

                     q = ht->arBuckets[num_index & ht->nTableMask];
                     while (q != NULL) {
                            if (!q->nKeyLength && q->h == num_index) {
                                   break;
                            }
                            q = q->pNext;
                     }
              } else if (key_type == HASH_KEY_IS_STRING) {
                     ulong h;

                     if (p->nKeyLength == str_length &&
                         memcmp(p->arKey, str_index, str_length) == 0) {
                            return SUCCESS;
                     }

                     h = zend_inline_hash_func(str_index, str_length);
                     q = ht->arBuckets[h & ht->nTableMask];

                     while (q != NULL) {
                            if (q->h == h && q->nKeyLength == str_length && 
                                       memcmp(q->arKey, str_index, str_length) == 0) {
                                   break;
                            }
                            q = q->pNext;
                     }
              } else {
                     return FAILURE;
              }

              HANDLE_BLOCK_INTERRUPTIONS();

              if (q) {
                     if (mode != HASH_UPDATE_KEY_ANYWAY) {
                            Bucket *r = p->pListLast;
                            int found = HASH_UPDATE_KEY_IF_BEFORE;
                                          
                            while (r) {
                                   if (r == q) {
                                          found = HASH_UPDATE_KEY_IF_AFTER;
                                          break;
                                   }
                                   r = r->pListLast;
                            }
                            if (mode & found) {
                                   /* delete current bucket */
                                   if (p == ht->arBuckets[p->h & ht->nTableMask]) {
                                          ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
                                   } else {
                                          p->pLast->pNext = p->pNext;
                                   }
                                   if (p->pNext) {
                                          p->pNext->pLast = p->pLast;
                                   }
                                   if (p->pListLast != NULL) {
                                          p->pListLast->pListNext = p->pListNext;
                                   } else { 
                                          /* Deleting the head of the list */
                                          ht->pListHead = p->pListNext;
                                   }
                                   if (p->pListNext != NULL) {
                                          p->pListNext->pListLast = p->pListLast;
                                   } else {
                                          ht->pListTail = p->pListLast;
                                   }
                                   if (ht->pInternalPointer == p) {
                                          ht->pInternalPointer = p->pListNext;
                                   }
                                   if (ht->pDestructor) {
                                          ht->pDestructor(p->pData);
                                   }
                                   if (p->pData != &p->pDataPtr) {
                                          pefree(p->pData, ht->persistent);
                                   }
                                   pefree(p, ht->persistent);
                                   ht->nNumOfElements--;
                                   HANDLE_UNBLOCK_INTERRUPTIONS();
                                   return FAILURE;
                            }
                     }
                     /* delete another bucket with the same key */
                     if (q == ht->arBuckets[q->h & ht->nTableMask]) {
                            ht->arBuckets[q->h & ht->nTableMask] = q->pNext;
                     } else {
                            q->pLast->pNext = q->pNext;
                     }
                     if (q->pNext) {
                            q->pNext->pLast = q->pLast;
                     }
                     if (q->pListLast != NULL) {
                            q->pListLast->pListNext = q->pListNext;
                     } else { 
                            /* Deleting the head of the list */
                            ht->pListHead = q->pListNext;
                     }
                     if (q->pListNext != NULL) {
                            q->pListNext->pListLast = q->pListLast;
                     } else {
                            ht->pListTail = q->pListLast;
                     }
                     if (ht->pInternalPointer == q) {
                            ht->pInternalPointer = q->pListNext;
                     }
                     if (ht->pDestructor) {
                            ht->pDestructor(q->pData);
                     }
                     if (q->pData != &q->pDataPtr) {
                            pefree(q->pData, ht->persistent);
                     }
                     pefree(q, ht->persistent);
                     ht->nNumOfElements--;
              }

              if (p->pNext) {
                     p->pNext->pLast = p->pLast;
              }
              if (p->pLast) {
                     p->pLast->pNext = p->pNext;
              } else {
                     ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
              }

              if (p->nKeyLength != str_length) {
                     Bucket *q = (Bucket *) pemalloc(sizeof(Bucket) - 1 + str_length, ht->persistent);

                     q->nKeyLength = str_length;
                     if (p->pData == &p->pDataPtr) {
                            q->pData = &q->pDataPtr;
                     } else {
                            q->pData = p->pData;
                     }
                     q->pDataPtr = p->pDataPtr;
                     q->pListNext = p->pListNext;
                     q->pListLast = p->pListLast;
                     if (q->pListNext) {
                            p->pListNext->pListLast = q;
                     } else {
                            ht->pListTail = q;
                     }
                     if (q->pListLast) {
                            p->pListLast->pListNext = q;
                     } else {
                            ht->pListHead = q;
                     }
                     if (ht->pInternalPointer == p) {
                            ht->pInternalPointer = q;
                     }
                     if (pos) {
                            *pos = q;
                     }
                     pefree(p, ht->persistent);
                     p = q;
              }

              if (key_type == HASH_KEY_IS_LONG) {
                     p->h = num_index;
              } else {
                     memcpy(p->arKey, str_index, str_length);
                     p->h = zend_inline_hash_func(str_index, str_length);
              }

              CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[p->h & ht->nTableMask]);
              ht->arBuckets[p->h & ht->nTableMask] = p;
              HANDLE_UNBLOCK_INTERRUPTIONS();

              return SUCCESS;
       } else {
              return FAILURE;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function: