Home | History | Annotate | Line # | Download | only in libctf
ctf-hash.c revision 1.1.1.3
      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