The second batch
[git] / khash.h
1 /* The MIT License
2
3    Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
4
5    Permission is hereby granted, free of charge, to any person obtaining
6    a copy of this software and associated documentation files (the
7    "Software"), to deal in the Software without restriction, including
8    without limitation the rights to use, copy, modify, merge, publish,
9    distribute, sublicense, and/or sell copies of the Software, and to
10    permit persons to whom the Software is furnished to do so, subject to
11    the following conditions:
12
13    The above copyright notice and this permission notice shall be
14    included in all copies or substantial portions of the Software.
15
16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23    SOFTWARE.
24 */
25
26 #ifndef __AC_KHASH_H
27 #define __AC_KHASH_H
28
29 #include "cache.h"
30 #include "hashmap.h"
31
32 #define AC_VERSION_KHASH_H "0.2.8"
33
34 typedef uint32_t khint32_t;
35 typedef uint64_t khint64_t;
36
37 typedef khint32_t khint_t;
38 typedef khint_t khiter_t;
39
40 #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
41 #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
42 #define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
43 #define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
44 #define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
45 #define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
46 #define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
47
48 #define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
49
50 #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
51
52 static inline khint_t __ac_X31_hash_string(const char *s)
53 {
54         khint_t h = (khint_t)*s;
55         if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
56         return h;
57 }
58
59 #define kh_str_hash_func(key) __ac_X31_hash_string(key)
60 #define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
61
62 static const double __ac_HASH_UPPER = 0.77;
63
64 #define __KHASH_TYPE(name, khkey_t, khval_t) \
65         typedef struct { \
66                 khint_t n_buckets, size, n_occupied, upper_bound; \
67                 khint32_t *flags; \
68                 khkey_t *keys; \
69                 khval_t *vals; \
70         } kh_##name##_t;
71
72 #define __KHASH_PROTOTYPES(name, khkey_t, khval_t)                              \
73         kh_##name##_t *kh_init_##name(void);                                            \
74         void kh_destroy_##name(kh_##name##_t *h);                                       \
75         void kh_clear_##name(kh_##name##_t *h);                                         \
76         khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
77         int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
78         khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
79         void kh_del_##name(kh_##name##_t *h, khint_t x);
80
81 #define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
82         SCOPE kh_##name##_t *kh_init_##name(void) {                                                     \
83                 return (kh_##name##_t*)xcalloc(1, sizeof(kh_##name##_t));               \
84         }                                                                                                                                       \
85         SCOPE void kh_release_##name(kh_##name##_t *h)                                          \
86         {                                                                                                                                       \
87                 free(h->flags);                                                                                                 \
88                 free((void *)h->keys);                                                                                  \
89                 free((void *)h->vals);                                                                                  \
90         }                                                                                                                                       \
91         SCOPE void kh_destroy_##name(kh_##name##_t *h)                                          \
92         {                                                                                                                                       \
93                 if (h) {                                                                                                                \
94                         kh_release_##name(h);                                                                           \
95                         free(h);                                                                                                        \
96                 }                                                                                                                               \
97         }                                                                                                                                       \
98         SCOPE void kh_clear_##name(kh_##name##_t *h)                                            \
99         {                                                                                                                                       \
100                 if (h && h->flags) {                                                                                    \
101                         memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
102                         h->size = h->n_occupied = 0;                                                            \
103                 }                                                                                                                               \
104         }                                                                                                                                       \
105         SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key)        \
106         {                                                                                                                                       \
107                 if (h->n_buckets) {                                                                                             \
108                         khint_t k, i, last, mask, step = 0; \
109                         mask = h->n_buckets - 1;                                                                        \
110                         k = __hash_func(key); i = k & mask;                                                     \
111                         last = i; \
112                         while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
113                                 i = (i + (++step)) & mask; \
114                                 if (i == last) return h->n_buckets;                                             \
115                         }                                                                                                                       \
116                         return __ac_iseither(h->flags, i)? h->n_buckets : i;            \
117                 } else return 0;                                                                                                \
118         }                                                                                                                                       \
119         SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
120         { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
121                 khint32_t *new_flags = NULL;                                                                            \
122                 khint_t j = 1;                                                                                                  \
123                 {                                                                                                                               \
124                         kroundup32(new_n_buckets);                                                                      \
125                         if (new_n_buckets < 4) new_n_buckets = 4;                                       \
126                         if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
127                         else { /* hash table size to be changed (shrink or expand); rehash */ \
128                                 ALLOC_ARRAY(new_flags, __ac_fsize(new_n_buckets)); \
129                                 if (!new_flags) return -1;                                                              \
130                                 memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
131                                 if (h->n_buckets < new_n_buckets) {     /* expand */            \
132                                         REALLOC_ARRAY(h->keys, new_n_buckets); \
133                                         if (kh_is_map) {                                                                        \
134                                                 REALLOC_ARRAY(h->vals, new_n_buckets); \
135                                         }                                                                                                       \
136                                 } /* otherwise shrink */                                                                \
137                         }                                                                                                                       \
138                 }                                                                                                                               \
139                 if (j) { /* rehashing is needed */                                                              \
140                         for (j = 0; j != h->n_buckets; ++j) {                                           \
141                                 if (__ac_iseither(h->flags, j) == 0) {                                  \
142                                         khkey_t key = h->keys[j];                                                       \
143                                         khval_t val;                                                                            \
144                                         khint_t new_mask;                                                                       \
145                                         new_mask = new_n_buckets - 1;                                           \
146                                         if (kh_is_map) val = h->vals[j];                                        \
147                                         __ac_set_isdel_true(h->flags, j);                                       \
148                                         while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
149                                                 khint_t k, i, step = 0; \
150                                                 k = __hash_func(key);                                                   \
151                                                 i = k & new_mask;                                                               \
152                                                 while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
153                                                 __ac_set_isempty_false(new_flags, i);                   \
154                                                 if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
155                                                         { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
156                                                         if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
157                                                         __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
158                                                 } else { /* write the element and jump out of the loop */ \
159                                                         h->keys[i] = key;                                                       \
160                                                         if (kh_is_map) h->vals[i] = val;                        \
161                                                         break;                                                                          \
162                                                 }                                                                                               \
163                                         }                                                                                                       \
164                                 }                                                                                                               \
165                         }                                                                                                                       \
166                         if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
167                                 REALLOC_ARRAY(h->keys, new_n_buckets); \
168                                 if (kh_is_map) REALLOC_ARRAY(h->vals, new_n_buckets); \
169                         }                                                                                                                       \
170                         free(h->flags); /* free the working space */                            \
171                         h->flags = new_flags;                                                                           \
172                         h->n_buckets = new_n_buckets;                                                           \
173                         h->n_occupied = h->size;                                                                        \
174                         h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
175                 }                                                                                                                               \
176                 return 0;                                                                                                               \
177         }                                                                                                                                       \
178         SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
179         {                                                                                                                                       \
180                 khint_t x;                                                                                                              \
181                 if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
182                         if (h->n_buckets > (h->size<<1)) {                                                      \
183                                 if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
184                                         *ret = -1; return h->n_buckets;                                         \
185                                 }                                                                                                               \
186                         } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
187                                 *ret = -1; return h->n_buckets;                                                 \
188                         }                                                                                                                       \
189                 } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
190                 {                                                                                                                               \
191                         khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
192                         x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
193                         if (__ac_isempty(h->flags, i)) x = i; /* for speed up */        \
194                         else {                                                                                                          \
195                                 last = i; \
196                                 while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
197                                         if (__ac_isdel(h->flags, i)) site = i;                          \
198                                         i = (i + (++step)) & mask; \
199                                         if (i == last) { x = site; break; }                                     \
200                                 }                                                                                                               \
201                                 if (x == h->n_buckets) {                                                                \
202                                         if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
203                                         else x = i;                                                                                     \
204                                 }                                                                                                               \
205                         }                                                                                                                       \
206                 }                                                                                                                               \
207                 if (__ac_isempty(h->flags, x)) { /* not present at all */               \
208                         h->keys[x] = key;                                                                                       \
209                         __ac_set_isboth_false(h->flags, x);                                                     \
210                         ++h->size; ++h->n_occupied;                                                                     \
211                         *ret = 1;                                                                                                       \
212                 } else if (__ac_isdel(h->flags, x)) { /* deleted */                             \
213                         h->keys[x] = key;                                                                                       \
214                         __ac_set_isboth_false(h->flags, x);                                                     \
215                         ++h->size;                                                                                                      \
216                         *ret = 2;                                                                                                       \
217                 } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
218                 return x;                                                                                                               \
219         }                                                                                                                                       \
220         SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x)                           \
221         {                                                                                                                                       \
222                 if (x != h->n_buckets && !__ac_iseither(h->flags, x)) {                 \
223                         __ac_set_isdel_true(h->flags, x);                                                       \
224                         --h->size;                                                                                                      \
225                 }                                                                                                                               \
226         }
227
228 #define KHASH_DECLARE(name, khkey_t, khval_t)                                                   \
229         __KHASH_TYPE(name, khkey_t, khval_t)                                                            \
230         __KHASH_PROTOTYPES(name, khkey_t, khval_t)
231
232 #define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
233         __KHASH_TYPE(name, khkey_t, khval_t)                                                            \
234         __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
235
236 #define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
237         KHASH_INIT2(name, MAYBE_UNUSED static inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
238
239 /* Other convenient macros... */
240
241 /*! @function
242   @abstract     Test whether a bucket contains data.
243   @param  h     Pointer to the hash table [khash_t(name)*]
244   @param  x     Iterator to the bucket [khint_t]
245   @return       1 if containing data; 0 otherwise [int]
246  */
247 #define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
248
249 /*! @function
250   @abstract     Get key given an iterator
251   @param  h     Pointer to the hash table [khash_t(name)*]
252   @param  x     Iterator to the bucket [khint_t]
253   @return       Key [type of keys]
254  */
255 #define kh_key(h, x) ((h)->keys[x])
256
257 /*! @function
258   @abstract     Get value given an iterator
259   @param  h     Pointer to the hash table [khash_t(name)*]
260   @param  x     Iterator to the bucket [khint_t]
261   @return       Value [type of values]
262   @discussion   For hash sets, calling this results in segfault.
263  */
264 #define kh_val(h, x) ((h)->vals[x])
265
266 /*! @function
267   @abstract     Alias of kh_val()
268  */
269 #define kh_value(h, x) ((h)->vals[x])
270
271 /*! @function
272   @abstract     Get the start iterator
273   @param  h     Pointer to the hash table [khash_t(name)*]
274   @return       The start iterator [khint_t]
275  */
276 #define kh_begin(h) (khint_t)(0)
277
278 /*! @function
279   @abstract     Get the end iterator
280   @param  h     Pointer to the hash table [khash_t(name)*]
281   @return       The end iterator [khint_t]
282  */
283 #define kh_end(h) ((h)->n_buckets)
284
285 /*! @function
286   @abstract     Get the number of elements in the hash table
287   @param  h     Pointer to the hash table [khash_t(name)*]
288   @return       Number of elements in the hash table [khint_t]
289  */
290 #define kh_size(h) ((h)->size)
291
292 /*! @function
293   @abstract     Get the number of buckets in the hash table
294   @param  h     Pointer to the hash table [khash_t(name)*]
295   @return       Number of buckets in the hash table [khint_t]
296  */
297 #define kh_n_buckets(h) ((h)->n_buckets)
298
299 /*! @function
300   @abstract     Iterate over the entries in the hash table
301   @param  h     Pointer to the hash table [khash_t(name)*]
302   @param  kvar  Variable to which key will be assigned
303   @param  vvar  Variable to which value will be assigned
304   @param  code  Block of code to execute
305  */
306 #define kh_foreach(h, kvar, vvar, code) { khint_t __i;          \
307         for (__i = kh_begin(h); __i != kh_end(h); ++__i) {              \
308                 if (!kh_exist(h,__i)) continue;                                         \
309                 (kvar) = kh_key(h,__i);                                                         \
310                 (vvar) = kh_val(h,__i);                                                         \
311                 code;                                                                                           \
312         } }
313
314 /*! @function
315   @abstract     Iterate over the values in the hash table
316   @param  h     Pointer to the hash table [khash_t(name)*]
317   @param  vvar  Variable to which value will be assigned
318   @param  code  Block of code to execute
319  */
320 #define kh_foreach_value(h, vvar, code) { khint_t __i;          \
321         for (__i = kh_begin(h); __i != kh_end(h); ++__i) {              \
322                 if (!kh_exist(h,__i)) continue;                                         \
323                 (vvar) = kh_val(h,__i);                                                         \
324                 code;                                                                                           \
325         } }
326
327 static inline unsigned int oidhash_by_value(struct object_id oid)
328 {
329         return oidhash(&oid);
330 }
331
332 static inline int oideq_by_value(struct object_id a, struct object_id b)
333 {
334         return oideq(&a, &b);
335 }
336
337 KHASH_INIT(oid_set, struct object_id, int, 0, oidhash_by_value, oideq_by_value)
338
339 KHASH_INIT(oid_map, struct object_id, void *, 1, oidhash_by_value, oideq_by_value)
340
341 KHASH_INIT(oid_pos, struct object_id, int, 1, oidhash_by_value, oideq_by_value)
342
343 #endif /* __AC_KHASH_H */