Browse Source

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.
Rusty Russell 15 years ago
parent
commit
b824ee6e4a
2 changed files with 61 additions and 30 deletions
  1. 30 30
      ccan/foreach/foreach.h
  2. 31 0
      ccan/foreach/test/run-single-arg.c

+ 30 - 30
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, ...);

+ 31 - 0
ccan/foreach/test/run-single-arg.c

@@ -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();
+}
+