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