Home | History | Annotate | Line # | Download | only in libctf
ctf-hash.c revision 1.1
      1  1.1  christos /* Interface to hashtable implementations.
      2  1.1  christos    Copyright (C) 2006-2020 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  christos /* We have two hashtable implementations: one, ctf_dynhash_*(), is an interface to
     26  1.1  christos    a dynamically-expanding hash with unknown size that should support addition
     27  1.1  christos    of large numbers of items, and removal as well, and is used only at
     28  1.1  christos    type-insertion time; the other, ctf_dynhash_*(), is an interface to a
     29  1.1  christos    fixed-size hash from const char * -> ctf_id_t with number of elements
     30  1.1  christos    specified at creation time, that should support addition of items but need
     31  1.1  christos    not support removal.  These can be implemented by the same underlying hashmap
     32  1.1  christos    if you wish.  */
     33  1.1  christos 
     34  1.1  christos typedef struct ctf_helem
     35  1.1  christos {
     36  1.1  christos   void *key;			 /* Either a pointer, or a coerced ctf_id_t.  */
     37  1.1  christos   void *value;			 /* The value (possibly a coerced int).  */
     38  1.1  christos   ctf_hash_free_fun key_free;
     39  1.1  christos   ctf_hash_free_fun value_free;
     40  1.1  christos } ctf_helem_t;
     41  1.1  christos 
     42  1.1  christos struct ctf_dynhash
     43  1.1  christos {
     44  1.1  christos   struct htab *htab;
     45  1.1  christos   ctf_hash_free_fun key_free;
     46  1.1  christos   ctf_hash_free_fun value_free;
     47  1.1  christos };
     48  1.1  christos 
     49  1.1  christos /* Hash functions. */
     50  1.1  christos 
     51  1.1  christos unsigned int
     52  1.1  christos ctf_hash_integer (const void *ptr)
     53  1.1  christos {
     54  1.1  christos   ctf_helem_t *hep = (ctf_helem_t *) ptr;
     55  1.1  christos 
     56  1.1  christos   return htab_hash_pointer (hep->key);
     57  1.1  christos }
     58  1.1  christos 
     59  1.1  christos int
     60  1.1  christos ctf_hash_eq_integer (const void *a, const void *b)
     61  1.1  christos {
     62  1.1  christos   ctf_helem_t *hep_a = (ctf_helem_t *) a;
     63  1.1  christos   ctf_helem_t *hep_b = (ctf_helem_t *) b;
     64  1.1  christos 
     65  1.1  christos   return htab_eq_pointer (hep_a->key, hep_b->key);
     66  1.1  christos }
     67  1.1  christos 
     68  1.1  christos unsigned int
     69  1.1  christos ctf_hash_string (const void *ptr)
     70  1.1  christos {
     71  1.1  christos   ctf_helem_t *hep = (ctf_helem_t *) ptr;
     72  1.1  christos 
     73  1.1  christos   return htab_hash_string (hep->key);
     74  1.1  christos }
     75  1.1  christos 
     76  1.1  christos int
     77  1.1  christos ctf_hash_eq_string (const void *a, const void *b)
     78  1.1  christos {
     79  1.1  christos   ctf_helem_t *hep_a = (ctf_helem_t *) a;
     80  1.1  christos   ctf_helem_t *hep_b = (ctf_helem_t *) b;
     81  1.1  christos 
     82  1.1  christos   return !strcmp((const char *) hep_a->key, (const char *) hep_b->key);
     83  1.1  christos }
     84  1.1  christos 
     85  1.1  christos /* Hash a type_mapping_key.  */
     86  1.1  christos unsigned int
     87  1.1  christos ctf_hash_type_mapping_key (const void *ptr)
     88  1.1  christos {
     89  1.1  christos   ctf_helem_t *hep = (ctf_helem_t *) ptr;
     90  1.1  christos   ctf_link_type_mapping_key_t *k = (ctf_link_type_mapping_key_t *) hep->key;
     91  1.1  christos 
     92  1.1  christos   return htab_hash_pointer (k->cltm_fp) + 59 * htab_hash_pointer ((void *) k->cltm_idx);
     93  1.1  christos }
     94  1.1  christos 
     95  1.1  christos int
     96  1.1  christos ctf_hash_eq_type_mapping_key (const void *a, const void *b)
     97  1.1  christos {
     98  1.1  christos   ctf_helem_t *hep_a = (ctf_helem_t *) a;
     99  1.1  christos   ctf_helem_t *hep_b = (ctf_helem_t *) b;
    100  1.1  christos   ctf_link_type_mapping_key_t *key_a = (ctf_link_type_mapping_key_t *) hep_a->key;
    101  1.1  christos   ctf_link_type_mapping_key_t *key_b = (ctf_link_type_mapping_key_t *) hep_b->key;
    102  1.1  christos 
    103  1.1  christos   return (key_a->cltm_fp == key_b->cltm_fp)
    104  1.1  christos     && (key_a->cltm_idx == key_b->cltm_idx);
    105  1.1  christos }
    106  1.1  christos 
    107  1.1  christos /* The dynhash, used for hashes whose size is not known at creation time. */
    108  1.1  christos 
    109  1.1  christos /* Free a single ctf_helem.  */
    110  1.1  christos 
    111  1.1  christos static void
    112  1.1  christos ctf_dynhash_item_free (void *item)
    113  1.1  christos {
    114  1.1  christos   ctf_helem_t *helem = item;
    115  1.1  christos 
    116  1.1  christos   if (helem->key_free && helem->key)
    117  1.1  christos     helem->key_free (helem->key);
    118  1.1  christos   if (helem->value_free && helem->value)
    119  1.1  christos     helem->value_free (helem->value);
    120  1.1  christos   free (helem);
    121  1.1  christos }
    122  1.1  christos 
    123  1.1  christos ctf_dynhash_t *
    124  1.1  christos ctf_dynhash_create (ctf_hash_fun hash_fun, ctf_hash_eq_fun eq_fun,
    125  1.1  christos                     ctf_hash_free_fun key_free, ctf_hash_free_fun value_free)
    126  1.1  christos {
    127  1.1  christos   ctf_dynhash_t *dynhash;
    128  1.1  christos 
    129  1.1  christos   dynhash = malloc (sizeof (ctf_dynhash_t));
    130  1.1  christos   if (!dynhash)
    131  1.1  christos     return NULL;
    132  1.1  christos 
    133  1.1  christos   /* 7 is arbitrary and untested for now..  */
    134  1.1  christos   if ((dynhash->htab = htab_create_alloc (7, (htab_hash) hash_fun, eq_fun,
    135  1.1  christos                                           ctf_dynhash_item_free, xcalloc, free)) == NULL)
    136  1.1  christos     {
    137  1.1  christos       free (dynhash);
    138  1.1  christos       return NULL;
    139  1.1  christos     }
    140  1.1  christos 
    141  1.1  christos   dynhash->key_free = key_free;
    142  1.1  christos   dynhash->value_free = value_free;
    143  1.1  christos 
    144  1.1  christos   return dynhash;
    145  1.1  christos }
    146  1.1  christos 
    147  1.1  christos static ctf_helem_t **
    148  1.1  christos ctf_hashtab_lookup (struct htab *htab, const void *key, enum insert_option insert)
    149  1.1  christos {
    150  1.1  christos   ctf_helem_t tmp = { .key = (void *) key };
    151  1.1  christos   return (ctf_helem_t **) htab_find_slot (htab, &tmp, insert);
    152  1.1  christos }
    153  1.1  christos 
    154  1.1  christos static ctf_helem_t *
    155  1.1  christos ctf_hashtab_insert (struct htab *htab, void *key, void *value,
    156  1.1  christos 		    ctf_hash_free_fun key_free,
    157  1.1  christos 		    ctf_hash_free_fun value_free)
    158  1.1  christos {
    159  1.1  christos   ctf_helem_t **slot;
    160  1.1  christos 
    161  1.1  christos   slot = ctf_hashtab_lookup (htab, key, INSERT);
    162  1.1  christos 
    163  1.1  christos   if (!slot)
    164  1.1  christos     {
    165  1.1  christos       errno = -ENOMEM;
    166  1.1  christos       return NULL;
    167  1.1  christos     }
    168  1.1  christos 
    169  1.1  christos   if (!*slot)
    170  1.1  christos     {
    171  1.1  christos       *slot = malloc (sizeof (ctf_helem_t));
    172  1.1  christos       if (!*slot)
    173  1.1  christos 	return NULL;
    174  1.1  christos     }
    175  1.1  christos   else
    176  1.1  christos     {
    177  1.1  christos       if (key_free)
    178  1.1  christos 	  key_free ((*slot)->key);
    179  1.1  christos       if (value_free)
    180  1.1  christos 	  value_free ((*slot)->value);
    181  1.1  christos     }
    182  1.1  christos   (*slot)->key = key;
    183  1.1  christos   (*slot)->value = value;
    184  1.1  christos   return *slot;
    185  1.1  christos }
    186  1.1  christos 
    187  1.1  christos int
    188  1.1  christos ctf_dynhash_insert (ctf_dynhash_t *hp, void *key, void *value)
    189  1.1  christos {
    190  1.1  christos   ctf_helem_t *slot;
    191  1.1  christos 
    192  1.1  christos   slot = ctf_hashtab_insert (hp->htab, key, value,
    193  1.1  christos 			     hp->key_free, hp->value_free);
    194  1.1  christos 
    195  1.1  christos   if (!slot)
    196  1.1  christos     return errno;
    197  1.1  christos 
    198  1.1  christos   /* We need to keep the key_free and value_free around in each item because the
    199  1.1  christos      del function has no visibility into the hash as a whole, only into the
    200  1.1  christos      individual items.  */
    201  1.1  christos 
    202  1.1  christos   slot->key_free = hp->key_free;
    203  1.1  christos   slot->value_free = hp->value_free;
    204  1.1  christos 
    205  1.1  christos   return 0;
    206  1.1  christos }
    207  1.1  christos 
    208  1.1  christos void
    209  1.1  christos ctf_dynhash_remove (ctf_dynhash_t *hp, const void *key)
    210  1.1  christos {
    211  1.1  christos   ctf_helem_t hep = { (void *) key, NULL, NULL, NULL };
    212  1.1  christos   htab_remove_elt (hp->htab, &hep);
    213  1.1  christos }
    214  1.1  christos 
    215  1.1  christos void
    216  1.1  christos ctf_dynhash_empty (ctf_dynhash_t *hp)
    217  1.1  christos {
    218  1.1  christos   htab_empty (hp->htab);
    219  1.1  christos }
    220  1.1  christos 
    221  1.1  christos void *
    222  1.1  christos ctf_dynhash_lookup (ctf_dynhash_t *hp, const void *key)
    223  1.1  christos {
    224  1.1  christos   ctf_helem_t **slot;
    225  1.1  christos 
    226  1.1  christos   slot = ctf_hashtab_lookup (hp->htab, key, NO_INSERT);
    227  1.1  christos 
    228  1.1  christos   if (slot)
    229  1.1  christos     return (*slot)->value;
    230  1.1  christos 
    231  1.1  christos   return NULL;
    232  1.1  christos }
    233  1.1  christos 
    234  1.1  christos typedef struct ctf_traverse_cb_arg
    235  1.1  christos {
    236  1.1  christos   ctf_hash_iter_f fun;
    237  1.1  christos   void *arg;
    238  1.1  christos } ctf_traverse_cb_arg_t;
    239  1.1  christos 
    240  1.1  christos static int
    241  1.1  christos ctf_hashtab_traverse (void **slot, void *arg_)
    242  1.1  christos {
    243  1.1  christos   ctf_helem_t *helem = *((ctf_helem_t **) slot);
    244  1.1  christos   ctf_traverse_cb_arg_t *arg = (ctf_traverse_cb_arg_t *) arg_;
    245  1.1  christos 
    246  1.1  christos   arg->fun (helem->key, helem->value, arg->arg);
    247  1.1  christos   return 1;
    248  1.1  christos }
    249  1.1  christos 
    250  1.1  christos void
    251  1.1  christos ctf_dynhash_iter (ctf_dynhash_t *hp, ctf_hash_iter_f fun, void *arg_)
    252  1.1  christos {
    253  1.1  christos   ctf_traverse_cb_arg_t arg = { fun, arg_ };
    254  1.1  christos   htab_traverse (hp->htab, ctf_hashtab_traverse, &arg);
    255  1.1  christos }
    256  1.1  christos 
    257  1.1  christos typedef struct ctf_traverse_remove_cb_arg
    258  1.1  christos {
    259  1.1  christos   struct htab *htab;
    260  1.1  christos   ctf_hash_iter_remove_f fun;
    261  1.1  christos   void *arg;
    262  1.1  christos } ctf_traverse_remove_cb_arg_t;
    263  1.1  christos 
    264  1.1  christos static int
    265  1.1  christos ctf_hashtab_traverse_remove (void **slot, void *arg_)
    266  1.1  christos {
    267  1.1  christos   ctf_helem_t *helem = *((ctf_helem_t **) slot);
    268  1.1  christos   ctf_traverse_remove_cb_arg_t *arg = (ctf_traverse_remove_cb_arg_t *) arg_;
    269  1.1  christos 
    270  1.1  christos   if (arg->fun (helem->key, helem->value, arg->arg))
    271  1.1  christos     htab_clear_slot (arg->htab, slot);
    272  1.1  christos   return 1;
    273  1.1  christos }
    274  1.1  christos 
    275  1.1  christos void
    276  1.1  christos ctf_dynhash_iter_remove (ctf_dynhash_t *hp, ctf_hash_iter_remove_f fun,
    277  1.1  christos                          void *arg_)
    278  1.1  christos {
    279  1.1  christos   ctf_traverse_remove_cb_arg_t arg = { hp->htab, fun, arg_ };
    280  1.1  christos   htab_traverse (hp->htab, ctf_hashtab_traverse_remove, &arg);
    281  1.1  christos }
    282  1.1  christos 
    283  1.1  christos void
    284  1.1  christos ctf_dynhash_destroy (ctf_dynhash_t *hp)
    285  1.1  christos {
    286  1.1  christos   if (hp != NULL)
    287  1.1  christos     htab_delete (hp->htab);
    288  1.1  christos   free (hp);
    289  1.1  christos }
    290  1.1  christos 
    291  1.1  christos /* ctf_hash, used for fixed-size maps from const char * -> ctf_id_t without
    292  1.1  christos    removal.  This is a straight cast of a hashtab.  */
    293  1.1  christos 
    294  1.1  christos ctf_hash_t *
    295  1.1  christos ctf_hash_create (unsigned long nelems, ctf_hash_fun hash_fun,
    296  1.1  christos 		 ctf_hash_eq_fun eq_fun)
    297  1.1  christos {
    298  1.1  christos   return (ctf_hash_t *) htab_create_alloc (nelems, (htab_hash) hash_fun,
    299  1.1  christos 					   eq_fun, free, xcalloc, free);
    300  1.1  christos }
    301  1.1  christos 
    302  1.1  christos uint32_t
    303  1.1  christos ctf_hash_size (const ctf_hash_t *hp)
    304  1.1  christos {
    305  1.1  christos   return htab_elements ((struct htab *) hp);
    306  1.1  christos }
    307  1.1  christos 
    308  1.1  christos int
    309  1.1  christos ctf_hash_insert_type (ctf_hash_t *hp, ctf_file_t *fp, uint32_t type,
    310  1.1  christos 		      uint32_t name)
    311  1.1  christos {
    312  1.1  christos   const char *str = ctf_strraw (fp, name);
    313  1.1  christos 
    314  1.1  christos   if (type == 0)
    315  1.1  christos     return EINVAL;
    316  1.1  christos 
    317  1.1  christos   if (str == NULL
    318  1.1  christos       && CTF_NAME_STID (name) == CTF_STRTAB_1
    319  1.1  christos       && fp->ctf_syn_ext_strtab == NULL
    320  1.1  christos       && fp->ctf_str[CTF_NAME_STID (name)].cts_strs == NULL)
    321  1.1  christos     return ECTF_STRTAB;
    322  1.1  christos 
    323  1.1  christos   if (str == NULL)
    324  1.1  christos     return ECTF_BADNAME;
    325  1.1  christos 
    326  1.1  christos   if (str[0] == '\0')
    327  1.1  christos     return 0;		   /* Just ignore empty strings on behalf of caller.  */
    328  1.1  christos 
    329  1.1  christos   if (ctf_hashtab_insert ((struct htab *) hp, (char *) str,
    330  1.1  christos 			  (void *) (ptrdiff_t) type, NULL, NULL) != NULL)
    331  1.1  christos     return 0;
    332  1.1  christos   return errno;
    333  1.1  christos }
    334  1.1  christos 
    335  1.1  christos /* if the key is already in the hash, override the previous definition with
    336  1.1  christos    this new official definition. If the key is not present, then call
    337  1.1  christos    ctf_hash_insert_type() and hash it in.  */
    338  1.1  christos int
    339  1.1  christos ctf_hash_define_type (ctf_hash_t *hp, ctf_file_t *fp, uint32_t type,
    340  1.1  christos                       uint32_t name)
    341  1.1  christos {
    342  1.1  christos   /* This matches the semantics of ctf_hash_insert_type() in this
    343  1.1  christos      implementation anyway.  */
    344  1.1  christos 
    345  1.1  christos   return ctf_hash_insert_type (hp, fp, type, name);
    346  1.1  christos }
    347  1.1  christos 
    348  1.1  christos ctf_id_t
    349  1.1  christos ctf_hash_lookup_type (ctf_hash_t *hp, ctf_file_t *fp __attribute__ ((__unused__)),
    350  1.1  christos 		      const char *key)
    351  1.1  christos {
    352  1.1  christos   ctf_helem_t **slot;
    353  1.1  christos 
    354  1.1  christos   slot = ctf_hashtab_lookup ((struct htab *) hp, key, NO_INSERT);
    355  1.1  christos 
    356  1.1  christos   if (slot)
    357  1.1  christos     return (ctf_id_t) ((*slot)->value);
    358  1.1  christos 
    359  1.1  christos   return 0;
    360  1.1  christos }
    361  1.1  christos 
    362  1.1  christos void
    363  1.1  christos ctf_hash_destroy (ctf_hash_t *hp)
    364  1.1  christos {
    365  1.1  christos   if (hp != NULL)
    366  1.1  christos     htab_delete ((struct htab *) hp);
    367  1.1  christos }
    368