hash_table.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /* hash_table.c: hash table implementation
  2. *
  3. */
  4. #include "common.h"
  5. #include "hash_table.h"
  6. static unsigned int my_string_hash(const void *key);
  7. static unsigned int my_int_hash(const void *key);
  8. static unsigned int my_mixed_hash (const void *key);
  9. static int my_int_cmp(const void *left, const void *right);
  10. hash_table_t *hash_table_create(hash_table_hash_alg alg, hash_table_cmp_alg cmp, int nrows, int flags)
  11. {
  12. hash_table_t *ht = NULL;
  13. if (nrows <= 0) nrows = 13; /* Give them a small table to start with. */
  14. ht = (hash_table_t *) my_calloc(1, sizeof(*ht));
  15. ht->rows = (hash_table_row_t *) my_calloc(nrows, sizeof(*ht->rows));
  16. if (alg) ht->hash = alg;
  17. else {
  18. if (flags & HASH_TABLE_STRINGS) ht->hash = my_string_hash;
  19. else if (flags & HASH_TABLE_INTS) ht->hash = my_int_hash;
  20. else ht->hash = my_mixed_hash;
  21. }
  22. if (cmp) ht->cmp = cmp;
  23. else {
  24. if (flags & HASH_TABLE_INTS) ht->cmp = my_int_cmp;
  25. else ht->cmp = (hash_table_cmp_alg) strcmp;
  26. }
  27. ht->flags = flags;
  28. ht->max_rows = nrows;
  29. return(ht);
  30. }
  31. int hash_table_delete(hash_table_t *ht)
  32. {
  33. hash_table_entry_t *entry = NULL, *next = NULL;
  34. hash_table_row_t *row = NULL;
  35. int i;
  36. if (!ht) return(-1);
  37. for (i = 0; i < ht->max_rows; i++) {
  38. row = ht->rows+i;
  39. for (entry = row->head; entry; entry = next) {
  40. next = entry->next;
  41. free(entry);
  42. }
  43. }
  44. free(ht->rows);
  45. free(ht);
  46. return(0);
  47. }
  48. int hash_table_check_resize(hash_table_t *ht)
  49. {
  50. if (!ht) return(-1);
  51. if (ht->cells_in_use / ht->max_rows > 100) {
  52. hash_table_resize(ht, ht->max_rows * 3);
  53. }
  54. return(0);
  55. }
  56. int hash_table_resize(hash_table_t *ht, int nrows)
  57. {
  58. int i, newidx;
  59. hash_table_row_t *oldrow = NULL, *newrows = NULL;
  60. hash_table_entry_t *entry = NULL, *next = NULL;
  61. if (!ht) return(-1);
  62. /* First allocate the new rows. */
  63. newrows = (hash_table_row_t *) my_calloc(nrows, sizeof(*newrows));
  64. /* Now populate it with the old entries. */
  65. for (i = 0; i < ht->max_rows; i++) {
  66. oldrow = ht->rows+i;
  67. for (entry = oldrow->head; entry; entry = next) {
  68. next = entry->next;
  69. newidx = entry->hash % nrows;
  70. entry->next = newrows[newidx].head;
  71. newrows[newidx].head = entry;
  72. newrows[newidx].len++;
  73. }
  74. }
  75. free(ht->rows);
  76. ht->rows = newrows;
  77. ht->max_rows = nrows;
  78. return(0);
  79. }
  80. int hash_table_insert(hash_table_t *ht, const void *key, void *data)
  81. {
  82. unsigned int hash;
  83. int idx;
  84. hash_table_entry_t *entry = NULL;
  85. hash_table_row_t *row = NULL;
  86. if (!ht) return(-1);
  87. hash = ht->hash(key);
  88. idx = hash % ht->max_rows;
  89. row = ht->rows+idx;
  90. /* Allocate an entry. */
  91. entry = (hash_table_entry_t *) calloc(1, sizeof(*entry));
  92. entry->key = key;
  93. entry->data = data;
  94. entry->hash = hash;
  95. /* Insert it into the list. */
  96. entry->next = row->head;
  97. row->head = entry;
  98. /* Update stats. */
  99. row->len++;
  100. ht->cells_in_use++;
  101. /* See if we need to update the table. */
  102. if (!(ht->flags & HASH_TABLE_NORESIZE)) {
  103. hash_table_check_resize(ht);
  104. }
  105. return(0);
  106. }
  107. int hash_table_find(hash_table_t *ht, const void *key, void *dataptr)
  108. {
  109. int idx;
  110. unsigned int hash;
  111. hash_table_entry_t *entry = NULL;
  112. hash_table_row_t *row = NULL;
  113. if (!ht) return (-1);
  114. hash = ht->hash(key);
  115. idx = hash % ht->max_rows;
  116. row = ht->rows+idx;
  117. for (entry = row->head; entry; entry = entry->next) {
  118. if (hash == entry->hash && !ht->cmp(key, entry->key)) {
  119. *(void **)dataptr = entry->data;
  120. return(0);
  121. }
  122. }
  123. return(-1);
  124. }
  125. int hash_table_remove(hash_table_t *ht, const void *key, void *dataptr)
  126. {
  127. int idx;
  128. unsigned int hash;
  129. hash_table_entry_t *entry = NULL, *last = NULL;
  130. hash_table_row_t *row = NULL;
  131. if (!ht) return(-1);
  132. hash = ht->hash(key);
  133. idx = hash % ht->max_rows;
  134. row = ht->rows+idx;
  135. last = NULL;
  136. for (entry = row->head; entry; entry = entry->next) {
  137. if (hash == entry->hash && !ht->cmp(key, entry->key)) {
  138. if (dataptr) *(void **)dataptr = entry->data;
  139. /* Remove it from the row's list. */
  140. if (last) last->next = entry->next;
  141. else row->head = entry->next;
  142. free(entry);
  143. ht->cells_in_use--;
  144. return(0);
  145. }
  146. last = entry;
  147. }
  148. return(-1);
  149. }
  150. int hash_table_walk(hash_table_t *ht, hash_table_node_func callback, void *param)
  151. {
  152. hash_table_row_t *row = NULL;
  153. hash_table_entry_t *entry = NULL, *next = NULL;
  154. int i;
  155. if (!ht) return(-1);
  156. for (i = 0; i < ht->max_rows; i++) {
  157. row = ht->rows+i;
  158. for (entry = row->head; entry;) {
  159. next = entry->next;
  160. callback(entry->key, &entry->data, param);
  161. entry = next;
  162. }
  163. }
  164. return(0);
  165. }
  166. static int my_int_cmp(const void *left, const void *right)
  167. {
  168. return((int) left - (int) right);
  169. }
  170. static unsigned int my_string_hash(const void *key)
  171. {
  172. int hash, loop;
  173. size_t keylen;
  174. const unsigned char *k = NULL;
  175. #define HASHC hash = *k++ + 65599 * hash
  176. hash = 0;
  177. k = (const unsigned char *) key;
  178. keylen = strlen((const char *) key);
  179. if (!keylen) return(0);
  180. loop = (keylen + 8 - 1) >> 3;
  181. switch (keylen & (8 - 1)) {
  182. case 0:
  183. do {
  184. HASHC;
  185. case 7:
  186. HASHC;
  187. case 6:
  188. HASHC;
  189. case 5:
  190. HASHC;
  191. case 4:
  192. HASHC;
  193. case 3:
  194. HASHC;
  195. case 2:
  196. HASHC;
  197. case 1:
  198. HASHC;
  199. } while (--loop);
  200. }
  201. return(hash);
  202. }
  203. static unsigned int my_int_hash(const void *key)
  204. {
  205. return((unsigned int)key);
  206. }
  207. static unsigned int my_mixed_hash (const void *key)
  208. {
  209. const unsigned char *k = NULL;
  210. unsigned int hash;
  211. k = (const unsigned char *) key;
  212. hash = 0;
  213. while (*k) {
  214. hash *= 16777619;
  215. hash ^= *k++;
  216. }
  217. return(hash);
  218. }