| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* The MIT License |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Copyright (c) 2019- by Attractive Chaos |
|
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_KHASHL_H |
|
27
|
|
|
|
|
|
|
#define __AC_KHASHL_H |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
#define AC_VERSION_KHASHL_H "r30" |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
#include |
|
32
|
|
|
|
|
|
|
#include |
|
33
|
|
|
|
|
|
|
#include |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
/************************************ |
|
36
|
|
|
|
|
|
|
* Compiler specific configurations * |
|
37
|
|
|
|
|
|
|
************************************/ |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
#if UINT_MAX == 0xffffffffu |
|
40
|
|
|
|
|
|
|
typedef unsigned int khint32_t; |
|
41
|
|
|
|
|
|
|
#elif ULONG_MAX == 0xffffffffu |
|
42
|
|
|
|
|
|
|
typedef unsigned long khint32_t; |
|
43
|
|
|
|
|
|
|
#endif |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
#if ULONG_MAX == ULLONG_MAX |
|
46
|
|
|
|
|
|
|
typedef unsigned long khint64_t; |
|
47
|
|
|
|
|
|
|
#else |
|
48
|
|
|
|
|
|
|
typedef unsigned long long khint64_t; |
|
49
|
|
|
|
|
|
|
#endif |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
#ifndef kh_inline |
|
52
|
|
|
|
|
|
|
#ifdef _MSC_VER |
|
53
|
|
|
|
|
|
|
#define kh_inline __inline |
|
54
|
|
|
|
|
|
|
#else |
|
55
|
|
|
|
|
|
|
#define kh_inline inline |
|
56
|
|
|
|
|
|
|
#endif |
|
57
|
|
|
|
|
|
|
#endif /* kh_inline */ |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
#ifndef klib_unused |
|
60
|
|
|
|
|
|
|
#if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3) |
|
61
|
|
|
|
|
|
|
#define klib_unused __attribute__ ((__unused__)) |
|
62
|
|
|
|
|
|
|
#else |
|
63
|
|
|
|
|
|
|
#define klib_unused |
|
64
|
|
|
|
|
|
|
#endif |
|
65
|
|
|
|
|
|
|
#endif /* klib_unused */ |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
#define KH_LOCAL static kh_inline klib_unused |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
typedef khint32_t khint_t; |
|
70
|
|
|
|
|
|
|
typedef const char *kh_cstr_t; |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
/*********************** |
|
73
|
|
|
|
|
|
|
* Configurable macros * |
|
74
|
|
|
|
|
|
|
***********************/ |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
#ifndef kh_max_count /* set the max load factor */ |
|
77
|
|
|
|
|
|
|
#define kh_max_count(cap) (((cap)>>1) + ((cap)>>2)) /* default load factor: 75% */ |
|
78
|
|
|
|
|
|
|
#endif |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
#ifndef kh_packed /* pack the key-value struct */ |
|
81
|
|
|
|
|
|
|
#define kh_packed __attribute__ ((__packed__)) |
|
82
|
|
|
|
|
|
|
#endif |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
#if !defined(Kmalloc) || !defined(Kcalloc) || !defined(Krealloc) || !defined(Kfree) |
|
85
|
|
|
|
|
|
|
#define Kmalloc(km, type, cnt) ((type*)malloc((cnt) * sizeof(type))) |
|
86
|
|
|
|
|
|
|
#define Kcalloc(km, type, cnt) ((type*)calloc((cnt), sizeof(type))) |
|
87
|
|
|
|
|
|
|
#define Krealloc(km, type, ptr, cnt) ((type*)realloc((ptr), (cnt) * sizeof(type))) |
|
88
|
|
|
|
|
|
|
#define Kfree(km, ptr) free(ptr) |
|
89
|
|
|
|
|
|
|
#endif |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
/**************************** |
|
92
|
|
|
|
|
|
|
* Simple private functions * |
|
93
|
|
|
|
|
|
|
****************************/ |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
#define __kh_used(flag, i) (flag[i>>5] >> (i&0x1fU) & 1U) |
|
96
|
|
|
|
|
|
|
#define __kh_set_used(flag, i) (flag[i>>5] |= 1U<<(i&0x1fU)) |
|
97
|
|
|
|
|
|
|
#define __kh_set_unused(flag, i) (flag[i>>5] &= ~(1U<<(i&0x1fU))) |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
#define __kh_fsize(m) ((m) < 32? 1 : (m)>>5) |
|
100
|
|
|
|
|
|
|
|
|
101
|
0
|
|
|
|
|
|
static kh_inline khint_t __kh_h2b(khint_t hash, khint_t bits) { return hash * 2654435769U >> (32 - bits); } /* Fibonacci hashing */ |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
/******************* |
|
104
|
|
|
|
|
|
|
* Hash table base * |
|
105
|
|
|
|
|
|
|
*******************/ |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
#define __KHASHL_TYPE(HType, khkey_t) \ |
|
108
|
|
|
|
|
|
|
typedef struct HType { \ |
|
109
|
|
|
|
|
|
|
void *km; \ |
|
110
|
|
|
|
|
|
|
khint_t bits, count; \ |
|
111
|
|
|
|
|
|
|
khint32_t *used; \ |
|
112
|
|
|
|
|
|
|
khkey_t *keys; \ |
|
113
|
|
|
|
|
|
|
} HType; |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
#define __KHASHL_PROTOTYPES(HType, prefix, khkey_t) \ |
|
116
|
|
|
|
|
|
|
extern HType *prefix##_init(void); \ |
|
117
|
|
|
|
|
|
|
extern HType *prefix##_init2(void *km); \ |
|
118
|
|
|
|
|
|
|
extern void prefix##_destroy(HType *h); \ |
|
119
|
|
|
|
|
|
|
extern void prefix##_clear(HType *h); \ |
|
120
|
|
|
|
|
|
|
extern khint_t prefix##_getp(const HType *h, const khkey_t *key); \ |
|
121
|
|
|
|
|
|
|
extern int prefix##_resize(HType *h, khint_t new_n_buckets); \ |
|
122
|
|
|
|
|
|
|
extern khint_t prefix##_putp(HType *h, const khkey_t *key, int *absent); \ |
|
123
|
|
|
|
|
|
|
extern void prefix##_del(HType *h, khint_t k); |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
#define __KHASHL_IMPL_BASIC(SCOPE, HType, prefix) \ |
|
126
|
|
|
|
|
|
|
SCOPE HType *prefix##_init2(void *km) { \ |
|
127
|
|
|
|
|
|
|
HType *h = Kcalloc(km, HType, 1); \ |
|
128
|
|
|
|
|
|
|
h->km = km; \ |
|
129
|
|
|
|
|
|
|
return h; \ |
|
130
|
|
|
|
|
|
|
} \ |
|
131
|
|
|
|
|
|
|
SCOPE HType *prefix##_init(void) { return prefix##_init2(0); } \ |
|
132
|
|
|
|
|
|
|
SCOPE void prefix##_destroy(HType *h) { \ |
|
133
|
|
|
|
|
|
|
if (!h) return; \ |
|
134
|
|
|
|
|
|
|
Kfree(h->km, (void*)h->keys); Kfree(h->km, h->used); \ |
|
135
|
|
|
|
|
|
|
Kfree(h->km, h); \ |
|
136
|
|
|
|
|
|
|
} \ |
|
137
|
|
|
|
|
|
|
SCOPE void prefix##_clear(HType *h) { \ |
|
138
|
|
|
|
|
|
|
if (h && h->used) { \ |
|
139
|
|
|
|
|
|
|
khint_t n_buckets = (khint_t)1U << h->bits; \ |
|
140
|
|
|
|
|
|
|
memset(h->used, 0, __kh_fsize(n_buckets) * sizeof(khint32_t)); \ |
|
141
|
|
|
|
|
|
|
h->count = 0; \ |
|
142
|
|
|
|
|
|
|
} \ |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
#define __KHASHL_IMPL_GET(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
146
|
|
|
|
|
|
|
SCOPE khint_t prefix##_getp_core(const HType *h, const khkey_t *key, khint_t hash) { \ |
|
147
|
|
|
|
|
|
|
khint_t i, last, n_buckets, mask; \ |
|
148
|
|
|
|
|
|
|
if (h->keys == 0) return 0; \ |
|
149
|
|
|
|
|
|
|
n_buckets = (khint_t)1U << h->bits; \ |
|
150
|
|
|
|
|
|
|
mask = n_buckets - 1U; \ |
|
151
|
|
|
|
|
|
|
i = last = __kh_h2b(hash, h->bits); \ |
|
152
|
|
|
|
|
|
|
while (__kh_used(h->used, i) && !__hash_eq(h->keys[i], *key)) { \ |
|
153
|
|
|
|
|
|
|
i = (i + 1U) & mask; \ |
|
154
|
|
|
|
|
|
|
if (i == last) return n_buckets; \ |
|
155
|
|
|
|
|
|
|
} \ |
|
156
|
|
|
|
|
|
|
return !__kh_used(h->used, i)? n_buckets : i; \ |
|
157
|
|
|
|
|
|
|
} \ |
|
158
|
|
|
|
|
|
|
SCOPE khint_t prefix##_getp(const HType *h, const khkey_t *key) { return prefix##_getp_core(h, key, __hash_fn(*key)); } \ |
|
159
|
|
|
|
|
|
|
SCOPE khint_t prefix##_get(const HType *h, khkey_t key) { return prefix##_getp_core(h, &key, __hash_fn(key)); } |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
#define __KHASHL_IMPL_RESIZE(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
162
|
|
|
|
|
|
|
SCOPE int prefix##_resize(HType *h, khint_t new_n_buckets) { \ |
|
163
|
|
|
|
|
|
|
khint32_t *new_used = 0; \ |
|
164
|
|
|
|
|
|
|
khint_t j = 0, x = new_n_buckets, n_buckets, new_bits, new_mask; \ |
|
165
|
|
|
|
|
|
|
while ((x >>= 1) != 0) ++j; \ |
|
166
|
|
|
|
|
|
|
if (new_n_buckets & (new_n_buckets - 1)) ++j; \ |
|
167
|
|
|
|
|
|
|
new_bits = j > 2? j : 2; \ |
|
168
|
|
|
|
|
|
|
new_n_buckets = (khint_t)1U << new_bits; \ |
|
169
|
|
|
|
|
|
|
if (h->count > kh_max_count(new_n_buckets)) return 0; /* requested size is too small */ \ |
|
170
|
|
|
|
|
|
|
new_used = Kmalloc(h->km, khint32_t, __kh_fsize(new_n_buckets)); \ |
|
171
|
|
|
|
|
|
|
memset(new_used, 0, __kh_fsize(new_n_buckets) * sizeof(khint32_t)); \ |
|
172
|
|
|
|
|
|
|
if (!new_used) return -1; /* not enough memory */ \ |
|
173
|
|
|
|
|
|
|
n_buckets = h->keys? (khint_t)1U<bits : 0U; \ |
|
174
|
|
|
|
|
|
|
if (n_buckets < new_n_buckets) { /* expand */ \ |
|
175
|
|
|
|
|
|
|
khkey_t *new_keys = Krealloc(h->km, khkey_t, h->keys, new_n_buckets); \ |
|
176
|
|
|
|
|
|
|
if (!new_keys) { Kfree(h->km, new_used); return -1; } \ |
|
177
|
|
|
|
|
|
|
h->keys = new_keys; \ |
|
178
|
|
|
|
|
|
|
} /* otherwise shrink */ \ |
|
179
|
|
|
|
|
|
|
new_mask = new_n_buckets - 1; \ |
|
180
|
|
|
|
|
|
|
for (j = 0; j != n_buckets; ++j) { \ |
|
181
|
|
|
|
|
|
|
khkey_t key; \ |
|
182
|
|
|
|
|
|
|
if (!__kh_used(h->used, j)) continue; \ |
|
183
|
|
|
|
|
|
|
key = h->keys[j]; \ |
|
184
|
|
|
|
|
|
|
__kh_set_unused(h->used, j); \ |
|
185
|
|
|
|
|
|
|
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ |
|
186
|
|
|
|
|
|
|
khint_t i; \ |
|
187
|
|
|
|
|
|
|
i = __kh_h2b(__hash_fn(key), new_bits); \ |
|
188
|
|
|
|
|
|
|
while (__kh_used(new_used, i)) i = (i + 1) & new_mask; \ |
|
189
|
|
|
|
|
|
|
__kh_set_used(new_used, i); \ |
|
190
|
|
|
|
|
|
|
if (i < n_buckets && __kh_used(h->used, i)) { /* kick out the existing element */ \ |
|
191
|
|
|
|
|
|
|
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \ |
|
192
|
|
|
|
|
|
|
__kh_set_unused(h->used, i); /* mark it as deleted in the old hash table */ \ |
|
193
|
|
|
|
|
|
|
} else { /* write the element and jump out of the loop */ \ |
|
194
|
|
|
|
|
|
|
h->keys[i] = key; \ |
|
195
|
|
|
|
|
|
|
break; \ |
|
196
|
|
|
|
|
|
|
} \ |
|
197
|
|
|
|
|
|
|
} \ |
|
198
|
|
|
|
|
|
|
} \ |
|
199
|
|
|
|
|
|
|
if (n_buckets > new_n_buckets) /* shrink the hash table */ \ |
|
200
|
|
|
|
|
|
|
h->keys = Krealloc(h->km, khkey_t, (void*)h->keys, new_n_buckets); \ |
|
201
|
|
|
|
|
|
|
Kfree(h->km, h->used); /* free the working space */ \ |
|
202
|
|
|
|
|
|
|
h->used = new_used, h->bits = new_bits; \ |
|
203
|
|
|
|
|
|
|
return 0; \ |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
#define __KHASHL_IMPL_PUT(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
207
|
|
|
|
|
|
|
SCOPE khint_t prefix##_putp_core(HType *h, const khkey_t *key, khint_t hash, int *absent) { \ |
|
208
|
|
|
|
|
|
|
khint_t n_buckets, i, last, mask; \ |
|
209
|
|
|
|
|
|
|
n_buckets = h->keys? (khint_t)1U<bits : 0U; \ |
|
210
|
|
|
|
|
|
|
*absent = -1; \ |
|
211
|
|
|
|
|
|
|
if (h->count >= kh_max_count(n_buckets)) { /* rehashing */ \ |
|
212
|
|
|
|
|
|
|
if (prefix##_resize(h, n_buckets + 1U) < 0) \ |
|
213
|
|
|
|
|
|
|
return n_buckets; \ |
|
214
|
|
|
|
|
|
|
n_buckets = (khint_t)1U<bits; \ |
|
215
|
|
|
|
|
|
|
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ |
|
216
|
|
|
|
|
|
|
mask = n_buckets - 1; \ |
|
217
|
|
|
|
|
|
|
i = last = __kh_h2b(hash, h->bits); \ |
|
218
|
|
|
|
|
|
|
while (__kh_used(h->used, i) && !__hash_eq(h->keys[i], *key)) { \ |
|
219
|
|
|
|
|
|
|
i = (i + 1U) & mask; \ |
|
220
|
|
|
|
|
|
|
if (i == last) break; \ |
|
221
|
|
|
|
|
|
|
} \ |
|
222
|
|
|
|
|
|
|
if (!__kh_used(h->used, i)) { /* not present at all */ \ |
|
223
|
|
|
|
|
|
|
h->keys[i] = *key; \ |
|
224
|
|
|
|
|
|
|
__kh_set_used(h->used, i); \ |
|
225
|
|
|
|
|
|
|
++h->count; \ |
|
226
|
|
|
|
|
|
|
*absent = 1; \ |
|
227
|
|
|
|
|
|
|
} else *absent = 0; /* Don't touch h->keys[i] if present */ \ |
|
228
|
|
|
|
|
|
|
return i; \ |
|
229
|
|
|
|
|
|
|
} \ |
|
230
|
|
|
|
|
|
|
SCOPE khint_t prefix##_putp(HType *h, const khkey_t *key, int *absent) { return prefix##_putp_core(h, key, __hash_fn(*key), absent); } \ |
|
231
|
|
|
|
|
|
|
SCOPE khint_t prefix##_put(HType *h, khkey_t key, int *absent) { return prefix##_putp_core(h, &key, __hash_fn(key), absent); } |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
#define __KHASHL_IMPL_DEL(SCOPE, HType, prefix, khkey_t, __hash_fn) \ |
|
234
|
|
|
|
|
|
|
SCOPE int prefix##_del(HType *h, khint_t i) { \ |
|
235
|
|
|
|
|
|
|
khint_t j = i, k, mask, n_buckets; \ |
|
236
|
|
|
|
|
|
|
if (h->keys == 0) return 0; \ |
|
237
|
|
|
|
|
|
|
n_buckets = (khint_t)1U<bits; \ |
|
238
|
|
|
|
|
|
|
mask = n_buckets - 1U; \ |
|
239
|
|
|
|
|
|
|
while (1) { \ |
|
240
|
|
|
|
|
|
|
j = (j + 1U) & mask; \ |
|
241
|
|
|
|
|
|
|
if (j == i || !__kh_used(h->used, j)) break; /* j==i only when the table is completely full */ \ |
|
242
|
|
|
|
|
|
|
k = __kh_h2b(__hash_fn(h->keys[j]), h->bits); \ |
|
243
|
|
|
|
|
|
|
if ((j > i && (k <= i || k > j)) || (j < i && (k <= i && k > j))) \ |
|
244
|
|
|
|
|
|
|
h->keys[i] = h->keys[j], i = j; \ |
|
245
|
|
|
|
|
|
|
} \ |
|
246
|
|
|
|
|
|
|
__kh_set_unused(h->used, i); \ |
|
247
|
|
|
|
|
|
|
--h->count; \ |
|
248
|
|
|
|
|
|
|
return 1; \ |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
#define KHASHL_DECLARE(HType, prefix, khkey_t) \ |
|
252
|
|
|
|
|
|
|
__KHASHL_TYPE(HType, khkey_t) \ |
|
253
|
|
|
|
|
|
|
__KHASHL_PROTOTYPES(HType, prefix, khkey_t) |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
#define KHASHL_INIT(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
256
|
|
|
|
|
|
|
__KHASHL_TYPE(HType, khkey_t) \ |
|
257
|
|
|
|
|
|
|
__KHASHL_IMPL_BASIC(SCOPE, HType, prefix) \ |
|
258
|
|
|
|
|
|
|
__KHASHL_IMPL_GET(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
259
|
|
|
|
|
|
|
__KHASHL_IMPL_RESIZE(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
260
|
|
|
|
|
|
|
__KHASHL_IMPL_PUT(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
261
|
|
|
|
|
|
|
__KHASHL_IMPL_DEL(SCOPE, HType, prefix, khkey_t, __hash_fn) |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
/*************************** |
|
264
|
|
|
|
|
|
|
* Ensemble of hash tables * |
|
265
|
|
|
|
|
|
|
***************************/ |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
typedef struct { |
|
268
|
|
|
|
|
|
|
khint_t sub, pos; |
|
269
|
|
|
|
|
|
|
} kh_ensitr_t; |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
#define KHASHE_INIT(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
272
|
|
|
|
|
|
|
KHASHL_INIT(KH_LOCAL, HType##_sub, prefix##_sub, khkey_t, __hash_fn, __hash_eq) \ |
|
273
|
|
|
|
|
|
|
typedef struct HType { \ |
|
274
|
|
|
|
|
|
|
void *km; \ |
|
275
|
|
|
|
|
|
|
khint64_t count:54, bits:8; \ |
|
276
|
|
|
|
|
|
|
HType##_sub *sub; \ |
|
277
|
|
|
|
|
|
|
} HType; \ |
|
278
|
|
|
|
|
|
|
SCOPE HType *prefix##_init2(void *km, int bits) { \ |
|
279
|
|
|
|
|
|
|
HType *g; \ |
|
280
|
|
|
|
|
|
|
g = Kcalloc(km, HType, 1); \ |
|
281
|
|
|
|
|
|
|
g->bits = bits, g->km = km; \ |
|
282
|
|
|
|
|
|
|
g->sub = Kcalloc(km, HType##_sub, 1U<
|
|
283
|
|
|
|
|
|
|
return g; \ |
|
284
|
|
|
|
|
|
|
} \ |
|
285
|
|
|
|
|
|
|
SCOPE HType *prefix##_init(int bits) { return prefix##_init2(0, bits); } \ |
|
286
|
|
|
|
|
|
|
SCOPE void prefix##_destroy(HType *g) { \ |
|
287
|
|
|
|
|
|
|
int t; \ |
|
288
|
|
|
|
|
|
|
if (!g) return; \ |
|
289
|
|
|
|
|
|
|
for (t = 0; t < 1<bits; ++t) { Kfree(g->km, (void*)g->sub[t].keys); Kfree(g->km, g->sub[t].used); } \ |
|
290
|
|
|
|
|
|
|
Kfree(g->km, g->sub); Kfree(g->km, g); \ |
|
291
|
|
|
|
|
|
|
} \ |
|
292
|
|
|
|
|
|
|
SCOPE kh_ensitr_t prefix##_getp(const HType *g, const khkey_t *key) { \ |
|
293
|
|
|
|
|
|
|
khint_t hash, low, ret; \ |
|
294
|
|
|
|
|
|
|
kh_ensitr_t r; \ |
|
295
|
|
|
|
|
|
|
HType##_sub *h; \ |
|
296
|
|
|
|
|
|
|
hash = __hash_fn(*key); \ |
|
297
|
|
|
|
|
|
|
low = hash & ((1U<bits) - 1); \ |
|
298
|
|
|
|
|
|
|
h = &g->sub[low]; \ |
|
299
|
|
|
|
|
|
|
ret = prefix##_sub_getp_core(h, key, hash); \ |
|
300
|
|
|
|
|
|
|
if (ret == kh_end(h)) r.sub = low, r.pos = (khint_t)-1; \ |
|
301
|
|
|
|
|
|
|
else r.sub = low, r.pos = ret; \ |
|
302
|
|
|
|
|
|
|
return r; \ |
|
303
|
|
|
|
|
|
|
} \ |
|
304
|
|
|
|
|
|
|
SCOPE kh_ensitr_t prefix##_get(const HType *g, const khkey_t key) { return prefix##_getp(g, &key); } \ |
|
305
|
|
|
|
|
|
|
SCOPE kh_ensitr_t prefix##_putp(HType *g, const khkey_t *key, int *absent) { \ |
|
306
|
|
|
|
|
|
|
khint_t hash, low, ret; \ |
|
307
|
|
|
|
|
|
|
kh_ensitr_t r; \ |
|
308
|
|
|
|
|
|
|
HType##_sub *h; \ |
|
309
|
|
|
|
|
|
|
hash = __hash_fn(*key); \ |
|
310
|
|
|
|
|
|
|
low = hash & ((1U<bits) - 1); \ |
|
311
|
|
|
|
|
|
|
h = &g->sub[low]; \ |
|
312
|
|
|
|
|
|
|
ret = prefix##_sub_putp_core(h, key, hash, absent); \ |
|
313
|
|
|
|
|
|
|
if (*absent) ++g->count; \ |
|
314
|
|
|
|
|
|
|
r.sub = low, r.pos = ret; \ |
|
315
|
|
|
|
|
|
|
return r; \ |
|
316
|
|
|
|
|
|
|
} \ |
|
317
|
|
|
|
|
|
|
SCOPE kh_ensitr_t prefix##_put(HType *g, const khkey_t key, int *absent) { return prefix##_putp(g, &key, absent); } \ |
|
318
|
|
|
|
|
|
|
SCOPE int prefix##_del(HType *g, kh_ensitr_t itr) { \ |
|
319
|
|
|
|
|
|
|
HType##_sub *h = &g->sub[itr.sub]; \ |
|
320
|
|
|
|
|
|
|
int ret; \ |
|
321
|
|
|
|
|
|
|
ret = prefix##_sub_del(h, itr.pos); \ |
|
322
|
|
|
|
|
|
|
if (ret) --g->count; \ |
|
323
|
|
|
|
|
|
|
return ret; \ |
|
324
|
|
|
|
|
|
|
} \ |
|
325
|
|
|
|
|
|
|
SCOPE void prefix##_clear(HType *g) { \ |
|
326
|
|
|
|
|
|
|
int i; \ |
|
327
|
|
|
|
|
|
|
for (i = 0; i < 1U<bits; ++i) prefix##_sub_clear(&g->sub[i]); \ |
|
328
|
|
|
|
|
|
|
g->count = 0; \ |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
/***************************** |
|
332
|
|
|
|
|
|
|
* More convenient interface * |
|
333
|
|
|
|
|
|
|
*****************************/ |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
/* common */ |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
#define KHASHL_SET_INIT(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
338
|
|
|
|
|
|
|
typedef struct { khkey_t key; } kh_packed HType##_s_bucket_t; \ |
|
339
|
|
|
|
|
|
|
static kh_inline khint_t prefix##_s_hash(HType##_s_bucket_t x) { return __hash_fn(x.key); } \ |
|
340
|
|
|
|
|
|
|
static kh_inline int prefix##_s_eq(HType##_s_bucket_t x, HType##_s_bucket_t y) { return __hash_eq(x.key, y.key); } \ |
|
341
|
|
|
|
|
|
|
KHASHL_INIT(KH_LOCAL, HType, prefix##_s, HType##_s_bucket_t, prefix##_s_hash, prefix##_s_eq) \ |
|
342
|
|
|
|
|
|
|
SCOPE HType *prefix##_init(void) { return prefix##_s_init(); } \ |
|
343
|
|
|
|
|
|
|
SCOPE HType *prefix##_init2(void *km) { return prefix##_s_init2(km); } \ |
|
344
|
|
|
|
|
|
|
SCOPE void prefix##_destroy(HType *h) { prefix##_s_destroy(h); } \ |
|
345
|
|
|
|
|
|
|
SCOPE void prefix##_resize(HType *h, khint_t new_n_buckets) { prefix##_s_resize(h, new_n_buckets); } \ |
|
346
|
|
|
|
|
|
|
SCOPE khint_t prefix##_get(const HType *h, khkey_t key) { HType##_s_bucket_t t; t.key = key; return prefix##_s_getp(h, &t); } \ |
|
347
|
|
|
|
|
|
|
SCOPE int prefix##_del(HType *h, khint_t k) { return prefix##_s_del(h, k); } \ |
|
348
|
|
|
|
|
|
|
SCOPE khint_t prefix##_put(HType *h, khkey_t key, int *absent) { HType##_s_bucket_t t; t.key = key; return prefix##_s_putp(h, &t, absent); } \ |
|
349
|
|
|
|
|
|
|
SCOPE void prefix##_clear(HType *h) { prefix##_s_clear(h); } |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
#define KHASHL_MAP_INIT(SCOPE, HType, prefix, khkey_t, kh_val_t, __hash_fn, __hash_eq) \ |
|
352
|
|
|
|
|
|
|
typedef struct { khkey_t key; kh_val_t val; } kh_packed HType##_m_bucket_t; \ |
|
353
|
|
|
|
|
|
|
static kh_inline khint_t prefix##_m_hash(HType##_m_bucket_t x) { return __hash_fn(x.key); } \ |
|
354
|
|
|
|
|
|
|
static kh_inline int prefix##_m_eq(HType##_m_bucket_t x, HType##_m_bucket_t y) { return __hash_eq(x.key, y.key); } \ |
|
355
|
|
|
|
|
|
|
KHASHL_INIT(KH_LOCAL, HType, prefix##_m, HType##_m_bucket_t, prefix##_m_hash, prefix##_m_eq) \ |
|
356
|
|
|
|
|
|
|
SCOPE HType *prefix##_init(void) { return prefix##_m_init(); } \ |
|
357
|
|
|
|
|
|
|
SCOPE HType *prefix##_init2(void *km) { return prefix##_m_init2(km); } \ |
|
358
|
|
|
|
|
|
|
SCOPE void prefix##_destroy(HType *h) { prefix##_m_destroy(h); } \ |
|
359
|
|
|
|
|
|
|
SCOPE void prefix##_resize(HType *h, khint_t new_n_buckets) { prefix##_m_resize(h, new_n_buckets); } \ |
|
360
|
|
|
|
|
|
|
SCOPE khint_t prefix##_get(const HType *h, khkey_t key) { HType##_m_bucket_t t; t.key = key; return prefix##_m_getp(h, &t); } \ |
|
361
|
|
|
|
|
|
|
SCOPE int prefix##_del(HType *h, khint_t k) { return prefix##_m_del(h, k); } \ |
|
362
|
|
|
|
|
|
|
SCOPE khint_t prefix##_put(HType *h, khkey_t key, int *absent) { HType##_m_bucket_t t; t.key = key; return prefix##_m_putp(h, &t, absent); } \ |
|
363
|
|
|
|
|
|
|
SCOPE void prefix##_clear(HType *h) { prefix##_m_clear(h); } |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
/* cached hashes to trade memory for performance when hashing and comparison are expensive */ |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
#define __kh_cached_hash(x) ((x).hash) |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
#define KHASHL_CSET_INIT(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
370
|
|
|
|
|
|
|
typedef struct { khkey_t key; khint_t hash; } kh_packed HType##_cs_bucket_t; \ |
|
371
|
|
|
|
|
|
|
static kh_inline int prefix##_cs_eq(HType##_cs_bucket_t x, HType##_cs_bucket_t y) { return x.hash == y.hash && __hash_eq(x.key, y.key); } \ |
|
372
|
|
|
|
|
|
|
KHASHL_INIT(KH_LOCAL, HType, prefix##_cs, HType##_cs_bucket_t, __kh_cached_hash, prefix##_cs_eq) \ |
|
373
|
|
|
|
|
|
|
SCOPE HType *prefix##_init(void) { return prefix##_cs_init(); } \ |
|
374
|
|
|
|
|
|
|
SCOPE void prefix##_destroy(HType *h) { prefix##_cs_destroy(h); } \ |
|
375
|
|
|
|
|
|
|
SCOPE khint_t prefix##_get(const HType *h, khkey_t key) { HType##_cs_bucket_t t; t.key = key; t.hash = __hash_fn(key); return prefix##_cs_getp(h, &t); } \ |
|
376
|
|
|
|
|
|
|
SCOPE int prefix##_del(HType *h, khint_t k) { return prefix##_cs_del(h, k); } \ |
|
377
|
|
|
|
|
|
|
SCOPE khint_t prefix##_put(HType *h, khkey_t key, int *absent) { HType##_cs_bucket_t t; t.key = key, t.hash = __hash_fn(key); return prefix##_cs_putp(h, &t, absent); } \ |
|
378
|
|
|
|
|
|
|
SCOPE void prefix##_clear(HType *h) { prefix##_cs_clear(h); } |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
#define KHASHL_CMAP_INIT(SCOPE, HType, prefix, khkey_t, kh_val_t, __hash_fn, __hash_eq) \ |
|
381
|
|
|
|
|
|
|
typedef struct { khkey_t key; kh_val_t val; khint_t hash; } kh_packed HType##_cm_bucket_t; \ |
|
382
|
|
|
|
|
|
|
static kh_inline int prefix##_cm_eq(HType##_cm_bucket_t x, HType##_cm_bucket_t y) { return x.hash == y.hash && __hash_eq(x.key, y.key); } \ |
|
383
|
|
|
|
|
|
|
KHASHL_INIT(KH_LOCAL, HType, prefix##_cm, HType##_cm_bucket_t, __kh_cached_hash, prefix##_cm_eq) \ |
|
384
|
|
|
|
|
|
|
SCOPE HType *prefix##_init(void) { return prefix##_cm_init(); } \ |
|
385
|
|
|
|
|
|
|
SCOPE void prefix##_destroy(HType *h) { prefix##_cm_destroy(h); } \ |
|
386
|
|
|
|
|
|
|
SCOPE khint_t prefix##_get(const HType *h, khkey_t key) { HType##_cm_bucket_t t; t.key = key; t.hash = __hash_fn(key); return prefix##_cm_getp(h, &t); } \ |
|
387
|
|
|
|
|
|
|
SCOPE int prefix##_del(HType *h, khint_t k) { return prefix##_cm_del(h, k); } \ |
|
388
|
|
|
|
|
|
|
SCOPE khint_t prefix##_put(HType *h, khkey_t key, int *absent) { HType##_cm_bucket_t t; t.key = key, t.hash = __hash_fn(key); return prefix##_cm_putp(h, &t, absent); } \ |
|
389
|
|
|
|
|
|
|
SCOPE void prefix##_clear(HType *h) { prefix##_cm_clear(h); } |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
/* ensemble for huge hash tables */ |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
#define KHASHE_SET_INIT(SCOPE, HType, prefix, khkey_t, __hash_fn, __hash_eq) \ |
|
394
|
|
|
|
|
|
|
typedef struct { khkey_t key; } kh_packed HType##_es_bucket_t; \ |
|
395
|
|
|
|
|
|
|
static kh_inline khint_t prefix##_es_hash(HType##_es_bucket_t x) { return __hash_fn(x.key); } \ |
|
396
|
|
|
|
|
|
|
static kh_inline int prefix##_es_eq(HType##_es_bucket_t x, HType##_es_bucket_t y) { return __hash_eq(x.key, y.key); } \ |
|
397
|
|
|
|
|
|
|
KHASHE_INIT(KH_LOCAL, HType, prefix##_es, HType##_es_bucket_t, prefix##_es_hash, prefix##_es_eq) \ |
|
398
|
|
|
|
|
|
|
SCOPE HType *prefix##_init(int bits) { return prefix##_es_init(bits); } \ |
|
399
|
|
|
|
|
|
|
SCOPE void prefix##_destroy(HType *h) { prefix##_es_destroy(h); } \ |
|
400
|
|
|
|
|
|
|
SCOPE kh_ensitr_t prefix##_get(const HType *h, khkey_t key) { HType##_es_bucket_t t; t.key = key; return prefix##_es_getp(h, &t); } \ |
|
401
|
|
|
|
|
|
|
SCOPE int prefix##_del(HType *h, kh_ensitr_t k) { return prefix##_es_del(h, k); } \ |
|
402
|
|
|
|
|
|
|
SCOPE kh_ensitr_t prefix##_put(HType *h, khkey_t key, int *absent) { HType##_es_bucket_t t; t.key = key; return prefix##_es_putp(h, &t, absent); } \ |
|
403
|
|
|
|
|
|
|
SCOPE void prefix##_clear(HType *h) { prefix##_es_clear(h); } |
|
404
|
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
#define KHASHE_MAP_INIT(SCOPE, HType, prefix, khkey_t, kh_val_t, __hash_fn, __hash_eq) \ |
|
406
|
|
|
|
|
|
|
typedef struct { khkey_t key; kh_val_t val; } kh_packed HType##_em_bucket_t; \ |
|
407
|
|
|
|
|
|
|
static kh_inline khint_t prefix##_em_hash(HType##_em_bucket_t x) { return __hash_fn(x.key); } \ |
|
408
|
|
|
|
|
|
|
static kh_inline int prefix##_em_eq(HType##_em_bucket_t x, HType##_em_bucket_t y) { return __hash_eq(x.key, y.key); } \ |
|
409
|
|
|
|
|
|
|
KHASHE_INIT(KH_LOCAL, HType, prefix##_em, HType##_em_bucket_t, prefix##_em_hash, prefix##_em_eq) \ |
|
410
|
|
|
|
|
|
|
SCOPE HType *prefix##_init(int bits) { return prefix##_em_init(bits); } \ |
|
411
|
|
|
|
|
|
|
SCOPE void prefix##_destroy(HType *h) { prefix##_em_destroy(h); } \ |
|
412
|
|
|
|
|
|
|
SCOPE kh_ensitr_t prefix##_get(const HType *h, khkey_t key) { HType##_em_bucket_t t; t.key = key; return prefix##_em_getp(h, &t); } \ |
|
413
|
|
|
|
|
|
|
SCOPE int prefix##_del(HType *h, kh_ensitr_t k) { return prefix##_em_del(h, k); } \ |
|
414
|
|
|
|
|
|
|
SCOPE kh_ensitr_t prefix##_put(HType *h, khkey_t key, int *absent) { HType##_em_bucket_t t; t.key = key; return prefix##_em_putp(h, &t, absent); } \ |
|
415
|
|
|
|
|
|
|
SCOPE void prefix##_clear(HType *h) { prefix##_em_clear(h); } |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
/************************** |
|
418
|
|
|
|
|
|
|
* Public macro functions * |
|
419
|
|
|
|
|
|
|
**************************/ |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
#define kh_bucket(h, x) ((h)->keys[x]) |
|
422
|
|
|
|
|
|
|
#define kh_size(h) ((h)->count) |
|
423
|
|
|
|
|
|
|
#define kh_capacity(h) ((h)->keys? 1U<<(h)->bits : 0U) |
|
424
|
|
|
|
|
|
|
#define kh_end(h) kh_capacity(h) |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
#define kh_key(h, x) ((h)->keys[x].key) |
|
427
|
|
|
|
|
|
|
#define kh_val(h, x) ((h)->keys[x].val) |
|
428
|
|
|
|
|
|
|
#define kh_exist(h, x) __kh_used((h)->used, (x)) |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
#define kh_foreach(h, x) for ((x) = 0; (x) != kh_end(h); ++(x)) if (kh_exist((h), (x))) |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
#define kh_ens_key(g, x) kh_key(&(g)->sub[(x).sub], (x).pos) |
|
433
|
|
|
|
|
|
|
#define kh_ens_val(g, x) kh_val(&(g)->sub[(x).sub], (x).pos) |
|
434
|
|
|
|
|
|
|
#define kh_ens_exist(g, x) kh_exist(&(g)->sub[(x).sub], (x).pos) |
|
435
|
|
|
|
|
|
|
#define kh_ens_is_end(x) ((x).pos == (khint_t)-1) |
|
436
|
|
|
|
|
|
|
#define kh_ens_size(g) ((g)->count) |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
#define kh_ens_foreach(g, x) for ((x).sub = 0; (x).sub != 1<<(g)->bits; ++(x).sub) for ((x).pos = 0; (x).pos != kh_end(&(g)->sub[(x).sub]); ++(x).pos) if (kh_ens_exist((g), (x))) |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
/************************************** |
|
441
|
|
|
|
|
|
|
* Common hash and equality functions * |
|
442
|
|
|
|
|
|
|
**************************************/ |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
#define kh_eq_generic(a, b) ((a) == (b)) |
|
445
|
|
|
|
|
|
|
#define kh_eq_str(a, b) (strcmp((a), (b)) == 0) |
|
446
|
|
|
|
|
|
|
#define kh_hash_dummy(x) ((khint_t)(x)) |
|
447
|
|
|
|
|
|
|
|
|
448
|
0
|
|
|
|
|
|
static kh_inline khint_t kh_hash_uint32(khint_t x) { /* murmur finishing */ |
|
449
|
0
|
|
|
|
|
|
x ^= x >> 16; |
|
450
|
0
|
|
|
|
|
|
x *= 0x85ebca6bU; |
|
451
|
0
|
|
|
|
|
|
x ^= x >> 13; |
|
452
|
0
|
|
|
|
|
|
x *= 0xc2b2ae35U; |
|
453
|
0
|
|
|
|
|
|
x ^= x >> 16; |
|
454
|
0
|
|
|
|
|
|
return x; |
|
455
|
|
|
|
|
|
|
} |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
static kh_inline khint_t kh_hash_uint64(khint64_t x) { /* splitmix64; see https://nullprogram.com/blog/2018/07/31/ for inversion */ |
|
458
|
|
|
|
|
|
|
x ^= x >> 30; |
|
459
|
|
|
|
|
|
|
x *= 0xbf58476d1ce4e5b9ULL; |
|
460
|
|
|
|
|
|
|
x ^= x >> 27; |
|
461
|
|
|
|
|
|
|
x *= 0x94d049bb133111ebULL; |
|
462
|
|
|
|
|
|
|
x ^= x >> 31; |
|
463
|
|
|
|
|
|
|
return (khint_t)x; |
|
464
|
|
|
|
|
|
|
} |
|
465
|
|
|
|
|
|
|
|
|
466
|
0
|
|
|
|
|
|
static kh_inline khint_t kh_hash_str(kh_cstr_t s) { /* FNV1a */ |
|
467
|
0
|
|
|
|
|
|
khint_t h = 2166136261U; |
|
468
|
0
|
|
|
|
|
|
const unsigned char *t = (const unsigned char*)s; |
|
469
|
0
|
0
|
|
|
|
|
for (; *t; ++t) |
|
470
|
0
|
|
|
|
|
|
h ^= *t, h *= 16777619; |
|
471
|
0
|
|
|
|
|
|
return h; |
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
static kh_inline khint_t kh_hash_bytes(int len, const unsigned char *s) { |
|
475
|
|
|
|
|
|
|
khint_t h = 2166136261U; |
|
476
|
|
|
|
|
|
|
int i; |
|
477
|
|
|
|
|
|
|
for (i = 0; i < len; ++i) |
|
478
|
|
|
|
|
|
|
h ^= s[i], h *= 16777619; |
|
479
|
|
|
|
|
|
|
return h; |
|
480
|
|
|
|
|
|
|
} |
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
#endif /* __AC_KHASHL_H */ |