]> git.ozlabs.org Git - ccan/blob - ccan/foreach/foreach.h
foreach: fix HAVE_FOR_LOOP_DECLARATION case.
[ccan] / ccan / foreach / foreach.h
1 #ifndef CCAN_FOREACH_H
2 #define CCAN_FOREACH_H
3 #include "config.h"
4 #include <stddef.h>
5 #include <assert.h>
6 #include <stdbool.h>
7
8 #if HAVE_COMPOUND_LITERALS
9 #if HAVE_FOR_LOOP_DECLARATION
10 /**
11  * foreach_int - iterate over a fixed series of integers
12  * @i: the int-compatible iteration variable
13  * @val: one or more integer-compatible values
14  *
15  * This is a convenient wrapper function for setting a variable to one or
16  * more explicit values in turn.  continue and break work as expected.
17  *
18  * Example:
19  *      int i;
20  *      foreach_int(i, 0, -1, 100, 0, -99) {
21  *              printf("i is %i\n", i);
22  *      }
23  */
24 #define foreach_int(i, val, ...)                                        \
25         for (unsigned _foreach_i = ((i) = val, 0);                      \
26              _foreach_i < sizeof((int[]) { val, __VA_ARGS__ })/sizeof(val); \
27              (i) = (int[]) { val, __VA_ARGS__, 0 }[++_foreach_i])
28
29 /**
30  * foreach_ptr - iterate over a non-NULL series of pointers
31  * @i: the pointer iteration variable
32  * @val: one or more compatible pointer values
33  *
34  * This is a convenient wrapper function for setting a variable to one
35  * or more explicit values in turn.  None of the values can be NULL;
36  * that is the termination condition (ie. @i will be NULL on
37  * completion).  continue and break work as expected.
38  *
39  * Example:
40  *      const char *p;
41  *      foreach_ptr(p, "Hello", "world") {
42  *              printf("p is %s\n", p);
43  *      }
44  */
45 #define foreach_ptr(i, val, ...)                                        \
46         for (unsigned _foreach_i = (unsigned long)((i) = (val), 0);     \
47              (i);                                                       \
48              (i) = ((FOREACH_TYPEOF(val)[]){(val), __VA_ARGS__, NULL})  \
49                      [++_foreach_i],                                    \
50                 _foreach_no_nullval(_foreach_i, i,                      \
51                                     ((void *[]){ val, __VA_ARGS__})))
52 #else /* !HAVE_FOR_LOOP_DECLARATION */
53 /* GCC in C89 mode still has compound literals, but no for-declarations */
54 #define foreach_int(i, val, ...)                                        \
55         for ((i) = (val), _foreach_iter_init(&(i));                     \
56              _foreach_iter(&(i)) < sizeof((int[]) { (val), __VA_ARGS__ }) \
57                            / sizeof(int);                               \
58              (i) = (int[]) { (val), __VA_ARGS__, 0 }[_foreach_iter_inc(&(i))])
59
60 #define foreach_ptr(i, val, ...)                                        \
61         for ((i) = (val), _foreach_iter_init(&(i));                     \
62              (i);                                                       \
63              (i) = ((FOREACH_TYPEOF(val)[]){ (val), __VA_ARGS__, 0 })   \
64                      [_foreach_iter_inc(&(i))],                         \
65                  _foreach_no_nullval(_foreach_iter(&(i)), i,            \
66                                      ((void *[]){ val, __VA_ARGS__})))
67
68 void _foreach_iter_init(const void *i);
69 unsigned int _foreach_iter(const void *i);
70 unsigned int _foreach_iter_inc(const void *i);
71
72 #endif /* !HAVE_FOR_LOOP_DECLARATION */
73
74 /* Make sure they don't put NULL values into array! */
75 #define _foreach_no_nullval(i, p, arr)                          \
76         assert((i) >= sizeof(arr)/sizeof(arr[0]) || (p))
77
78 #if HAVE_TYPEOF
79 #define FOREACH_TYPEOF(val) __typeof__(&*(val))
80 #else
81 #define FOREACH_TYPEOF(val) void *
82 #endif
83
84 #else /* !HAVE_COMPOUND_LITERALS */
85
86 /* No compound literals, but it's still (just) possible. */
87 #define foreach_int(i, val, ...)                                        \
88         for (i = _foreach_intval_init(&(i), val, __VA_ARGS__,   \
89                                           _foreach_term);               \
90              !_foreach_intval_done(&i);                         \
91              i = _foreach_intval_next(&(i), val, __VA_ARGS__,   \
92                                           _foreach_term))
93
94 #define foreach_ptr(i, val, ...)                                        \
95         for (i = _foreach_ptrval_init(&(i), val, __VA_ARGS__, NULL);    \
96              (i);                                                       \
97              i = _foreach_ptrval_next(&(i), val, __VA_ARGS__, NULL))
98
99 extern int _foreach_term;
100 int _foreach_intval_init(const void *i, int val, ...);
101 bool _foreach_intval_done(const void *i);
102 int _foreach_intval_next(const void *i, int val, ...);
103 void *_foreach_ptrval_init(const void *i, const void *val, ...);
104 void *_foreach_ptrval_next(const void *i, const void *val, ...);
105 #endif /* !HAVE_COMPOUND_LITERALS */
106
107 #endif /* CCAN_FOREACH_H */