You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dict.c 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. if (entry) {
  152. auxentry = *entry;
  153. dictSetHashVal(ht, entry, val);
  154. dictFreeEntryVal(ht, &auxentry);
  155. }
  156. return 0;
  157. }
  158. /* Search and remove an element */
  159. static int dictDelete(dict *ht, const void *key) {
  160. unsigned int h;
  161. dictEntry *de, *prevde;
  162. if (ht->size == 0)
  163. return DICT_ERR;
  164. h = dictHashKey(ht, key) & ht->sizemask;
  165. de = ht->table[h];
  166. prevde = NULL;
  167. while(de) {
  168. if (dictCompareHashKeys(ht,key,de->key)) {
  169. /* Unlink the element from the list */
  170. if (prevde)
  171. prevde->next = de->next;
  172. else
  173. ht->table[h] = de->next;
  174. dictFreeEntryKey(ht,de);
  175. dictFreeEntryVal(ht,de);
  176. free(de);
  177. ht->used--;
  178. return DICT_OK;
  179. }
  180. prevde = de;
  181. de = de->next;
  182. }
  183. return DICT_ERR; /* not found */
  184. }
  185. /* Destroy an entire hash table */
  186. static int _dictClear(dict *ht) {
  187. unsigned long i;
  188. /* Free all the elements */
  189. for (i = 0; i < ht->size && ht->used > 0; i++) {
  190. dictEntry *he, *nextHe;
  191. if ((he = ht->table[i]) == NULL) continue;
  192. while(he) {
  193. nextHe = he->next;
  194. dictFreeEntryKey(ht, he);
  195. dictFreeEntryVal(ht, he);
  196. free(he);
  197. ht->used--;
  198. he = nextHe;
  199. }
  200. }
  201. /* Free the table and the allocated cache structure */
  202. free(ht->table);
  203. /* Re-initialize the table */
  204. _dictReset(ht);
  205. return DICT_OK; /* never fails */
  206. }
  207. /* Clear & Release the hash table */
  208. static void dictRelease(dict *ht) {
  209. _dictClear(ht);
  210. free(ht);
  211. }
  212. static dictEntry *dictFind(dict *ht, const void *key) {
  213. dictEntry *he;
  214. unsigned int h;
  215. if (ht->size == 0) return NULL;
  216. h = dictHashKey(ht, key) & ht->sizemask;
  217. he = ht->table[h];
  218. while(he) {
  219. if (dictCompareHashKeys(ht, key, he->key))
  220. return he;
  221. he = he->next;
  222. }
  223. return NULL;
  224. }
  225. static dictIterator *dictGetIterator(dict *ht) {
  226. dictIterator *iter = malloc(sizeof(*iter));
  227. iter->ht = ht;
  228. iter->index = -1;
  229. iter->entry = NULL;
  230. iter->nextEntry = NULL;
  231. return iter;
  232. }
  233. static dictEntry *dictNext(dictIterator *iter) {
  234. while (1) {
  235. if (iter->entry == NULL) {
  236. iter->index++;
  237. if (iter->index >=
  238. (signed)iter->ht->size) break;
  239. iter->entry = iter->ht->table[iter->index];
  240. } else {
  241. iter->entry = iter->nextEntry;
  242. }
  243. if (iter->entry) {
  244. /* We need to save the 'next' here, the iterator user
  245. * may delete the entry we are returning. */
  246. iter->nextEntry = iter->entry->next;
  247. return iter->entry;
  248. }
  249. }
  250. return NULL;
  251. }
  252. static void dictReleaseIterator(dictIterator *iter) {
  253. free(iter);
  254. }
  255. /* ------------------------- private functions ------------------------------ */
  256. /* Expand the hash table if needed */
  257. static int _dictExpandIfNeeded(dict *ht) {
  258. /* If the hash table is empty expand it to the initial size,
  259. * if the table is "full" dobule its size. */
  260. if (ht->size == 0)
  261. return dictExpand(ht, DICT_HT_INITIAL_SIZE);
  262. if (ht->used == ht->size)
  263. return dictExpand(ht, ht->size*2);
  264. return DICT_OK;
  265. }
  266. /* Our hash table capability is a power of two */
  267. static unsigned long _dictNextPower(unsigned long size) {
  268. unsigned long i = DICT_HT_INITIAL_SIZE;
  269. if (size >= LONG_MAX) return LONG_MAX;
  270. while(1) {
  271. if (i >= size)
  272. return i;
  273. i *= 2;
  274. }
  275. }
  276. /* Returns the index of a free slot that can be populated with
  277. * an hash entry for the given 'key'.
  278. * If the key already exists, -1 is returned. */
  279. static int _dictKeyIndex(dict *ht, const void *key) {
  280. unsigned int h;
  281. dictEntry *he;
  282. /* Expand the hashtable if needed */
  283. if (_dictExpandIfNeeded(ht) == DICT_ERR)
  284. return -1;
  285. /* Compute the key hash value */
  286. h = dictHashKey(ht, key) & ht->sizemask;
  287. /* Search if this slot does not already contain the given key */
  288. he = ht->table[h];
  289. while(he) {
  290. if (dictCompareHashKeys(ht, key, he->key))
  291. return -1;
  292. he = he->next;
  293. }
  294. return h;
  295. }