khashmzx.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. /* The MIT License
  2. Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
  3. Permission is hereby granted, free of charge, to any person obtaining
  4. a copy of this software and associated documentation files (the
  5. "Software"), to deal in the Software without restriction, including
  6. without limitation the rights to use, copy, modify, merge, publish,
  7. distribute, sublicense, and/or sell copies of the Software, and to
  8. permit persons to whom the Software is furnished to do so, subject to
  9. the following conditions:
  10. The above copyright notice and this permission notice shall be
  11. included in all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  13. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  16. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  17. ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  18. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. SOFTWARE.
  20. */
  21. /**
  22. * NOTE: this is a significantly altered of khash specifically for MegaZeux.
  23. * The default key types have been replaced with a single key type expected to
  24. * be a struct with a key pointer field and a key length field. The names of
  25. * these fields can be specified. The kh_get function has also been altered to
  26. * optionally take a separate key pointer and key length parameters instead of
  27. * a key struct. Additionally, alternate macros have been added to make its
  28. * interface look more like uthash.
  29. *
  30. * This header is not currently compatible with the standard khash header.
  31. * See khash.h for the original example and changelog from this file.
  32. */
  33. #ifndef KHASHMZX_H
  34. #define KHASHMZX_H
  35. // We want to use the MZX check alloc functions.
  36. #include "../../src/compat.h"
  37. #define kcalloc(N,Z) ccalloc(N,Z)
  38. #define kmalloc(Z) cmalloc(Z)
  39. #define krealloc(P,Z) crealloc(P,Z)
  40. /*!
  41. @header
  42. Generic hash table library.
  43. */
  44. #define AC_VERSION_KHASH_H "0.2.8"
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <limits.h>
  48. /* compiler specific configuration */
  49. #if UINT_MAX == 0xffffffffu
  50. typedef unsigned int khint32_t;
  51. #elif ULONG_MAX == 0xffffffffu
  52. typedef unsigned long khint32_t;
  53. #endif
  54. #ifndef kh_inline
  55. #ifdef _MSC_VER
  56. #define kh_inline __inline
  57. #else
  58. #define kh_inline inline
  59. #endif
  60. #endif /* kh_inline */
  61. #ifndef klib_unused
  62. #if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3)
  63. #define klib_unused __attribute__ ((__unused__))
  64. #else
  65. #define klib_unused
  66. #endif
  67. #endif /* klib_unused */
  68. typedef khint32_t khint_t;
  69. typedef khint_t khiter_t;
  70. #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
  71. #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
  72. #define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
  73. #define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
  74. #define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
  75. #define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
  76. #define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
  77. #define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
  78. #ifndef kroundup32
  79. #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
  80. #endif
  81. #ifndef kcalloc
  82. #define kcalloc(N,Z) calloc(N,Z)
  83. #endif
  84. #ifndef kmalloc
  85. #define kmalloc(Z) malloc(Z)
  86. #endif
  87. #ifndef krealloc
  88. #define krealloc(P,Z) realloc(P,Z)
  89. #endif
  90. #ifndef kfree
  91. #define kfree(P) free(P)
  92. #endif
  93. static const double __ac_HASH_UPPER = 0.77;
  94. #define __KHASH_TYPE(name, khkey_t, khval_t) \
  95. typedef struct kh_##name##_s { \
  96. khint_t n_buckets, size, n_occupied, upper_bound; \
  97. khint32_t *flags; \
  98. khkey_t *keys; \
  99. khval_t *vals; \
  100. } kh_##name##_t;
  101. #define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
  102. extern kh_##name##_t *kh_init_##name(void); \
  103. extern void kh_destroy_##name(kh_##name##_t *h); \
  104. extern void kh_clear_##name(kh_##name##_t *h); \
  105. extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
  106. extern khint_t kh_get_no_obj_##name(const kh_##name##_t *h, const void *key_ptr, khint_t key_len); \
  107. extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
  108. extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
  109. extern void kh_del_##name(kh_##name##_t *h, khint_t x);
  110. #define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, ptr_field, len_field, __hash_func, __hash_equal) \
  111. SCOPE kh_##name##_t *kh_init_##name(void) { \
  112. return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
  113. } \
  114. SCOPE void kh_destroy_##name(kh_##name##_t *h) \
  115. { \
  116. if (h) { \
  117. kfree((void *)h->keys); kfree(h->flags); \
  118. kfree((void *)h->vals); \
  119. kfree(h); \
  120. } \
  121. } \
  122. SCOPE void kh_clear_##name(kh_##name##_t *h) \
  123. { \
  124. if (h && h->flags) { \
  125. memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
  126. h->size = h->n_occupied = 0; \
  127. } \
  128. } \
  129. SCOPE khint_t kh_get_no_obj_##name(const kh_##name##_t *h, const void *key_ptr, khint_t key_len) \
  130. { \
  131. if (h->n_buckets) { \
  132. khint_t k, i, last, mask, step = 0; \
  133. mask = h->n_buckets - 1; \
  134. k = __hash_func(key_ptr, key_len); i = k & mask; \
  135. last = i; \
  136. while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || \
  137. !__hash_equal(h->keys[i]->ptr_field, key_ptr, h->keys[i]->len_field, key_len))) { \
  138. i = (i + (++step)) & mask; \
  139. if (i == last) return h->n_buckets; \
  140. } \
  141. return __ac_iseither(h->flags, i)? h->n_buckets : i; \
  142. } else return 0; \
  143. } \
  144. SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
  145. { \
  146. return kh_get_no_obj_##name(h, key->ptr_field, key->len_field); \
  147. } \
  148. SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
  149. { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
  150. khint32_t *new_flags = 0; \
  151. khint_t j = 1; \
  152. { \
  153. kroundup32(new_n_buckets); \
  154. if (new_n_buckets < 4) new_n_buckets = 4; \
  155. if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
  156. else { /* hash table size to be changed (shrink or expand); rehash */ \
  157. new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
  158. if (!new_flags) return -1; \
  159. memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
  160. if (h->n_buckets < new_n_buckets) { /* expand */ \
  161. khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
  162. if (!new_keys) { kfree(new_flags); return -1; } \
  163. h->keys = new_keys; \
  164. if (kh_is_map) { \
  165. khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
  166. if (!new_vals) { kfree(new_flags); return -1; } \
  167. h->vals = new_vals; \
  168. } \
  169. } /* otherwise shrink */ \
  170. } \
  171. } \
  172. if (j) { /* rehashing is needed */ \
  173. for (j = 0; j != h->n_buckets; ++j) { \
  174. if (__ac_iseither(h->flags, j) == 0) { \
  175. khkey_t key = h->keys[j]; \
  176. khval_t val; \
  177. khint_t new_mask; \
  178. new_mask = new_n_buckets - 1; \
  179. if (kh_is_map) val = h->vals[j]; \
  180. __ac_set_isdel_true(h->flags, j); \
  181. while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
  182. khint_t k, i, step = 0; \
  183. k = __hash_func(key->ptr_field, key->len_field); \
  184. i = k & new_mask; \
  185. while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
  186. __ac_set_isempty_false(new_flags, i); \
  187. if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
  188. { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
  189. if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
  190. __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
  191. } else { /* write the element and jump out of the loop */ \
  192. h->keys[i] = key; \
  193. if (kh_is_map) h->vals[i] = val; \
  194. break; \
  195. } \
  196. } \
  197. } \
  198. } \
  199. if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
  200. h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
  201. if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
  202. } \
  203. kfree(h->flags); /* free the working space */ \
  204. h->flags = new_flags; \
  205. h->n_buckets = new_n_buckets; \
  206. h->n_occupied = h->size; \
  207. h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
  208. } \
  209. return 0; \
  210. } \
  211. SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
  212. { \
  213. khint_t x; \
  214. if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
  215. if (h->n_buckets > (h->size<<1)) { \
  216. if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
  217. *ret = -1; return h->n_buckets; \
  218. } \
  219. } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
  220. *ret = -1; return h->n_buckets; \
  221. } \
  222. } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
  223. { \
  224. khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
  225. x = site = h->n_buckets; k = __hash_func(key->ptr_field, key->len_field); i = k & mask; \
  226. if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
  227. else { \
  228. last = i; \
  229. while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || \
  230. !__hash_equal(h->keys[i]->ptr_field, key->ptr_field, h->keys[i]->len_field, key->len_field))) { \
  231. if (__ac_isdel(h->flags, i)) site = i; \
  232. i = (i + (++step)) & mask; \
  233. if (i == last) { x = site; break; } \
  234. } \
  235. if (x == h->n_buckets) { \
  236. if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
  237. else x = i; \
  238. } \
  239. } \
  240. } \
  241. if (__ac_isempty(h->flags, x)) { /* not present at all */ \
  242. h->keys[x] = key; \
  243. __ac_set_isboth_false(h->flags, x); \
  244. ++h->size; ++h->n_occupied; \
  245. *ret = 1; \
  246. } else if (__ac_isdel(h->flags, x)) { /* deleted */ \
  247. h->keys[x] = key; \
  248. __ac_set_isboth_false(h->flags, x); \
  249. ++h->size; \
  250. *ret = 2; \
  251. } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
  252. return x; \
  253. } \
  254. SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
  255. { \
  256. if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
  257. __ac_set_isdel_true(h->flags, x); \
  258. --h->size; \
  259. } \
  260. }
  261. #define KHASH_DECLARE(name, khkey_t, khval_t) \
  262. __KHASH_TYPE(name, khkey_t, khval_t) \
  263. __KHASH_PROTOTYPES(name, khkey_t, khval_t)
  264. #define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, ptr_field, len_field, __hash_func, __hash_equal) \
  265. __KHASH_TYPE(name, khkey_t, khval_t) \
  266. __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, ptr_field, len_field, __hash_func, __hash_equal)
  267. #define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, ptr_field, len_field, __hash_func, __hash_equal) \
  268. KHASH_INIT2(name, static kh_inline klib_unused, khkey_t, khval_t, kh_is_map, ptr_field, len_field, __hash_func, __hash_equal)
  269. /* Other convenient macros... */
  270. /*!
  271. @abstract Type of the hash table.
  272. @param name Name of the hash table [symbol]
  273. */
  274. #define khash_t(name) kh_##name##_t
  275. /*! @function
  276. @abstract Initiate a hash table.
  277. @param name Name of the hash table [symbol]
  278. @return Pointer to the hash table [khash_t(name)*]
  279. */
  280. #define kh_init(name) kh_init_##name()
  281. /*! @function
  282. @abstract Destroy a hash table.
  283. @param name Name of the hash table [symbol]
  284. @param h Pointer to the hash table [khash_t(name)*]
  285. */
  286. #define kh_destroy(name, h) kh_destroy_##name(h)
  287. /*! @function
  288. @abstract Reset a hash table without deallocating memory.
  289. @param name Name of the hash table [symbol]
  290. @param h Pointer to the hash table [khash_t(name)*]
  291. */
  292. #define kh_clear(name, h) kh_clear_##name(h)
  293. /*! @function
  294. @abstract Resize a hash table.
  295. @param name Name of the hash table [symbol]
  296. @param h Pointer to the hash table [khash_t(name)*]
  297. @param s New size [khint_t]
  298. */
  299. #define kh_resize(name, h, s) kh_resize_##name(h, s)
  300. /*! @function
  301. @abstract Insert a key to the hash table.
  302. @param name Name of the hash table [symbol]
  303. @param h Pointer to the hash table [khash_t(name)*]
  304. @param k Key [type of keys]
  305. @param r Extra return code: -1 if the operation failed;
  306. 0 if the key is present in the hash table;
  307. 1 if the bucket is empty (never used); 2 if the element in
  308. the bucket has been deleted [int*]
  309. @return Iterator to the inserted element [khint_t]
  310. */
  311. #define kh_put(name, h, k, r) kh_put_##name(h, k, r)
  312. /*! @function
  313. @abstract Retrieve a key from the hash table.
  314. @param name Name of the hash table [symbol]
  315. @param h Pointer to the hash table [khash_t(name)*]
  316. @param k Key [type of keys]
  317. @return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
  318. */
  319. #define kh_get(name, h, k) kh_get_##name(h, k)
  320. #define kh_get_no_obj(name, h, kp, kl) kh_get_no_obj_##name(h, kp, kl)
  321. /*! @function
  322. @abstract Remove a key from the hash table.
  323. @param name Name of the hash table [symbol]
  324. @param h Pointer to the hash table [khash_t(name)*]
  325. @param k Iterator to the element to be deleted [khint_t]
  326. */
  327. #define kh_del(name, h, k) kh_del_##name(h, k)
  328. /*! @function
  329. @abstract Test whether a bucket contains data.
  330. @param h Pointer to the hash table [khash_t(name)*]
  331. @param x Iterator to the bucket [khint_t]
  332. @return 1 if containing data; 0 otherwise [int]
  333. */
  334. #define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
  335. /*! @function
  336. @abstract Get key given an iterator
  337. @param h Pointer to the hash table [khash_t(name)*]
  338. @param x Iterator to the bucket [khint_t]
  339. @return Key [type of keys]
  340. */
  341. #define kh_key(h, x) ((h)->keys[x])
  342. /*! @function
  343. @abstract Get value given an iterator
  344. @param h Pointer to the hash table [khash_t(name)*]
  345. @param x Iterator to the bucket [khint_t]
  346. @return Value [type of values]
  347. @discussion For hash sets, calling this results in segfault.
  348. */
  349. #define kh_val(h, x) ((h)->vals[x])
  350. /*! @function
  351. @abstract Alias of kh_val()
  352. */
  353. #define kh_value(h, x) ((h)->vals[x])
  354. /*! @function
  355. @abstract Get the start iterator
  356. @param h Pointer to the hash table [khash_t(name)*]
  357. @return The start iterator [khint_t]
  358. */
  359. #define kh_begin(h) (khint_t)(0)
  360. /*! @function
  361. @abstract Get the end iterator
  362. @param h Pointer to the hash table [khash_t(name)*]
  363. @return The end iterator [khint_t]
  364. */
  365. #define kh_end(h) ((h)->n_buckets)
  366. /*! @function
  367. @abstract Get the number of elements in the hash table
  368. @param h Pointer to the hash table [khash_t(name)*]
  369. @return Number of elements in the hash table [khint_t]
  370. */
  371. #define kh_size(h) ((h)->size)
  372. /*! @function
  373. @abstract Get the number of buckets in the hash table
  374. @param h Pointer to the hash table [khash_t(name)*]
  375. @return Number of buckets in the hash table [khint_t]
  376. */
  377. #define kh_n_buckets(h) ((h)->n_buckets)
  378. /*! @function
  379. @abstract Iterate over the entries in the hash table
  380. @param h Pointer to the hash table [khash_t(name)*]
  381. @param kvar Variable to which key will be assigned
  382. @param vvar Variable to which value will be assigned
  383. @param code Block of code to execute
  384. */
  385. #define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
  386. for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
  387. if (!kh_exist(h,__i)) continue; \
  388. (kvar) = kh_key(h,__i); \
  389. (vvar) = kh_val(h,__i); \
  390. code; \
  391. } }
  392. /*! @function
  393. @abstract Iterate over the values in the hash table
  394. @param h Pointer to the hash table [khash_t(name)*]
  395. @param vvar Variable to which value will be assigned
  396. @param code Block of code to execute
  397. */
  398. #define kh_foreach_value(h, vvar, code) { khint_t __i; \
  399. for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
  400. if (!kh_exist(h,__i)) continue; \
  401. (vvar) = kh_val(h,__i); \
  402. code; \
  403. } }
  404. /* --- BEGIN OF HASH FUNCTIONS --- */
  405. #include "../../src/memcasecmp.h"
  406. /**
  407. * This hash function results in far better distribution than the default X31
  408. * function and isn't significantly more expensive.
  409. *
  410. * http://isthe.com/chongo/tech/comp/fnv/#FNV-1a
  411. */
  412. // TODO make case sensitive version?
  413. static kh_inline khint_t fnv_1a_hash_string_len(const void *_str, khint_t len)
  414. {
  415. const char *str = _str;
  416. khint_t h = 0;
  417. for(; len; len--)
  418. h = (h ^ (khint_t)memtolower((int)*(str++))) * 16777619;
  419. return h;
  420. }
  421. #define kh_mem_hash_func(keyptr, keylen) \
  422. fnv_1a_hash_string_len(keyptr, keylen)
  423. // TODO make case sensitive version?
  424. #define kh_mem_hash_equal(aptr, bptr, alen, blen) \
  425. (((khint_t)alen == (khint_t)blen) && !memcasecmp(aptr, bptr, blen))
  426. /* --- END OF HASH FUNCTIONS --- */
  427. #define KHASH_SET_INIT(name, khkey_t, key_ptr_field, key_len_field) \
  428. KHASH_INIT(name, khkey_t, char, 0, \
  429. key_ptr_field, key_len_field, kh_mem_hash_func, kh_mem_hash_equal)
  430. #define KHASH_MAP_INIT(name, khkey_t, khval_t, key_ptr_field, key_len_field) \
  431. KHASH_INIT(name, khkey_t, khval_t, 1, \
  432. key_ptr_field, key_len_field, kh_mem_hash_func, kh_mem_hash_equal)
  433. // uthash-like macros.
  434. #define KHASH_ADD(n, h, keyobj) do \
  435. { \
  436. int _res; \
  437. if(!h) h = kh_init(n); \
  438. kh_put(n, (khash_t(n) *)h, keyobj, &_res); \
  439. } while(0)
  440. #define KHASH_FIND(n, _h, keyptr, keylen, destobj) do \
  441. { \
  442. destobj = NULL; \
  443. if(_h) \
  444. { \
  445. khash_t(n) *h = _h; \
  446. khint_t iter = kh_get_no_obj(n, h, keyptr, (khint_t)keylen); \
  447. \
  448. if(iter < kh_end(h)) destobj = h->keys[iter]; \
  449. } \
  450. } while(0)
  451. #define KHASH_DELETE(n, _h, keyobj) do \
  452. { \
  453. if(_h) \
  454. { \
  455. khash_t(n) *h = _h; \
  456. khint_t iter = kh_get(n, h, keyobj); \
  457. \
  458. if(iter < kh_end(h)) kh_del(n, h, iter); \
  459. } \
  460. } while(0)
  461. #define KHASH_CLEAR(n, _h) do \
  462. { \
  463. if(_h) \
  464. { \
  465. khash_t(n) *h = _h; \
  466. kh_destroy(n, h); \
  467. _h = NULL; \
  468. } \
  469. } while(0)
  470. #define KHASH_ITER(n, _h, element, code) do \
  471. { \
  472. khash_t(n) *__h = _h; \
  473. khint_t __i; \
  474. if(_h) for(__i = kh_begin(__h); __i != kh_end(__h); __i++) \
  475. { \
  476. if(!kh_exist(__h, __i)) continue; \
  477. (element) = kh_key(__h, __i); \
  478. code; \
  479. } \
  480. } while(0)
  481. #endif // KHASHMZX_H