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