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