hashset.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * category: [data structure]
  3. * apply status: log_mgr, sp_log, SpEntity, mod_evtconverter
  4. * edit status: not
  5. * build status:
  6. * description:
  7. */
  8. #ifndef HASHSET_H
  9. #define HASHSET_H
  10. #pragma once
  11. #include "config.h"
  12. #ifdef __cplusplus
  13. extern "C" {
  14. #endif
  15. #include "list.h"
  16. #define HASH_DEFAULT_INIT_HASH_SIZE 15
  17. #define HASH_DEFAULT_LOAD_FACTOR 0.72f
  18. typedef struct hashset_t hashset_t;
  19. typedef struct hashset_iterator hashset_iterator;
  20. TOOLKIT_API int hash_get_prime(int min);
  21. typedef const void* (*hashset_getkey)(const void *obj);
  22. typedef unsigned int (*hashset_hash)(const void *key);
  23. typedef int (*hashset_cmpkey)(const void *key_x, const void *key_y);
  24. struct hashset_iterator {
  25. hashset_t *ht;
  26. int slot;
  27. struct hlist_node *pos, *pos_next;
  28. };
  29. struct hashset_t {
  30. struct hlist_head *buckets;
  31. int count;
  32. int size;
  33. int node_offset;
  34. float load_factor;
  35. hashset_getkey getkey_fn;
  36. hashset_hash hash_fn;
  37. hashset_cmpkey cmp_fn;
  38. hashset_iterator default_iterator;
  39. };
  40. /**
  41. * hash a set of object pointers
  42. * @param node_offset struct hlist_node offset in the structure, use offset_of macro
  43. * @param init_size initial size
  44. * @param getkey_fn get key from object
  45. * @param hash_fn get hashcode from key
  46. * @param cmp_fn compare key
  47. */
  48. TOOLKIT_API hashset_t *hashset_create2(int init_size,
  49. float load_factor,
  50. int node_offset,
  51. hashset_getkey getkey_fn,
  52. hashset_hash hash_fn,
  53. hashset_cmpkey cmp_fn);
  54. TOOLKIT_API hashset_t * hashset_create(int node_offset,
  55. hashset_getkey getkey_fn,
  56. hashset_hash hash_fn,
  57. hashset_cmpkey cmp_fn);
  58. /**
  59. * remove an object by key
  60. * @return NULL obj not find
  61. */
  62. TOOLKIT_API void* hashset_remove(hashset_t *ht, const void *key);
  63. /**
  64. * add an object to hashset
  65. */
  66. TOOLKIT_API int hashset_add(hashset_t *ht, void *obj);
  67. /**
  68. * find object by key
  69. * @return null failed
  70. */
  71. TOOLKIT_API void* hashset_find(hashset_t *ht, const void *key);
  72. /**
  73. * get the number of objects in the hashset
  74. */
  75. TOOLKIT_API int hashset_count(hashset_t *ht);
  76. /**
  77. * destroy hashset
  78. */
  79. TOOLKIT_API void hashset_destroy(hashset_t *ht);
  80. TOOLKIT_API hashset_iterator *hashset_default_iterator(hashset_t *ht);
  81. TOOLKIT_API hashset_iterator *hashset_iterator_create(hashset_t *ht);
  82. TOOLKIT_API void hashset_iterator_destroy(hashset_iterator *iter);
  83. TOOLKIT_API int hashset_iterator_next(hashset_iterator *iter);
  84. TOOLKIT_API void *hashset_iterator_get_object(hashset_iterator *iter);
  85. TOOLKIT_API hashset_iterator *hashset_iterator_reset(hashset_iterator *iter);
  86. static __inline struct hlist_node * __hashset_next_node(hashset_t *ht, struct hlist_node *pos, int *slot)
  87. {
  88. if (pos)
  89. pos = pos->next;
  90. while (*slot < ht->size && !pos) {
  91. pos = ht->buckets[*slot].first;
  92. *slot = *slot + 1;
  93. }
  94. return pos;
  95. }
  96. /**
  97. * walk through hashset
  98. * @param tpos pointer to type
  99. * @param pos temp pointer to struct hlist_node
  100. * @param slot temp int variable
  101. * @param ht hashtable pointer
  102. * @param type object type
  103. */
  104. #define hashset_for_each(tpos, pos, slot, ht, type) \
  105. for (slot = 0, pos = NULL; \
  106. pos = __hashset_next_node(ht, pos, &slot), tpos = pos ? (type*)((char*)pos-(ht)->node_offset) : NULL;)
  107. /**
  108. * walk through hashset, can remove tpos
  109. * @param pos temp pointer to struct hlist_node
  110. * @param n temp pointer to struct hlist_node
  111. */
  112. #define hashset_for_each_safe(tpos, pos, n, slot, ht, type) \
  113. for (slot = 0, pos = __hashset_next_node(ht, NULL, &slot), n = __hashset_next_node(ht, pos, &slot); \
  114. tpos = (pos) ? (type*)((char*)pos-(ht)->node_offset) : NULL; \
  115. pos = n, n = __hashset_next_node(ht, pos, &slot))
  116. /* string map(hash table) */
  117. typedef struct stringmap_t stringmap_t;
  118. TOOLKIT_API stringmap_t *stringmap_create(int init_size);
  119. TOOLKIT_API void stringmap_destroy(stringmap_t *map);
  120. typedef struct stringmap_kv_pair stringmap_kv_pair;
  121. TOOLKIT_API const char* stringmap_kv_pair_get_key(stringmap_kv_pair *kv);
  122. TOOLKIT_API void *stringmap_kv_pair_get_value(stringmap_kv_pair *kv);
  123. TOOLKIT_API void *stringmap_kv_pair_set_value(stringmap_kv_pair *kv, void *newval);
  124. TOOLKIT_API stringmap_kv_pair *stringmap_find(stringmap_t *map, const char *key);
  125. TOOLKIT_API int stringmap_add(stringmap_t *map, const char *key, void *value);
  126. TOOLKIT_API void *stringmap_remove(stringmap_t *map, const char *key);
  127. TOOLKIT_API int stringmap_count(stringmap_t *map);
  128. typedef struct stringmap_iterator stringmap_iterator;
  129. TOOLKIT_API stringmap_iterator *stringmap_default_iterator(stringmap_t *map);
  130. TOOLKIT_API stringmap_iterator *stringmap_iterator_create(stringmap_t *map);
  131. TOOLKIT_API void stringmap_iterator_destroy(stringmap_iterator *iter);
  132. TOOLKIT_API int stringmap_iterator_next(stringmap_iterator *iter);
  133. TOOLKIT_API const char *stringmap_iterator_get_key(stringmap_iterator *iter);
  134. TOOLKIT_API void *stringmap_iterator_get_value(stringmap_iterator *iter);
  135. TOOLKIT_API stringmap_iterator *stringmap_iterator_reset(stringmap_iterator *iter);
  136. // template version of hash table
  137. typedef unsigned int (*__htable_hash)(const void *key);
  138. typedef int (*__htable_compare)(const void *key1, const void *key2);
  139. typedef struct htable_t {
  140. struct hlist_head *buckets;
  141. int count;
  142. int size;
  143. }htable_t;
  144. TOOLKIT_API int htable_init(htable_t *ht, int init_size);
  145. TOOLKIT_API void htable_term(htable_t *ht);
  146. TOOLKIT_API htable_t *htable_create(int init_size);
  147. TOOLKIT_API void htable_destroy(htable_t *ht);
  148. static __inline int htable_get_count(htable_t *ht)
  149. {
  150. return ht->count;
  151. }
  152. #define __DECLARE_HTABLE(prefix, TKey, TObject, modifier) \
  153. modifier int prefix##_check_expand(htable_t *ht); \
  154. modifier TObject* prefix##_find(htable_t *ht, TKey* key); \
  155. modifier int prefix##_add(htable_t *ht, TObject* obj); \
  156. modifier void prefix##_remove(htable_t *ht, TObject* obj);
  157. #define __IMPLEMENT_HTABLE(prefix, TKey, TObject, member_key, member_node, fun_hash, fun_cmp, modifier) \
  158. modifier int prefix##_check_expand(htable_t *ht) \
  159. { \
  160. if ((ht->count+1)/(float)ht->size > HASH_DEFAULT_LOAD_FACTOR) { \
  161. int i; \
  162. int new_size = hash_get_prime(ht->size * 2); \
  163. struct hlist_head *new_buckets = (struct hlist_head *)ZALLOC(new_size*sizeof(struct hlist_head)); \
  164. if (!new_buckets) \
  165. return -1; \
  166. for (i = 0; i < ht->size; ++i) { \
  167. TObject *tpos; \
  168. struct hlist_node *pos, *n; \
  169. hlist_for_each_entry_safe(tpos, pos, n, &ht->buckets[i], TObject, member_node) { \
  170. unsigned int new_slot = fun_hash(&tpos->member_key) % new_size; \
  171. hlist_del(pos); \
  172. hlist_add_head(&tpos->member_node, &new_buckets[new_slot]); \
  173. } \
  174. } \
  175. FREE(ht->buckets); \
  176. ht->buckets = new_buckets; \
  177. ht->size = new_size; \
  178. } \
  179. return 0; \
  180. } \
  181. modifier TObject* prefix##_find_continue(htable_t *ht, struct hlist_node *position, TKey *key) \
  182. { \
  183. TObject *tpos; \
  184. struct hlist_node *pos = position; \
  185. hlist_for_each_entry_continue(tpos, pos, TObject, member_node) { \
  186. if (fun_cmp(&tpos->member_key, key) == 0) \
  187. return tpos; \
  188. } \
  189. return NULL; \
  190. } \
  191. modifier TObject* prefix##_find_from(htable_t *ht, struct hlist_node *position, TKey *key) \
  192. { \
  193. TObject *tpos; \
  194. struct hlist_node *pos = position; \
  195. hlist_for_each_entry_from(tpos, pos, TObject, member_node) { \
  196. if (fun_cmp(&tpos->member_key, key) == 0) \
  197. return tpos; \
  198. } \
  199. return NULL; \
  200. } \
  201. modifier TObject* prefix##_find(htable_t *ht, TKey *key) \
  202. { \
  203. unsigned int k = fun_hash(key); \
  204. int slot = k % ht->size; \
  205. TObject *tpos; \
  206. struct hlist_node *pos; \
  207. hlist_for_each_entry(tpos, pos, &ht->buckets[slot], TObject, member_node) { \
  208. if (fun_cmp(&tpos->member_key, key) == 0) \
  209. return tpos; \
  210. } \
  211. return NULL; \
  212. } \
  213. modifier int prefix##_add(htable_t *ht, TObject *obj) \
  214. { \
  215. int rc; \
  216. rc = prefix##_check_expand(ht); \
  217. if (rc == 0) { \
  218. unsigned int k = fun_hash(&obj->member_key); \
  219. int slot = k % ht->size; \
  220. hlist_add_head(&obj->member_node, &ht->buckets[slot]); \
  221. ht->count++; \
  222. } \
  223. return rc; \
  224. } \
  225. modifier void prefix##_remove(htable_t *ht, TObject* obj) \
  226. { \
  227. hlist_del_init(&obj->member_node); \
  228. ht->count --; \
  229. }
  230. #define __HTABLE_NOTHING
  231. #define __HTABLE_STATIC static
  232. #define DECLARE_HTABLE(prefix, TKey, TObject) __DECLARE_HTABLE(prefix, TKey, TObject, __HTABLE_NOTHING)
  233. #define DECLARE_HTABLE_STATIC(prefix, TKey, TObject) __DECLARE_HTABLE(prefix, TKey, TObject, __HTABLE_STATIC)
  234. #define IMPLEMENT_HTABLE(prefix, TKey, TObject, member_key, member_node, fun_hash, fun_cmp) __IMPLEMENT_HTABLE(prefix, TKey, TObject, member_key, member_node, fun_hash, fun_cmp, __HTABLE_NOTHING)
  235. #define IMPLEMENT_HTABLE_STATIC(prefix, TKey, TObject, member_key, member_node, fun_hash, fun_cmp) __IMPLEMENT_HTABLE(prefix, TKey, TObject, member_key, member_node, fun_hash, fun_cmp, __HTABLE_STATIC)
  236. #ifdef __cplusplus
  237. } // extern "C" {
  238. #endif
  239. #endif // HASHSET_H