]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/ |
2 | Copyright Oliver Kowalke 2014. | |
3 | Distributed under the Boost Software License, Version 1.0. | |
4 | (See accompanying file LICENSE_1_0.txt or copy at | |
5 | http://www.boost.org/LICENSE_1_0.txt | |
6 | ] | |
7 | ||
8 | [section:asymmetric Asymmetric coroutine] | |
9 | ||
10 | Two asymmetric coroutine types - __push_coro__ and __pull_coro__ - provide a | |
11 | unidirectional transfer of data. | |
12 | [note ['asymmetric_coroutine<>] is a typedef of __coro__.] | |
13 | ||
14 | ||
15 | [heading __pull_coro__] | |
16 | __pull_coro__ transfers data from another execution context (== pulled-from). | |
17 | The template parameter defines the transferred parameter type. | |
18 | The constructor of __pull_coro__ takes a function (__coro_fn__) accepting a | |
19 | reference to an __push_coro__ as argument. Instantiating an __pull_coro__ passes | |
20 | the control of execution to __coro_fn__ and a complementary __push_coro__ is | |
21 | synthesized by the library and passed as reference to __coro_fn__. | |
22 | ||
23 | This kind of coroutine provides __pull_coro_op__. This method only switches | |
24 | context; it transfers no data. | |
25 | ||
26 | __pull_coro__ provides input iterators (__pull_coro_it__) and __begin__/__end__ | |
27 | are overloaded. The increment-operation switches the context and transfers data. | |
28 | ||
29 | typedef boost::coroutines2::coroutine<int> coro_t; | |
30 | ||
31 | coro_t::pull_type source( | |
32 | [&](coro_t::push_type& sink){ | |
33 | int first=1,second=1; | |
34 | sink(first); | |
35 | sink(second); | |
36 | for(int i=0;i<8;++i){ | |
37 | int third=first+second; | |
38 | first=second; | |
39 | second=third; | |
40 | sink(third); | |
41 | } | |
42 | }); | |
43 | ||
44 | for(auto i:source) | |
45 | std::cout << i << " "; | |
46 | ||
47 | output: | |
48 | 1 1 2 3 5 8 13 21 34 55 | |
49 | ||
50 | In this example an __pull_coro__ is created in the main execution context taking | |
51 | a lambda function (== __coro_fn__) which calculates Fibonacci numbers in a | |
52 | simple ['for]-loop. | |
53 | The __coro_fn__ is executed in a newly created execution context which is | |
54 | managed by the instance of __pull_coro__. | |
55 | An __push_coro__ is automatically generated by the library and passed as | |
56 | reference to the lambda function. Each time the lambda function calls | |
57 | __push_coro_op__ with another Fibonacci number, __push_coro__ transfers it back | |
58 | to the main execution context. The local state of __coro_fn__ is preserved and | |
59 | will be restored upon transferring execution control back to __coro_fn__ | |
60 | to calculate the next Fibonacci number. | |
61 | Because __pull_coro__ provides input iterators and __begin__/__end__ are | |
62 | overloaded, a ['range-based for]-loop can be used to iterate over the generated | |
63 | Fibonacci numbers. | |
64 | ||
65 | ||
66 | [heading __push_coro__] | |
67 | __push_coro__ transfers data to the other execution context (== pushed-to). | |
68 | The template parameter defines the transferred parameter type. | |
69 | The constructor of __push_coro__ takes a function (__coro_fn__) accepting a | |
70 | reference to an __pull_coro__ as argument. In contrast to __pull_coro__, | |
71 | instantiating an __push_coro__ does not pass the control of execution to | |
72 | __coro_fn__ - instead the first call of __push_coro_op__ synthesizes a | |
73 | complementary __pull_coro__ and passes it as reference to __coro_fn__. | |
74 | ||
75 | The __push_coro__ interface does not contain a ['get()]-function: you can not retrieve | |
76 | values from another execution context with this kind of coroutine. | |
77 | ||
78 | __push_coro__ provides output iterators (__push_coro_it__) and | |
79 | __begin__/__end__ are overloaded. The increment-operation switches the context | |
80 | and transfers data. | |
81 | ||
82 | typedef boost::coroutines2::coroutine<std::string> coro_t; | |
83 | ||
84 | struct FinalEOL{ | |
85 | ~FinalEOL(){ | |
86 | std::cout << std::endl; | |
87 | } | |
88 | }; | |
89 | ||
90 | const int num=5, width=15; | |
91 | coro_t::push_type writer( | |
92 | [&](coro_t::pull_type& in){ | |
93 | // finish the last line when we leave by whatever means | |
94 | FinalEOL eol; | |
95 | // pull values from upstream, lay them out 'num' to a line | |
96 | for (;;){ | |
97 | for(int i=0;i<num;++i){ | |
98 | // when we exhaust the input, stop | |
99 | if(!in) return; | |
100 | std::cout << std::setw(width) << in.get(); | |
101 | // now that we've handled this item, advance to next | |
102 | in(); | |
103 | } | |
104 | // after 'num' items, line break | |
105 | std::cout << std::endl; | |
106 | } | |
107 | }); | |
108 | ||
109 | std::vector<std::string> words{ | |
110 | "peas", "porridge", "hot", "peas", | |
111 | "porridge", "cold", "peas", "porridge", | |
112 | "in", "the", "pot", "nine", | |
113 | "days", "old" }; | |
114 | ||
115 | std::copy(begin(words),end(words),begin(writer)); | |
116 | ||
117 | output: | |
118 | peas porridge hot peas porridge | |
119 | cold peas porridge in the | |
120 | pot nine days old | |
121 | ||
122 | In this example an __push_coro__ is created in the main execution context | |
123 | accepting a lambda function (== __coro_fn__) which requests strings and lays out | |
124 | 'num' of them on each line. | |
125 | This demonstrates the inversion of control permitted by coroutines. Without | |
126 | coroutines, a utility function to perform the same job would necessarily | |
127 | accept each new value as a function parameter, returning after processing that | |
128 | single value. That function would depend on a static state variable. A | |
129 | __coro_fn__, however, can request each new value as if by calling a function | |
130 | -- even though its caller also passes values as if by calling a function. | |
131 | The __coro_fn__ is executed in a newly created execution context which is | |
132 | managed by the instance of __push_coro__. | |
133 | The main execution context passes the strings to the __coro_fn__ by calling | |
134 | __push_coro_op__. | |
135 | An __pull_coro__ instance is automatically generated by the library and passed as | |
136 | reference to the lambda function. The __coro_fn__ accesses the strings passed | |
137 | from the main execution context by calling __pull_coro_get__ and lays those | |
138 | strings out on ['std::cout] according the parameters 'num' and 'width'. | |
139 | The local state of __coro_fn__ is preserved and will be restored after | |
140 | transferring execution control back to __coro_fn__. | |
141 | Because __push_coro__ provides output iterators and __begin__/__end__ are | |
142 | overloaded, the ['std::copy] algorithm can be used to iterate over the vector | |
143 | containing the strings and pass them one by one to the coroutine. | |
144 | ||
145 | ||
146 | [heading coroutine-function] | |
147 | The __coro_fn__ returns ['void] and takes its counterpart-coroutine as | |
148 | argument, so that using the coroutine passed as argument to __coro_fn__ is the | |
149 | only way to transfer data and execution control back to the caller. | |
150 | Both coroutine types take the same template argument. | |
151 | For __pull_coro__ the __coro_fn__ is entered at __pull_coro__ construction. | |
152 | For __push_coro__ the __coro_fn__ is not entered at __push_coro__ construction | |
153 | but entered by the first invocation of __push_coro_op__. | |
154 | After execution control is returned from __coro_fn__ the state of the | |
155 | coroutine can be checked via __pull_coro_bool__ returning `true` if the | |
156 | coroutine is still valid (__coro_fn__ has not terminated). Unless the first | |
157 | template parameter is `void`, `true` also implies that a data value is | |
158 | available. | |
159 | ||
160 | ||
161 | [heading passing data from a pull-coroutine to main-context] | |
162 | In order to transfer data from an __pull_coro__ to the main-context the framework | |
163 | synthesizes an __push_coro__ associated with the __pull_coro__ instance in the | |
164 | main-context. The synthesized __push_coro__ is passed as argument to __coro_fn__. | |
165 | The __coro_fn__ must call this __push_coro_op__ in order to transfer each | |
166 | data value back to the main-context. | |
167 | In the main-context, the __pull_coro_bool__ determines whether the coroutine is | |
168 | still valid and a data value is available or __coro_fn__ has terminated | |
169 | (__pull_coro__ is invalid; no data value available). Access to the transferred | |
170 | data value is given by __pull_coro_get__. | |
171 | ||
172 | typedef boost::coroutines2::coroutine<int> coro_t; | |
173 | ||
174 | coro_t::pull_type source( // constructor enters coroutine-function | |
175 | [&](coro_t::push_type& sink){ | |
176 | sink(1); // push {1} back to main-context | |
177 | sink(1); // push {1} back to main-context | |
178 | sink(2); // push {2} back to main-context | |
179 | sink(3); // push {3} back to main-context | |
180 | sink(5); // push {5} back to main-context | |
181 | sink(8); // push {8} back to main-context | |
182 | }); | |
183 | ||
184 | while(source){ // test if pull-coroutine is valid | |
185 | int ret=source.get(); // access data value | |
186 | source(); // context-switch to coroutine-function | |
187 | } | |
188 | ||
189 | ||
190 | [heading passing data from main-context to a push-coroutine] | |
191 | In order to transfer data to an __push_coro__ from the main-context the framework | |
192 | synthesizes an __pull_coro__ associated with the __push_coro__ instance in the | |
193 | main-context. The synthesized __pull_coro__ is passed as argument to __coro_fn__. | |
194 | The main-context must call this __push_coro_op__ in order to transfer each data | |
195 | value into the __coro_fn__. | |
196 | Access to the transferred data value is given by __pull_coro_get__. | |
197 | ||
198 | typedef boost::coroutines2::coroutine<int> coro_t; | |
199 | ||
200 | coro_t::push_type sink( // constructor does NOT enter coroutine-function | |
201 | [&](coro_t::pull_type& source){ | |
202 | for (int i:source) { | |
203 | std::cout << i << " "; | |
204 | } | |
205 | }); | |
206 | ||
207 | std::vector<int> v{1,1,2,3,5,8,13,21,34,55}; | |
208 | for( int i:v){ | |
209 | sink(i); // push {i} to coroutine-function | |
210 | } | |
211 | ||
212 | ||
213 | [heading accessing parameters] | |
214 | Parameters returned from or transferred to the __coro_fn__ can be accessed with | |
215 | __pull_coro_get__. | |
216 | ||
217 | Splitting-up the access of parameters from context switch function enables to | |
218 | check if __pull_coro__ is valid after return from __pull_coro_op__, e.g. | |
219 | __pull_coro__ has values and __coro_fn__ has not terminated. | |
220 | ||
221 | typedef boost::coroutines2::coroutine<boost::tuple<int,int>> coro_t; | |
222 | ||
223 | coro_t::push_type sink( | |
224 | [&](coro_t::pull_type& source){ | |
225 | // access tuple {7,11}; x==7 y==1 | |
226 | int x,y; | |
227 | boost::tie(x,y)=source.get(); | |
228 | }); | |
229 | ||
230 | sink(boost::make_tuple(7,11)); | |
231 | ||
232 | ||
233 | [heading exceptions] | |
234 | An exception thrown inside an __pull_coro__'s __coro_fn__ before its first call | |
235 | to __push_coro_op__ will be re-thrown by the __pull_coro__ constructor. After an | |
236 | __pull_coro__'s __coro_fn__'s first call to __push_coro_op__, any subsequent | |
237 | exception inside that __coro_fn__ will be re-thrown by __pull_coro_op__. | |
238 | __pull_coro_get__ does not throw. | |
239 | ||
240 | An exception thrown inside an __push_coro__'s __coro_fn__ will be re-thrown by | |
241 | __push_coro_op__. | |
242 | ||
243 | [important Code executed by __coro_fn__ must not prevent the propagation of the | |
244 | __forced_unwind__ exception. Absorbing that exception will cause stack | |
245 | unwinding to fail. Thus, any code that catches all exceptions must re-throw any | |
246 | pending __forced_unwind__ exception.] | |
247 | ||
248 | try { | |
249 | // code that might throw | |
250 | } catch(const boost::coroutines2::detail::forced_unwind&) { | |
251 | throw; | |
252 | } catch(...) { | |
253 | // possibly not re-throw pending exception | |
254 | } | |
255 | ||
256 | [important Do not jump from inside a catch block and than re-throw the | |
257 | exception in another execution context.] | |
258 | ||
259 | ||
260 | [heading Stack unwinding] | |
261 | Sometimes it is necessary to unwind the stack of an unfinished coroutine to | |
262 | destroy local stack variables so they can release allocated resources (RAII | |
263 | pattern). The `attributes` argument of the coroutine constructor | |
264 | indicates whether the destructor should unwind the stack (stack is unwound by | |
265 | default). | |
266 | ||
267 | Stack unwinding assumes the following preconditions: | |
268 | ||
269 | * The coroutine is not __not_a_coro__ | |
270 | * The coroutine is not complete | |
271 | * The coroutine is not running | |
272 | * The coroutine owns a stack | |
273 | ||
274 | After unwinding, a __coro__ is complete. | |
275 | ||
276 | struct X { | |
277 | X(){ | |
278 | std::cout<<"X()"<<std::endl; | |
279 | } | |
280 | ||
281 | ~X(){ | |
282 | std::cout<<"~X()"<<std::endl; | |
283 | } | |
284 | }; | |
285 | ||
286 | { | |
287 | typedef boost::coroutines2::coroutine<void>::push_type coro_t; | |
288 | ||
289 | coro_t::push_type sink( | |
290 | [&](coro_t::pull_type& source){ | |
291 | X x; | |
292 | for(int=0;;++i){ | |
293 | std::cout<<"fn(): "<<i<<std::endl; | |
294 | // transfer execution control back to main() | |
295 | source(); | |
296 | } | |
297 | }); | |
298 | ||
299 | sink(); | |
300 | sink(); | |
301 | sink(); | |
302 | sink(); | |
303 | sink(); | |
304 | ||
305 | std::cout<<"sink is complete: "<<std::boolalpha<<!sink<<"\n"; | |
306 | } | |
307 | ||
308 | output: | |
309 | X() | |
310 | fn(): 0 | |
311 | fn(): 1 | |
312 | fn(): 2 | |
313 | fn(): 3 | |
314 | fn(): 4 | |
315 | fn(): 5 | |
316 | sink is complete: false | |
317 | ~X() | |
318 | ||
319 | ||
320 | [heading Range iterators] | |
321 | __boost_coroutine__ provides output- and input-iterators using __boost_range__. | |
322 | __pull_coro__ can be used via input-iterators using __begin__ and __end__. | |
323 | ||
324 | typedef boost::coroutines2::coroutine< int > coro_t; | |
325 | ||
326 | int number=2,exponent=8; | |
327 | coro_t::pull_type source( | |
328 | [&](coro_t::push_type & sink){ | |
329 | int counter=0,result=1; | |
330 | while(counter++<exponent){ | |
331 | result=result*number; | |
332 | sink(result); | |
333 | } | |
334 | }); | |
335 | ||
336 | for (auto i:source) | |
337 | std::cout << i << " "; | |
338 | ||
339 | output: | |
340 | 2 4 8 16 32 64 128 256 | |
341 | ||
342 | ['coroutine<>::pull_type::iterator::operator++()] corresponds to | |
343 | __pull_coro_op__; ['coroutine<>::pull_type::iterator::operator*()] | |
344 | roughly corresponds to __pull_coro_get__. An iterator originally obtained from | |
345 | __begin__ of an __pull_coro__ compares equal to an iterator obtained from | |
346 | __end__ of that same __pull_coro__ instance when its __pull_coro_bool__ would | |
347 | return `false`]. | |
348 | ||
349 | [note If `T` is a move-only type, then | |
350 | ['coroutine<T>::pull_type::iterator] may only be dereferenced once | |
351 | before it is incremented again.] | |
352 | ||
353 | Output-iterators can be created from __push_coro__. | |
354 | ||
355 | typedef boost::coroutines2::coroutine<int> coro_t; | |
356 | ||
357 | coro_t::push_type sink( | |
358 | [&](coro_t::pull_type& source){ | |
359 | while(source){ | |
360 | std::cout << source.get() << " "; | |
361 | source(); | |
362 | } | |
363 | }); | |
364 | ||
365 | std::vector<int> v{1,1,2,3,5,8,13,21,34,55}; | |
366 | std::copy(begin(v),end(v),begin(sink)); | |
367 | ||
368 | ['coroutine<>::push_type::iterator::operator*()] roughly | |
369 | corresponds to __push_coro_op__. An iterator originally obtained from | |
370 | __begin__ of an __push_coro__ compares equal to an iterator obtained from | |
371 | __end__ of that same __push_coro__ instance when its __push_coro_bool__ would | |
372 | return `false`. | |
373 | ||
374 | ||
375 | [heading Exit a __coro_fn__] | |
376 | __coro_fn__ is exited with a simple return statement jumping back to the calling | |
377 | routine. The __pull_coro__, __push_coro__ becomes complete, e.g. __pull_coro_bool__, | |
378 | __push_coro_bool__ will return `false`. | |
379 | ||
380 | [important After returning from __coro_fn__ the __coro__ is complete (can not | |
381 | resumed with __push_coro_op__, __pull_coro_op__).] | |
382 | ||
383 | ||
384 | ||
385 | [section:pull_coro Class `coroutine<>::pull_type`] | |
386 | ||
387 | #include <boost/coroutine2/coroutine.hpp> | |
388 | ||
389 | template< typename R > | |
390 | class coroutine<>::pull_type | |
391 | { | |
392 | public: | |
393 | pull_type() noexcept; | |
394 | ||
395 | template< typename Fn > | |
396 | pull_type( Fn && fn, attributes const& attr = attributes() ); | |
397 | ||
398 | template< typename Fn, typename StackAllocator > | |
399 | pull_type( Fn && fn, attributes const& attr, StackAllocator stack_alloc); | |
400 | ||
401 | pull_type( pull_type const& other)=delete; | |
402 | ||
403 | pull_type & operator=( pull_type const& other)=delete; | |
404 | ||
405 | ~pull_type(); | |
406 | ||
407 | pull_type( pull_type && other) noexcept; | |
408 | ||
409 | pull_type & operator=( pull_type && other) noexcept; | |
410 | ||
411 | operator unspecified-bool-type() const noexcept; | |
412 | ||
413 | bool operator!() const noexcept; | |
414 | ||
415 | void swap( pull_type & other) noexcept; | |
416 | ||
417 | pull_type & operator()(); | |
418 | ||
419 | R get() const; | |
420 | }; | |
421 | ||
422 | template< typename R > | |
423 | void swap( pull_type< R > & l, pull_type< R > & r); | |
424 | ||
425 | template< typename R > | |
426 | range_iterator< pull_type< R > >::type begin( pull_type< R > &); | |
427 | ||
428 | template< typename R > | |
429 | range_iterator< pull_type< R > >::type end( pull_type< R > &); | |
430 | ||
431 | [heading `pull_type()`] | |
432 | [variablelist | |
433 | [[Effects:] [Creates a coroutine representing __not_a_coro__.]] | |
434 | [[Throws:] [Nothing.]] | |
435 | ] | |
436 | ||
437 | [heading `template< typename Fn > | |
438 | pull_type( Fn && fn, attributes const& attr)`] | |
439 | [variablelist | |
440 | [[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize() | |
441 | when ! is_stack_unbounded().]] | |
442 | [[Effects:] [Creates a coroutine which will execute `fn`, and enters it. | |
443 | Argument `attr` determines stack clean-up and preserving floating-point | |
444 | registers.]] | |
445 | [[Throws:] [Exceptions thrown inside __coro_fn__.]] | |
446 | ] | |
447 | ||
448 | [heading `template< typename Fn, typename StackAllocator > | |
449 | pull_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`] | |
450 | [variablelist | |
451 | [[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize() | |
452 | when ! is_stack_unbounded().]] | |
453 | [[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` | |
454 | determines stack clean-up and preserving floating-point registers. | |
455 | For allocating/deallocating the stack `stack_alloc` is used.]] | |
456 | [[Throws:] [Exceptions thrown inside __coro_fn__.]] | |
457 | ] | |
458 | ||
459 | [heading `~pull_type()`] | |
460 | [variablelist | |
461 | [[Effects:] [Destroys the context and deallocates the stack.]] | |
462 | ] | |
463 | ||
464 | [heading `pull_type( pull_type && other)`] | |
465 | [variablelist | |
466 | [[Effects:] [Moves the internal data of `other` to `*this`. | |
467 | `other` becomes __not_a_coro__.]] | |
468 | [[Throws:] [Nothing.]] | |
469 | ] | |
470 | ||
471 | [heading `pull_type & operator=( pull_type && other)`] | |
472 | [variablelist | |
473 | [[Effects:] [Destroys the internal data of `*this` and moves the | |
474 | internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] | |
475 | [[Throws:] [Nothing.]] | |
476 | ] | |
477 | ||
478 | [heading `operator unspecified-bool-type() const`] | |
479 | [variablelist | |
480 | [[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function | |
481 | has returned (completed), the function returns `false`. Otherwise `true`.]] | |
482 | [[Throws:] [Nothing.]] | |
483 | ] | |
484 | ||
485 | [heading `bool operator!() const`] | |
486 | [variablelist | |
487 | [[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function | |
488 | has returned (completed), the function returns `true`. Otherwise `false`.]] | |
489 | [[Throws:] [Nothing.]] | |
490 | ] | |
491 | ||
492 | [heading `pull_type<> & operator()()`] | |
493 | [variablelist | |
494 | [[Preconditions:] [`*this` is not a __not_a_coro__.]] | |
495 | [[Effects:] [Execution control is transferred to __coro_fn__ (no parameter is | |
496 | passed to the coroutine-function).]] | |
497 | [[Throws:] [Exceptions thrown inside __coro_fn__.]] | |
498 | ] | |
499 | ||
500 | [heading `R get()`] | |
501 | ||
502 | R coroutine<R,StackAllocator>::pull_type::get(); | |
503 | R& coroutine<R&,StackAllocator>::pull_type::get(); | |
504 | void coroutine<void,StackAllocator>::pull_type::get()=delete; | |
505 | ||
506 | [variablelist | |
507 | [[Preconditions:] [`*this` is not a __not_a_coro__.]] | |
508 | [[Returns:] [Returns data transferred from coroutine-function via | |
509 | __push_coro_op__.]] | |
510 | [[Throws:] [`invalid_result`]] | |
511 | [[Note:] [If `R` is a move-only type, you may only call `get()` once before | |
512 | the next __pull_coro_op__ call.]] | |
513 | ] | |
514 | ||
515 | [heading `void swap( pull_type & other)`] | |
516 | [variablelist | |
517 | [[Effects:] [Swaps the internal data from `*this` with the values | |
518 | of `other`.]] | |
519 | [[Throws:] [Nothing.]] | |
520 | ] | |
521 | ||
522 | [heading Non-member function `swap()`] | |
523 | ||
524 | template< typename R > | |
525 | void swap( pull_type< R > & l, pull_type< R > & r); | |
526 | ||
527 | [variablelist | |
528 | [[Effects:] [As if 'l.swap( r)'.]] | |
529 | ] | |
530 | ||
531 | [heading Non-member function `begin( pull_type< R > &)`] | |
532 | template< typename R > | |
533 | range_iterator< pull_type< R > >::type begin( pull_type< R > &); | |
534 | ||
535 | [variablelist | |
536 | [[Returns:] [Returns a range-iterator (input-iterator).]] | |
537 | ] | |
538 | ||
539 | [heading Non-member function `end( pull_type< R > &)`] | |
540 | template< typename R > | |
541 | range_iterator< pull_type< R > >::type end( pull_type< R > &); | |
542 | ||
543 | [variablelist | |
544 | [[Returns:] [Returns an end range-iterator (input-iterator).]] | |
545 | [[Note:] [When first obtained from `begin( pull_type< R > &)`, or after some | |
546 | number of increment operations, an iterator will compare equal to the iterator | |
547 | returned by `end( pull_type< R > &)` when the corresponding __pull_coro_bool__ | |
548 | would return `false`.]] | |
549 | ] | |
550 | ||
551 | [endsect] | |
552 | ||
553 | ||
554 | [section:push_coro Class `coroutine<>::push_type`] | |
555 | ||
556 | #include <boost/coroutine2/coroutine.hpp> | |
557 | ||
558 | template< typename Arg > | |
559 | class coroutine<>::push_type | |
560 | { | |
561 | public: | |
562 | push_type() noexcept; | |
563 | ||
564 | template< typename Fn > | |
565 | push_type( Fn && fn, attributes const& attr = attributes() ); | |
566 | ||
567 | template< typename Fn, typename StackAllocator > | |
568 | push_type( Fn && fn, attributes const& attr, StackAllocator stack_alloc); | |
569 | ||
570 | push_type( push_type const& other)=delete; | |
571 | ||
572 | push_type & operator=( push_type const& other)=delete; | |
573 | ||
574 | ~push_type(); | |
575 | ||
576 | push_type( push_type && other) noexcept; | |
577 | ||
578 | push_type & operator=( push_type && other) noexcept; | |
579 | ||
580 | operator unspecified-bool-type() const noexcept; | |
581 | ||
582 | bool operator!() const noexcept; | |
583 | ||
584 | void swap( push_type & other) noexcept; | |
585 | ||
586 | push_type & operator()( Arg arg); | |
587 | }; | |
588 | ||
589 | template< typename Arg > | |
590 | void swap( push_type< Arg > & l, push_type< Arg > & r); | |
591 | ||
592 | template< typename Arg > | |
593 | range_iterator< push_type< Arg > >::type begin( push_type< Arg > &); | |
594 | ||
595 | template< typename Arg > | |
596 | range_iterator< push_type< Arg > >::type end( push_type< Arg > &); | |
597 | ||
598 | [heading `push_type()`] | |
599 | [variablelist | |
600 | [[Effects:] [Creates a coroutine representing __not_a_coro__.]] | |
601 | [[Throws:] [Nothing.]] | |
602 | ] | |
603 | ||
604 | [heading `template< typename Fn > | |
605 | push_type( Fn && fn, attributes const& attr)`] | |
606 | [variablelist | |
607 | [[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize() | |
608 | when ! is_stack_unbounded().]] | |
609 | [[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` | |
610 | determines stack clean-up and preserving floating-point registers.]] | |
611 | ] | |
612 | ||
613 | [heading `template< typename Fn, typename StackAllocator > | |
614 | push_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`] | |
615 | [variablelist | |
616 | [[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize() | |
617 | when ! is_stack_unbounded().]] | |
618 | [[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` | |
619 | determines stack clean-up and preserving floating-point registers. | |
620 | For allocating/deallocating the stack `stack_alloc` is used.]] | |
621 | ] | |
622 | ||
623 | [heading `~push_type()`] | |
624 | [variablelist | |
625 | [[Effects:] [Destroys the context and deallocates the stack.]] | |
626 | ] | |
627 | ||
628 | [heading `push_type( push_type && other)`] | |
629 | [variablelist | |
630 | [[Effects:] [Moves the internal data of `other` to `*this`. | |
631 | `other` becomes __not_a_coro__.]] | |
632 | [[Throws:] [Nothing.]] | |
633 | ] | |
634 | ||
635 | [heading `push_type & operator=( push_type && other)`] | |
636 | [variablelist | |
637 | [[Effects:] [Destroys the internal data of `*this` and moves the | |
638 | internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] | |
639 | [[Throws:] [Nothing.]] | |
640 | ] | |
641 | ||
642 | [heading `operator unspecified-bool-type() const`] | |
643 | [variablelist | |
644 | [[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function | |
645 | has returned (completed), the function returns `false`. Otherwise `true`.]] | |
646 | [[Throws:] [Nothing.]] | |
647 | ] | |
648 | ||
649 | [heading `bool operator!() const`] | |
650 | [variablelist | |
651 | [[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function | |
652 | has returned (completed), the function returns `true`. Otherwise `false`.]] | |
653 | [[Throws:] [Nothing.]] | |
654 | ] | |
655 | ||
656 | [heading `push_type & operator()(Arg arg)`] | |
657 | ||
658 | push_type& coroutine<Arg>::push_type::operator()(Arg); | |
659 | push_type& coroutine<Arg&>::push_type::operator()(Arg&); | |
660 | push_type& coroutine<void>::push_type::operator()(); | |
661 | ||
662 | [variablelist | |
663 | [[Preconditions:] [operator unspecified-bool-type() returns `true` for `*this`.]] | |
664 | [[Effects:] [Execution control is transferred to __coro_fn__ and the argument | |
665 | `arg` is passed to the coroutine-function.]] | |
666 | [[Throws:] [Exceptions thrown inside __coro_fn__.]] | |
667 | ] | |
668 | ||
669 | [heading `void swap( push_type & other)`] | |
670 | [variablelist | |
671 | [[Effects:] [Swaps the internal data from `*this` with the values | |
672 | of `other`.]] | |
673 | [[Throws:] [Nothing.]] | |
674 | ] | |
675 | ||
676 | [heading Non-member function `swap()`] | |
677 | ||
678 | template< typename Arg > | |
679 | void swap( push_type< Arg > & l, push_type< Arg > & r); | |
680 | ||
681 | [variablelist | |
682 | [[Effects:] [As if 'l.swap( r)'.]] | |
683 | ] | |
684 | ||
685 | [heading Non-member function `begin( push_type< Arg > &)`] | |
686 | template< typename Arg > | |
687 | range_iterator< push_type< Arg > >::type begin( push_type< Arg > &); | |
688 | ||
689 | [variablelist | |
690 | [[Returns:] [Returns a range-iterator (output-iterator).]] | |
691 | ] | |
692 | ||
693 | [heading Non-member function `end( push_type< Arg > &)`] | |
694 | template< typename Arg > | |
695 | range_iterator< push_type< Arg > >::type end( push_type< Arg > &); | |
696 | ||
697 | [variablelist | |
698 | [[Returns:] [Returns a end range-iterator (output-iterator).]] | |
699 | [[Note:] [When first obtained from `begin( push_type< R > &)`, or after some | |
700 | number of increment operations, an iterator will compare equal to the iterator | |
701 | returned by `end( push_type< R > &)` when the corresponding __push_coro_bool__ | |
702 | would return `false`.]] | |
703 | ] | |
704 | ||
705 | [endsect] | |
706 | ||
707 | ||
708 | ||
709 | [endsect] |