asymmetric.qbk 25 KB

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