]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/coroutine2/doc/asymmetric.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / coroutine2 / doc / asymmetric.qbk
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]