2
0

dict.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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 <stdlib.h>
  37. #include <assert.h>
  38. #include <limits.h>
  39. #include "dict.h"
  40. /* -------------------------- private prototypes ---------------------------- */
  41. static int _dictExpandIfNeeded(dict *ht);
  42. static unsigned long _dictNextPower(unsigned long size);
  43. static int _dictKeyIndex(dict *ht, const void *key);
  44. static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
  45. /* -------------------------- hash functions -------------------------------- */
  46. /* Generic hash function (a popular one from Bernstein).
  47. * I tested a few and this was the best. */
  48. static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
  49. unsigned int hash = 5381;
  50. while (len--)
  51. hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
  52. return hash;
  53. }
  54. /* ----------------------------- API implementation ------------------------- */
  55. /* Reset an hashtable already initialized with ht_init().
  56. * NOTE: This function should only called by ht_destroy(). */
  57. static void _dictReset(dict *ht) {
  58. ht->table = NULL;
  59. ht->size = 0;
  60. ht->sizemask = 0;
  61. ht->used = 0;
  62. }
  63. /* Create a new hash table */
  64. static dict *dictCreate(dictType *type, void *privDataPtr) {
  65. dict *ht = malloc(sizeof(*ht));
  66. _dictInit(ht,type,privDataPtr);
  67. return ht;
  68. }
  69. /* Initialize the hash table */
  70. static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
  71. _dictReset(ht);
  72. ht->type = type;
  73. ht->privdata = privDataPtr;
  74. return DICT_OK;
  75. }
  76. /* Expand or create the hashtable */
  77. static int dictExpand(dict *ht, unsigned long size) {
  78. dict n; /* the new hashtable */
  79. unsigned long realsize = _dictNextPower(size), i;
  80. /* the size is invalid if it is smaller than the number of
  81. * elements already inside the hashtable */
  82. if (ht->used > size)
  83. return DICT_ERR;
  84. _dictInit(&n, ht->type, ht->privdata);
  85. n.size = realsize;
  86. n.sizemask = realsize-1;
  87. n.table = calloc(realsize,sizeof(dictEntry*));
  88. /* Copy all the elements from the old to the new table:
  89. * note that if the old hash table is empty ht->size is zero,
  90. * so dictExpand just creates an hash table. */
  91. n.used = ht->used;
  92. for (i = 0; i < ht->size && ht->used > 0; i++) {
  93. dictEntry *he, *nextHe;
  94. if (ht->table[i] == NULL) continue;
  95. /* For each hash entry on this slot... */
  96. he = ht->table[i];
  97. while(he) {
  98. unsigned int h;
  99. nextHe = he->next;
  100. /* Get the new element index */
  101. h = dictHashKey(ht, he->key) & n.sizemask;
  102. he->next = n.table[h];
  103. n.table[h] = he;
  104. ht->used--;
  105. /* Pass to the next element */
  106. he = nextHe;
  107. }
  108. }
  109. assert(ht->used == 0);
  110. free(ht->table);
  111. /* Remap the new hashtable in the old */
  112. *ht = n;
  113. return DICT_OK;
  114. }
  115. /* Add an element to the target hash table */
  116. static int dictAdd(dict *ht, void *key, void *val) {
  117. int index;
  118. dictEntry *entry;
  119. /* Get the index of the new element, or -1 if
  120. * the element already exists. */
  121. if ((index = _dictKeyIndex(ht, key)) == -1)
  122. return DICT_ERR;
  123. /* Allocates the memory and stores key */
  124. entry = malloc(sizeof(*entry));
  125. entry->next = ht->table[index];
  126. ht->table[index] = entry;
  127. /* Set the hash entry fields. */
  128. dictSetHashKey(ht, entry, key);
  129. dictSetHashVal(ht, entry, val);
  130. ht->used++;
  131. return DICT_OK;
  132. }
  133. /* Add an element, discarding the old if the key already exists.
  134. * Return 1 if the key was added from scratch, 0 if there was already an
  135. * element with such key and dictReplace() just performed a value update
  136. * operation. */
  137. static int dictReplace(dict *ht, void *key, void *val) {
  138. dictEntry *entry, auxentry;
  139. /* Try to add the element. If the key
  140. * does not exists dictAdd will succeed. */
  141. if (dictAdd(ht, key, val) == DICT_OK)
  142. return 1;
  143. /* It already exists, get the entry */
  144. entry = dictFind(ht, key);
  145. /* Free the old value and set the new one */
  146. /* Set the new value and free the old one. Note that it is important
  147. * to do that in this order, as the value may just be exactly the same
  148. * as the previous one. In this context, think to reference counting,
  149. * you want to increment (set), and then decrement (free), and not the
  150. * reverse. */
  151. auxentry = *entry;
  152. dictSetHashVal(ht, entry, val);
  153. dictFreeEntryVal(ht, &auxentry);
  154. return 0;
  155. }
  156. /* Search and remove an element */
  157. static int dictDelete(dict *ht, const void *key) {
  158. unsigned int h;
  159. dictEntry *de, *prevde;
  160. if (ht->size == 0)
  161. return DICT_ERR;
  162. h = dictHashKey(ht, key) & ht->sizemask;
  163. de = ht->table[h];
  164. prevde = NULL;
  165. while(de) {
  166. if (dictCompareHashKeys(ht,key,de->key)) {
  167. /* Unlink the element from the list */
  168. if (prevde)
  169. prevde->next = de->next;
  170. else
  171. ht->table[h] = de->next;
  172. dictFreeEntryKey(ht,de);
  173. dictFreeEntryVal(ht,de);
  174. free(de);
  175. ht->used--;
  176. return DICT_OK;
  177. }
  178. prevde = de;
  179. de = de->next;
  180. }
  181. return DICT_ERR; /* not found */
  182. }
  183. /* Destroy an entire hash table */
  184. static int _dictClear(dict *ht) {
  185. unsigned long i;
  186. /* Free all the elements */
  187. for (i = 0; i < ht->size && ht->used > 0; i++) {
  188. dictEntry *he, *nextHe;
  189. if ((he = ht->table[i]) == NULL) continue;
  190. while(he) {
  191. nextHe = he->next;
  192. dictFreeEntryKey(ht, he);
  193. dictFreeEntryVal(ht, he);
  194. free(he);
  195. ht->used--;
  196. he = nextHe;
  197. }
  198. }
  199. /* Free the table and the allocated cache structure */
  200. free(ht->table);
  201. /* Re-initialize the table */
  202. _dictReset(ht);
  203. return DICT_OK; /* never fails */
  204. }
  205. /* Clear & Release the hash table */
  206. static void dictRelease(dict *ht) {
  207. _dictClear(ht);
  208. free(ht);
  209. }
  210. static dictEntry *dictFind(dict *ht, const void *key) {
  211. dictEntry *he;
  212. unsigned int h;
  213. if (ht->size == 0) return NULL;
  214. h = dictHashKey(ht, key) & ht->sizemask;
  215. he = ht->table[h];
  216. while(he) {
  217. if (dictCompareHashKeys(ht, key, he->key))
  218. return he;
  219. he = he->next;
  220. }
  221. return NULL;
  222. }
  223. static dictIterator *dictGetIterator(dict *ht) {
  224. dictIterator *iter = malloc(sizeof(*iter));
  225. iter->ht = ht;
  226. iter->index = -1;
  227. iter->entry = NULL;
  228. iter->nextEntry = NULL;
  229. return iter;
  230. }
  231. static dictEntry *dictNext(dictIterator *iter) {
  232. while (1) {
  233. if (iter->entry == NULL) {
  234. iter->index++;
  235. if (iter->index >=
  236. (signed)iter->ht->size) break;
  237. iter->entry = iter->ht->table[iter->index];
  238. } else {
  239. iter->entry = iter->nextEntry;
  240. }
  241. if (iter->entry) {
  242. /* We need to save the 'next' here, the iterator user
  243. * may delete the entry we are returning. */
  244. iter->nextEntry = iter->entry->next;
  245. return iter->entry;
  246. }
  247. }
  248. return NULL;
  249. }
  250. static void dictReleaseIterator(dictIterator *iter) {
  251. free(iter);
  252. }
  253. /* ------------------------- private functions ------------------------------ */
  254. /* Expand the hash table if needed */
  255. static int _dictExpandIfNeeded(dict *ht) {
  256. /* If the hash table is empty expand it to the initial size,
  257. * if the table is "full" dobule its size. */
  258. if (ht->size == 0)
  259. return dictExpand(ht, DICT_HT_INITIAL_SIZE);
  260. if (ht->used == ht->size)
  261. return dictExpand(ht, ht->size*2);
  262. return DICT_OK;
  263. }
  264. /* Our hash table capability is a power of two */
  265. static unsigned long _dictNextPower(unsigned long size) {
  266. unsigned long i = DICT_HT_INITIAL_SIZE;
  267. if (size >= LONG_MAX) return LONG_MAX;
  268. while(1) {
  269. if (i >= size)
  270. return i;
  271. i *= 2;
  272. }
  273. }
  274. /* Returns the index of a free slot that can be populated with
  275. * an hash entry for the given 'key'.
  276. * If the key already exists, -1 is returned. */
  277. static int _dictKeyIndex(dict *ht, const void *key) {
  278. unsigned int h;
  279. dictEntry *he;
  280. /* Expand the hashtable if needed */
  281. if (_dictExpandIfNeeded(ht) == DICT_ERR)
  282. return -1;
  283. /* Compute the key hash value */
  284. h = dictHashKey(ht, key) & ht->sizemask;
  285. /* Search if this slot does not already contain the given key */
  286. he = ht->table[h];
  287. while(he) {
  288. if (dictCompareHashKeys(ht, key, he->key))
  289. return -1;
  290. he = he->next;
  291. }
  292. return h;
  293. }