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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

山寨“饿了么”应用中添加菜品数量按钮效果

山寨“饿了么”应用中添加菜品数量按钮效果 本人视频教程系类 iOS中CALayer的使用 最终效果&#xff1a; 山寨源头&#xff1a; 源码&#xff1a;&#xff08;此源码解决了重用问题&#xff0c;可以放心的放在cell中使用&#xff09; AddAndDeleteButton.h 与 AddAndDeleteBu…

html间数据传送,Express框架与html之间如何进行数据传递(示例代码)

关于Node.js 的Express框架介绍&#xff0c;推荐看菜鸟教程的Express框架&#xff0c;很适合入门&#xff0c;这里不再赘述&#xff0c;这里主要讲一下Express框架与html之间如何进行数据传递我采用的是JQuery的Ajax()向后台传参方式(url传参)1、Type属性为Get时&#xff1a;(1…

数字图像去噪典型算法及matlab实现

图像去噪是数字图像处理中的重要环节和步骤。去噪效果的好坏直接影响到后续的图像处理工作如图像分割、边缘检测等。图像信号在产生、传输过程中都可能会受到噪声的污染&#xff0c;一般数字图像系统中的常见噪声主要有&#xff1a;高斯噪声&#xff08;主要由阻性元器件内部产…

pat1100. Mars Numbers (20)

1100. Mars Numbers (20) 时间限制400 ms内存限制65536 kB代码长度限制16000 B判题程序Standard 作者CHEN, YuePeople on Mars count their numbers with base 13: Zero on Earth is called "tret" on Mars.The numbers 1 to 12 on Earch is called "jan, feb, …

【USACO1.1】Broken Necklace

题意 一个环形项链&#xff0c;有rbw三种珠子&#xff0c;r代表red&#xff0c;b代表blue&#xff0c;w代表white&#xff0c;从任意一个位置断开&#xff0c;两端分别取珠子&#xff0c;同一端取的珠子要相同颜色&#xff0c;w可以染成想要的颜色&#xff0c;即既可当作r也可以…

html+注释格式化,使用xml注释来生成格式化的html输出

我试图从我在xml文件中的注释中生成一个格式良好的html文档。目前我有一个xml文件&#xff0c;用于生成xml表格的html列表。为了让我添加有关表格的评论&#xff0c;我手动将注释添加到输出html文件中。使用xml注释来生成格式化的html输出我想如果可能将html代码放在xml文件中作…

图像增强-图像锐化

图像锐化主要影响图像中的低频分量&#xff0c;不影响图像中的高频分量。 图像锐化的主要目的有两个&#xff1a; 1.增强图像边缘&#xff0c;使模糊的图像变得更加清晰&#xff0c;颜色变得鲜明突出&#xff0c;图像的质量有所改善&#xff0c;产生更适合人眼观察和识别的图像…

[译]git revert

git revert git revert用来撤销一个已经提交了的快照. 但不是从项目历史中移除这个commit, 而是生成一个新的commit, 老的commit还是保留在历史项目里面的. 这样做的好处是防止了项目丢失历史. 用法 git revert <commit>生成一个新的commit, 撤销老的<commit>的所有…

图像二值化算法总结

****************************************************************************************************************************************** 红&#xff1a;数字图像处理视频教程&#xff08;两部&#xff09; {中科院版36讲视频教程 电子科大版70讲视频教程&#xff…

html 替换反斜杠,在URL直接替换反斜杠反斜杠

我们有一个系统&#xff0c;基于Moodle的平台&#xff0c;在这里的文件是这样引用&#xff1a;在URL直接替换反斜杠反斜杠的http&#xff1a;// [服务器] /file.php/3/LR4/info/ index.html的现在&#xff0c;这个伟大的工程&#xff0c;但是我们的一些老师错误地使用落后的斜杠…

VMware桥接模式无法连网

2019独角兽企业重金招聘Python工程师标准>>> #VMware桥接模式无法连网 在VMware上装了个CentOS7&#xff0c;使用桥接模式连网&#xff0c;开始使用的时候没有问题&#xff0c;可以正常上网。最近打开的时候发现上不了网了&#xff0c; 使用ifconfig查看也没有分配到…

Java 7 中 NIO.2 的使用——第四节 文件和目录

Files类提供了很多方法用于检查在于你真正实际去操作一个文件或目录。这些方法强烈推荐&#xff0c;也非常有用&#xff0c;也能避免很多异常的发生。例如&#xff0c;一个很好的习惯就是在你试着移动一个文件从一个地方到另一个地方的时候&#xff0c;先检查文件是否存在。 检…

计算机二级access知识点6,2019年计算机二级ACCESS考试知识点:关系数据模型

【导语】2019年计算机二级考试备考正在进行中&#xff0c;为了方便考生及时有效的备考&#xff0c;那么&#xff0c;无忧考网为您精心整理了2019年计算机二级ACCESS考试知识点&#xff1a;关系数据模型&#xff0c;欢迎大家的关注。如想获取更多计算机二级考试的备考资料&#…

乘方取模计算(模幂计算)

乘方取模计算也称为模幂计算&#xff0c;在密码系统中经常使用&#xff0c;是不可缺少的。 使用本程序可以解HDU2035&#xff0c;只需要考虑输入和输出。 /** 乘方取模** 已知给定的正整数a、n和m&#xff0c;计算x的值&#xff0c;a^n x (mod m)。** 二分法用在这里也很有效果…

Moldflow中文版注塑流动分析案例导航视频教程

http://item.taobao.com/item.htm?spma1z10.5.w4002-9510581626.18.30lDTO&id43054534418 QQ&#xff1a;2911984429 http://aidem.lingw.net/

Jaxb annotation使用

JAXB&#xff08;Java Architecture for XML Binding) 是一个业界的标准&#xff0c;是一项可以根据XML Schema产生Java类的技术。该过程中&#xff0c;JAXB也提供了将XML实例文档反向生成Java对象树的方法&#xff0c;并能将Java对象树的内容重新写到XML实例文档。从另一方面来…

湖北大学计算机袁云,暑期走访不停歇 远赴异地送关怀——学校慰问离退休教职工和校友...

不畏酷暑送清风&#xff0c;心常为老怀关爱。7月至8月&#xff0c;正值高温时节&#xff0c;校领导和各单位负责人根据学校党委的安排&#xff0c;赴深圳、广州、北京、上海等地走访慰问70岁以上离退休教职工和部分校友&#xff0c;把学校的问候和祝福送到他们身边。“对老同志…

MATLAB各类函数详细讲解 simulike系统仿真分析

http://item.taobao.com/item.htm?spma230r.1.14.40.yWjJFw&id43113292964&ns1&abbucket2&_uk10ekfuf6120#detail Matlab基本操作函数 SIMULINK仿真函数 插值与拟合函数视频教程 符号运算函数视频教程 概率统计函数视频教程 级数与微积分函数视频教程 矩阵运…

Github Coding Developer Book For LiuGuiLinAndroid

Github Coding Developer Book For LiuGuiLinAndroid 收集了这么多开源的PDF&#xff0c;也许会帮到一些人&#xff0c;现在里面的书籍还不是很多&#xff0c;我也在一点点的上传&#xff0c;才上传不到一半&#xff0c;没办法&#xff0c;库存太多了 觉得全部pull麻烦的话&…

#个人博客作业week2——结对编程伙伴代码复审

General 1.程序能够顺利地运行。程序通过命令行输入&#xff0c;能够向对应的文件中输出符合要求的题目和答案。程序能够根据用户的不同选择&#xff0c;进行题目的生产或答案的校验&#xff0c;生成出的题目符合参数要求和项目的查重等各种要求&#xff0c;答案校验准确迅速。…