PageRenderTime 77ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/hash.c

https://bitbucket.org/youngtrips/ifreechat
C | 260 lines | 215 code | 43 blank | 2 comment | 30 complexity | a07aa6ede8b743857c4b5e4b2ee636d5 MD5 | raw file
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "hash.h"
  5. /* Thomas Wang's 32 bit Mix Function */
  6. unsigned int hash_integer(unsigned int key) {
  7. key += ~(key << 15);
  8. key ^= (key >> 10);
  9. key += (key << 3);
  10. key ^= (key >> 6);
  11. key += ~(key << 11);
  12. key ^= (key >> 16);
  13. return key;
  14. }
  15. /* Generic hash function (a popular one from Bernstein) */
  16. unsigned int hash_string(const unsigned char *buf, int len) {
  17. unsigned int hash = 5381;
  18. while(len--)
  19. hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
  20. return hash;
  21. }
  22. hash_t *create_hash(size_t hsize, int ktype) {
  23. char *base;
  24. size_t size;
  25. int i;
  26. hash_t *h;
  27. size = sizeof(hash_t) + sizeof(hash_entry_t*) * (1 + hsize);
  28. base = (char*)malloc(size);
  29. memset(base, 0, size);
  30. h = (hash_t*)base; base += sizeof(hash_t);
  31. h->hash_entry = (hash_entry_t**)base;
  32. h->hash_size = hsize;
  33. h->ktype = ktype;
  34. #ifdef USE_LOCK
  35. pthread_mutex_init(&(h->lock), NULL);
  36. #endif
  37. return h;
  38. }
  39. hash_entry_t *hash_entry_alloc() {
  40. hash_entry_t *entry;
  41. entry = (hash_entry_t*)malloc(sizeof(hash_entry_t));
  42. init_dlist_node(&(entry->node));
  43. return entry;
  44. }
  45. void hash_entry_free(hash_entry_t *entry) {
  46. if (entry) {
  47. if (entry->key)
  48. free(entry->key);
  49. free(entry);
  50. }
  51. }
  52. void hash_entry_set_key(hash_entry_t *entry, int ktype,
  53. const void *key) {
  54. size_t size;
  55. if (ktype == KEY_INT) {
  56. size = sizeof(unsigned int);
  57. } else {
  58. size = strlen((char*)key) + 1;
  59. }
  60. entry->key = malloc(size);
  61. memcpy(entry->key, key, size);
  62. }
  63. void hash_entry_set_val(hash_entry_t *entry, const void *val) {
  64. entry->val = (void*)val;
  65. }
  66. unsigned int hash_index(hash_t *h, const void *key) {
  67. unsigned int idx;
  68. if (h->ktype == KEY_INT) {
  69. idx = hash_integer(*(unsigned int*)key);
  70. } else {
  71. idx = hash_string((char*)key, strlen((char*)key));
  72. idx = hash_integer(idx);
  73. }
  74. return (idx & h->hash_size);
  75. }
  76. int hash_insert(hash_t *h, const void *key, const void *val) {
  77. hash_entry_t *entry;
  78. unsigned int idx;
  79. entry = hash_entry_alloc();
  80. if (entry == NULL)
  81. return -1;
  82. hash_entry_set_key(entry, h->ktype, key);
  83. hash_entry_set_val(entry, val);
  84. idx = hash_index(h, key);
  85. h->hash_entry[idx] = entry;
  86. #ifdef USE_LOCK
  87. pthread_mutex_lock(&(h->lock));
  88. #endif
  89. if (h->hash_entry[idx] == NULL) {
  90. h->hash_entry[idx] = entry;
  91. } else {
  92. dlist_add_tail(&(entry->node), &(h->hash_entry[idx]->node));
  93. }
  94. #ifdef USE_LOCK
  95. pthread_mutex_unlock(&(h->lock));
  96. #endif
  97. return 0;
  98. }
  99. int hash_key_equal(int ktype, const void *k1, const void *k2) {
  100. if (ktype == KEY_INT) {
  101. return *((unsigned int*)k1) == *((unsigned int*)k2);
  102. }
  103. return !strcmp((char*)k1, (char*)k2);
  104. }
  105. int hash_del(hash_t *h, const void *key, void **val) {
  106. hash_entry_t *entry;
  107. hash_entry_t *next;
  108. unsigned int idx;
  109. dlist_t *p;
  110. idx = hash_index(h, key);
  111. entry = h->hash_entry[idx];
  112. if (entry == NULL)
  113. return -1;
  114. if (hash_key_equal(h->ktype, entry->key, key)) {
  115. #ifdef USE_LOCK
  116. pthread_mutex_lock(&(h->lock));
  117. #endif
  118. *val = entry->val;
  119. hash_entry_free(entry);
  120. h->hash_entry[idx] = NULL;
  121. #ifdef USE_LOCK
  122. pthread_mutex_unlock(&(h->lock));
  123. #endif
  124. return 0;
  125. }
  126. dlist_foreach(p, &(entry->node)) {
  127. next = (hash_entry_t*)dlist_entry(p, hash_entry_t, node);
  128. if (hash_key_equal(h->ktype, next->key, key)) {
  129. #ifdef USE_LOCK
  130. pthread_mutex_lock(&(h->lock));
  131. #endif
  132. *val = next->val;
  133. dlist_del(&(next->node));
  134. hash_entry_free(next);
  135. #ifdef USE_LOCK
  136. pthread_mutex_unlock(&(h->lock));
  137. #endif
  138. return 0;
  139. }
  140. }
  141. return -1;
  142. }
  143. int hash_find(hash_t *h, const void *key, void **val) {
  144. hash_entry_t *entry;
  145. hash_entry_t *next;
  146. unsigned int idx;
  147. dlist_t *p;
  148. idx = hash_index(h, key);
  149. entry = h->hash_entry[idx];
  150. if (entry == NULL)
  151. return -1;
  152. if (hash_key_equal(h->ktype, entry->key, key)) {
  153. *val = entry->val;
  154. return 0;
  155. }
  156. #ifdef USE_LOCK
  157. pthread_mutex_lock(&(h->lock));
  158. #endif
  159. dlist_foreach(p, &(entry->node)) {
  160. next = (hash_entry_t*)dlist_entry(p, hash_entry_t, node);
  161. if (hash_key_equal(h->ktype, next->key, key)) {
  162. *val = next->val;
  163. #ifdef USE_LOCK
  164. pthread_mutex_unlock(&(h->lock));
  165. #endif
  166. return 0;
  167. }
  168. }
  169. #ifdef USE_LOCK
  170. pthread_mutex_unlock(&(h->lock));
  171. #endif
  172. return -1;
  173. }
  174. void destroy_hash(hash_t *h) {
  175. hash_entry_t *entry;
  176. hash_entry_t *next;
  177. dlist_t *p;
  178. dlist_t *q;
  179. int i;
  180. if (h == NULL)
  181. return;
  182. for(i = 0;i < h->hash_size; i++) {
  183. entry = h->hash_entry[i];
  184. if (entry) {
  185. dlist_foreach_safe(p, q, &(entry->node)) {
  186. next = (hash_entry_t*)dlist_entry(p, hash_entry_t, node);
  187. dlist_del(&(next->node));
  188. hash_entry_free(next);
  189. }
  190. }
  191. }
  192. free(h);
  193. }
  194. #ifdef __TEST_
  195. typedef struct pair_t {
  196. char a[64];
  197. char b[64];
  198. }pair_t;
  199. pair_t test[2] = {
  200. {"192.168.1.3", "hello java"},
  201. {"192.168.1.2", "hello perl"}
  202. };
  203. int main() {
  204. hash_t *hash;
  205. char *val;
  206. int ret;
  207. hash = create_hash(KEY_STR, 0xffff);
  208. hash_insert(hash, test[0].a, test[0].b);
  209. hash_insert(hash, test[1].a, test[1].b);
  210. ret = hash_find(hash, "192.168.1.2", (void**)&val);
  211. printf("ret: %d\n", ret);
  212. if (ret == 0)
  213. printf("val: [%s]\n", val);
  214. destroy_hash(hash);
  215. return 0;
  216. }
  217. #endif