]> git.ozlabs.org Git - ccan/blob - ccan/generator/generator.h
cast: fix indentation in example.
[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 #include <ccan/compiler/compiler.h>
27
28 /*
29  * Internals - included just for the use of inlines and macros
30  */
31
32 struct generator_ {
33         ucontext_t gen;
34         ucontext_t caller;
35         bool complete;
36         void *base;
37 };
38
39 static inline struct generator_ *generator_state_(const void *ret)
40 {
41         return (struct generator_ *)ret - 1;
42 }
43
44 static inline void *generator_argp_(const void *ret)
45 {
46         return generator_state_(ret)->base;
47 }
48
49 struct generator_incomplete_;
50
51 #define generator_rtype_(gen_)                  \
52         typeof((*(gen_))((struct generator_incomplete_ *)NULL))
53
54 #if HAVE_POINTER_SAFE_MAKECONTEXT
55 #define generator_wrapper_args_()       void *ret
56 #else
57 #define generator_wrapper_args_()       int lo, int hi
58 #endif
59 typedef void generator_wrapper_(generator_wrapper_args_());
60
61 void *generator_new_(generator_wrapper_ *fn, size_t retsize);
62 void generator_free_(void *ret);
63
64 /*
65  * API
66  */
67
68 /**
69  * generator_t - type for an in-progress generator
70  * @rtype: type of values the generator yield
71  */
72 #define generator_t(rtype_)                     \
73         typeof(rtype_ (*)(struct generator_incomplete_ *))
74
75 /**
76  * generator_declare - declare (but don't define) a generator function
77  * @name: name for the generator
78  * @rtype: return type for the generator
79  *
80  * Declares (as an extern) a generator function named @name, which
81  * will yield return values of type @rtype.
82  *
83  * Example:
84  *      generator_declare(count_to_3, int);
85  */
86 #define generator_declare(name_, rtype_, ...)   \
87         generator_t(rtype_) name_(generator_parms_outer_(__VA_ARGS__))
88
89 /**
90  * generator_def - define a generator function
91  * @name: name for the generator
92  * @rtype: return type for the generator
93  *
94  * Define a generator function named @name yielding return values of
95  * type @rtype.  The generator_def() line is followed immediately by a
96  * block containing the generator's code.
97  *
98  * Example:
99  *      generator_def(count_to_3, int)
100  *      {
101  *              generator_yield(1);
102  *              generator_yield(2);
103  *              generator_yield(3);
104  *      }
105  */
106 #define generator_parm_(t_, n_)                 t_ n_
107 #define generator_parms_(...)                                           \
108         CPPMAGIC_2MAP(generator_parm_, __VA_ARGS__)
109 #define generator_parms_inner_(...)                                     \
110         CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__))                 \
111                 (, generator_parms_(__VA_ARGS__))()
112 #define generator_parms_outer_(...)                                     \
113         CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
114                 (generator_parms_(__VA_ARGS__))(void)
115 #define generator_argfield_(t_, n_)             t_ n_;
116 #define generator_argstruct_(...)                                       \
117         struct {                                                        \
118                 CPPMAGIC_JOIN(, CPPMAGIC_2MAP(generator_argfield_,      \
119                                               __VA_ARGS__))             \
120         }
121 #define generator_arg_unpack_(t_, n_)           args->n_
122 #define generator_args_unpack_(...)             \
123         CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__))                 \
124                 (, CPPMAGIC_2MAP(generator_arg_unpack_, __VA_ARGS__))()
125 #define generator_arg_pack_(t_, n_)             args->n_ = n_
126 #define generator_args_pack_(...)                                       \
127         CPPMAGIC_JOIN(;, CPPMAGIC_2MAP(generator_arg_pack_, __VA_ARGS__))
128 #define generator_def_(name_, rtype_, storage_, ...)                    \
129         static void name_##_generator_(rtype_ *ret_                     \
130                                        generator_parms_inner_(__VA_ARGS__)); \
131         static void name_##_generator__(generator_wrapper_args_())      \
132         {                                                               \
133                 struct generator_ *gen;                                 \
134                 UNNEEDED generator_argstruct_(__VA_ARGS__) *args;       \
135                 CPPMAGIC_IFELSE(HAVE_POINTER_SAFE_MAKECONTEXT)          \
136                         ()                                              \
137                         (ptrdiff_t hilo = ((ptrdiff_t)hi << (8*sizeof(int))) \
138                                 + (ptrdiff_t)lo;                        \
139                         rtype_ *ret = (rtype_ *)int2ptr(hilo);          \
140                         BUILD_ASSERT(sizeof(struct generator_ *)        \
141                                      <= 2*sizeof(int));)                \
142                 gen = generator_state_(ret);                            \
143                 args = generator_argp_(ret);                            \
144                 name_##_generator_(ret generator_args_unpack_(__VA_ARGS__)); \
145                 gen->complete = true;                                   \
146                 setcontext(&gen->caller);                               \
147                 assert(0);                                              \
148         }                                                               \
149         storage_ generator_t(rtype_)                                    \
150         name_(generator_parms_outer_(__VA_ARGS__))                      \
151         {                                                               \
152                 generator_t(rtype_) gen = generator_new_(name_##_generator__, \
153                                                          sizeof(rtype_)); \
154                 UNNEEDED generator_argstruct_(__VA_ARGS__) *args =      \
155                         generator_argp_(gen);                           \
156                 generator_args_pack_(__VA_ARGS__);                      \
157                 return gen;                                             \
158         }                                                               \
159         static void name_##_generator_(rtype_ *ret_                     \
160                                        generator_parms_inner_(__VA_ARGS__))
161 #define generator_def(name_, rtype_, ...)       \
162         generator_def_(name_, rtype_, , __VA_ARGS__)
163
164 /**
165  * generator_def_static - define a private / local generator function
166  * @name: name for the generator
167  * @rtype: return type for the generator
168  *
169  * As generator_def, but the resulting generator function will be
170  * local to this module.
171  */
172 #define generator_def_static(name_, rtype_, ...)        \
173         generator_def_(name_, rtype_, static, __VA_ARGS__)
174
175 /**
176  * generator_yield - yield (return) a value from a generator
177  * @val: value to yield
178  *
179  * Invoke only from within a generator.  Yield the given value to the
180  * caller.  This will stop execution of the generator code until the
181  * caller next invokes generator_next(), at which point it will
182  * continue from the generator_yield statement.
183  */
184 #define generator_yield(val_)                                           \
185         do {                                                            \
186                 struct generator_ *gen_ = generator_state_(ret_);       \
187                 int rc;                                                 \
188                 *(ret_) = (val_);                                       \
189                 rc = swapcontext(&gen_->gen, &gen_->caller);            \
190                 assert(rc == 0);                                        \
191         } while (0)
192
193 /**
194  * generator_next - get next value from a generator
195  * @gen: a generator state variable
196  *
197  * Returns a pointer to a (correctly typed) buffer containing the next
198  * value yielded by @gen, or NULL if @gen is finished.  The buffer
199  * contents is only valid until the next time @gen is called or
200  * manipulated.
201  */
202 static inline void *generator_next_(void *ret_)
203 {
204         struct generator_ *gen = generator_state_(ret_);
205         int rc;
206
207         if (gen->complete)
208                 return NULL;
209
210         rc = swapcontext(&gen->caller, &gen->gen);
211         assert(rc == 0);
212
213         return gen->complete ? NULL : ret_;
214 }
215 #define generator_next(gen_)                            \
216         ((generator_rtype_(gen_) *)generator_next_(gen_))
217
218 /**
219  * generator_next_val - store next value from a generator
220  * @val: a variable of type suitable to store the generator's return
221  *       type (lvalue)
222  * @gen: a generator state variable
223  *
224  * Returns 'true' if @gen yielded a new value, false if @gen is
225  * complete.  If a new value was yielded, it is stored in @val.
226  */
227 #define generator_next_val(val_, gen_)                  \
228         ({                                              \
229                 generator_rtype_(gen_) *ret;            \
230                 ret = generator_next(gen_);             \
231                 if (ret)                                \
232                         (val_) = *ret;                  \
233                 !!ret;                                  \
234         })
235
236 #define generator_free(gen_)                                    \
237         generator_free_((generator_rtype_(gen_) *)(gen_))
238
239 #endif /* CCAN_GENERATOR_H */