diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-08-25 16:06:58 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-08-25 16:06:58 +0300 |
commit | c2f02c56a38a3e6d50b8ca2081db9d2de658b8ed (patch) | |
tree | a6c80fd81a6b5aad899d8fb0e3e41ece650eed9b /src/list.c | |
parent | 102d1b9c1a94548dfa0c498845c77933db6a7738 (diff) | |
download | grecs-c2f02c56a38a3e6d50b8ca2081db9d2de658b8ed.tar.gz grecs-c2f02c56a38a3e6d50b8ca2081db9d2de658b8ed.tar.bz2 |
symtabs: allow to modify the list during iteration over it.
* include/grecs/list.h (grecs_list_remove): New proto.
* include/grecs/symtab.h (grecs_symtab_count_entries):
Rename to grecs_symtab_count.
* src/list.c (grecs_list_remove): New function.
(grecs_list_remove_tail, grecs_list_clear)
(grecs_list_locate,grecs_list_index): Treat NULL list
as empty list.
* src/symtab.c: Defer table modifications during iteration
(symtab_defer_type): New enum.
(grecs_symtab)<elcount,itr_level,defer_list>: New members.
(symtab_defer_op): New static function.
(grecs_symtab_remove): When called during iteration, add the
entry to the defer_del deferment list, unless it is already
in defer_add, in which case remove it from there.
Update elcount.
(grecs_symtab_lookup_or_install): Defer addition when iterating.
Update elcount.
(grecs_symtab_clear): Reset elcount to 0.
(grecs_symtab_create): Initialize elcount.
(grecs_symtab_foreach): Process deferred modifications.
Diffstat (limited to 'src/list.c')
-rw-r--r-- | src/list.c | 84 |
1 files changed, 59 insertions, 25 deletions
@@ -86,6 +86,46 @@ grecs_list_remove_entry(struct grecs_list *lp, struct grecs_list_entry *ent) lp->count--; } +void * +grecs_list_remove_tail(struct grecs_list *lp) +{ + void *data; + struct grecs_list_entry *ep; + + if (!lp || !lp->tail) + return NULL; + ep = lp->tail; + data = lp->tail->data; + grecs_list_remove_entry(lp, ep); + return data; +} + +static int +_ptrcmp(const void *a, const void *b) +{ + return a != b; +} + +int +grecs_list_remove(struct grecs_list *lp, void *data) +{ + struct grecs_list_entry *ep; + int (*cmp)(const void *, const void *); + + + if (!lp) + return 1; + + cmp = lp->cmp ? lp->cmp : _ptrcmp; + for (ep = lp->head; ep; ep = ep->next) { + if (cmp(ep->data, data) == 0) { + grecs_list_remove_entry(lp, ep); + return 0; + } + } + return 1; +} + void grecs_list_append(struct grecs_list *lp, void *val) { @@ -123,7 +163,11 @@ void * grecs_list_pop(struct grecs_list *lp) { void *data; - struct grecs_list_entry *ep = lp->head; + struct grecs_list_entry *ep; + + if (!lp) + return NULL; + ep = lp->head; if (ep) { data = ep->data; grecs_list_remove_entry(lp, ep); @@ -132,25 +176,14 @@ grecs_list_pop(struct grecs_list *lp) return data; } -void * -grecs_list_remove_tail(struct grecs_list *lp) -{ - void *data; - struct grecs_list_entry *ep; - - if (!lp->tail) - return NULL; - ep = lp->tail; - data = lp->tail->data; - grecs_list_remove_entry(lp, ep); - return data; -} - void grecs_list_clear(struct grecs_list *lp) { - struct grecs_list_entry *ep = lp->head; + struct grecs_list_entry *ep; + if (!lp) + return; + ep = lp->head; while (ep) { struct grecs_list_entry *next = ep->next; if (lp->free_entry) @@ -171,17 +204,16 @@ grecs_list_free(struct grecs_list *lp) } } -static int -_ptrcmp(const void *a, const void *b) -{ - return a != b; -} - void * grecs_list_locate(struct grecs_list *lp, void *data) { struct grecs_list_entry *ep; - int (*cmp)(const void *, const void *) = lp->cmp ? lp->cmp : _ptrcmp; + int (*cmp)(const void *, const void *); + + if (!lp) + return NULL; + + cmp = lp->cmp ? lp->cmp : _ptrcmp; for (ep = lp->head; ep; ep = ep->next) { if (cmp(ep->data, data) == 0) @@ -194,7 +226,9 @@ void * grecs_list_index(struct grecs_list *lp, size_t idx) { struct grecs_list_entry *ep; - + + if (!lp) + return NULL; for (ep = lp->head; ep && idx; ep = ep->next, idx--) ; return ep ? ep->data : NULL; @@ -219,7 +253,7 @@ grecs_list_compare(struct grecs_list *a, struct grecs_list *b) cmp = a->cmp ? a->cmp : _ptrcmp; for (ap = a->head, bp = b->head; ap; ap = ap->next, bp = bp->next) - if (cmp (ap->data, bp->data)) + if (cmp(ap->data, bp->data)) return 1; return 0; |