诸暨麻将添加redis
您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
 
 
 
 
 
 

340 行
10 KiB

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