1 /* radare2 - BSD 3 Clause License - crowell, pancake, ret2libc 2016-2018 */
2
3 #define LOAD_FACTOR 1
4 #define S_ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
5
6 // Sizes of the ht.
7 static const ut32 ht_primes_sizes[] = {
8 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131,
9 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
10 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861,
11 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023,
12 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523,
13 108631, 130363, 156437, 187751, 225307, 270371, 324449,
14 389357, 467237, 560689, 672827, 807403, 968897, 1162687,
15 1395263, 1674319, 2009191, 2411033, 2893249, 3471899,
16 4166287, 4999559, 5999471, 7199369
17 };
18
hashfn(HtName_ (Ht)* ht,const KEY_TYPE k)19 static inline ut32 hashfn(HtName_(Ht) *ht, const KEY_TYPE k) {
20 return ht->opt.hashfn ? ht->opt.hashfn (k) : KEY_TO_HASH (k);
21 }
22
bucketfn(HtName_ (Ht)* ht,const KEY_TYPE k)23 static inline ut32 bucketfn(HtName_(Ht) *ht, const KEY_TYPE k) {
24 return hashfn (ht, k) % ht->size;
25 }
26
dupkey(HtName_ (Ht)* ht,const KEY_TYPE k)27 static inline KEY_TYPE dupkey(HtName_(Ht) *ht, const KEY_TYPE k) {
28 return ht->opt.dupkey ? ht->opt.dupkey (k) : (KEY_TYPE)k;
29 }
30
dupval(HtName_ (Ht)* ht,const VALUE_TYPE v)31 static inline VALUE_TYPE dupval(HtName_(Ht) *ht, const VALUE_TYPE v) {
32 return ht->opt.dupvalue ? ht->opt.dupvalue (v) : (VALUE_TYPE)v;
33 }
34
calcsize_key(HtName_ (Ht)* ht,const KEY_TYPE k)35 static inline ut32 calcsize_key(HtName_(Ht) *ht, const KEY_TYPE k) {
36 return ht->opt.calcsizeK ? ht->opt.calcsizeK (k) : 0;
37 }
38
calcsize_val(HtName_ (Ht)* ht,const VALUE_TYPE v)39 static inline ut32 calcsize_val(HtName_(Ht) *ht, const VALUE_TYPE v) {
40 return ht->opt.calcsizeV ? ht->opt.calcsizeV (v) : 0;
41 }
42
freefn(HtName_ (Ht)* ht,HT_ (Kv)* kv)43 static inline void freefn(HtName_(Ht) *ht, HT_(Kv) *kv) {
44 if (ht->opt.freefn) {
45 ht->opt.freefn (kv);
46 }
47 }
48
next_idx(ut32 idx)49 static inline ut32 next_idx(ut32 idx) {
50 if (idx != UT32_MAX && idx < S_ARRAY_SIZE (ht_primes_sizes) - 1) {
51 return idx + 1;
52 }
53 return UT32_MAX;
54 }
55
compute_size(ut32 idx,ut32 sz)56 static inline ut32 compute_size(ut32 idx, ut32 sz) {
57 // when possible, use the precomputed prime numbers which help with
58 // collisions, otherwise, at least make the number odd with |1
59 return idx != UT32_MAX && idx < S_ARRAY_SIZE(ht_primes_sizes) ? ht_primes_sizes[idx] : (sz | 1);
60 }
61
is_kv_equal(HtName_ (Ht)* ht,const KEY_TYPE key,const ut32 key_len,const HT_ (Kv)* kv)62 static inline bool is_kv_equal(HtName_(Ht) *ht, const KEY_TYPE key, const ut32 key_len, const HT_(Kv) *kv) {
63 if (key_len != kv->key_len) {
64 return false;
65 }
66
67 bool res = key == kv->key;
68 if (!res && ht->opt.cmp) {
69 res = !ht->opt.cmp (key, kv->key);
70 }
71 return res;
72 }
73
HT_(Kv)74 static inline HT_(Kv) *kv_at(HtName_(Ht) *ht, HT_(Bucket) *bt, ut32 i) {
75 return (HT_(Kv) *)((char *)bt->arr + i * ht->opt.elem_size);
76 }
77
HT_(Kv)78 static inline HT_(Kv) *next_kv(HtName_(Ht) *ht, HT_(Kv) *kv) {
79 return (HT_(Kv) *)((char *)kv + ht->opt.elem_size);
80 }
81
82 #define BUCKET_FOREACH(ht, bt, j, kv) \
83 if ((bt)->arr) \
84 for ((j) = 0, (kv) = (bt)->arr; (j) < (bt)->count; (j)++, (kv) = next_kv (ht, kv))
85
86 #define BUCKET_FOREACH_SAFE(ht, bt, j, count, kv) \
87 if ((bt)->arr) \
88 for ((j) = 0, (kv) = (bt)->arr, (count) = (ht)->count; \
89 (j) < (bt)->count; \
90 (j) = (count) == (ht)->count? j + 1: j, (kv) = (count) == (ht)->count? next_kv (ht, kv): kv, (count) = (ht)->count)
91
92 // Create a new hashtable and return a pointer to it.
93 // size - number of buckets in the hashtable
94 // hashfunction - the function that does the hashing, must not be null.
95 // comparator - the function to check if values are equal, if NULL, just checks
96 // == (for storing ints).
97 // keydup - function to duplicate to key (eg strdup), if NULL just does strup.
98 // valdup - same as keydup, but for values but if NULL just assign
99 // pair_free - function for freeing a keyvaluepair - if NULL just does free.
100 // calcsize - function to calculate the size of a value. if NULL, just stores 0.
HtName_(Ht)101 static HtName_(Ht)* internal_ht_new(ut32 size, ut32 prime_idx, HT_(Options) *opt) {
102 HtName_(Ht)* ht = calloc (1, sizeof (*ht));
103 if (!ht) {
104 return NULL;
105 }
106 ht->size = size;
107 ht->count = 0;
108 ht->prime_idx = prime_idx;
109 ht->table = calloc (ht->size, sizeof (*ht->table));
110 if (!ht->table) {
111 free (ht);
112 return NULL;
113 }
114 ht->opt = *opt;
115 // if not provided, assume we are dealing with a regular HtName_(Ht), with
116 // HT_(Kv) as elements
117 if (ht->opt.elem_size == 0) {
118 ht->opt.elem_size = sizeof (HT_(Kv));
119 }
120 return ht;
121 }
122
HtName_(Ht)123 SDB_API HtName_(Ht) *Ht_(new_opt)(HT_(Options) *opt) {
124 return internal_ht_new (ht_primes_sizes[0], 0, opt);
125 }
126
Ht_(free)127 SDB_API void Ht_(free)(HtName_(Ht)* ht) {
128 if (!ht) {
129 return;
130 }
131
132 ut32 i;
133 for (i = 0; i < ht->size; i++) {
134 HT_(Bucket) *bt = &ht->table[i];
135 HT_(Kv) *kv;
136 ut32 j;
137
138 if (ht->opt.freefn) {
139 BUCKET_FOREACH (ht, bt, j, kv) {
140 ht->opt.freefn (kv);
141 }
142 }
143
144 free (bt->arr);
145 }
146 free (ht->table);
147 free (ht);
148 }
149
150 // Increases the size of the hashtable by 2.
internal_ht_grow(HtName_ (Ht)* ht)151 static void internal_ht_grow(HtName_(Ht)* ht) {
152 HtName_(Ht)* ht2;
153 HtName_(Ht) swap;
154 ut32 idx = next_idx (ht->prime_idx);
155 ut32 sz = compute_size (idx, ht->size * 2);
156 ut32 i;
157
158 ht2 = internal_ht_new (sz, idx, &ht->opt);
159 if (!ht2) {
160 // we can't grow the ht anymore. Never mind, we'll be slower,
161 // but everything can continue to work
162 return;
163 }
164
165 for (i = 0; i < ht->size; i++) {
166 HT_(Bucket) *bt = &ht->table[i];
167 HT_(Kv) *kv;
168 ut32 j;
169
170 BUCKET_FOREACH (ht, bt, j, kv) {
171 Ht_(insert_kv) (ht2, kv, false);
172 }
173 }
174 // And now swap the internals.
175 swap = *ht;
176 *ht = *ht2;
177 *ht2 = swap;
178
179 ht2->opt.freefn = NULL;
180 Ht_(free) (ht2);
181 }
182
check_growing(HtName_ (Ht)* ht)183 static void check_growing(HtName_(Ht) *ht) {
184 if (ht->count >= LOAD_FACTOR * ht->size) {
185 internal_ht_grow (ht);
186 }
187 }
188
HT_(Kv)189 static HT_(Kv) *reserve_kv(HtName_(Ht) *ht, const KEY_TYPE key, const int key_len, bool update) {
190 HT_(Bucket) *bt = &ht->table[bucketfn (ht, key)];
191 HT_(Kv) *kvtmp;
192 ut32 j;
193
194 BUCKET_FOREACH (ht, bt, j, kvtmp) {
195 if (is_kv_equal (ht, key, key_len, kvtmp)) {
196 if (update) {
197 freefn (ht, kvtmp);
198 return kvtmp;
199 }
200 return NULL;
201 }
202 }
203
204 HT_(Kv) *newkvarr = realloc (bt->arr, (bt->count + 1) * ht->opt.elem_size);
205 if (!newkvarr) {
206 return NULL;
207 }
208
209 bt->arr = newkvarr;
210 bt->count++;
211 ht->count++;
212 return kv_at (ht, bt, bt->count - 1);
213 }
214
Ht_(insert_kv)215 SDB_API bool Ht_(insert_kv)(HtName_(Ht) *ht, HT_(Kv) *kv, bool update) {
216 HT_(Kv) *kv_dst = reserve_kv (ht, kv->key, kv->key_len, update);
217 if (!kv_dst) {
218 return false;
219 }
220
221 memcpy (kv_dst, kv, ht->opt.elem_size);
222 check_growing (ht);
223 return true;
224 }
225
insert_update(HtName_ (Ht)* ht,const KEY_TYPE key,VALUE_TYPE value,bool update)226 static bool insert_update(HtName_(Ht) *ht, const KEY_TYPE key, VALUE_TYPE value, bool update) {
227 ut32 key_len = calcsize_key (ht, key);
228 HT_(Kv)* kv_dst = reserve_kv (ht, key, key_len, update);
229 if (!kv_dst) {
230 return false;
231 }
232
233 kv_dst->key = dupkey (ht, key);
234 kv_dst->key_len = key_len;
235 kv_dst->value = dupval (ht, value);
236 kv_dst->value_len = calcsize_val (ht, value);
237 check_growing (ht);
238 return true;
239 }
240
241 // Inserts the key value pair key, value into the hashtable.
242 // Doesn't allow for "update" of the value.
Ht_(insert)243 SDB_API bool Ht_(insert)(HtName_(Ht)* ht, const KEY_TYPE key, VALUE_TYPE value) {
244 return insert_update (ht, key, value, false);
245 }
246
247 // Inserts the key value pair key, value into the hashtable.
248 // Does allow for "update" of the value.
Ht_(update)249 SDB_API bool Ht_(update)(HtName_(Ht)* ht, const KEY_TYPE key, VALUE_TYPE value) {
250 return insert_update (ht, key, value, true);
251 }
252
253 // Update the key of an element that has old_key as key and replace it with new_key
Ht_(update_key)254 SDB_API bool Ht_(update_key)(HtName_(Ht)* ht, const KEY_TYPE old_key, const KEY_TYPE new_key) {
255 // First look for the value associated with old_key
256 bool found;
257 VALUE_TYPE value = Ht_(find) (ht, old_key, &found);
258 if (!found) {
259 return false;
260 }
261
262 // Associate the existing value with new_key
263 bool inserted = insert_update (ht, new_key, value, false);
264 if (!inserted) {
265 return false;
266 }
267
268 // Remove the old_key kv, paying attention to not double free the value
269 HT_(Bucket) *bt = &ht->table[bucketfn (ht, old_key)];
270 const int old_key_len = calcsize_key (ht, old_key);
271 HT_(Kv) *kv;
272 ut32 j;
273
274 BUCKET_FOREACH (ht, bt, j, kv) {
275 if (is_kv_equal (ht, old_key, old_key_len, kv)) {
276 if (!ht->opt.dupvalue) {
277 // do not free the value part if dupvalue is not
278 // set, because the old value has been
279 // associated with the new key and it should not
280 // be freed
281 kv->value = HT_NULL_VALUE;
282 kv->value_len = 0;
283 }
284 freefn (ht, kv);
285
286 void *src = next_kv (ht, kv);
287 memmove (kv, src, (bt->count - j - 1) * ht->opt.elem_size);
288 bt->count--;
289 ht->count--;
290 return true;
291 }
292 }
293
294 return false;
295 }
296
297 // Returns the corresponding SdbKv entry from the key.
298 // If `found` is not NULL, it will be set to true if the entry was found, false
299 // otherwise.
HT_(Kv)300 SDB_API HT_(Kv)* Ht_(find_kv)(HtName_(Ht)* ht, const KEY_TYPE key, bool* found) {
301 if (found) {
302 *found = false;
303 }
304 if (!ht) {
305 *found = false;
306 return NULL;
307 }
308
309 HT_(Bucket) *bt = &ht->table[bucketfn (ht, key)];
310 ut32 key_len = calcsize_key (ht, key);
311 HT_(Kv) *kv;
312 ut32 j;
313
314 BUCKET_FOREACH (ht, bt, j, kv) {
315 if (is_kv_equal (ht, key, key_len, kv)) {
316 if (found) {
317 *found = true;
318 }
319 return kv;
320 }
321 }
322 return NULL;
323 }
324
325 // Looks up the corresponding value from the key.
326 // If `found` is not NULL, it will be set to true if the entry was found, false
327 // otherwise.
Ht_(find)328 SDB_API VALUE_TYPE Ht_(find)(HtName_(Ht)* ht, const KEY_TYPE key, bool* found) {
329 HT_(Kv) *res = Ht_(find_kv) (ht, key, found);
330 return res ? res->value : HT_NULL_VALUE;
331 }
332
333 // Deletes a entry from the hash table from the key, if the pair exists.
Ht_(delete)334 SDB_API bool Ht_(delete)(HtName_(Ht)* ht, const KEY_TYPE key) {
335 HT_(Bucket) *bt = &ht->table[bucketfn (ht, key)];
336 ut32 key_len = calcsize_key (ht, key);
337 HT_(Kv) *kv;
338 ut32 j;
339
340 BUCKET_FOREACH (ht, bt, j, kv) {
341 if (is_kv_equal (ht, key, key_len, kv)) {
342 freefn (ht, kv);
343 void *src = next_kv (ht, kv);
344 memmove (kv, src, (bt->count - j - 1) * ht->opt.elem_size);
345 bt->count--;
346 ht->count--;
347 return true;
348 }
349 }
350 return false;
351 }
352
Ht_(foreach)353 SDB_API void Ht_(foreach)(HtName_(Ht) *ht, HT_(ForeachCallback) cb, void *user) {
354 ut32 i;
355
356 for (i = 0; i < ht->size; ++i) {
357 HT_(Bucket) *bt = &ht->table[i];
358 HT_(Kv) *kv;
359 ut32 j, count;
360
361 BUCKET_FOREACH_SAFE (ht, bt, j, count, kv) {
362 if (!cb (user, kv->key, kv->value)) {
363 return;
364 }
365 }
366 }
367 }
368