ctf-hash.c revision 1.1.1.2 1 1.1 christos /* Interface to hashtable implementations.
2 1.1.1.2 christos Copyright (C) 2006-2022 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of libctf.
5 1.1 christos
6 1.1 christos libctf is free software; you can redistribute it and/or modify it under
7 1.1 christos the terms of the GNU General Public License as published by the Free
8 1.1 christos Software Foundation; either version 3, or (at your option) any later
9 1.1 christos version.
10 1.1 christos
11 1.1 christos This program is distributed in the hope that it will be useful, but
12 1.1 christos WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 1.1 christos See the GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program; see the file COPYING. If not see
18 1.1 christos <http://www.gnu.org/licenses/>. */
19 1.1 christos
20 1.1 christos #include <ctf-impl.h>
21 1.1 christos #include <string.h>
22 1.1 christos #include "libiberty.h"
23 1.1 christos #include "hashtab.h"
24 1.1 christos
25 1.1.1.2 christos /* We have three hashtable implementations:
26 1.1.1.2 christos
27 1.1.1.2 christos - ctf_hash_* is an interface to a fixed-size hash from const char * ->
28 1.1.1.2 christos ctf_id_t with number of elements specified at creation time, that should
29 1.1.1.2 christos support addition of items but need not support removal.
30 1.1.1.2 christos
31 1.1.1.2 christos - ctf_dynhash_* is an interface to a dynamically-expanding hash with
32 1.1.1.2 christos unknown size that should support addition of large numbers of items, and
33 1.1.1.2 christos removal as well, and is used only at type-insertion time and during
34 1.1.1.2 christos linking.
35 1.1.1.2 christos
36 1.1.1.2 christos - ctf_dynset_* is an interface to a dynamically-expanding hash that contains
37 1.1.1.2 christos only keys: no values.
38 1.1.1.2 christos
39 1.1.1.2 christos These can be implemented by the same underlying hashmap if you wish. */
40 1.1.1.2 christos
41 1.1.1.2 christos /* The helem is used for general key/value mappings in both the ctf_hash and
42 1.1.1.2 christos ctf_dynhash: the owner may not have space allocated for it, and will be
43 1.1.1.2 christos garbage (not NULL!) in that case. */
44 1.1 christos
45 1.1 christos typedef struct ctf_helem
46 1.1 christos {
47 1.1 christos void *key; /* Either a pointer, or a coerced ctf_id_t. */
48 1.1 christos void *value; /* The value (possibly a coerced int). */
49 1.1.1.2 christos ctf_dynhash_t *owner; /* The hash that owns us. */
50 1.1 christos } ctf_helem_t;
51 1.1 christos
52 1.1.1.2 christos /* Equally, the key_free and value_free may not exist. */
53 1.1.1.2 christos
54 1.1 christos struct ctf_dynhash
55 1.1 christos {
56 1.1 christos struct htab *htab;
57 1.1 christos ctf_hash_free_fun key_free;
58 1.1 christos ctf_hash_free_fun value_free;
59 1.1 christos };
60 1.1 christos
61 1.1.1.2 christos /* Hash and eq functions for the dynhash and hash. */
62 1.1 christos
63 1.1 christos unsigned int
64 1.1 christos ctf_hash_integer (const void *ptr)
65 1.1 christos {
66 1.1 christos ctf_helem_t *hep = (ctf_helem_t *) ptr;
67 1.1 christos
68 1.1 christos return htab_hash_pointer (hep->key);
69 1.1 christos }
70 1.1 christos
71 1.1 christos int
72 1.1 christos ctf_hash_eq_integer (const void *a, const void *b)
73 1.1 christos {
74 1.1 christos ctf_helem_t *hep_a = (ctf_helem_t *) a;
75 1.1 christos ctf_helem_t *hep_b = (ctf_helem_t *) b;
76 1.1 christos
77 1.1 christos return htab_eq_pointer (hep_a->key, hep_b->key);
78 1.1 christos }
79 1.1 christos
80 1.1 christos unsigned int
81 1.1 christos ctf_hash_string (const void *ptr)
82 1.1 christos {
83 1.1 christos ctf_helem_t *hep = (ctf_helem_t *) ptr;
84 1.1 christos
85 1.1 christos return htab_hash_string (hep->key);
86 1.1 christos }
87 1.1 christos
88 1.1 christos int
89 1.1 christos ctf_hash_eq_string (const void *a, const void *b)
90 1.1 christos {
91 1.1 christos ctf_helem_t *hep_a = (ctf_helem_t *) a;
92 1.1 christos ctf_helem_t *hep_b = (ctf_helem_t *) b;
93 1.1 christos
94 1.1 christos return !strcmp((const char *) hep_a->key, (const char *) hep_b->key);
95 1.1 christos }
96 1.1 christos
97 1.1.1.2 christos /* Hash a type_key. */
98 1.1.1.2 christos unsigned int
99 1.1.1.2 christos ctf_hash_type_key (const void *ptr)
100 1.1.1.2 christos {
101 1.1.1.2 christos ctf_helem_t *hep = (ctf_helem_t *) ptr;
102 1.1.1.2 christos ctf_link_type_key_t *k = (ctf_link_type_key_t *) hep->key;
103 1.1.1.2 christos
104 1.1.1.2 christos return htab_hash_pointer (k->cltk_fp) + 59
105 1.1.1.2 christos * htab_hash_pointer ((void *) (uintptr_t) k->cltk_idx);
106 1.1.1.2 christos }
107 1.1.1.2 christos
108 1.1.1.2 christos int
109 1.1.1.2 christos ctf_hash_eq_type_key (const void *a, const void *b)
110 1.1.1.2 christos {
111 1.1.1.2 christos ctf_helem_t *hep_a = (ctf_helem_t *) a;
112 1.1.1.2 christos ctf_helem_t *hep_b = (ctf_helem_t *) b;
113 1.1.1.2 christos ctf_link_type_key_t *key_a = (ctf_link_type_key_t *) hep_a->key;
114 1.1.1.2 christos ctf_link_type_key_t *key_b = (ctf_link_type_key_t *) hep_b->key;
115 1.1.1.2 christos
116 1.1.1.2 christos return (key_a->cltk_fp == key_b->cltk_fp)
117 1.1.1.2 christos && (key_a->cltk_idx == key_b->cltk_idx);
118 1.1.1.2 christos }
119 1.1.1.2 christos
120 1.1.1.2 christos /* Hash a type_id_key. */
121 1.1 christos unsigned int
122 1.1.1.2 christos ctf_hash_type_id_key (const void *ptr)
123 1.1 christos {
124 1.1 christos ctf_helem_t *hep = (ctf_helem_t *) ptr;
125 1.1.1.2 christos ctf_type_id_key_t *k = (ctf_type_id_key_t *) hep->key;
126 1.1 christos
127 1.1.1.2 christos return htab_hash_pointer ((void *) (uintptr_t) k->ctii_input_num)
128 1.1.1.2 christos + 59 * htab_hash_pointer ((void *) (uintptr_t) k->ctii_type);
129 1.1 christos }
130 1.1 christos
131 1.1 christos int
132 1.1.1.2 christos ctf_hash_eq_type_id_key (const void *a, const void *b)
133 1.1 christos {
134 1.1 christos ctf_helem_t *hep_a = (ctf_helem_t *) a;
135 1.1 christos ctf_helem_t *hep_b = (ctf_helem_t *) b;
136 1.1.1.2 christos ctf_type_id_key_t *key_a = (ctf_type_id_key_t *) hep_a->key;
137 1.1.1.2 christos ctf_type_id_key_t *key_b = (ctf_type_id_key_t *) hep_b->key;
138 1.1 christos
139 1.1.1.2 christos return (key_a->ctii_input_num == key_b->ctii_input_num)
140 1.1.1.2 christos && (key_a->ctii_type == key_b->ctii_type);
141 1.1 christos }
142 1.1 christos
143 1.1 christos /* The dynhash, used for hashes whose size is not known at creation time. */
144 1.1 christos
145 1.1.1.2 christos /* Free a single ctf_helem with arbitrary key/value functions. */
146 1.1 christos
147 1.1 christos static void
148 1.1 christos ctf_dynhash_item_free (void *item)
149 1.1 christos {
150 1.1 christos ctf_helem_t *helem = item;
151 1.1 christos
152 1.1.1.2 christos if (helem->owner->key_free && helem->key)
153 1.1.1.2 christos helem->owner->key_free (helem->key);
154 1.1.1.2 christos if (helem->owner->value_free && helem->value)
155 1.1.1.2 christos helem->owner->value_free (helem->value);
156 1.1 christos free (helem);
157 1.1 christos }
158 1.1 christos
159 1.1 christos ctf_dynhash_t *
160 1.1 christos ctf_dynhash_create (ctf_hash_fun hash_fun, ctf_hash_eq_fun eq_fun,
161 1.1 christos ctf_hash_free_fun key_free, ctf_hash_free_fun value_free)
162 1.1 christos {
163 1.1 christos ctf_dynhash_t *dynhash;
164 1.1.1.2 christos htab_del del = ctf_dynhash_item_free;
165 1.1 christos
166 1.1.1.2 christos if (key_free || value_free)
167 1.1.1.2 christos dynhash = malloc (sizeof (ctf_dynhash_t));
168 1.1.1.2 christos else
169 1.1.1.2 christos dynhash = malloc (offsetof (ctf_dynhash_t, key_free));
170 1.1 christos if (!dynhash)
171 1.1 christos return NULL;
172 1.1 christos
173 1.1.1.2 christos if (key_free == NULL && value_free == NULL)
174 1.1.1.2 christos del = free;
175 1.1.1.2 christos
176 1.1.1.2 christos /* 7 is arbitrary and untested for now. */
177 1.1 christos if ((dynhash->htab = htab_create_alloc (7, (htab_hash) hash_fun, eq_fun,
178 1.1.1.2 christos del, xcalloc, free)) == NULL)
179 1.1 christos {
180 1.1 christos free (dynhash);
181 1.1 christos return NULL;
182 1.1 christos }
183 1.1 christos
184 1.1.1.2 christos if (key_free || value_free)
185 1.1.1.2 christos {
186 1.1.1.2 christos dynhash->key_free = key_free;
187 1.1.1.2 christos dynhash->value_free = value_free;
188 1.1.1.2 christos }
189 1.1 christos
190 1.1 christos return dynhash;
191 1.1 christos }
192 1.1 christos
193 1.1 christos static ctf_helem_t **
194 1.1 christos ctf_hashtab_lookup (struct htab *htab, const void *key, enum insert_option insert)
195 1.1 christos {
196 1.1 christos ctf_helem_t tmp = { .key = (void *) key };
197 1.1 christos return (ctf_helem_t **) htab_find_slot (htab, &tmp, insert);
198 1.1 christos }
199 1.1 christos
200 1.1 christos static ctf_helem_t *
201 1.1 christos ctf_hashtab_insert (struct htab *htab, void *key, void *value,
202 1.1 christos ctf_hash_free_fun key_free,
203 1.1 christos ctf_hash_free_fun value_free)
204 1.1 christos {
205 1.1 christos ctf_helem_t **slot;
206 1.1 christos
207 1.1 christos slot = ctf_hashtab_lookup (htab, key, INSERT);
208 1.1 christos
209 1.1 christos if (!slot)
210 1.1 christos {
211 1.1.1.2 christos errno = ENOMEM;
212 1.1 christos return NULL;
213 1.1 christos }
214 1.1 christos
215 1.1 christos if (!*slot)
216 1.1 christos {
217 1.1.1.2 christos /* Only spend space on the owner if we're going to use it: if there is a
218 1.1.1.2 christos key or value freeing function. */
219 1.1.1.2 christos if (key_free || value_free)
220 1.1.1.2 christos *slot = malloc (sizeof (ctf_helem_t));
221 1.1.1.2 christos else
222 1.1.1.2 christos *slot = malloc (offsetof (ctf_helem_t, owner));
223 1.1 christos if (!*slot)
224 1.1 christos return NULL;
225 1.1.1.2 christos (*slot)->key = key;
226 1.1 christos }
227 1.1 christos else
228 1.1 christos {
229 1.1 christos if (key_free)
230 1.1.1.2 christos key_free (key);
231 1.1 christos if (value_free)
232 1.1 christos value_free ((*slot)->value);
233 1.1 christos }
234 1.1 christos (*slot)->value = value;
235 1.1 christos return *slot;
236 1.1 christos }
237 1.1 christos
238 1.1 christos int
239 1.1 christos ctf_dynhash_insert (ctf_dynhash_t *hp, void *key, void *value)
240 1.1 christos {
241 1.1 christos ctf_helem_t *slot;
242 1.1.1.2 christos ctf_hash_free_fun key_free = NULL, value_free = NULL;
243 1.1 christos
244 1.1.1.2 christos if (hp->htab->del_f == ctf_dynhash_item_free)
245 1.1.1.2 christos {
246 1.1.1.2 christos key_free = hp->key_free;
247 1.1.1.2 christos value_free = hp->value_free;
248 1.1.1.2 christos }
249 1.1 christos slot = ctf_hashtab_insert (hp->htab, key, value,
250 1.1.1.2 christos key_free, value_free);
251 1.1 christos
252 1.1 christos if (!slot)
253 1.1 christos return errno;
254 1.1 christos
255 1.1.1.2 christos /* Keep track of the owner, so that the del function can get at the key_free
256 1.1.1.2 christos and value_free functions. Only do this if one of those functions is set:
257 1.1.1.2 christos if not, the owner is not even present in the helem. */
258 1.1 christos
259 1.1.1.2 christos if (key_free || value_free)
260 1.1.1.2 christos slot->owner = hp;
261 1.1 christos
262 1.1 christos return 0;
263 1.1 christos }
264 1.1 christos
265 1.1 christos void
266 1.1 christos ctf_dynhash_remove (ctf_dynhash_t *hp, const void *key)
267 1.1 christos {
268 1.1.1.2 christos ctf_helem_t hep = { (void *) key, NULL, NULL };
269 1.1 christos htab_remove_elt (hp->htab, &hep);
270 1.1 christos }
271 1.1 christos
272 1.1 christos void
273 1.1 christos ctf_dynhash_empty (ctf_dynhash_t *hp)
274 1.1 christos {
275 1.1 christos htab_empty (hp->htab);
276 1.1 christos }
277 1.1 christos
278 1.1.1.2 christos size_t
279 1.1.1.2 christos ctf_dynhash_elements (ctf_dynhash_t *hp)
280 1.1.1.2 christos {
281 1.1.1.2 christos return htab_elements (hp->htab);
282 1.1.1.2 christos }
283 1.1.1.2 christos
284 1.1 christos void *
285 1.1 christos ctf_dynhash_lookup (ctf_dynhash_t *hp, const void *key)
286 1.1 christos {
287 1.1 christos ctf_helem_t **slot;
288 1.1 christos
289 1.1 christos slot = ctf_hashtab_lookup (hp->htab, key, NO_INSERT);
290 1.1 christos
291 1.1 christos if (slot)
292 1.1 christos return (*slot)->value;
293 1.1 christos
294 1.1 christos return NULL;
295 1.1 christos }
296 1.1 christos
297 1.1.1.2 christos /* TRUE/FALSE return. */
298 1.1.1.2 christos int
299 1.1.1.2 christos ctf_dynhash_lookup_kv (ctf_dynhash_t *hp, const void *key,
300 1.1.1.2 christos const void **orig_key, void **value)
301 1.1.1.2 christos {
302 1.1.1.2 christos ctf_helem_t **slot;
303 1.1.1.2 christos
304 1.1.1.2 christos slot = ctf_hashtab_lookup (hp->htab, key, NO_INSERT);
305 1.1.1.2 christos
306 1.1.1.2 christos if (slot)
307 1.1.1.2 christos {
308 1.1.1.2 christos if (orig_key)
309 1.1.1.2 christos *orig_key = (*slot)->key;
310 1.1.1.2 christos if (value)
311 1.1.1.2 christos *value = (*slot)->value;
312 1.1.1.2 christos return 1;
313 1.1.1.2 christos }
314 1.1.1.2 christos return 0;
315 1.1.1.2 christos }
316 1.1.1.2 christos
317 1.1 christos typedef struct ctf_traverse_cb_arg
318 1.1 christos {
319 1.1 christos ctf_hash_iter_f fun;
320 1.1 christos void *arg;
321 1.1 christos } ctf_traverse_cb_arg_t;
322 1.1 christos
323 1.1 christos static int
324 1.1 christos ctf_hashtab_traverse (void **slot, void *arg_)
325 1.1 christos {
326 1.1 christos ctf_helem_t *helem = *((ctf_helem_t **) slot);
327 1.1 christos ctf_traverse_cb_arg_t *arg = (ctf_traverse_cb_arg_t *) arg_;
328 1.1 christos
329 1.1 christos arg->fun (helem->key, helem->value, arg->arg);
330 1.1 christos return 1;
331 1.1 christos }
332 1.1 christos
333 1.1 christos void
334 1.1 christos ctf_dynhash_iter (ctf_dynhash_t *hp, ctf_hash_iter_f fun, void *arg_)
335 1.1 christos {
336 1.1 christos ctf_traverse_cb_arg_t arg = { fun, arg_ };
337 1.1 christos htab_traverse (hp->htab, ctf_hashtab_traverse, &arg);
338 1.1 christos }
339 1.1 christos
340 1.1.1.2 christos typedef struct ctf_traverse_find_cb_arg
341 1.1.1.2 christos {
342 1.1.1.2 christos ctf_hash_iter_find_f fun;
343 1.1.1.2 christos void *arg;
344 1.1.1.2 christos void *found_key;
345 1.1.1.2 christos } ctf_traverse_find_cb_arg_t;
346 1.1.1.2 christos
347 1.1.1.2 christos static int
348 1.1.1.2 christos ctf_hashtab_traverse_find (void **slot, void *arg_)
349 1.1.1.2 christos {
350 1.1.1.2 christos ctf_helem_t *helem = *((ctf_helem_t **) slot);
351 1.1.1.2 christos ctf_traverse_find_cb_arg_t *arg = (ctf_traverse_find_cb_arg_t *) arg_;
352 1.1.1.2 christos
353 1.1.1.2 christos if (arg->fun (helem->key, helem->value, arg->arg))
354 1.1.1.2 christos {
355 1.1.1.2 christos arg->found_key = helem->key;
356 1.1.1.2 christos return 0;
357 1.1.1.2 christos }
358 1.1.1.2 christos return 1;
359 1.1.1.2 christos }
360 1.1.1.2 christos
361 1.1.1.2 christos void *
362 1.1.1.2 christos ctf_dynhash_iter_find (ctf_dynhash_t *hp, ctf_hash_iter_find_f fun, void *arg_)
363 1.1.1.2 christos {
364 1.1.1.2 christos ctf_traverse_find_cb_arg_t arg = { fun, arg_, NULL };
365 1.1.1.2 christos htab_traverse (hp->htab, ctf_hashtab_traverse_find, &arg);
366 1.1.1.2 christos return arg.found_key;
367 1.1.1.2 christos }
368 1.1.1.2 christos
369 1.1 christos typedef struct ctf_traverse_remove_cb_arg
370 1.1 christos {
371 1.1 christos struct htab *htab;
372 1.1 christos ctf_hash_iter_remove_f fun;
373 1.1 christos void *arg;
374 1.1 christos } ctf_traverse_remove_cb_arg_t;
375 1.1 christos
376 1.1 christos static int
377 1.1 christos ctf_hashtab_traverse_remove (void **slot, void *arg_)
378 1.1 christos {
379 1.1 christos ctf_helem_t *helem = *((ctf_helem_t **) slot);
380 1.1 christos ctf_traverse_remove_cb_arg_t *arg = (ctf_traverse_remove_cb_arg_t *) arg_;
381 1.1 christos
382 1.1 christos if (arg->fun (helem->key, helem->value, arg->arg))
383 1.1 christos htab_clear_slot (arg->htab, slot);
384 1.1 christos return 1;
385 1.1 christos }
386 1.1 christos
387 1.1 christos void
388 1.1 christos ctf_dynhash_iter_remove (ctf_dynhash_t *hp, ctf_hash_iter_remove_f fun,
389 1.1 christos void *arg_)
390 1.1 christos {
391 1.1 christos ctf_traverse_remove_cb_arg_t arg = { hp->htab, fun, arg_ };
392 1.1 christos htab_traverse (hp->htab, ctf_hashtab_traverse_remove, &arg);
393 1.1 christos }
394 1.1 christos
395 1.1.1.2 christos /* Traverse a dynhash in arbitrary order, in _next iterator form.
396 1.1.1.2 christos
397 1.1.1.2 christos Mutating the dynhash while iterating is not supported (just as it isn't for
398 1.1.1.2 christos htab_traverse).
399 1.1.1.2 christos
400 1.1.1.2 christos Note: unusually, this returns zero on success and a *positive* value on
401 1.1.1.2 christos error, because it does not take an fp, taking an error pointer would be
402 1.1.1.2 christos incredibly clunky, and nearly all error-handling ends up stuffing the result
403 1.1.1.2 christos of this into some sort of errno or ctf_errno, which is invariably
404 1.1.1.2 christos positive. So doing this simplifies essentially all callers. */
405 1.1.1.2 christos int
406 1.1.1.2 christos ctf_dynhash_next (ctf_dynhash_t *h, ctf_next_t **it, void **key, void **value)
407 1.1.1.2 christos {
408 1.1.1.2 christos ctf_next_t *i = *it;
409 1.1.1.2 christos ctf_helem_t *slot;
410 1.1.1.2 christos
411 1.1.1.2 christos if (!i)
412 1.1.1.2 christos {
413 1.1.1.2 christos size_t size = htab_size (h->htab);
414 1.1.1.2 christos
415 1.1.1.2 christos /* If the table has too many entries to fit in an ssize_t, just give up.
416 1.1.1.2 christos This might be spurious, but if any type-related hashtable has ever been
417 1.1.1.2 christos nearly as large as that then something very odd is going on. */
418 1.1.1.2 christos if (((ssize_t) size) < 0)
419 1.1.1.2 christos return EDOM;
420 1.1.1.2 christos
421 1.1.1.2 christos if ((i = ctf_next_create ()) == NULL)
422 1.1.1.2 christos return ENOMEM;
423 1.1.1.2 christos
424 1.1.1.2 christos i->u.ctn_hash_slot = h->htab->entries;
425 1.1.1.2 christos i->cu.ctn_h = h;
426 1.1.1.2 christos i->ctn_n = 0;
427 1.1.1.2 christos i->ctn_size = (ssize_t) size;
428 1.1.1.2 christos i->ctn_iter_fun = (void (*) (void)) ctf_dynhash_next;
429 1.1.1.2 christos *it = i;
430 1.1.1.2 christos }
431 1.1.1.2 christos
432 1.1.1.2 christos if ((void (*) (void)) ctf_dynhash_next != i->ctn_iter_fun)
433 1.1.1.2 christos return ECTF_NEXT_WRONGFUN;
434 1.1.1.2 christos
435 1.1.1.2 christos if (h != i->cu.ctn_h)
436 1.1.1.2 christos return ECTF_NEXT_WRONGFP;
437 1.1.1.2 christos
438 1.1.1.2 christos if ((ssize_t) i->ctn_n == i->ctn_size)
439 1.1.1.2 christos goto hash_end;
440 1.1.1.2 christos
441 1.1.1.2 christos while ((ssize_t) i->ctn_n < i->ctn_size
442 1.1.1.2 christos && (*i->u.ctn_hash_slot == HTAB_EMPTY_ENTRY
443 1.1.1.2 christos || *i->u.ctn_hash_slot == HTAB_DELETED_ENTRY))
444 1.1.1.2 christos {
445 1.1.1.2 christos i->u.ctn_hash_slot++;
446 1.1.1.2 christos i->ctn_n++;
447 1.1.1.2 christos }
448 1.1.1.2 christos
449 1.1.1.2 christos if ((ssize_t) i->ctn_n == i->ctn_size)
450 1.1.1.2 christos goto hash_end;
451 1.1.1.2 christos
452 1.1.1.2 christos slot = *i->u.ctn_hash_slot;
453 1.1.1.2 christos
454 1.1.1.2 christos if (key)
455 1.1.1.2 christos *key = slot->key;
456 1.1.1.2 christos if (value)
457 1.1.1.2 christos *value = slot->value;
458 1.1.1.2 christos
459 1.1.1.2 christos i->u.ctn_hash_slot++;
460 1.1.1.2 christos i->ctn_n++;
461 1.1.1.2 christos
462 1.1.1.2 christos return 0;
463 1.1.1.2 christos
464 1.1.1.2 christos hash_end:
465 1.1.1.2 christos ctf_next_destroy (i);
466 1.1.1.2 christos *it = NULL;
467 1.1.1.2 christos return ECTF_NEXT_END;
468 1.1.1.2 christos }
469 1.1.1.2 christos
470 1.1.1.2 christos int
471 1.1.1.2 christos ctf_dynhash_sort_by_name (const ctf_next_hkv_t *one, const ctf_next_hkv_t *two,
472 1.1.1.2 christos void *unused _libctf_unused_)
473 1.1.1.2 christos {
474 1.1.1.2 christos return strcmp ((char *) one->hkv_key, (char *) two->hkv_key);
475 1.1.1.2 christos }
476 1.1.1.2 christos
477 1.1.1.2 christos /* Traverse a sorted dynhash, in _next iterator form.
478 1.1.1.2 christos
479 1.1.1.2 christos See ctf_dynhash_next for notes on error returns, etc.
480 1.1.1.2 christos
481 1.1.1.2 christos Sort keys before iterating over them using the SORT_FUN and SORT_ARG.
482 1.1.1.2 christos
483 1.1.1.2 christos If SORT_FUN is null, thunks to ctf_dynhash_next. */
484 1.1.1.2 christos int
485 1.1.1.2 christos ctf_dynhash_next_sorted (ctf_dynhash_t *h, ctf_next_t **it, void **key,
486 1.1.1.2 christos void **value, ctf_hash_sort_f sort_fun, void *sort_arg)
487 1.1.1.2 christos {
488 1.1.1.2 christos ctf_next_t *i = *it;
489 1.1.1.2 christos
490 1.1.1.2 christos if (sort_fun == NULL)
491 1.1.1.2 christos return ctf_dynhash_next (h, it, key, value);
492 1.1.1.2 christos
493 1.1.1.2 christos if (!i)
494 1.1.1.2 christos {
495 1.1.1.2 christos size_t els = ctf_dynhash_elements (h);
496 1.1.1.2 christos ctf_next_t *accum_i = NULL;
497 1.1.1.2 christos void *key, *value;
498 1.1.1.2 christos int err;
499 1.1.1.2 christos ctf_next_hkv_t *walk;
500 1.1.1.2 christos
501 1.1.1.2 christos if (((ssize_t) els) < 0)
502 1.1.1.2 christos return EDOM;
503 1.1.1.2 christos
504 1.1.1.2 christos if ((i = ctf_next_create ()) == NULL)
505 1.1.1.2 christos return ENOMEM;
506 1.1.1.2 christos
507 1.1.1.2 christos if ((i->u.ctn_sorted_hkv = calloc (els, sizeof (ctf_next_hkv_t))) == NULL)
508 1.1.1.2 christos {
509 1.1.1.2 christos ctf_next_destroy (i);
510 1.1.1.2 christos return ENOMEM;
511 1.1.1.2 christos }
512 1.1.1.2 christos walk = i->u.ctn_sorted_hkv;
513 1.1.1.2 christos
514 1.1.1.2 christos i->cu.ctn_h = h;
515 1.1.1.2 christos
516 1.1.1.2 christos while ((err = ctf_dynhash_next (h, &accum_i, &key, &value)) == 0)
517 1.1.1.2 christos {
518 1.1.1.2 christos walk->hkv_key = key;
519 1.1.1.2 christos walk->hkv_value = value;
520 1.1.1.2 christos walk++;
521 1.1.1.2 christos }
522 1.1.1.2 christos if (err != ECTF_NEXT_END)
523 1.1.1.2 christos {
524 1.1.1.2 christos ctf_next_destroy (i);
525 1.1.1.2 christos return err;
526 1.1.1.2 christos }
527 1.1.1.2 christos
528 1.1.1.2 christos if (sort_fun)
529 1.1.1.2 christos ctf_qsort_r (i->u.ctn_sorted_hkv, els, sizeof (ctf_next_hkv_t),
530 1.1.1.2 christos (int (*) (const void *, const void *, void *)) sort_fun,
531 1.1.1.2 christos sort_arg);
532 1.1.1.2 christos i->ctn_n = 0;
533 1.1.1.2 christos i->ctn_size = (ssize_t) els;
534 1.1.1.2 christos i->ctn_iter_fun = (void (*) (void)) ctf_dynhash_next_sorted;
535 1.1.1.2 christos *it = i;
536 1.1.1.2 christos }
537 1.1.1.2 christos
538 1.1.1.2 christos if ((void (*) (void)) ctf_dynhash_next_sorted != i->ctn_iter_fun)
539 1.1.1.2 christos return ECTF_NEXT_WRONGFUN;
540 1.1.1.2 christos
541 1.1.1.2 christos if (h != i->cu.ctn_h)
542 1.1.1.2 christos return ECTF_NEXT_WRONGFP;
543 1.1.1.2 christos
544 1.1.1.2 christos if ((ssize_t) i->ctn_n == i->ctn_size)
545 1.1.1.2 christos {
546 1.1.1.2 christos ctf_next_destroy (i);
547 1.1.1.2 christos *it = NULL;
548 1.1.1.2 christos return ECTF_NEXT_END;
549 1.1.1.2 christos }
550 1.1.1.2 christos
551 1.1.1.2 christos if (key)
552 1.1.1.2 christos *key = i->u.ctn_sorted_hkv[i->ctn_n].hkv_key;
553 1.1.1.2 christos if (value)
554 1.1.1.2 christos *value = i->u.ctn_sorted_hkv[i->ctn_n].hkv_value;
555 1.1.1.2 christos i->ctn_n++;
556 1.1.1.2 christos return 0;
557 1.1.1.2 christos }
558 1.1.1.2 christos
559 1.1 christos void
560 1.1 christos ctf_dynhash_destroy (ctf_dynhash_t *hp)
561 1.1 christos {
562 1.1 christos if (hp != NULL)
563 1.1 christos htab_delete (hp->htab);
564 1.1 christos free (hp);
565 1.1 christos }
566 1.1 christos
567 1.1.1.2 christos /* The dynset, used for sets of keys with no value. The implementation of this
568 1.1.1.2 christos can be much simpler, because without a value the slot can simply be the
569 1.1.1.2 christos stored key, which means we don't need to store the freeing functions and the
570 1.1.1.2 christos dynset itself is just a htab. */
571 1.1.1.2 christos
572 1.1.1.2 christos ctf_dynset_t *
573 1.1.1.2 christos ctf_dynset_create (htab_hash hash_fun, htab_eq eq_fun,
574 1.1.1.2 christos ctf_hash_free_fun key_free)
575 1.1.1.2 christos {
576 1.1.1.2 christos /* 7 is arbitrary and untested for now. */
577 1.1.1.2 christos return (ctf_dynset_t *) htab_create_alloc (7, (htab_hash) hash_fun, eq_fun,
578 1.1.1.2 christos key_free, xcalloc, free);
579 1.1.1.2 christos }
580 1.1.1.2 christos
581 1.1.1.2 christos /* The dynset has one complexity: the underlying implementation reserves two
582 1.1.1.2 christos values for internal hash table implementation details (empty versus deleted
583 1.1.1.2 christos entries). These values are otherwise very useful for pointers cast to ints,
584 1.1.1.2 christos so transform the ctf_dynset_inserted value to allow for it. (This
585 1.1.1.2 christos introduces an ambiguity in that one can no longer store these two values in
586 1.1.1.2 christos the dynset, but if we pick high enough values this is very unlikely to be a
587 1.1.1.2 christos problem.)
588 1.1.1.2 christos
589 1.1.1.2 christos We leak this implementation detail to the freeing functions on the grounds
590 1.1.1.2 christos that any use of these functions is overwhelmingly likely to be in sets using
591 1.1.1.2 christos real pointers, which will be unaffected. */
592 1.1.1.2 christos
593 1.1.1.2 christos #define DYNSET_EMPTY_ENTRY_REPLACEMENT ((void *) (uintptr_t) -64)
594 1.1.1.2 christos #define DYNSET_DELETED_ENTRY_REPLACEMENT ((void *) (uintptr_t) -63)
595 1.1.1.2 christos
596 1.1.1.2 christos static void *
597 1.1.1.2 christos key_to_internal (const void *key)
598 1.1.1.2 christos {
599 1.1.1.2 christos if (key == HTAB_EMPTY_ENTRY)
600 1.1.1.2 christos return DYNSET_EMPTY_ENTRY_REPLACEMENT;
601 1.1.1.2 christos else if (key == HTAB_DELETED_ENTRY)
602 1.1.1.2 christos return DYNSET_DELETED_ENTRY_REPLACEMENT;
603 1.1.1.2 christos
604 1.1.1.2 christos return (void *) key;
605 1.1.1.2 christos }
606 1.1.1.2 christos
607 1.1.1.2 christos static void *
608 1.1.1.2 christos internal_to_key (const void *internal)
609 1.1.1.2 christos {
610 1.1.1.2 christos if (internal == DYNSET_EMPTY_ENTRY_REPLACEMENT)
611 1.1.1.2 christos return HTAB_EMPTY_ENTRY;
612 1.1.1.2 christos else if (internal == DYNSET_DELETED_ENTRY_REPLACEMENT)
613 1.1.1.2 christos return HTAB_DELETED_ENTRY;
614 1.1.1.2 christos return (void *) internal;
615 1.1.1.2 christos }
616 1.1.1.2 christos
617 1.1.1.2 christos int
618 1.1.1.2 christos ctf_dynset_insert (ctf_dynset_t *hp, void *key)
619 1.1.1.2 christos {
620 1.1.1.2 christos struct htab *htab = (struct htab *) hp;
621 1.1.1.2 christos void **slot;
622 1.1.1.2 christos
623 1.1.1.2 christos slot = htab_find_slot (htab, key, INSERT);
624 1.1.1.2 christos
625 1.1.1.2 christos if (!slot)
626 1.1.1.2 christos {
627 1.1.1.2 christos errno = ENOMEM;
628 1.1.1.2 christos return -errno;
629 1.1.1.2 christos }
630 1.1.1.2 christos
631 1.1.1.2 christos if (*slot)
632 1.1.1.2 christos {
633 1.1.1.2 christos if (htab->del_f)
634 1.1.1.2 christos (*htab->del_f) (*slot);
635 1.1.1.2 christos }
636 1.1.1.2 christos
637 1.1.1.2 christos *slot = key_to_internal (key);
638 1.1.1.2 christos
639 1.1.1.2 christos return 0;
640 1.1.1.2 christos }
641 1.1.1.2 christos
642 1.1.1.2 christos void
643 1.1.1.2 christos ctf_dynset_remove (ctf_dynset_t *hp, const void *key)
644 1.1.1.2 christos {
645 1.1.1.2 christos htab_remove_elt ((struct htab *) hp, key_to_internal (key));
646 1.1.1.2 christos }
647 1.1.1.2 christos
648 1.1.1.2 christos void
649 1.1.1.2 christos ctf_dynset_destroy (ctf_dynset_t *hp)
650 1.1.1.2 christos {
651 1.1.1.2 christos if (hp != NULL)
652 1.1.1.2 christos htab_delete ((struct htab *) hp);
653 1.1.1.2 christos }
654 1.1.1.2 christos
655 1.1.1.2 christos void *
656 1.1.1.2 christos ctf_dynset_lookup (ctf_dynset_t *hp, const void *key)
657 1.1.1.2 christos {
658 1.1.1.2 christos void **slot = htab_find_slot ((struct htab *) hp,
659 1.1.1.2 christos key_to_internal (key), NO_INSERT);
660 1.1.1.2 christos
661 1.1.1.2 christos if (slot)
662 1.1.1.2 christos return internal_to_key (*slot);
663 1.1.1.2 christos return NULL;
664 1.1.1.2 christos }
665 1.1.1.2 christos
666 1.1.1.2 christos size_t
667 1.1.1.2 christos ctf_dynset_elements (ctf_dynset_t *hp)
668 1.1.1.2 christos {
669 1.1.1.2 christos return htab_elements ((struct htab *) hp);
670 1.1.1.2 christos }
671 1.1.1.2 christos
672 1.1.1.2 christos /* TRUE/FALSE return. */
673 1.1.1.2 christos int
674 1.1.1.2 christos ctf_dynset_exists (ctf_dynset_t *hp, const void *key, const void **orig_key)
675 1.1.1.2 christos {
676 1.1.1.2 christos void **slot = htab_find_slot ((struct htab *) hp,
677 1.1.1.2 christos key_to_internal (key), NO_INSERT);
678 1.1.1.2 christos
679 1.1.1.2 christos if (orig_key && slot)
680 1.1.1.2 christos *orig_key = internal_to_key (*slot);
681 1.1.1.2 christos return (slot != NULL);
682 1.1.1.2 christos }
683 1.1.1.2 christos
684 1.1.1.2 christos /* Look up a completely random value from the set, if any exist.
685 1.1.1.2 christos Keys with value zero cannot be distinguished from a nonexistent key. */
686 1.1.1.2 christos void *
687 1.1.1.2 christos ctf_dynset_lookup_any (ctf_dynset_t *hp)
688 1.1.1.2 christos {
689 1.1.1.2 christos struct htab *htab = (struct htab *) hp;
690 1.1.1.2 christos void **slot = htab->entries;
691 1.1.1.2 christos void **limit = slot + htab_size (htab);
692 1.1.1.2 christos
693 1.1.1.2 christos while (slot < limit
694 1.1.1.2 christos && (*slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY))
695 1.1.1.2 christos slot++;
696 1.1.1.2 christos
697 1.1.1.2 christos if (slot < limit)
698 1.1.1.2 christos return internal_to_key (*slot);
699 1.1.1.2 christos return NULL;
700 1.1.1.2 christos }
701 1.1.1.2 christos
702 1.1.1.2 christos /* Traverse a dynset in arbitrary order, in _next iterator form.
703 1.1.1.2 christos
704 1.1.1.2 christos Otherwise, just like ctf_dynhash_next. */
705 1.1.1.2 christos int
706 1.1.1.2 christos ctf_dynset_next (ctf_dynset_t *hp, ctf_next_t **it, void **key)
707 1.1.1.2 christos {
708 1.1.1.2 christos struct htab *htab = (struct htab *) hp;
709 1.1.1.2 christos ctf_next_t *i = *it;
710 1.1.1.2 christos void *slot;
711 1.1.1.2 christos
712 1.1.1.2 christos if (!i)
713 1.1.1.2 christos {
714 1.1.1.2 christos size_t size = htab_size (htab);
715 1.1.1.2 christos
716 1.1.1.2 christos /* If the table has too many entries to fit in an ssize_t, just give up.
717 1.1.1.2 christos This might be spurious, but if any type-related hashtable has ever been
718 1.1.1.2 christos nearly as large as that then somthing very odd is going on. */
719 1.1.1.2 christos
720 1.1.1.2 christos if (((ssize_t) size) < 0)
721 1.1.1.2 christos return EDOM;
722 1.1.1.2 christos
723 1.1.1.2 christos if ((i = ctf_next_create ()) == NULL)
724 1.1.1.2 christos return ENOMEM;
725 1.1.1.2 christos
726 1.1.1.2 christos i->u.ctn_hash_slot = htab->entries;
727 1.1.1.2 christos i->cu.ctn_s = hp;
728 1.1.1.2 christos i->ctn_n = 0;
729 1.1.1.2 christos i->ctn_size = (ssize_t) size;
730 1.1.1.2 christos i->ctn_iter_fun = (void (*) (void)) ctf_dynset_next;
731 1.1.1.2 christos *it = i;
732 1.1.1.2 christos }
733 1.1.1.2 christos
734 1.1.1.2 christos if ((void (*) (void)) ctf_dynset_next != i->ctn_iter_fun)
735 1.1.1.2 christos return ECTF_NEXT_WRONGFUN;
736 1.1.1.2 christos
737 1.1.1.2 christos if (hp != i->cu.ctn_s)
738 1.1.1.2 christos return ECTF_NEXT_WRONGFP;
739 1.1.1.2 christos
740 1.1.1.2 christos if ((ssize_t) i->ctn_n == i->ctn_size)
741 1.1.1.2 christos goto set_end;
742 1.1.1.2 christos
743 1.1.1.2 christos while ((ssize_t) i->ctn_n < i->ctn_size
744 1.1.1.2 christos && (*i->u.ctn_hash_slot == HTAB_EMPTY_ENTRY
745 1.1.1.2 christos || *i->u.ctn_hash_slot == HTAB_DELETED_ENTRY))
746 1.1.1.2 christos {
747 1.1.1.2 christos i->u.ctn_hash_slot++;
748 1.1.1.2 christos i->ctn_n++;
749 1.1.1.2 christos }
750 1.1.1.2 christos
751 1.1.1.2 christos if ((ssize_t) i->ctn_n == i->ctn_size)
752 1.1.1.2 christos goto set_end;
753 1.1.1.2 christos
754 1.1.1.2 christos slot = *i->u.ctn_hash_slot;
755 1.1.1.2 christos
756 1.1.1.2 christos if (key)
757 1.1.1.2 christos *key = internal_to_key (slot);
758 1.1.1.2 christos
759 1.1.1.2 christos i->u.ctn_hash_slot++;
760 1.1.1.2 christos i->ctn_n++;
761 1.1.1.2 christos
762 1.1.1.2 christos return 0;
763 1.1.1.2 christos
764 1.1.1.2 christos set_end:
765 1.1.1.2 christos ctf_next_destroy (i);
766 1.1.1.2 christos *it = NULL;
767 1.1.1.2 christos return ECTF_NEXT_END;
768 1.1.1.2 christos }
769 1.1.1.2 christos
770 1.1 christos /* ctf_hash, used for fixed-size maps from const char * -> ctf_id_t without
771 1.1 christos removal. This is a straight cast of a hashtab. */
772 1.1 christos
773 1.1 christos ctf_hash_t *
774 1.1 christos ctf_hash_create (unsigned long nelems, ctf_hash_fun hash_fun,
775 1.1 christos ctf_hash_eq_fun eq_fun)
776 1.1 christos {
777 1.1 christos return (ctf_hash_t *) htab_create_alloc (nelems, (htab_hash) hash_fun,
778 1.1 christos eq_fun, free, xcalloc, free);
779 1.1 christos }
780 1.1 christos
781 1.1 christos uint32_t
782 1.1 christos ctf_hash_size (const ctf_hash_t *hp)
783 1.1 christos {
784 1.1 christos return htab_elements ((struct htab *) hp);
785 1.1 christos }
786 1.1 christos
787 1.1 christos int
788 1.1.1.2 christos ctf_hash_insert_type (ctf_hash_t *hp, ctf_dict_t *fp, uint32_t type,
789 1.1 christos uint32_t name)
790 1.1 christos {
791 1.1 christos const char *str = ctf_strraw (fp, name);
792 1.1 christos
793 1.1 christos if (type == 0)
794 1.1 christos return EINVAL;
795 1.1 christos
796 1.1 christos if (str == NULL
797 1.1 christos && CTF_NAME_STID (name) == CTF_STRTAB_1
798 1.1 christos && fp->ctf_syn_ext_strtab == NULL
799 1.1 christos && fp->ctf_str[CTF_NAME_STID (name)].cts_strs == NULL)
800 1.1 christos return ECTF_STRTAB;
801 1.1 christos
802 1.1 christos if (str == NULL)
803 1.1 christos return ECTF_BADNAME;
804 1.1 christos
805 1.1 christos if (str[0] == '\0')
806 1.1 christos return 0; /* Just ignore empty strings on behalf of caller. */
807 1.1 christos
808 1.1 christos if (ctf_hashtab_insert ((struct htab *) hp, (char *) str,
809 1.1 christos (void *) (ptrdiff_t) type, NULL, NULL) != NULL)
810 1.1 christos return 0;
811 1.1 christos return errno;
812 1.1 christos }
813 1.1 christos
814 1.1 christos /* if the key is already in the hash, override the previous definition with
815 1.1 christos this new official definition. If the key is not present, then call
816 1.1.1.2 christos ctf_hash_insert_type and hash it in. */
817 1.1 christos int
818 1.1.1.2 christos ctf_hash_define_type (ctf_hash_t *hp, ctf_dict_t *fp, uint32_t type,
819 1.1 christos uint32_t name)
820 1.1 christos {
821 1.1.1.2 christos /* This matches the semantics of ctf_hash_insert_type in this
822 1.1 christos implementation anyway. */
823 1.1 christos
824 1.1 christos return ctf_hash_insert_type (hp, fp, type, name);
825 1.1 christos }
826 1.1 christos
827 1.1 christos ctf_id_t
828 1.1.1.2 christos ctf_hash_lookup_type (ctf_hash_t *hp, ctf_dict_t *fp __attribute__ ((__unused__)),
829 1.1 christos const char *key)
830 1.1 christos {
831 1.1 christos ctf_helem_t **slot;
832 1.1 christos
833 1.1 christos slot = ctf_hashtab_lookup ((struct htab *) hp, key, NO_INSERT);
834 1.1 christos
835 1.1 christos if (slot)
836 1.1.1.2 christos return (ctf_id_t) (uintptr_t) ((*slot)->value);
837 1.1 christos
838 1.1 christos return 0;
839 1.1 christos }
840 1.1 christos
841 1.1 christos void
842 1.1 christos ctf_hash_destroy (ctf_hash_t *hp)
843 1.1 christos {
844 1.1 christos if (hp != NULL)
845 1.1 christos htab_delete ((struct htab *) hp);
846 1.1 christos }
847