swhash.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. #include "swapi.h"
  2. #include "swmem.h"
  3. #include "swhash.h"
  4. //////////////////////////////////////////////////////////////////////////////////////////
  5. // base struct
  6. /* hash表操作结构 */
  7. struct hash_ops
  8. {
  9. int32_t (*insert)(hash_t, const void *, int32_t, const void *); // 插入
  10. int32_t (*delete)(hash_t, const void *, int32_t, bool); // 删除
  11. int32_t (*replace)(hash_t, const void *, int32_t, const void *, void **); // 替换
  12. void *(*lookup)(hash_t, const void *, int32_t); // 查找
  13. void (*visit)(hash_t, hash_visit_cb); // 遍历hash表
  14. void (*destroy)(hash_t, bool); // 销毁
  15. };
  16. /* hash表结构 */
  17. struct shash_t
  18. {
  19. uint32_t tsize; // 表长
  20. uint32_t ksize; // key值长度,默认0为变长
  21. uint32_t nelems; // hash表中已存在元素的数目
  22. uint32_t nElemCollisionCnts; // hash表中元素发生碰撞的次数(mixed-value)
  23. struct hash_ops *h_ops; // hash操作结构
  24. hash_ex_func_hash hash_fn; // hash函数
  25. hash_ex_func_cmp cmp_fn; // hash比较key函数
  26. hash_data_free_cb free_cb; // hash释放data函数
  27. union
  28. {
  29. struct elem **chtable; // 链表类型
  30. } dm; // hash表数据管理者(无论哪种类型,都必须解决碰撞冲突的问题)
  31. };
  32. //////////////////////////////////////////////////////////////////////////////////////////
  33. // "chain hash" struct
  34. struct elem
  35. {
  36. void *key; // 关键字
  37. int32_t keylen; // 关键字长度
  38. void *data; // 数据指针
  39. struct elem *next; // 指向下一个元素
  40. };
  41. static int32_t ch_insert(hash_t, const void *, int32_t, const void *);
  42. static int32_t ch_delete(hash_t, const void *, int32_t, bool);
  43. static int32_t ch_replace(hash_t, const void *, int32_t, const void *, void **);
  44. static void *ch_lookup(hash_t, const void *, int32_t);
  45. static void ch_visit(hash_t, hash_visit_cb);
  46. static void ch_destroy(hash_t, bool);
  47. static struct hash_ops ch_ops = {
  48. ch_insert,
  49. ch_delete,
  50. ch_replace,
  51. ch_lookup,
  52. ch_visit,
  53. ch_destroy,
  54. };
  55. //////////////////////////////////////////////////////////////////////////////////////////
  56. // hash functions
  57. /* bob hash(http://burtleburtle.net/bob/index.html) */
  58. #define mix(a, b, c) \
  59. { \
  60. a -= b; a -= c; a ^= (c >> 13); \
  61. b -= c; b -= a; b ^= (a << 8); \
  62. c -= a; c -= b; c ^= (b >> 13); \
  63. a -= b; a -= c; a ^= (c >> 12); \
  64. b -= c; b -= a; b ^= (a << 16); \
  65. c -= a; c -= b; c ^= (b >> 5); \
  66. a -= b; a -= c; a ^= (c >> 3); \
  67. b -= c; b -= a; b ^= (a << 10); \
  68. c -= a; c -= b; c ^= (b >> 15); \
  69. }
  70. static uint32_t bob_hash(const unsigned char *k, uint32_t length)
  71. {
  72. uint32_t a, b, c, len;
  73. /* set up the internal state */
  74. len = length;
  75. a = b = c = 0x9e3779b9; // the golden ratio; an arbitrary data
  76. /* handle most of the key */
  77. while (len >= 12)
  78. {
  79. a += (k[0] +((uint32_t)k[1] << 8) +((uint32_t)k[2] << 16) +((uint32_t)k[3] << 24));
  80. b += (k[4] +((uint32_t)k[5] << 8) +((uint32_t)k[6] << 16) +((uint32_t)k[7] << 24));
  81. c += (k[8] +((uint32_t)k[9] << 8) +((uint32_t)k[10]<< 16)+((uint32_t)k[11] << 24));
  82. mix(a, b, c);
  83. k += 12; len -= 12;
  84. }
  85. /* handle the last 11 bytes */
  86. c += length;
  87. switch(len)
  88. { /* all the case statements fall through */
  89. case 11: c += ((uint32_t)k[10] << 24);
  90. case 10: c += ((uint32_t)k[9] << 16);
  91. case 9 : c += ((uint32_t)k[8] << 8);
  92. /* the first byte of c is reserved for the length */
  93. case 8 : b += ((uint32_t)k[7] << 24);
  94. case 7 : b += ((uint32_t)k[6] << 16);
  95. case 6 : b += ((uint32_t)k[5] << 8);
  96. case 5 : b += k[4];
  97. case 4 : a += ((uint32_t)k[3] << 24);
  98. case 3 : a += ((uint32_t)k[2] << 16);
  99. case 2 : a += ((uint32_t)k[1] << 8);
  100. case 1 : a += k[0];
  101. /* case 0: nothing left to add */
  102. }
  103. mix(a, b, c);
  104. return c;
  105. }
  106. /* one-at-a-time hash */
  107. static uint32_t oneatatime_hash(const unsigned char *k, uint32_t length)
  108. {
  109. uint32_t hash = 0;
  110. uint32_t i;
  111. for(i = 0; i < length; ++i)
  112. {
  113. hash += k[i];
  114. hash += (hash << 10);
  115. hash ^= (hash >> 6);
  116. }
  117. hash += (hash << 3);
  118. hash ^= (hash >> 11);
  119. hash += (hash << 15);
  120. return hash;
  121. }
  122. /* time33 hash */
  123. static uint32_t time33_hash(const unsigned char *k, uint32_t length)
  124. {
  125. uint32_t hash = 5381;
  126. uint32_t i = 0;
  127. for(i = 0; i < length; i++)
  128. {
  129. hash = (hash<<5) + hash + k[i]; // hash = hash*31 + k[i];
  130. }
  131. return hash;
  132. }
  133. /* mixed computing imaging to my hash table */
  134. static uint32_t getHash(hash_t htable, const void *key, int32_t keylen)
  135. {
  136. int32_t len;
  137. if(htable->ksize == 0) len = keylen;
  138. else len = htable->ksize;
  139. return ((htable->hash_fn(key, len)) & (htable->tsize-1)); // hash the key and get the meaningful bits for our table
  140. }
  141. //////////////////////////////////////////////////////////////////////////////////////////
  142. // default hash key compare functions
  143. static int32_t default_hash_key_cmp(const void *p1, int32_t len1,const void *p2, int32_t len2)
  144. {
  145. if(len1 != len2) return -1;
  146. else return memcmp(p1, p2, len1); // return strncmp((const char * )p1, (const char * )p2, len1);
  147. }
  148. //////////////////////////////////////////////////////////////////////////////////////////
  149. // main functions
  150. hash_t sw_hash_create(uint32_t sizehint, uint32_t keysize, enum hash_alg alg, hash_ex_func_hash hfunc, hash_ex_func_cmp cfunc, hash_data_free_cb fcb, uint32_t flag)
  151. {
  152. hash_t htable;
  153. uint32_t size = 0; // htable size
  154. uint32_t i = 1;
  155. /* 1, take the size hint and round it to the next higher power of two */
  156. while(size < sizehint)
  157. {
  158. size = 1<<i++;
  159. if(size == 0) { size = 1<<(i-2); break; }
  160. }
  161. /* 2, create hash htable */
  162. htable = (hash_t)sw_heap_malloc(sizeof(struct shash_t));
  163. if(!htable) { errno = ENOMEM; goto ErrorP; }
  164. /* 3, initialize hash htable common fields */
  165. htable->tsize = size;
  166. htable->ksize = keysize;
  167. htable->nelems = 0;
  168. htable->nElemCollisionCnts = 0;
  169. switch(alg)
  170. {
  171. case BOB_HASH:
  172. htable->hash_fn = bob_hash;
  173. break;
  174. case ONEATATIME_HASH:
  175. htable->hash_fn = oneatatime_hash;
  176. break;
  177. case TIME33_HASH:
  178. htable->hash_fn = time33_hash;
  179. break;
  180. default:
  181. if(hfunc) htable->hash_fn = hfunc;
  182. else {
  183. errno = EINVAL;
  184. goto ErrorP;
  185. }
  186. }
  187. if(cfunc) htable->cmp_fn = cfunc;
  188. else htable->cmp_fn = default_hash_key_cmp;
  189. htable->free_cb = fcb;
  190. /* 4, create elements for each hash htable type */
  191. switch(flag)
  192. {
  193. case CHAIN_H:
  194. htable->h_ops = &ch_ops;
  195. htable->dm.chtable = (struct elem **)sw_heap_malloc(size*sizeof(struct elem *));
  196. if(!htable->dm.chtable) { errno = ENOMEM; goto ErrorP; }
  197. else memset(htable->dm.chtable, 0, size*sizeof(struct elem *));
  198. break;
  199. default:
  200. errno = EINVAL;
  201. goto ErrorP;
  202. }
  203. return htable;
  204. ErrorP:
  205. if(htable && flag == CHAIN_H && htable->dm.chtable) sw_heap_free((void *)htable->dm.chtable);
  206. if(htable) sw_heap_free((void *)htable);
  207. return NULL;
  208. }
  209. int32_t sw_hash_insert(hash_t htable, const void *key, int32_t keylen, const void *data)
  210. {
  211. if(!htable || !key || keylen <= 0 || !data) return -1;
  212. else return htable->h_ops->insert(htable, key, keylen, data);
  213. }
  214. int32_t sw_hash_delete(hash_t htable, const void *key, int32_t keylen, bool bAutoFreeData)
  215. {
  216. if(!htable || !key || keylen <= 0) return -1;
  217. else return htable->h_ops->delete(htable, key, keylen, bAutoFreeData);
  218. }
  219. int32_t sw_hash_replace(hash_t htable, const void *key, int32_t keylen, const void *newdata, void **olddata)
  220. {
  221. if(!htable || !key || keylen <= 0 || !newdata || !olddata) return -1;
  222. else return htable->h_ops->replace(htable, key, keylen, newdata, olddata);
  223. }
  224. void *sw_hash_lookup(hash_t htable, const void *key, int32_t keylen)
  225. {
  226. if(!htable || !key || keylen <= 0) return NULL;
  227. else return htable->h_ops->lookup(htable, key, keylen);
  228. }
  229. uint32_t sw_hash_getTableSize(hash_t htable)
  230. {
  231. assert(htable);
  232. return htable->tsize;
  233. }
  234. uint32_t sw_hash_getElemsCnt(hash_t htable)
  235. {
  236. assert(htable);
  237. return htable->nelems;
  238. }
  239. uint32_t sw_hash_getElemCollisionCnts(hash_t htable)
  240. {
  241. assert(htable);
  242. return htable->nElemCollisionCnts;
  243. }
  244. void sw_hash_visit(hash_t htable, hash_visit_cb vcb)
  245. {
  246. if(!htable) return;
  247. htable->h_ops->visit(htable, vcb);
  248. }
  249. void sw_hash_destroy(hash_t htable, bool bAutoFreeData)
  250. {
  251. if(!htable) return;
  252. htable->h_ops->destroy(htable, bAutoFreeData);
  253. sw_heap_free((void *)htable);
  254. }
  255. //////////////////////////////////////////////////////////////////////////////////////////
  256. // "chain hash" functions
  257. static int32_t ch_insert(hash_t htable, const void *key, int32_t keylen, const void *data)
  258. {
  259. uint32_t idx;
  260. struct elem *cursor = NULL;
  261. struct elem *newelem = NULL;
  262. void *keycopy = NULL;
  263. newelem = (struct elem *)sw_heap_malloc(sizeof(struct elem));
  264. if(!newelem) { errno = ENOMEM; goto ErrorP; }
  265. keycopy = (struct elem *)sw_heap_malloc(keylen*sizeof(char));
  266. if(!keycopy) { errno = ENOMEM; goto ErrorP; }
  267. else memcpy(keycopy, key, keylen);
  268. newelem->key = keycopy;
  269. newelem->keylen = keylen;
  270. newelem->data = (void *)data;
  271. newelem->next = NULL;
  272. idx = getHash(htable, key, keylen);
  273. if(htable->dm.chtable[idx] == NULL)
  274. { // no collision, first element in this bucket
  275. htable->dm.chtable[idx] = newelem;
  276. }
  277. else
  278. { // collision, insert at the end of the chain
  279. cursor = htable->dm.chtable[idx];
  280. while(1)
  281. {
  282. if(htable->cmp_fn(cursor->key, cursor->keylen, newelem->key, keylen) == 0)
  283. { // key is already inserted in the table, insert fails
  284. errno = EINVAL;
  285. goto ErrorP;
  286. }
  287. if(cursor->next == NULL) break;
  288. else cursor = cursor->next;
  289. }
  290. cursor->next = newelem; // insert element at the end of the chain
  291. htable->nElemCollisionCnts++;
  292. }
  293. htable->nelems++;
  294. return 0;
  295. ErrorP:
  296. if(newelem && newelem->key) sw_heap_free((void *)newelem->key);
  297. if(newelem) sw_heap_free((void *)newelem);
  298. return -1;
  299. }
  300. static int32_t ch_delete(hash_t htable, const void *key, int32_t keylen, bool bAutoFreeData)
  301. {
  302. uint32_t idx;
  303. struct elem *cursor;
  304. struct elem *delelem;
  305. bool bElemCollisionDecrement;
  306. idx = getHash(htable, key, keylen);
  307. if(!htable->dm.chtable[idx]) return 0;
  308. delelem = NULL, bElemCollisionDecrement = false;
  309. if(htable->cmp_fn(htable->dm.chtable[idx]->key, htable->dm.chtable[idx]->keylen, key, keylen) == 0)
  310. { // element to delete is the first in the chain
  311. delelem = htable->dm.chtable[idx];
  312. htable->dm.chtable[idx] = delelem->next;
  313. if(htable->dm.chtable[idx]) bElemCollisionDecrement = true;
  314. }
  315. else
  316. { // search thru the chain for the element
  317. cursor = htable->dm.chtable[idx];
  318. while(cursor->next)
  319. {
  320. if(htable->cmp_fn(cursor->next->key, cursor->next->keylen, key, keylen) == 0)
  321. {
  322. delelem = cursor->next;
  323. cursor->next = delelem->next;
  324. bElemCollisionDecrement = true;
  325. break;
  326. }
  327. cursor = cursor->next;
  328. }
  329. }
  330. if(delelem)
  331. {
  332. sw_heap_free((void *)delelem->key);
  333. if(bAutoFreeData && htable->free_cb) htable->free_cb((void *)delelem->data);
  334. sw_heap_free((void *)delelem);
  335. htable->nelems--;
  336. if(bElemCollisionDecrement) htable->nElemCollisionCnts--;
  337. }
  338. return 0;
  339. }
  340. static int32_t ch_replace(hash_t htable, const void *key, int32_t keylen, const void *newdata, void **olddata)
  341. {
  342. uint32_t idx;
  343. struct elem *cursor;
  344. idx = getHash(htable, key, keylen);
  345. cursor = htable->dm.chtable[idx];
  346. while(cursor)
  347. {
  348. if(htable->cmp_fn(cursor->key, cursor->keylen, key, keylen) == 0)
  349. {
  350. *olddata = cursor->data;
  351. cursor->data = (void *)newdata;
  352. return 0;
  353. }
  354. cursor = cursor->next;
  355. }
  356. return -1;
  357. }
  358. static void *ch_lookup(hash_t htable, const void *key, int32_t keylen)
  359. {
  360. uint32_t idx;
  361. struct elem *cursor;
  362. idx = getHash(htable, key, keylen);
  363. cursor = htable->dm.chtable[idx];
  364. while(cursor)
  365. {
  366. if(htable->cmp_fn(cursor->key, cursor->keylen, key, keylen) == 0) return cursor->data;
  367. cursor = cursor->next;
  368. }
  369. return NULL;
  370. }
  371. static void ch_visit(hash_t htable, hash_visit_cb vcb)
  372. {
  373. uint32_t idx;
  374. struct elem *cursor;
  375. for(idx = 0; idx < htable->tsize; idx++)
  376. {
  377. cursor = htable->dm.chtable[idx];
  378. while(cursor)
  379. {
  380. if(vcb) vcb(cursor->key, cursor->keylen, cursor->data);
  381. cursor = cursor->next;
  382. }
  383. }
  384. }
  385. static void ch_destroy(hash_t htable, bool bAutoFreeData)
  386. {
  387. uint32_t idx;
  388. struct elem *cursor, *delelem;
  389. for(idx = 0; idx < htable->tsize; idx++)
  390. {
  391. cursor = htable->dm.chtable[idx];
  392. while(cursor)
  393. {
  394. delelem = cursor;
  395. cursor = cursor->next;
  396. sw_heap_free((void *)delelem->key);
  397. if(bAutoFreeData && htable->free_cb) htable->free_cb((void *)delelem->data);
  398. sw_heap_free((void *)delelem);
  399. }
  400. }
  401. sw_heap_free((void *)htable->dm.chtable);
  402. }