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