foreach: allow a single argument to foreach_int() and foreach_ptr().
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 21 Mar 2011 02:43:51 +0000 (13:13 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 21 Mar 2011 02:43:51 +0000 (13:13 +1030)
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.

ccan/foreach/foreach.h
ccan/foreach/test/run-single-arg.c [new file with mode: 0644]

index c7e878f89c9fdc3877395220082f044a746dd09e..73c4c693ebf7f58297b092f943716d07701f809b 100644 (file)
@@ -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.
  *             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;
  *             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 (file)
index 0000000..2541318
--- /dev/null
@@ -0,0 +1,31 @@
+#include <ccan/foreach/foreach.h>
+#include <ccan/tap/tap.h>
+#include <stdio.h>
+#include <string.h>
+#include <ccan/foreach/foreach.c>
+
+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();
+}
+