hashset.h 8.4 KB

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