X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fforeach%2Fforeach.c;fp=ccan%2Fforeach%2Fforeach.c;h=07108b67574cbab76d2371fe97e7875e41fc6ad3;hb=daddafe53685b0b6f90a7746cbbd1a2e7df59216;hp=0000000000000000000000000000000000000000;hpb=2965496c70c345ea83e14d4b25e8687f7c682531;p=ccan diff --git a/ccan/foreach/foreach.c b/ccan/foreach/foreach.c new file mode 100644 index 00000000..07108b67 --- /dev/null +++ b/ccan/foreach/foreach.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include + +#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 */