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