zc_hashtable.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /*
  2. * This file is part of the zlog Library.
  3. *
  4. * Copyright (C) 2011 by Hardy Simpson <HardySimpson1984@gmail.com>
  5. *
  6. * Licensed under the LGPL v2.1, see the file COPYING in base directory.
  7. */
  8. #include <stdlib.h>
  9. #include <errno.h>
  10. #include <pthread.h>
  11. #include "zc_defs.h"
  12. #include "zc_hashtable.h"
  13. struct zc_hashtable_s {
  14. size_t nelem;
  15. zc_hashtable_entry_t **tab;
  16. size_t tab_size;
  17. zc_hashtable_hash_fn hash;
  18. zc_hashtable_equal_fn equal;
  19. zc_hashtable_del_fn key_del;
  20. zc_hashtable_del_fn value_del;
  21. };
  22. zc_hashtable_t *zc_hashtable_new(size_t a_size,
  23. zc_hashtable_hash_fn hash,
  24. zc_hashtable_equal_fn equal,
  25. zc_hashtable_del_fn key_del,
  26. zc_hashtable_del_fn value_del)
  27. {
  28. zc_hashtable_t *a_table;
  29. a_table = calloc(1, sizeof(*a_table));
  30. if (!a_table) {
  31. zc_error("calloc fail, errno[%d]", errno);
  32. return NULL;
  33. }
  34. a_table->tab = calloc(a_size, sizeof(*(a_table->tab)));
  35. if (!a_table->tab) {
  36. zc_error("calloc fail, errno[%d]", errno);
  37. free(a_table);
  38. return NULL;
  39. }
  40. a_table->tab_size = a_size;
  41. a_table->nelem = 0;
  42. a_table->hash = hash;
  43. a_table->equal = equal;
  44. /* these two could be NULL */
  45. a_table->key_del = key_del;
  46. a_table->value_del = value_del;
  47. return a_table;
  48. }
  49. void zc_hashtable_del(zc_hashtable_t * a_table)
  50. {
  51. size_t i;
  52. zc_hashtable_entry_t *p;
  53. zc_hashtable_entry_t *q;
  54. if (!a_table) {
  55. zc_error("a_table[%p] is NULL, just do nothing", a_table);
  56. return;
  57. }
  58. for (i = 0; i < a_table->tab_size; i++) {
  59. for (p = (a_table->tab)[i]; p; p = q) {
  60. q = p->next;
  61. if (a_table->key_del) {
  62. a_table->key_del(p->key);
  63. }
  64. if (a_table->value_del) {
  65. a_table->value_del(p->value);
  66. }
  67. free(p);
  68. }
  69. }
  70. if (a_table->tab)
  71. free(a_table->tab);
  72. free(a_table);
  73. return;
  74. }
  75. void zc_hashtable_clean(zc_hashtable_t * a_table)
  76. {
  77. size_t i;
  78. zc_hashtable_entry_t *p;
  79. zc_hashtable_entry_t *q;
  80. for (i = 0; i < a_table->tab_size; i++) {
  81. for (p = (a_table->tab)[i]; p; p = q) {
  82. q = p->next;
  83. if (a_table->key_del) {
  84. a_table->key_del(p->key);
  85. }
  86. if (a_table->value_del) {
  87. a_table->value_del(p->value);
  88. }
  89. free(p);
  90. }
  91. (a_table->tab)[i] = NULL;
  92. }
  93. a_table->nelem = 0;
  94. return;
  95. }
  96. static int zc_hashtable_rehash(zc_hashtable_t * a_table)
  97. {
  98. size_t i;
  99. size_t j;
  100. size_t tab_size;
  101. zc_hashtable_entry_t **tab;
  102. zc_hashtable_entry_t *p;
  103. zc_hashtable_entry_t *q;
  104. tab_size = 2 * a_table->tab_size;
  105. tab = calloc(tab_size, sizeof(*tab));
  106. if (!tab) {
  107. zc_error("calloc fail, errno[%d]", errno);
  108. return -1;
  109. }
  110. for (i = 0; i < a_table->tab_size; i++) {
  111. for (p = (a_table->tab)[i]; p; p = q) {
  112. q = p->next;
  113. p->next = NULL;
  114. p->prev = NULL;
  115. j = p->hash_key % tab_size;
  116. if (tab[j]) {
  117. tab[j]->prev = p;
  118. p->next = tab[j];
  119. }
  120. tab[j] = p;
  121. }
  122. }
  123. free(a_table->tab);
  124. a_table->tab = tab;
  125. a_table->tab_size = tab_size;
  126. return 0;
  127. }
  128. zc_hashtable_entry_t *zc_hashtable_get_entry(zc_hashtable_t * a_table, const void *a_key)
  129. {
  130. unsigned int i;
  131. zc_hashtable_entry_t *p;
  132. i = a_table->hash(a_key) % a_table->tab_size;
  133. for (p = (a_table->tab)[i]; p; p = p->next) {
  134. if (a_table->equal(a_key, p->key))
  135. return p;
  136. }
  137. return NULL;
  138. }
  139. void *zc_hashtable_get(zc_hashtable_t * a_table, const void *a_key)
  140. {
  141. unsigned int i;
  142. zc_hashtable_entry_t *p;
  143. i = a_table->hash(a_key) % a_table->tab_size;
  144. for (p = (a_table->tab)[i]; p; p = p->next) {
  145. if (a_table->equal(a_key, p->key))
  146. return p->value;
  147. }
  148. return NULL;
  149. }
  150. int zc_hashtable_put(zc_hashtable_t * a_table, void *a_key, void *a_value)
  151. {
  152. int rc = 0;
  153. unsigned int i;
  154. zc_hashtable_entry_t *p = NULL;
  155. i = a_table->hash(a_key) % a_table->tab_size;
  156. for (p = (a_table->tab)[i]; p; p = p->next) {
  157. if (a_table->equal(a_key, p->key))
  158. break;
  159. }
  160. if (p) {
  161. if (a_table->key_del) {
  162. a_table->key_del(p->key);
  163. }
  164. if (a_table->value_del) {
  165. a_table->value_del(p->value);
  166. }
  167. p->key = a_key;
  168. p->value = a_value;
  169. return 0;
  170. } else {
  171. if (a_table->nelem > a_table->tab_size * 1.3) {
  172. rc = zc_hashtable_rehash(a_table);
  173. if (rc) {
  174. zc_error("rehash fail");
  175. return -1;
  176. }
  177. }
  178. p = calloc(1, sizeof(*p));
  179. if (!p) {
  180. zc_error("calloc fail, errno[%d]", errno);
  181. return -1;
  182. }
  183. p->hash_key = a_table->hash(a_key);
  184. p->key = a_key;
  185. p->value = a_value;
  186. p->next = NULL;
  187. p->prev = NULL;
  188. i = p->hash_key % a_table->tab_size;
  189. if ((a_table->tab)[i]) {
  190. (a_table->tab)[i]->prev = p;
  191. p->next = (a_table->tab)[i];
  192. }
  193. (a_table->tab)[i] = p;
  194. a_table->nelem++;
  195. }
  196. return 0;
  197. }
  198. void zc_hashtable_remove(zc_hashtable_t * a_table, const void *a_key)
  199. {
  200. zc_hashtable_entry_t *p;
  201. unsigned int i;
  202. if (!a_table || !a_key) {
  203. zc_error("a_table[%p] or a_key[%p] is NULL, just do nothing", a_table, a_key);
  204. return;
  205. }
  206. i = a_table->hash(a_key) % a_table->tab_size;
  207. for (p = (a_table->tab)[i]; p; p = p->next) {
  208. if (a_table->equal(a_key, p->key))
  209. break;
  210. }
  211. if (!p) {
  212. zc_error("p[%p] not found in hashtable", p);
  213. return;
  214. }
  215. if (a_table->key_del) {
  216. a_table->key_del(p->key);
  217. }
  218. if (a_table->value_del) {
  219. a_table->value_del(p->value);
  220. }
  221. if (p->next) {
  222. p->next->prev = p->prev;
  223. }
  224. if (p->prev) {
  225. p->prev->next = p->next;
  226. } else {
  227. unsigned int i;
  228. i = p->hash_key % a_table->tab_size;
  229. a_table->tab[i] = p->next;
  230. }
  231. free(p);
  232. a_table->nelem--;
  233. return;
  234. }
  235. zc_hashtable_entry_t *zc_hashtable_begin(zc_hashtable_t * a_table)
  236. {
  237. size_t i;
  238. zc_hashtable_entry_t *p;
  239. for (i = 0; i < a_table->tab_size; i++) {
  240. for (p = (a_table->tab)[i]; p; p = p->next) {
  241. if (p)
  242. return p;
  243. }
  244. }
  245. return NULL;
  246. }
  247. zc_hashtable_entry_t *zc_hashtable_next(zc_hashtable_t * a_table, zc_hashtable_entry_t * a_entry)
  248. {
  249. size_t i;
  250. size_t j;
  251. if (a_entry->next)
  252. return a_entry->next;
  253. i = a_entry->hash_key % a_table->tab_size;
  254. for (j = i + 1; j < a_table->tab_size; j++) {
  255. if ((a_table->tab)[j]) {
  256. return (a_table->tab)[j];
  257. }
  258. }
  259. return NULL;
  260. }
  261. /*******************************************************************************/
  262. unsigned int zc_hashtable_str_hash(const void *str)
  263. {
  264. unsigned int h = 5381;
  265. const char *p = (const char *)str;
  266. while (*p != '\0')
  267. h = ((h << 5) + h) + (*p++); /* hash * 33 + c */
  268. return h;
  269. }
  270. int zc_hashtable_str_equal(const void *key1, const void *key2)
  271. {
  272. return (STRCMP((const char *)key1, ==, (const char *)key2));
  273. }