aboutsummaryrefslogtreecommitdiff
path: root/src/symtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/symtab.c')
-rw-r--r--src/symtab.c113
1 files changed, 91 insertions, 22 deletions
diff --git a/src/symtab.c b/src/symtab.c
index 540ea0f..3647a81 100644
--- a/src/symtab.c
+++ b/src/symtab.c
@@ -33,16 +33,36 @@ static unsigned int hash_size[] = {
33/* |max_rehash| keeps the number of entries in |hash_size| table. */ 33/* |max_rehash| keeps the number of entries in |hash_size| table. */
34static unsigned int max_rehash = sizeof(hash_size) / sizeof(hash_size[0]); 34static unsigned int max_rehash = sizeof(hash_size) / sizeof(hash_size[0]);
35 35
36enum symtab_defer_type {
37 defer_add,
38 defer_del
39};
40
36struct grecs_symtab { 41struct grecs_symtab {
37 int flags; 42 int flags;
38 unsigned int hash_num; /* Index to hash_size table */ 43 unsigned int hash_num; /* Index to hash_size table */
39 size_t elsize; /* Size of an element */ 44 size_t elsize; /* Size of an element */
40 struct grecs_syment **tab; 45 size_t elcount; /* Number of elements in use */
41 unsigned (*hash_fun)(void *, unsigned long hash_num); 46 struct grecs_syment **tab; /* Table of element pointers */
47
48 /* Functions that can be overridden when creating the symtab: */
49 unsigned (*hash_fun)(void *, unsigned long);
42 int (*cmp_fun)(const void *, const void *); 50 int (*cmp_fun)(const void *, const void *);
43 int (*copy_fun)(void *, void *); 51 int (*copy_fun)(void *, void *);
44 void *(*syment_alloc_fun)(size_t size); 52 void *(*syment_alloc_fun)(size_t);
45 void (*syment_free_fun) (void *); 53 void (*syment_free_fun) (void *);
54
55 /* Support for deferred operations. When an insertion or deletion
56 is requested while the symtab is being iterated over, this operation
57 is deferred until the iteration is finished. */
58
59 /* Iteration level. Gets increased upon entry to grecs_symtab_foreach,
60 and decreased right before leaving it. */
61 unsigned int itr_level;
62 /* Two deferment lists keep track of the deferred additions and
63 removals:
64 */
65 grecs_list_ptr_t defer_list[2];
46}; 66};
47 67
48static void 68static void
@@ -72,7 +92,17 @@ syment_alloc(struct grecs_symtab *st, void *key)
72 } 92 }
73 return ent; 93 return ent;
74} 94}
75 95
96static void
97symtab_defer_op(struct grecs_symtab *st, enum symtab_defer_type type,
98 struct grecs_syment *ent)
99{
100 if (!st->defer_list[type]) {
101 st->defer_list[type] = grecs_list_create();
102 st->defer_list[type]->cmp = st->cmp_fun;
103 }
104 grecs_list_append(st->defer_list[type], ent);
105}
76 106
77unsigned 107unsigned
78grecs_hash_string(const char *name, unsigned long hashsize) 108grecs_hash_string(const char *name, unsigned long hashsize)
@@ -101,8 +131,8 @@ grecs_hash_string_ci(const char *name, unsigned long hashsize)
101static unsigned 131static unsigned
102def_hash(void *data, unsigned long hashsize) 132def_hash(void *data, unsigned long hashsize)
103{ 133{
104 struct grecs_syment *sym = data; 134 struct grecs_syment *sym = data;
105 return grecs_hash_string(sym->name, hashsize); 135 return grecs_hash_string(sym->name, hashsize);
106} 136}
107 137
108static int 138static int
@@ -218,6 +248,11 @@ grecs_symtab_remove(struct grecs_symtab *st, void *elt)
218 unsigned int pos, i, j, r; 248 unsigned int pos, i, j, r;
219 struct grecs_syment *entry; 249 struct grecs_syment *entry;
220 250
251 if (st->itr_level) {
252 if (grecs_list_remove(st->defer_list[defer_add], elt) == 0)
253 return 0;
254 }
255
221 pos = st->hash_fun(elt, hash_size[st->hash_num]); 256 pos = st->hash_fun(elt, hash_size[st->hash_num]);
222 for (i = pos; (entry = st->tab[i]);) { 257 for (i = pos; (entry = st->tab[i]);) {
223 if (st->cmp_fun(entry, elt) == 0) 258 if (st->cmp_fun(entry, elt) == 0)
@@ -231,7 +266,14 @@ grecs_symtab_remove(struct grecs_symtab *st, void *elt)
231 if (!entry) 266 if (!entry)
232 return ENOENT; 267 return ENOENT;
233 268
269 if (st->itr_level) {
270 symtab_defer_op(st, defer_del, entry);
271 //FIXME: mark the entry as deleted
272 return 0;
273 }
274
234 syment_free(st, entry); 275 syment_free(st, entry);
276 st->elcount--;
235 277
236 for (;;) { 278 for (;;) {
237 st->tab[i] = NULL; 279 st->tab[i] = NULL;
@@ -312,10 +354,20 @@ grecs_symtab_lookup_or_install(struct grecs_symtab *st, void *key,
312 errno = ENOMEM; 354 errno = ENOMEM;
313 return NULL; 355 return NULL;
314 } 356 }
315 st->tab[i] = ent; 357 if (st->itr_level) {
358 symtab_defer_op(st, defer_add, ent);
359 } else {
360 st->tab[i] = ent;
361 st->elcount++;
362 }
316 return ent; 363 return ent;
317 } else 364 } else
318 return st->tab[i]; 365 return st->tab[i];
366 } else if (rc == ENOENT && st->itr_level) {
367 void *ptr = grecs_list_locate(st->defer_list[defer_add], key);
368 if (ptr)
369 return ptr;
370 rc = ENOENT;
319 } 371 }
320 errno = rc; 372 errno = rc;
321 return NULL; 373 return NULL;
@@ -337,6 +389,7 @@ grecs_symtab_clear(struct grecs_symtab *st)
337 st->tab[i] = NULL; 389 st->tab[i] = NULL;
338 } 390 }
339 } 391 }
392 st->elcount = 0;
340} 393}
341 394
342struct grecs_symtab * 395struct grecs_symtab *
@@ -350,6 +403,7 @@ grecs_symtab_create(size_t elsize,
350 if (st) { 403 if (st) {
351 memset(st, 0, sizeof(*st)); 404 memset(st, 0, sizeof(*st));
352 st->elsize = elsize; 405 st->elsize = elsize;
406 st->elcount = 0;
353 st->hash_fun = hash_fun ? hash_fun : def_hash; 407 st->hash_fun = hash_fun ? hash_fun : def_hash;
354 st->cmp_fun = cmp_fun ? cmp_fun : def_cmp; 408 st->cmp_fun = cmp_fun ? cmp_fun : def_cmp;
355 st->copy_fun = copy_fun ? copy_fun : def_copy; 409 st->copy_fun = copy_fun ? copy_fun : def_copy;
@@ -381,39 +435,54 @@ grecs_symtab_free(struct grecs_symtab *st)
381{ 435{
382 if (st) { 436 if (st) {
383 grecs_symtab_clear(st); 437 grecs_symtab_clear(st);
438 grecs_list_free(st->defer_list[defer_add]);
439 grecs_list_free(st->defer_list[defer_del]);
384 free(st->tab); 440 free(st->tab);
385 free(st); 441 free(st);
386 } 442 }
387} 443}
388 444
389size_t 445size_t
390grecs_symtab_count_entries(struct grecs_symtab *st) 446grecs_symtab_count(struct grecs_symtab *st)
391{ 447{
392 unsigned i; 448 return st->elcount;
393 size_t count = 0;
394
395 for (i = 0; i < hash_size[st->hash_num]; i++)
396 if (st->tab[i])
397 count++;
398 return count;
399} 449}
400 450
401int 451int
402grecs_symtab_enumerate(struct grecs_symtab *st, grecs_symtab_enumerator_t fun, 452grecs_symtab_foreach(struct grecs_symtab *st, grecs_symtab_enumerator_t fun,
403 void *data) 453 void *data)
404{ 454{
405 unsigned i; 455 unsigned i;
406 456 struct grecs_syment *ep;
457
407 if (!st) 458 if (!st)
408 return 0; 459 return 0;
460
461 ++st->itr_level;
462
409 for (i = 0; i < hash_size[st->hash_num]; i++) { 463 for (i = 0; i < hash_size[st->hash_num]; i++) {
410 struct grecs_syment *ep = st->tab[i]; 464 ep = st->tab[i];
411 if (ep) { 465 if (ep && !grecs_list_locate(st->defer_list[defer_del], ep)) {
412 int rc = fun(ep, data); 466 int rc = fun(ep, data);
413 if (rc) 467 if (rc)
414 return rc; 468 return rc;
415 } 469 }
416 } 470 }
471
472 if (--st->itr_level == 0) {
473 while ((ep = grecs_list_pop(st->defer_list[defer_del])) != NULL)
474 grecs_symtab_remove(st, ep);
475
476 while ((ep = grecs_list_pop(st->defer_list[defer_add])) != NULL) {
477 int install = 1;
478 if (grecs_symtab_get_index(&i, st, ep,
479 &install) == 0) {
480 st->tab[i] = ep;
481 st->elcount++;
482 }
483 }
484 }
485
417 return 0; 486 return 0;
418} 487}
419 488

Return to:

Send suggestions and report system problems to the System administrator.