| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- #include <ccan/foreach/foreach.h>
- #include <ccan/list/list.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #if !HAVE_COMPOUND_LITERALS || !HAVE_FOR_LOOP_DECLARATION
- /* This list is normally very short. */
- static LIST_HEAD(iters);
- struct iter_info {
- struct list_node list;
- const void *index;
- unsigned int i, num;
- };
- static void free_old_iters(const void *index)
- {
- struct iter_info *i, *next;
- list_for_each_safe(&iters, i, next, list) {
- /* If we're re-using an index, free the old one.
- * Otherwise, if it's past i on the stack, it's old. Don't
- * assume stack direction, but we know index is downstack. */
- if (i->index == index
- || (((uintptr_t)index < (uintptr_t)&i)
- == ((uintptr_t)&i < (uintptr_t)i->index))) {
- list_del(&i->list);
- free(i);
- }
- }
- }
- static struct iter_info *find_iter(const void *index)
- {
- struct iter_info *i;
- list_for_each(&iters, i, list) {
- if (i->index == index)
- return i;
- }
- abort();
- }
- static struct iter_info *new_iter(const void *index)
- {
- struct iter_info *info = malloc(sizeof *info);
- info->index = index;
- info->i = info->num = 0;
- list_add(&iters, &info->list);
- return info;
- };
- #if HAVE_COMPOUND_LITERALS
- void _foreach_iter_init(const void *i)
- {
- free_old_iters(i);
- new_iter(i);
- }
- unsigned int _foreach_iter(const void *i)
- {
- struct iter_info *info = find_iter(i);
- return info->i;
- }
- unsigned int _foreach_iter_inc(const void *i)
- {
- struct iter_info *info = find_iter(i);
- return ++info->i;
- }
- #else /* Don't have compound literals... */
- int _foreach_term = 0x42430199;
- /* We count values at beginning, and every time around the loop. We change
- * the terminator each time, so we don't get fooled in case it really appears
- * in the list. */
- static unsigned int count_vals(struct iter_info *info, va_list *ap)
- {
- unsigned int i;
- int val = 0;
- for (i = 0; i < info->num || val != _foreach_term; i++) {
- val = va_arg(*ap, int);
- }
- _foreach_term++;
- return i;
- }
- int _foreach_intval_init(const void *i, int val, ...)
- {
- va_list ap;
- struct iter_info *info;
- free_old_iters(i);
- info = new_iter(i);
- va_start(ap, val);
- info->num = count_vals(info, &ap);
- va_end(ap);
- return val;
- }
- bool _foreach_intval_done(const void *i)
- {
- struct iter_info *info = find_iter(i);
- return info->i == info->num;
- }
-
- int _foreach_intval_next(const void *i, int val, ...)
- {
- struct iter_info *info = find_iter(i);
- va_list ap;
- unsigned int num;
- va_start(ap, val);
- info->num = count_vals(info, &ap);
- va_end(ap);
- info->i++;
- assert(info->i <= info->num);
- if (info->i == info->num)
- return 0;
- va_start(ap, val);
- for (num = 0; num < info->i; num++)
- val = va_arg(ap, int);
- va_end(ap);
- return val;
- }
- void *_foreach_ptrval_init(const void *i, const void *val, ...)
- {
- struct iter_info *info;
- free_old_iters(i);
- info = new_iter(i);
- return (void *)val;
- }
- void *_foreach_ptrval_next(const void *i, const void *val, ...)
- {
- struct iter_info *info = find_iter(i);
- va_list ap;
- unsigned int num;
- info->i++;
- va_start(ap, val);
- for (num = 0; num < info->i; num++)
- val = va_arg(ap, void *);
- va_end(ap);
- return (void *)val;
- }
- #endif /* !HAVE_COMPOUND_LITERALS */
- #endif /* !HAVE_COMPOUND_LITERALS || !HAVE_FOR_LOOP_DECLARATION */
|