//添加or替换,如果key不存在就执行添加操作,返回1 //如果key存在更新value的值,返回0 int dictReplace(dict *d, void *key, void *val) { dictEntry *entry, auxentry; /* Try to add the element. If the key * does not exists dictAdd will suceed. */ //只有在这个key存在的情况下,才会返回DICT_ERR,所以如果返回为DICT_OK, //说明key不存在,并且添加成功. if (dictAdd(d, key, val) == DICT_OK) return 1; /* It already exists, get the entry */ entry = dictFind(d, key); /* Set the new value and free the old one. Note that it is important * to do that in this order, as the value may just be exactly the same * as the previous one. In this context, think to reference counting, * you want to increment (set), and then decrement (free), and not the * reverse. */ auxentry = *entry; //!!!这里有个疑问,这里说明必须首先设置然后再释放,但是执行了设置操作之后 //该entry的值为新的value(可能是覆盖),接下来的释放操作如果将它free了呢? //也就是该哈希表的valDup函数为NULL,但是ValDestructor函数将free这个entry的value //那么这就编程了一个空悬指针!!! //有待加深理解。。。 //既然作者的注释说明这样的顺序是防止两个value为同一个对象并且使用了引用计数, //如果这样可以简单的进行判断是否指向同一个对象,如果是直接返回 //不知道我这样理解是否违反了作者的意图~~~ dictSetVal(d, entry, val); dictFreeVal(d, &auxentry); return 0; }
/* 删除字典中指定的哈希表 * * Destroy an entire dictionary * * Args: * d 被删除的哈希表所属的字典 * ht 被删除的哈希表 * * Returns: * DICT_OK 删除成功(这个函数不可能失败) */ int _dictClear(dict *d, dictht *ht) { unsigned long i; // 遍历整个哈希表,删除所有节点链 /* Free all the elements */ for (i = 0; i < ht->size && ht->used > 0; i++) { dictEntry *he, *nextHe; // 碰到空节点链,跳到下一个节点链去 if ((he = ht->table[i]) == NULL) continue; // 如果节点链非空,就遍历删除所有节点 while(he) { nextHe = he->next; dictFreeKey(d, he); // 释放 key 空间 dictFreeVal(d, he); // 释放 value 空间 zfree(he); // 释放节点 ht->used--; // 减少计数器 he = nextHe; } } // 释放哈希表节点指针数组的空间 /* Free the table and the allocated cache structure */ zfree(ht->table); // 并重置(清空)哈希表各项属性 /* Re-initialize the table */ _dictReset(ht); return DICT_OK; /* never fails */ }
/* Destroy an entire dictionary */ int _dictClear(dict *d, dictht *ht) { #ifdef _WIN32 size_t i; #else unsigned long i; #endif /* Free all the elements */ for (i = 0; i < ht->size && ht->used > 0; i++) { dictEntry *he, *nextHe; if ((he = ht->table[i]) == NULL) continue; while(he) { nextHe = he->next; dictFreeKey(d, he); dictFreeVal(d, he); zfree(he); ht->used--; he = nextHe; } } /* Free the table and the allocated cache structure */ zfree(ht->table); /* Re-initialize the table */ _dictReset(ht); return DICT_OK; /* never fails */ }
/* 删除指定元素的底层实现代码 * * Args: * d * key * nofree 指示是否释放被删除元素的键和值 * * Returns: * DICT_ERR 字典为空,删除失败 * DICT_OK 删除成功 */ static int dictGenericDelete(dict *d, const void *key, int nofree) { unsigned int h, idx; dictEntry *he, *prevHe; int table; // 字典为空,删除失败 if (d->ht[0].size == 0) return DICT_ERR; // 平摊 rehash if (dictIsRehashing(d)) _dictRehashStep(d); // 哈希值 h = dictHashKey(d, key); // 遍历 for (table = 0; table <= 1; table++) { idx = h & d->ht[table].sizemask; // 地址索引 he = d->ht[table].table[idx]; // 表头节点 prevHe = NULL; while(he) { if (dictCompareKeys(d, key, he->key)) { /* Unlink the element from the list */ if (prevHe) prevHe->next = he->next; else d->ht[table].table[idx] = he->next; if (!nofree) { dictFreeKey(d, he); dictFreeVal(d, he); } zfree(he); d->ht[table].used--; return DICT_OK; } // 推进指针 prevHe = he; he = he->next; } if (!dictIsRehashing(d)) break; } return DICT_ERR; /* not found */ }
/* 将新元素添加到字典,如果 key 已经存在,那么新元素覆盖旧元素。 * * Args: * d * key 新元素的关键字 * val 新元素的值 * * Return: * 1 key 不存在,新建元素添加成功 * 0 key 已经存在,旧元素被新元素覆盖 */ int dictReplace(dict *d, void *key, void *val) { dictEntry *entry, auxentry; // 尝试添加元素,如果 key 不存在, 那么 dictAdd 完成工作 if (dictAdd(d, key, val) == DICT_OK) return 1; // dictAdd 不成功,说明 key 已经存在 // 找出这个元素并更新它的值 entry = dictFind(d, key); auxentry = *entry; // 用变量保存 entry 的引用 dictSetVal(d, entry, val); // 设置新值 dictFreeVal(d, &auxentry); // 释放旧值 return 0; }
/* Add an element, discarding the old if the key already exists. * Return 1 if the key was added from scratch, 0 if there was already an * element with such key and dictReplace() just performed a value update * operation. */ int dictReplace(dict *d, void *key, void *val) { dictEntry *entry, auxentry; /* Try to add the element. If the key * does not exists dictAdd will suceed. */ if (dictAdd(d, key, val) == DICT_OK) return 1; /* It already exists, get the entry */ entry = dictFind(d, key); /* Set the new value and free the old one. Note that it is important * to do that in this order, as the value may just be exactly the same * as the previous one. In this context, think to reference counting, * you want to increment (set), and then decrement (free), and not the * reverse. */ auxentry = *entry; dictSetVal(d, entry, val); dictFreeVal(d, &auxentry); return 0; }