• PHP的HashTable(一)


    数据定义 :

    /*zend_hash.h */

    typedef struct bucket {
        ulong h;                        /* Used for numeric indexing */
        uint nKeyLength;  
        void *pData; /* 这里是array里面item对对应的数据,有点特殊的是,若存的是指针,这是指向下一个成员pDataPtr的指针,pDataPtr才是真正存放指针value的地方,有点不明白 */
        void *pDataPtr;
        struct bucket *pListNext;
        struct bucket *pListLast;
        struct bucket *pNext;
        struct bucket *pLast;
        char arKey[1]; /* Must be last element 这是柔性数组成员或者叫伸缩性数组成员 */
    } Bucket;

    typedef struct _hashtable {
        uint nTableSize; 
        uint nTableMask; /* nTableSize-1,用来给key的hash值取模决定key最终落在哪个槽内 */
        uint nNumOfElements;
        ulong nNextFreeElement;
        Bucket *pInternalPointer;    /* Used for element traversal */
        Bucket *pListHead;
        Bucket *pListTail;
        Bucket **arBuckets;
        dtor_func_t pDestructor;
        zend_bool persistent;
        unsigned char nApplyCount;
        zend_bool bApplyProtection;
    #if ZEND_DEBUG
        int inconsistent;
    #endif

    } HashTable;  

     #define UPDATE_DATA(ht, p, pData, nDataSize)                                            \

        if (nDataSize == sizeof(void*)) { /* 若value所占字节数 == sizeof(void*) */              \
            if ((p)->pData != &(p)->pDataPtr) {                                               \
                pefree_rel((p)->pData, (ht)->persistent);                                     \
            }                                                                                 \
            memcpy(&(p)->pDataPtr, pData, sizeof(void *));   /* 把pData存入pDataPtr */          \
            (p)->pData = &(p)->pDataPtr;                     /* pData指向 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);          /* pData 存入 Bucket->pData */     \
        }

    #define INIT_DATA(ht, p, pData, nDataSize);                                \
        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;                                                \
        }
    /* zend_hash_add_or_update */
    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)
    {
        ulong h; /* key的hash值 */
        uint nIndex; /*  hash 值 对应的槽的 索引 */
        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);  /*  计算key的hash值 */
        nIndex = h & ht->nTableMask;  /* 通过取模计算key的hash值所对应的槽的索引 */

        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; /* 槽头指向这个新的Bucket */
        HANDLE_UNBLOCK_INTERRUPTIONS();

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

    /* end */ 

  • 相关阅读:
    云原生生态周报 Vol. 16 | CNCF 归档 rkt,容器运行时“上古”之战老兵凋零
    Knative 基本功能深入剖析:Knative Eventing 之 Sequence 介绍
    基于 K8s 做应用发布的工具那么多, 阿里为啥选择灰姑娘般的 Tekton ?
    Serverless 的喧哗与骚动(一)附Serverless行业发展回顾
    239. Sliding Window Maximum
    237. Delete Node in a Linked List
    146. LRU Cache
    140. Word Break II
    165. Compare Version Numbers
    258. Add Digits
  • 原文地址:https://www.cnblogs.com/bqrm/p/2709841.html
Copyright © 2020-2023  润新知