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