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