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