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