]> git.ozlabs.org Git - ccan/blob - ccan/foreach/foreach.c
foreach: fix HAVE_FOR_LOOP_DECLARATION case.
[ccan] / ccan / foreach / foreach.c
1 #include <ccan/foreach/foreach.h>
2 #if !HAVE_COMPOUND_LITERALS || !HAVE_FOR_LOOP_DECLARATION
3 #include <ccan/list/list.h>
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <stdarg.h>
7
8 /* This list is normally very short. */
9 static LIST_HEAD(iters);
10
11 struct iter_info {
12         struct list_node list;
13         const void *index;
14         unsigned int i, num;
15 };
16
17 static void free_old_iters(const void *index)
18 {
19         struct iter_info *i, *next;
20
21         list_for_each_safe(&iters, i, next, list) {
22                 /* If we're re-using an index, free the old one.
23                  * Otherwise, if it's past i on the stack, it's old.  Don't
24                  * assume stack direction, but we know index is downstack. */
25                 if (i->index == index
26                     || (((uintptr_t)index < (uintptr_t)&i)
27                         == ((uintptr_t)&i < (uintptr_t)i->index))) {
28                         list_del(&i->list);
29                         free(i);
30                 }
31         }
32 }
33
34 static struct iter_info *find_iter(const void *index)
35 {
36         struct iter_info *i;
37
38         list_for_each(&iters, i, list) {
39                 if (i->index == index)
40                         return i;
41         }
42         abort();
43 }
44
45 static struct iter_info *new_iter(const void *index)
46 {
47         struct iter_info *info = malloc(sizeof *info);
48         info->index = index;
49         info->i = info->num = 0;
50         list_add(&iters, &info->list);
51         return info;
52 };
53
54 #if HAVE_COMPOUND_LITERALS
55 void _foreach_iter_init(const void *i)
56 {
57         free_old_iters(i);
58         new_iter(i);
59 }
60
61 unsigned int _foreach_iter(const void *i)
62 {
63         struct iter_info *info = find_iter(i);
64         return info->i;
65 }
66
67 unsigned int _foreach_iter_inc(const void *i)
68 {
69         struct iter_info *info = find_iter(i);
70         return ++info->i;
71 }
72 #else /* Don't have compound literals... */
73 int _foreach_term = 0x42430199;
74
75 /* We count values at beginning, and every time around the loop.  We change
76  * the terminator each time, so we don't get fooled in case it really appears
77  * in the list. */
78 static unsigned int count_vals(struct iter_info *info, va_list *ap)
79 {
80         unsigned int i;
81         int val = 0;
82
83         for (i = 0; i < info->num || val != _foreach_term; i++) {
84                 val = va_arg(*ap, int);
85         }
86         _foreach_term++;
87         return i;
88 }
89
90 int _foreach_intval_init(const void *i, int val, ...)
91 {
92         va_list ap;
93         struct iter_info *info;
94
95         free_old_iters(i);
96         info = new_iter(i);
97
98         va_start(ap, val);
99         info->num = count_vals(info, &ap);
100         va_end(ap);
101
102         return val;
103 }
104
105 bool _foreach_intval_done(const void *i)
106 {
107         struct iter_info *info = find_iter(i);
108         return info->i == info->num;
109 }
110         
111 int _foreach_intval_next(const void *i, int val, ...)
112 {
113         struct iter_info *info = find_iter(i);
114         va_list ap;
115         unsigned int num;
116
117         va_start(ap, val);
118         info->num = count_vals(info, &ap);
119         va_end(ap);
120
121         info->i++;
122         assert(info->i <= info->num);
123         if (info->i == info->num)
124                 return 0;
125
126         va_start(ap, val);
127         for (num = 0; num < info->i; num++)
128                 val = va_arg(ap, int);
129
130         va_end(ap);
131         return val;
132 }
133
134 void *_foreach_ptrval_init(const void *i, const void *val, ...)
135 {
136         struct iter_info *info;
137
138         free_old_iters(i);
139         info = new_iter(i);
140
141         return (void *)val;
142 }
143
144 void *_foreach_ptrval_next(const void *i, const void *val, ...)
145 {
146         struct iter_info *info = find_iter(i);
147         va_list ap;
148         unsigned int num;
149
150         info->i++;
151         va_start(ap, val);
152         for (num = 0; num < info->i; num++)
153                 val = va_arg(ap, void *);
154         va_end(ap);
155         return (void *)val;
156 }
157 #endif /* !HAVE_COMPOUND_LITERALS */
158 #endif /* !HAVE_COMPOUND_LITERALS || !HAVE_FOR_LOOP_DECLARATION */