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