日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

php Hash Table(四) Hash Table添加和更新元素

發布時間:2023/12/18 php 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php Hash Table(四) Hash Table添加和更新元素 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

HashTable添加和更新的函數:

有4個主要的函數用于插入和更新HashTable的數據:

int zend_hash_add(HashTable *ht, char *arKey, uint nKeyLen,void **pData, uint nDataSize, void *pDest); int zend_hash_update(HashTable *ht, char *arKey, uint nKeyLen, void *pData, uint nDataSize, void **pDest);
int zend_hash_index_update(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest);
int zend_hash_next_index_insert(HashTable *ht, void *pData, uint nDataSize, void **pDest);

這里的前兩個函數用于新增關聯索引數據, 比如$foo['bar'] = 'baz';對應的C語言代碼如下:

zend_hash_add(fooHashTbl, "bar", sizeof("bar"), &barZval, sizeof(zval*), NULL);

zend_hash_add()和zend_hash_update()唯一的區別是如果key存在, zend_hash_add()將會失敗.

接下來的兩個函數以類似的方式處理數值索引的HashTable. 這兩行之間的區別在于是否指定索引 或者說是否自動賦值為下一個可用索引.

如果需要存儲使用zend_hash_next_index_insert()插入的元素的索引值, 可以調用zend_hash_next_free_element()函數獲得:

ulong nextid = zend_hash_next_free_element(ht); zend_hash_index_update(ht, nextid, &data, sizeof(data), NULL);

?

HashTable添加更新元素:

在初始化了HashTable之后,可以用zend_hash_add來向HashTable添加元素 ,zend_hash_add是一個宏:

#define zend_hash_add(ht, arKey, nKeyLength, pData, nDataSize, pDest) \_zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC)

?我們來看看_zend_hash_add_or_update的定義,同樣在Zend/zend_hash.c下

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; /*存貯arKey在hash之后的值*/uint nIndex; /*存貯h & nTableMask之后的值*/Bucket *p; #ifdef ZEND_SIGNALSTSRMLS_FETCH(); //這個還不知道是什么意思 #endifIS_CONSISTENT(ht); //調試信息輸出if (nKeyLength <= 0) { //添加的是字符串索引的,所以nKeyLength不可能<=0 #if ZEND_DEBUGZEND_PUTS("zend_hash_update: Can't put in empty key\n"); #endifreturn FAILURE;}/** * 檢查是否初始化buckets空間,若沒有初始化則初始化buckets的內存空間* 為arBuckets申請內存,為nTableSize賦值,因為在zend_hash_init里邊nTableSize設置為0 */CHECK_INIT(ht); h = zend_inline_hash_func(arKey, nKeyLength); /* 計算key的hash值 */nIndex = h & ht->nTableMask; /* 利用掩碼得到key的實際存儲位置 */p = ht->arBuckets[nIndex]; /* 取到指定位置的bucket指針 */while (p != NULL) { /* 若指針不為空,則表示當前位置已有bucket了 */if (p->arKey == arKey || ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) {/* 若當前bucket的key和要存入的key相同,那么需要更新 */if (flag & HASH_ADD) { /* 如果當前指定是add操作,此時就返回失敗了 */return FAILURE;}/*** interruptions,打斷,中斷的意思*/HANDLE_BLOCK_INTERRUPTIONS(); #if ZEND_DEBUGif (p->pData == pData) {ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");HANDLE_UNBLOCK_INTERRUPTIONS();return FAILURE;} #endifif (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; /* 若當前key和要存入的key不同,那么查找Hash拉鏈的下一個bucket}/* 運行到這里,表示沒有找到任何已存在的key和要存入的key相同的,那么申請一個sizeof(bucket)+nKeyLength大小的新空間給key *///interned用google搜了一下,發現是'字符串駐留'的概念,也沒搞太清楚//大概就是維護了一個駐留池,會把在編譯期間相同的字符串只保留一份拷貝。if (IS_INTERNED(arKey)) { p = (Bucket *) pemalloc(sizeof(Bucket), ht->persistent);if (!p) {return FAILURE;}p->arKey = arKey;} else {p = (Bucket *) pemalloc(sizeof(Bucket) + nKeyLength, ht->persistent); //柔性數組的概念if (!p) {return FAILURE;}p->arKey = (const char*)(p + 1); //p+1就是arKey的起始地址memcpy((char*)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); /* 將Bucket 加入到HashTable的雙向鏈表中 */ht->arBuckets[nIndex] = p;HANDLE_UNBLOCK_INTERRUPTIONS();ht->nNumOfElements++;// 如果HashTable已滿,重新調整HashTable的大小。ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */return SUCCESS;

上邊的函數中涉及到宏CHECK_INIT,在Zend_hash.c中定義如下,

#define CHECK_INIT(ht) do { \if (UNEXPECTED((ht)->nTableMask == 0)) { \(ht)->arBuckets = (Bucket **) pecalloc((ht)->nTableSize, sizeof(Bucket *), (ht)->persistent); \(ht)->nTableMask = (ht)->nTableSize - 1; \} \ } while (0)

INIT_DATA宏的定義,

#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; \}

這里有一個tricks,PHP判斷數據的大小和一個void指針相同時,就不為其申請額外的空間,而是將數據copy到pDataPtr字段中,也就是 說,如果你add到HashTable的是一個指針,那么他直接被保存在pDataPtr字段中,同時pData字段也會保存一份。如果你add到 HashTable的是一個更大的結構,那么PHP會為這個結構單獨申請內存空間,將數據copy到這片新申請的內存空間中,然后將pDataPtr設置 為NULL。

?

轉載于:https://www.cnblogs.com/leezhxing/p/4838927.html

總結

以上是生活随笔為你收集整理的php Hash Table(四) Hash Table添加和更新元素的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。