From: Rusty Russell Date: Mon, 21 Mar 2011 02:43:51 +0000 (+1030) Subject: foreach: allow a single argument to foreach_int() and foreach_ptr(). X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=b824ee6e4ad48687325106c60ddb7f0b43565189;ds=sidebyside foreach: allow a single argument to foreach_int() and foreach_ptr(). David Gibson noted that foreach requires more than one argument. There's no particularly good reason for this, other than lack of imagination on my part. --- diff --git a/ccan/foreach/foreach.h b/ccan/foreach/foreach.h index c7e878f8..73c4c693 100644 --- a/ccan/foreach/foreach.h +++ b/ccan/foreach/foreach.h @@ -10,7 +10,7 @@ /** * foreach_int - iterate over a fixed series of integers * @i: the int-compatible iteration variable - * @val: one or more integer-compatible values + * ...: one or more integer-compatible values * * This is a convenient wrapper function for setting a variable to one or * more explicit values in turn. continue and break work as expected. @@ -21,15 +21,15 @@ * printf("i is %i\n", i); * } */ -#define foreach_int(i, val, ...) \ - for (unsigned _foreach_i = ((i) = val, 0); \ - _foreach_i < sizeof((int[]) { val, __VA_ARGS__ })/sizeof(val); \ - (i) = (int[]) { val, __VA_ARGS__, 0 }[++_foreach_i]) +#define foreach_int(i, ...) \ + for (unsigned _foreach_i = (((i) = ((int[]) { __VA_ARGS__ })[0]), 0); \ + _foreach_i < sizeof((int[]) { __VA_ARGS__ })/sizeof(int); \ + (i) = ((int[]) { __VA_ARGS__, 0 })[++_foreach_i]) /** * foreach_ptr - iterate over a non-NULL series of pointers * @i: the pointer iteration variable - * @val: one or more compatible pointer values + * ...: one or more compatible pointer values * * This is a convenient wrapper function for setting a variable to one * or more explicit values in turn. None of the values can be NULL; @@ -42,28 +42,30 @@ * printf("p is %s\n", p); * } */ -#define foreach_ptr(i, val, ...) \ - for (unsigned _foreach_i = (unsigned long)((i) = (val), 0); \ +#define foreach_ptr(i, ...) \ + for (unsigned _foreach_i \ + = (((i) = ((const void *[]){ __VA_ARGS__ })[0]), 0); \ (i); \ - (i) = ((FOREACH_TYPEOF(val)[]){(val), __VA_ARGS__, NULL}) \ - [++_foreach_i], \ + (i) = (void *)((FOREACH_TYPEOF(i)[]) \ + { __VA_ARGS__, NULL})[++_foreach_i], \ _foreach_no_nullval(_foreach_i, i, \ - ((void *[]){ val, __VA_ARGS__}))) + ((const void *[]){ __VA_ARGS__}))) #else /* !HAVE_FOR_LOOP_DECLARATION */ /* GCC in C89 mode still has compound literals, but no for-declarations */ -#define foreach_int(i, val, ...) \ - for ((i) = (val), _foreach_iter_init(&(i)); \ - _foreach_iter(&(i)) < sizeof((int[]) { (val), __VA_ARGS__ }) \ +#define foreach_int(i, ...) \ + for ((i) = ((int[]){ __VA_ARGS__ })[0], _foreach_iter_init(&(i)); \ + _foreach_iter(&(i)) < sizeof((int[]) { __VA_ARGS__ }) \ / sizeof(int); \ - (i) = (int[]) { (val), __VA_ARGS__, 0 }[_foreach_iter_inc(&(i))]) + (i) = (int[]) { __VA_ARGS__, 0 }[_foreach_iter_inc(&(i))]) -#define foreach_ptr(i, val, ...) \ - for ((i) = (val), _foreach_iter_init(&(i)); \ +#define foreach_ptr(i, ...) \ + for ((i) = ((FOREACH_TYPEOF(i)[]){ __VA_ARGS__ })[0], \ + _foreach_iter_init(&(i)); \ (i); \ - (i) = ((FOREACH_TYPEOF(val)[]){ (val), __VA_ARGS__, 0 }) \ + (i) = (void *)((FOREACH_TYPEOF(i)[]){ __VA_ARGS__, NULL }) \ [_foreach_iter_inc(&(i))], \ _foreach_no_nullval(_foreach_iter(&(i)), i, \ - ((void *[]){ val, __VA_ARGS__}))) + ((void *[]){ __VA_ARGS__}))) void _foreach_iter_init(const void *i); unsigned int _foreach_iter(const void *i); @@ -76,25 +78,23 @@ unsigned int _foreach_iter_inc(const void *i); assert((i) >= sizeof(arr)/sizeof(arr[0]) || (p)) #if HAVE_TYPEOF -#define FOREACH_TYPEOF(val) __typeof__(&*(val)) +#define FOREACH_TYPEOF(i) __typeof__(i) #else -#define FOREACH_TYPEOF(val) void * +#define FOREACH_TYPEOF(i) const void * #endif #else /* !HAVE_COMPOUND_LITERALS */ /* No compound literals, but it's still (just) possible. */ -#define foreach_int(i, val, ...) \ - for (i = _foreach_intval_init(&(i), val, __VA_ARGS__, \ - _foreach_term); \ - !_foreach_intval_done(&i); \ - i = _foreach_intval_next(&(i), val, __VA_ARGS__, \ - _foreach_term)) +#define foreach_int(i, ...) \ + for (i = _foreach_intval_init(&(i), __VA_ARGS__, _foreach_term); \ + !_foreach_intval_done(&i); \ + i = _foreach_intval_next(&(i), __VA_ARGS__, _foreach_term)) -#define foreach_ptr(i, val, ...) \ - for (i = _foreach_ptrval_init(&(i), val, __VA_ARGS__, NULL); \ +#define foreach_ptr(i, ...) \ + for (i = _foreach_ptrval_init(&(i), __VA_ARGS__, NULL); \ (i); \ - i = _foreach_ptrval_next(&(i), val, __VA_ARGS__, NULL)) + i = _foreach_ptrval_next(&(i), __VA_ARGS__, NULL)) extern int _foreach_term; int _foreach_intval_init(const void *i, int val, ...); diff --git a/ccan/foreach/test/run-single-arg.c b/ccan/foreach/test/run-single-arg.c new file mode 100644 index 00000000..25413181 --- /dev/null +++ b/ccan/foreach/test/run-single-arg.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +int main(void) +{ + int i, num; + const char *p; + + plan_tests(5); + + num = 0; + foreach_int(i, 0) { + ok1(i == 0); + num++; + } + ok1(num == 1); + + num = 0; + foreach_ptr(p, "hello") { + ok1(strcmp("hello", p) == 0); + num++; + } + ok1(p == NULL); + ok1(num == 1); + + return exit_status(); +} +