]> git.ozlabs.org Git - ccan/blob - ccan/generator/generator.h
6b2bd92fe526411a56d254969d4d8b3e6f35ad55
[ccan] / ccan / generator / generator.h
1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
2 #ifndef CCAN_GENERATOR_H
3 #define CCAN_GENERATOR_H
4 #include "config.h"
5
6 #if !HAVE_UCONTEXT
7 #error Generators require working ucontext.h functions
8 #endif
9
10 #if !HAVE_TYPEOF
11 #error Generators require typeof
12 #endif
13
14 #if !HAVE_STATEMENT_EXPR
15 #error Generators require statement expressions
16 #endif
17
18 #include <assert.h>
19 #include <stddef.h>
20 #include <stdbool.h>
21 #include <ucontext.h>
22
23 #include <ccan/ptrint/ptrint.h>
24 #include <ccan/build_assert/build_assert.h>
25 #include <ccan/cppmagic/cppmagic.h>
26
27 /*
28  * Internals - included just for the use of inlines and macros
29  */
30
31 struct generator_ {
32         ucontext_t gen;
33         ucontext_t caller;
34         bool complete;
35         void *base;
36 };
37
38 static inline struct generator_ *generator_state_(const void *ret)
39 {
40         return (struct generator_ *)ret - 1;
41 }
42
43 struct generator_incomplete_;
44
45 #define generator_rtype_(gen_)                  \
46         typeof((*(gen_))((struct generator_incomplete_ *)NULL))
47
48 #if HAVE_POINTER_SAFE_MAKECONTEXT
49 #define generator_wrapper_args_()       void *ret
50 #else
51 #define generator_wrapper_args_()       int lo, int hi
52 #endif
53 typedef void generator_wrapper_(generator_wrapper_args_());
54
55 void *generator_new_(generator_wrapper_ *fn, size_t retsize);
56 void generator_free_(void *ret);
57
58 /*
59  * API
60  */
61
62 /**
63  * generator_t - type for an in-progress generator
64  * @rtype: type of values the generator yield
65  */
66 #define generator_t(rtype_)                     \
67         typeof(rtype_ (*)(struct generator_incomplete_ *))
68
69 /**
70  * generator_declare - declare (but don't define) a generator function
71  * @name: name for the generator
72  * @rtype: return type for the generator
73  *
74  * Declares (as an extern) a generator function named @name, which
75  * will yield return values of type @rtype.
76  *
77  * Example:
78  *      generator_declare(count_to_3, int);
79  */
80 #define generator_declare(name_, rtype_)        \
81         generator_t(rtype_) name_(void)
82
83 /**
84  * generator_def - define a generator function
85  * @name: name for the generator
86  * @rtype: return type for the generator
87  *
88  * Define a generator function named @name yielding return values of
89  * type @rtype.  The generator_def() line is followed immediately by a
90  * block containing the generator's code.
91  *
92  * Example:
93  *      generator_def(count_to_3, int)
94  *      {
95  *              generator_yield(1);
96  *              generator_yield(2);
97  *              generator_yield(3);
98  *      }
99  */
100 #define generator_def_(name_, rtype_, storage_)                         \
101         static void name_##_generator_(rtype_ *ret_);                   \
102         static void name_##_generator__(generator_wrapper_args_())      \
103         {                                                               \
104                 struct generator_ *gen;                                 \
105                 CPPMAGIC_IFELSE(HAVE_POINTER_SAFE_MAKECONTEXT)          \
106                         ()                                              \
107                         (ptrdiff_t hilo = ((ptrdiff_t)hi << (8*sizeof(int))) \
108                                 + (ptrdiff_t)lo;                        \
109                         rtype_ *ret = (rtype_ *)int2ptr(hilo);          \
110                         BUILD_ASSERT(sizeof(struct generator_ *)        \
111                                      <= 2*sizeof(int));)                \
112                 gen = generator_state_(ret);                            \
113                 name_##_generator_(ret);                                \
114                 gen->complete = true;                                   \
115                 setcontext(&gen->caller);                               \
116                 assert(0);                                              \
117         }                                                               \
118         storage_ generator_t(rtype_) name_(void)                        \
119         {                                                               \
120                 return generator_new_(name_##_generator__,              \
121                                       sizeof(rtype_));                  \
122         }                                                               \
123         static void name_##_generator_(rtype_ *ret_)
124 #define generator_def(name_, rtype_)            \
125         generator_def_(name_, rtype_, )
126
127 /**
128  * generator_def_static - define a private / local generator function
129  * @name: name for the generator
130  * @rtype: return type for the generator
131  *
132  * As generator_def, but the resulting generator function will be
133  * local to this module.
134  */
135 #define generator_def_static(name_, rtype_)     \
136         generator_def_(name_, rtype_, static)
137
138 /**
139  * generator_yield - yield (return) a value from a generator
140  * @val: value to yield
141  *
142  * Invoke only from within a generator.  Yield the given value to the
143  * caller.  This will stop execution of the generator code until the
144  * caller next invokes generator_next(), at which point it will
145  * continue from the generator_yield statement.
146  */
147 #define generator_yield(val_)                                           \
148         do {                                                            \
149                 struct generator_ *gen_ = generator_state_(ret_);       \
150                 int rc;                                                 \
151                 *(ret_) = (val_);                                       \
152                 rc = swapcontext(&gen_->gen, &gen_->caller);            \
153                 assert(rc == 0);                                        \
154         } while (0)
155
156 /**
157  * generator_next - get next value from a generator
158  * @gen: a generator state variable
159  *
160  * Returns a pointer to a (correctly typed) buffer containing the next
161  * value yielded by @gen, or NULL if @gen is finished.  The buffer
162  * contents is only valid until the next time @gen is called or
163  * manipulated.
164  */
165 static inline void *generator_next_(void *ret_)
166 {
167         struct generator_ *gen = generator_state_(ret_);
168         int rc;
169
170         if (gen->complete)
171                 return NULL;
172
173         rc = swapcontext(&gen->caller, &gen->gen);
174         assert(rc == 0);
175
176         return gen->complete ? NULL : ret_;
177 }
178 #define generator_next(gen_)                            \
179         ((generator_rtype_(gen_) *)generator_next_(gen_))
180
181 /**
182  * generator_next_val - store next value from a generator
183  * @val: a variable of type suitable to store the generator's return
184  *       type (lvalue)
185  * @gen: a generator state variable
186  *
187  * Returns 'true' if @gen yielded a new value, false if @gen is
188  * complete.  If a new value was yielded, it is stored in @val.
189  */
190 #define generator_next_val(val_, gen_)                  \
191         ({                                              \
192                 generator_rtype_(gen_) *ret;            \
193                 ret = generator_next(gen_);             \
194                 if (ret)                                \
195                         (val_) = *ret;                  \
196                 !!ret;                                  \
197         })
198
199 #define generator_free(gen_)                                    \
200         generator_free_((generator_rtype_(gen_) *)(gen_))
201
202 #endif /* CCAN_GENERATOR_H */