hash_table.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2008 Bryan Drewery
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. /* hash_table.c: hash table implementation
  21. *
  22. */
  23. #include "common.h"
  24. #include "hash_table.h"
  25. static unsigned int my_string_hash(const void *key);
  26. static unsigned int my_int_hash(const void *key);
  27. static unsigned int my_mixed_hash (const void *key);
  28. static int my_int_cmp(const void *left, const void *right);
  29. hash_table_t *hash_table_create(hash_table_hash_alg alg, hash_table_cmp_alg cmp, int nrows, int flags)
  30. {
  31. hash_table_t *ht = NULL;
  32. if (nrows <= 0) nrows = 13; /* Give them a small table to start with. */
  33. ht = (hash_table_t *) my_calloc(1, sizeof(*ht));
  34. ht->rows = (hash_table_row_t *) my_calloc(nrows, sizeof(*ht->rows));
  35. if (alg) ht->hash = alg;
  36. else {
  37. if (flags & HASH_TABLE_STRINGS) ht->hash = my_string_hash;
  38. else if (flags & HASH_TABLE_INTS) ht->hash = my_int_hash;
  39. else ht->hash = my_mixed_hash;
  40. }
  41. if (cmp) ht->cmp = cmp;
  42. else {
  43. if (flags & HASH_TABLE_INTS) ht->cmp = my_int_cmp;
  44. else ht->cmp = (hash_table_cmp_alg) strcmp;
  45. }
  46. ht->flags = flags;
  47. ht->max_rows = nrows;
  48. return(ht);
  49. }
  50. int hash_table_delete(hash_table_t *ht)
  51. {
  52. hash_table_entry_t *entry = NULL, *next = NULL;
  53. hash_table_row_t *row = NULL;
  54. int i;
  55. if (!ht) return(-1);
  56. for (i = 0; i < ht->max_rows; i++) {
  57. row = ht->rows+i;
  58. for (entry = row->head; entry; entry = next) {
  59. next = entry->next;
  60. free(entry);
  61. }
  62. }
  63. free(ht->rows);
  64. free(ht);
  65. return(0);
  66. }
  67. int hash_table_check_resize(hash_table_t *ht)
  68. {
  69. if (!ht) return(-1);
  70. /* This 100 allows (ht->max_rows) linked lists each with an average of 100 elements in the list
  71. * before actually resizing.
  72. * This is done to avoid a very slow and cpu intensive resize which requires recalculating all hashes.
  73. * Having (ht->max_rows) linked lists is still more effecient than one large linked list.
  74. */
  75. if (ht->cells_in_use / ht->max_rows > 100) {
  76. hash_table_resize(ht, ht->max_rows * 3);
  77. }
  78. return(0);
  79. }
  80. int hash_table_resize(hash_table_t *ht, int nrows)
  81. {
  82. int i, newidx;
  83. hash_table_row_t *oldrow = NULL, *newrows = NULL;
  84. hash_table_entry_t *entry = NULL, *next = NULL;
  85. if (!ht) return(-1);
  86. /* First allocate the new rows. */
  87. newrows = (hash_table_row_t *) my_calloc(nrows, sizeof(*newrows));
  88. /* Now populate it with the old entries. */
  89. for (i = 0; i < ht->max_rows; i++) {
  90. oldrow = ht->rows+i;
  91. for (entry = oldrow->head; entry; entry = next) {
  92. next = entry->next;
  93. newidx = entry->hash % nrows;
  94. entry->next = newrows[newidx].head;
  95. newrows[newidx].head = entry;
  96. newrows[newidx].len++;
  97. }
  98. }
  99. free(ht->rows);
  100. ht->rows = newrows;
  101. ht->max_rows = nrows;
  102. return(0);
  103. }
  104. int hash_table_insert(hash_table_t *ht, const void *key, void *data)
  105. {
  106. unsigned int hash;
  107. int idx;
  108. hash_table_entry_t *entry = NULL;
  109. hash_table_row_t *row = NULL;
  110. if (!ht) return(-1);
  111. hash = ht->hash(key);
  112. idx = hash % ht->max_rows;
  113. row = ht->rows+idx;
  114. /* Allocate an entry. */
  115. entry = (hash_table_entry_t *) my_calloc(1, sizeof(*entry));
  116. entry->key = key;
  117. entry->data = data;
  118. entry->hash = hash;
  119. /* Insert it into the list. */
  120. entry->next = row->head;
  121. row->head = entry;
  122. /* Update stats. */
  123. row->len++;
  124. ht->cells_in_use++;
  125. /* See if we need to update the table. */
  126. if (!(ht->flags & HASH_TABLE_NORESIZE)) {
  127. hash_table_check_resize(ht);
  128. }
  129. return(0);
  130. }
  131. int hash_table_find(hash_table_t *ht, const void *key, void *dataptr)
  132. {
  133. int idx;
  134. unsigned int hash;
  135. hash_table_entry_t *entry = NULL;
  136. hash_table_row_t *row = NULL;
  137. if (!ht) return (-1);
  138. hash = ht->hash(key);
  139. idx = hash % ht->max_rows;
  140. row = ht->rows+idx;
  141. for (entry = row->head; entry; entry = entry->next) {
  142. if (hash == entry->hash && !ht->cmp(key, entry->key)) {
  143. *(void **)dataptr = entry->data;
  144. return(0);
  145. }
  146. }
  147. return(-1);
  148. }
  149. int hash_table_remove(hash_table_t *ht, const void *key, void *dataptr)
  150. {
  151. int idx;
  152. unsigned int hash;
  153. hash_table_entry_t *entry = NULL, *last = NULL;
  154. hash_table_row_t *row = NULL;
  155. if (!ht) return(-1);
  156. hash = ht->hash(key);
  157. idx = hash % ht->max_rows;
  158. row = ht->rows+idx;
  159. last = NULL;
  160. for (entry = row->head; entry; entry = entry->next) {
  161. if (hash == entry->hash && !ht->cmp(key, entry->key)) {
  162. if (dataptr) *(void **)dataptr = entry->data;
  163. /* Remove it from the row's list. */
  164. if (last) last->next = entry->next;
  165. else row->head = entry->next;
  166. free(entry);
  167. ht->cells_in_use--;
  168. return(0);
  169. }
  170. last = entry;
  171. }
  172. return(-1);
  173. }
  174. int hash_table_walk(hash_table_t *ht, hash_table_node_func callback, void *param)
  175. {
  176. if (!ht) return(-1);
  177. hash_table_row_t *row = NULL;
  178. hash_table_entry_t *entry = NULL, *next = NULL;
  179. int i;
  180. for (i = 0; i < ht->max_rows; i++) {
  181. row = ht->rows+i;
  182. for (entry = row->head; entry;) {
  183. next = entry->next;
  184. callback(entry->key, &entry->data, param);
  185. entry = next;
  186. }
  187. }
  188. return(0);
  189. }
  190. static int my_int_cmp(const void *left, const void *right)
  191. {
  192. return((long) left - (long) right);
  193. }
  194. static unsigned int my_string_hash(const void *key)
  195. {
  196. int hash, loop;
  197. size_t keylen;
  198. const unsigned char *k = NULL;
  199. #define HASHC hash = *k++ + 65599 * hash
  200. hash = 0;
  201. k = (const unsigned char *) key;
  202. keylen = strlen((const char *) key);
  203. if (!keylen) return(0);
  204. loop = (keylen + 8 - 1) >> 3;
  205. switch (keylen & (8 - 1)) {
  206. case 0:
  207. do {
  208. HASHC;
  209. case 7:
  210. HASHC;
  211. case 6:
  212. HASHC;
  213. case 5:
  214. HASHC;
  215. case 4:
  216. HASHC;
  217. case 3:
  218. HASHC;
  219. case 2:
  220. HASHC;
  221. case 1:
  222. HASHC;
  223. } while (--loop);
  224. }
  225. return(hash);
  226. }
  227. static unsigned int my_int_hash(const void *key)
  228. {
  229. return((unsigned long)key);
  230. }
  231. static unsigned int my_mixed_hash (const void *key)
  232. {
  233. const unsigned char *k = NULL;
  234. unsigned int hash;
  235. k = (const unsigned char *) key;
  236. hash = 0;
  237. while (*k) {
  238. hash *= 16777619;
  239. hash ^= *k++;
  240. }
  241. return(hash);
  242. }