2
0

dict.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /* Hash table implementation.
  2. *
  3. * This file implements in memory hash tables with insert/del/replace/find/
  4. * get-random-element operations. Hash tables will auto resize if needed
  5. * tables of power of two in size are used, collisions are handled by
  6. * chaining. See the source code for more information... :)
  7. *
  8. * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions are met:
  13. *
  14. * * Redistributions of source code must retain the above copyright notice,
  15. * this list of conditions and the following disclaimer.
  16. * * Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * * Neither the name of Redis nor the names of its contributors may be used
  20. * to endorse or promote products derived from this software without
  21. * specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  27. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  30. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  31. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. #include "fmacros.h"
  36. #include "alloc.h"
  37. #include <stdlib.h>
  38. #include <assert.h>
  39. #include <limits.h>
  40. #include "dict.h"
  41. /* -------------------------- private prototypes ---------------------------- */
  42. static int _dictExpandIfNeeded(dict *ht);
  43. static unsigned long _dictNextPower(unsigned long size);
  44. static int _dictKeyIndex(dict *ht, const void *key);
  45. static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
  46. /* -------------------------- hash functions -------------------------------- */
  47. /* Generic hash function (a popular one from Bernstein).
  48. * I tested a few and this was the best. */
  49. static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
  50. unsigned int hash = 5381;
  51. while (len--)
  52. hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
  53. return hash;
  54. }
  55. /* ----------------------------- API implementation ------------------------- */
  56. /* Reset an hashtable already initialized with ht_init().
  57. * NOTE: This function should only called by ht_destroy(). */
  58. static void _dictReset(dict *ht) {
  59. ht->table = NULL;
  60. ht->size = 0;
  61. ht->sizemask = 0;
  62. ht->used = 0;
  63. }
  64. /* Create a new hash table */
  65. static dict *dictCreate(dictType *type, void *privDataPtr) {
  66. dict *ht = hi_malloc(sizeof(*ht));
  67. if (ht == NULL)
  68. return NULL;
  69. _dictInit(ht,type,privDataPtr);
  70. return ht;
  71. }
  72. /* Initialize the hash table */
  73. static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
  74. _dictReset(ht);
  75. ht->type = type;
  76. ht->privdata = privDataPtr;
  77. return DICT_OK;
  78. }
  79. /* Expand or create the hashtable */
  80. static int dictExpand(dict *ht, unsigned long size) {
  81. dict n; /* the new hashtable */
  82. unsigned long realsize = _dictNextPower(size), i;
  83. /* the size is invalid if it is smaller than the number of
  84. * elements already inside the hashtable */
  85. if (ht->used > size)
  86. return DICT_ERR;
  87. _dictInit(&n, ht->type, ht->privdata);
  88. n.size = realsize;
  89. n.sizemask = realsize-1;
  90. n.table = hi_calloc(realsize,sizeof(dictEntry*));
  91. if (n.table == NULL)
  92. return DICT_ERR;
  93. /* Copy all the elements from the old to the new table:
  94. * note that if the old hash table is empty ht->size is zero,
  95. * so dictExpand just creates an hash table. */
  96. n.used = ht->used;
  97. for (i = 0; i < ht->size && ht->used > 0; i++) {
  98. dictEntry *he, *nextHe;
  99. if (ht->table[i] == NULL) continue;
  100. /* For each hash entry on this slot... */
  101. he = ht->table[i];
  102. while(he) {
  103. unsigned int h;
  104. nextHe = he->next;
  105. /* Get the new element index */
  106. h = dictHashKey(ht, he->key) & n.sizemask;
  107. he->next = n.table[h];
  108. n.table[h] = he;
  109. ht->used--;
  110. /* Pass to the next element */
  111. he = nextHe;
  112. }
  113. }
  114. assert(ht->used == 0);
  115. hi_free(ht->table);
  116. /* Remap the new hashtable in the old */
  117. *ht = n;
  118. return DICT_OK;
  119. }
  120. /* Add an element to the target hash table */
  121. static int dictAdd(dict *ht, void *key, void *val) {
  122. int index;
  123. dictEntry *entry;
  124. /* Get the index of the new element, or -1 if
  125. * the element already exists. */
  126. if ((index = _dictKeyIndex(ht, key)) == -1)
  127. return DICT_ERR;
  128. /* Allocates the memory and stores key */
  129. entry = hi_malloc(sizeof(*entry));
  130. if (entry == NULL)
  131. return DICT_ERR;
  132. entry->next = ht->table[index];
  133. ht->table[index] = entry;
  134. /* Set the hash entry fields. */
  135. dictSetHashKey(ht, entry, key);
  136. dictSetHashVal(ht, entry, val);
  137. ht->used++;
  138. return DICT_OK;
  139. }
  140. /* Add an element, discarding the old if the key already exists.
  141. * Return 1 if the key was added from scratch, 0 if there was already an
  142. * element with such key and dictReplace() just performed a value update
  143. * operation. */
  144. static int dictReplace(dict *ht, void *key, void *val) {
  145. dictEntry *entry, auxentry;
  146. /* Try to add the element. If the key
  147. * does not exists dictAdd will succeed. */
  148. if (dictAdd(ht, key, val) == DICT_OK)
  149. return 1;
  150. /* It already exists, get the entry */
  151. entry = dictFind(ht, key);
  152. if (entry == NULL)
  153. return 0;
  154. /* Free the old value and set the new one */
  155. /* Set the new value and free the old one. Note that it is important
  156. * to do that in this order, as the value may just be exactly the same
  157. * as the previous one. In this context, think to reference counting,
  158. * you want to increment (set), and then decrement (free), and not the
  159. * reverse. */
  160. auxentry = *entry;
  161. dictSetHashVal(ht, entry, val);
  162. dictFreeEntryVal(ht, &auxentry);
  163. return 0;
  164. }
  165. /* Search and remove an element */
  166. static int dictDelete(dict *ht, const void *key) {
  167. unsigned int h;
  168. dictEntry *de, *prevde;
  169. if (ht->size == 0)
  170. return DICT_ERR;
  171. h = dictHashKey(ht, key) & ht->sizemask;
  172. de = ht->table[h];
  173. prevde = NULL;
  174. while(de) {
  175. if (dictCompareHashKeys(ht,key,de->key)) {
  176. /* Unlink the element from the list */
  177. if (prevde)
  178. prevde->next = de->next;
  179. else
  180. ht->table[h] = de->next;
  181. dictFreeEntryKey(ht,de);
  182. dictFreeEntryVal(ht,de);
  183. hi_free(de);
  184. ht->used--;
  185. return DICT_OK;
  186. }
  187. prevde = de;
  188. de = de->next;
  189. }
  190. return DICT_ERR; /* not found */
  191. }
  192. /* Destroy an entire hash table */
  193. static int _dictClear(dict *ht) {
  194. unsigned long i;
  195. /* Free all the elements */
  196. for (i = 0; i < ht->size && ht->used > 0; i++) {
  197. dictEntry *he, *nextHe;
  198. if ((he = ht->table[i]) == NULL) continue;
  199. while(he) {
  200. nextHe = he->next;
  201. dictFreeEntryKey(ht, he);
  202. dictFreeEntryVal(ht, he);
  203. hi_free(he);
  204. ht->used--;
  205. he = nextHe;
  206. }
  207. }
  208. /* Free the table and the allocated cache structure */
  209. hi_free(ht->table);
  210. /* Re-initialize the table */
  211. _dictReset(ht);
  212. return DICT_OK; /* never fails */
  213. }
  214. /* Clear & Release the hash table */
  215. static void dictRelease(dict *ht) {
  216. _dictClear(ht);
  217. hi_free(ht);
  218. }
  219. static dictEntry *dictFind(dict *ht, const void *key) {
  220. dictEntry *he;
  221. unsigned int h;
  222. if (ht->size == 0) return NULL;
  223. h = dictHashKey(ht, key) & ht->sizemask;
  224. he = ht->table[h];
  225. while(he) {
  226. if (dictCompareHashKeys(ht, key, he->key))
  227. return he;
  228. he = he->next;
  229. }
  230. return NULL;
  231. }
  232. static dictIterator *dictGetIterator(dict *ht) {
  233. dictIterator *iter = hi_malloc(sizeof(*iter));
  234. if (iter == NULL)
  235. return NULL;
  236. iter->ht = ht;
  237. iter->index = -1;
  238. iter->entry = NULL;
  239. iter->nextEntry = NULL;
  240. return iter;
  241. }
  242. static dictEntry *dictNext(dictIterator *iter) {
  243. while (1) {
  244. if (iter->entry == NULL) {
  245. iter->index++;
  246. if (iter->index >=
  247. (signed)iter->ht->size) break;
  248. iter->entry = iter->ht->table[iter->index];
  249. } else {
  250. iter->entry = iter->nextEntry;
  251. }
  252. if (iter->entry) {
  253. /* We need to save the 'next' here, the iterator user
  254. * may delete the entry we are returning. */
  255. iter->nextEntry = iter->entry->next;
  256. return iter->entry;
  257. }
  258. }
  259. return NULL;
  260. }
  261. static void dictReleaseIterator(dictIterator *iter) {
  262. hi_free(iter);
  263. }
  264. /* ------------------------- private functions ------------------------------ */
  265. /* Expand the hash table if needed */
  266. static int _dictExpandIfNeeded(dict *ht) {
  267. /* If the hash table is empty expand it to the initial size,
  268. * if the table is "full" double its size. */
  269. if (ht->size == 0)
  270. return dictExpand(ht, DICT_HT_INITIAL_SIZE);
  271. if (ht->used == ht->size)
  272. return dictExpand(ht, ht->size*2);
  273. return DICT_OK;
  274. }
  275. /* Our hash table capability is a power of two */
  276. static unsigned long _dictNextPower(unsigned long size) {
  277. unsigned long i = DICT_HT_INITIAL_SIZE;
  278. if (size >= LONG_MAX) return LONG_MAX;
  279. while(1) {
  280. if (i >= size)
  281. return i;
  282. i *= 2;
  283. }
  284. }
  285. /* Returns the index of a free slot that can be populated with
  286. * an hash entry for the given 'key'.
  287. * If the key already exists, -1 is returned. */
  288. static int _dictKeyIndex(dict *ht, const void *key) {
  289. unsigned int h;
  290. dictEntry *he;
  291. /* Expand the hashtable if needed */
  292. if (_dictExpandIfNeeded(ht) == DICT_ERR)
  293. return -1;
  294. /* Compute the key hash value */
  295. h = dictHashKey(ht, key) & ht->sizemask;
  296. /* Search if this slot does not already contain the given key */
  297. he = ht->table[h];
  298. while(he) {
  299. if (dictCompareHashKeys(ht, key, he->key))
  300. return -1;
  301. he = he->next;
  302. }
  303. return h;
  304. }