785 lines
27 KiB
Plaintext
785 lines
27 KiB
Plaintext
[/
|
|
Copyright Oliver Kowalke 2009.
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt
|
|
]
|
|
|
|
[section:unidirect Unidirectional coroutine]
|
|
|
|
[note This is the default interface (macro BOOST_COROUTINES_UNIDIRECT).]
|
|
|
|
Two coroutine types - __push_coro__ and __pull_coro__ - providing a
|
|
unidirectional transfer of data.
|
|
|
|
|
|
[heading __pull_coro__]
|
|
__pull_coro__ transfers data from another execution context (== pulled-from).
|
|
The class has only one template parameter defining the transferred parameter
|
|
type.
|
|
The constructor of __pull_coro__ takes a function (__coro_fn__) accepting a
|
|
reference to a __push_coro__ as argument. Instantiating a __pull_coro__ passes
|
|
the control of execution to __coro_fn__ and a complementary __push_coro__ is
|
|
synthesized by the runtime and passed as reference to __coro_fn__.
|
|
|
|
This kind of coroutine provides __pull_coro_op__. This method only switches
|
|
context; it transfers no data.
|
|
|
|
__pull_coro__ provides input iterators (__pull_coro_it__) and __begin__/__end__
|
|
are overloaded. The increment-operation switches the context and transfers data.
|
|
|
|
boost::coroutines::coroutine<int>::pull_type source(
|
|
[&](boost::coroutines::coroutine<int>::push_type& sink){
|
|
int first=1,second=1;
|
|
sink(first);
|
|
sink(second);
|
|
for(int i=0;i<8;++i){
|
|
int third=first+second;
|
|
first=second;
|
|
second=third;
|
|
sink(third);
|
|
}
|
|
});
|
|
|
|
for(auto i:source)
|
|
std::cout << i << " ";
|
|
|
|
std::cout << "\nDone" << std::endl;
|
|
|
|
output:
|
|
1 1 2 3 5 8 13 21 34 55
|
|
Done
|
|
|
|
In this example a __pull_coro__ is created in the main execution context taking
|
|
a lambda function (== __coro_fn__) which calculates Fibonacci numbers in a
|
|
simple ['for]-loop).
|
|
The __coro_fn__ is executed in a newly created execution context which is
|
|
managed by the instance of __pull_coro__.
|
|
A __push_coro__ is automatically generated by the runtime and passed as
|
|
reference to the lambda function. Each time the lambda function calls
|
|
__push_coro_op__ with another Fibonacci number, __push_coro__ transfers it back
|
|
to the main execution context. The local state of __coro_fn__ is preserved and
|
|
will be restored upon transferring execution control back to __coro_fn__
|
|
to calculate the next Fibonacci number.
|
|
Because __pull_coro__ provides input iterators and __begin__/__end__ are
|
|
overloaded, a ['range-based for]-loop can be used to iterate over the generated
|
|
Fibonacci numbers.
|
|
|
|
|
|
[heading __push_coro__]
|
|
__push_coro__ transfers data to the other execution context (== pushed-to).
|
|
The class has only one template parameter defining the transferred parameter
|
|
type.
|
|
The constructor of __push_coro__ takes a function (__coro_fn__) accepting a
|
|
reference to a __pull_coro__ as argument. In contrast to __pull_coro__,
|
|
instantiating a __push_coro__ does not pass the control of execution to
|
|
__coro_fn__ - instead the first call of __push_coro_op__ synthesizes a
|
|
complementary __pull_coro__ and passes it as reference to __coro_fn__.
|
|
|
|
The interface does not contain a ['get()]-function: you can not retrieve
|
|
values from another execution context with this kind of coroutine.
|
|
|
|
__push_coro__ provides output iterators (__push_coro__iterator) and
|
|
__begin__/__end__ are overloaded. The increment-operation switches the context
|
|
and transfers data.
|
|
|
|
struct FinalEOL{
|
|
~FinalEOL(){
|
|
std::cout << std::endl;
|
|
}
|
|
};
|
|
|
|
const int num=5, width=15;
|
|
boost::coroutines::coroutine<std::string>::push_type writer(
|
|
[&](boost::coroutines::coroutine<std::string>::pull_type& in){
|
|
// finish the last line when we leave by whatever means
|
|
FinalEOL eol;
|
|
// pull values from upstream, lay them out 'num' to a line
|
|
for (;;){
|
|
for(int i=0;i<num;++i){
|
|
// when we exhaust the input, stop
|
|
if(!in) return;
|
|
std::cout << std::setw(width) << in.get();
|
|
// now that we've handled this item, advance to next
|
|
in();
|
|
}
|
|
// after 'num' items, line break
|
|
std::cout << std::endl;
|
|
}
|
|
});
|
|
|
|
std::vector<std::string> words{
|
|
"peas", "porridge", "hot", "peas",
|
|
"porridge", "cold", "peas", "porridge",
|
|
"in", "the", "pot", "nine",
|
|
"days", "old" };
|
|
|
|
std::copy(boost::begin(words),boost::end(words),boost::begin(writer));
|
|
|
|
output:
|
|
peas porridge hot peas porridge
|
|
cold peas porridge in the
|
|
pot nine days old
|
|
|
|
In this example a __push_coro__ is created in the main execution context
|
|
accepting a lambda function (== __coro_fn__) which requests strings and lays out
|
|
'num' of them on each line.
|
|
This demonstrates the inversion of control permitted by coroutines. Without
|
|
coroutines, a utility function to perform the same job would necessarily
|
|
accept each new value as a function parameter, returning after processing that
|
|
single value. That function would depend on a static state variable. A
|
|
__coro_fn__, however, can request each new value as if by calling a function
|
|
-- even though its caller also passes values as if by calling a function.
|
|
The __coro_fn__ is executed in a newly created execution context which is
|
|
managed by the instance of __push_coro__.
|
|
The main execution context passes the strings to the __coro_fn__ by calling
|
|
__push_coro_op__.
|
|
A __pull_coro__ is automatically generated by the runtime and passed as
|
|
reference to the lambda function. The __coro_fn__ accesses the strings passed
|
|
from the main execution context by calling __pull_coro_get__ and lays those
|
|
strings out on ['std::cout] according the parameters 'num' and 'width'.
|
|
The local state of __coro_fn__ is preserved and will be restored after
|
|
transferring execution control back to __coro_fn__.
|
|
Because __push_coro__ provides output iterators and __begin__/__end__ are
|
|
overloaded, the ['std::copy] algorithm can be used to iterate over the vector
|
|
containing the strings and pass them one by one to the coroutine.
|
|
|
|
|
|
[heading stackful]
|
|
Each instance of a coroutine has its own stack.
|
|
|
|
In contrast to stackless coroutines, stackful coroutines allow invoking the
|
|
suspend operation out of arbitrary sub-stackframes, enabling escape-and-reenter
|
|
recursive operations.
|
|
|
|
|
|
[heading move-only]
|
|
A coroutine is moveable-only.
|
|
|
|
If it were copyable, then its stack with all the objects allocated on it
|
|
would be copied too. That would force undefined behaviour if some of these
|
|
objects were RAII-classes (manage a resource via RAII pattern). When the first
|
|
of the coroutine copies terminates (unwinds its stack), the RAII class
|
|
destructors will release their managed resources. When the second copy
|
|
terminates, the same destructors will try to doubly-release the same resources,
|
|
leading to undefined behavior.
|
|
|
|
|
|
[heading clean-up]
|
|
On coroutine destruction the associated stack will be unwound.
|
|
|
|
The constructor of coroutine allows to pass an customized ['stack-allocator].
|
|
['stack-allocator] is free to deallocate the stack or cache it for future usage
|
|
(for coroutines created later).
|
|
|
|
|
|
[heading segmented stack]
|
|
__push_coro__ and __pull_coro__ does support segmented stacks (growing on
|
|
demand).
|
|
|
|
It is not always possible to estimated the required stack size - in most cases
|
|
too much memory is allocated (waste of virtual address-space).
|
|
|
|
At construction a coroutine starts with a default (minimal) stack size. This
|
|
minimal stack size is the maximum of page size and the canonical size for signal
|
|
stack (macro SIGSTKSZ on POSIX).
|
|
|
|
At this time of writing only GCC (4.7)\cite{gccsplit} is known to support
|
|
segmented stacks. With version 1.54 __boost_coroutine__ provides support for
|
|
segmented stacks.
|
|
|
|
The destructor releases the associated stack. The implementer is free to
|
|
deallocate the stack or to cache it for later usage.
|
|
|
|
|
|
[heading context switch]
|
|
A coroutine saves and restores registers according to the underlying ABI on
|
|
each context switch.
|
|
|
|
Some applications do not use floating-point registers and can disable preserving
|
|
fpu registers for performance reasons.
|
|
|
|
[note According to the calling convention the FPU registers are preserved by
|
|
default.]
|
|
|
|
On POSIX systems, the coroutine context switch does not preserve signal masks
|
|
for performance reasons.
|
|
|
|
A context switch is done via __push_coro_op__ and __pull_coro_op__.
|
|
|
|
[warning Calling __push_coro_op__/__pull_coro_op__ from inside the [_same]
|
|
coroutine results in undefined behaviour.]
|
|
|
|
|
|
[heading coroutine-function]
|
|
The __coro_fn__ returns ['void] and takes its counterpart-coroutine as
|
|
argument, so that using the coroutine passed as argument to __coro_fn__ is the
|
|
only way to transfer data and execution control back to the caller.
|
|
Both coroutine types take the same template argument.
|
|
For __pull_coro__ the __coro_fn__ is entered at __pull_coro__ construction.
|
|
For __push_coro__ the __coro_fn__ is not entered at __push_coro__ construction
|
|
but entered by the first invocation of __push_coro_op__.
|
|
After execution control is returned from __coro_fn__ the state of the
|
|
coroutine can be checked via
|
|
__pull_coro_bool__ returning true if the coroutine is still valid (__coro_fn__
|
|
has not terminated). Unless T is void, true also implies that a data value is
|
|
available.
|
|
|
|
|
|
[heading passing data from a pull-coroutine to main-context]
|
|
In order to transfer data from a __pull_coro__ to the main-context the framework
|
|
synthesizes a __push_coro__ associated with the __pull_coro__ instance in the
|
|
main-context. The synthesized __push_coro__ is passed as argument to __coro_fn__.\\
|
|
The __coro_fn__ must call this __push_coro_op__ in order to transfer each
|
|
data value back to the main-context.
|
|
In the main-context, the __pull_coro_bool__ determines whether the coroutine is
|
|
still valid and a data value is available or __coro_fn__ has terminated
|
|
(__pull_coro__ is invalid; no data value available). Access to the transferred
|
|
data value is given by __pull_coro_get__.
|
|
|
|
boost::coroutines::coroutine<int>::pull_type source( // constructor enters coroutine-function
|
|
[&](boost::coroutines::coroutine<int>::push_type& sink){
|
|
sink(1); // push {1} back to main-context
|
|
sink(1); // push {1} back to main-context
|
|
sink(2); // push {2} back to main-context
|
|
sink(3); // push {3} back to main-context
|
|
sink(5); // push {5} back to main-context
|
|
sink(8); // push {8} back to main-context
|
|
});
|
|
|
|
while(source){ // test if pull-coroutine is valid
|
|
int ret=source.get(); // access data value
|
|
source(); // context-switch to coroutine-function
|
|
}
|
|
|
|
|
|
[heading passing data from main-context to a push-coroutine]
|
|
In order to transfer data to a __push_coro__ from the main-context the framework
|
|
synthesizes a __pull_coro__ associated with the __push_coro__ instance in the
|
|
main-context. The synthesized __pull_coro__ is passed as argument to __coro_fn__.
|
|
The main-context must call this __push_coro_op__ in order to transfer each data
|
|
value into the __coro_fn__.
|
|
Access to the transferred data value is given by __pull_coro_get__.
|
|
|
|
boost::coroutines::coroutine<int>::push_type sink( // constructor does NOT enter coroutine-function
|
|
[&](boost::coroutines::coroutine<int>::pull_type& source){
|
|
for (int i:source) {
|
|
std::cout << i << " ";
|
|
}
|
|
});
|
|
|
|
std::vector<int> v{1,1,2,3,5,8,13,21,34,55};
|
|
for( int i:v){
|
|
sink(i); // push {i} to coroutine-function
|
|
}
|
|
|
|
|
|
[heading accessing parameters]
|
|
Parameters returned from or transferred to the __coro_fn__ can be accessed with
|
|
__pull_coro_get__.
|
|
|
|
Splitting-up the access of parameters from context switch function enables to
|
|
check if __pull_coro__ is valid after return from __pull_coro_op__, e.g.
|
|
__pull_coro__ has values and __coro_fn__ has not terminated.
|
|
|
|
boost::coroutines::coroutine<boost::tuple<int,int>>::push_type sink(
|
|
[&](boost::coroutines::coroutine<boost::tuple<int,int>>::pull_type& source){
|
|
// access tuple {7,11}; x==7 y==1
|
|
int x,y;
|
|
boost::tie(x,y)=source.get();
|
|
});
|
|
|
|
sink(boost::make_tuple(7,11));
|
|
|
|
|
|
[heading exceptions]
|
|
An exception thrown inside a __pull_coro__'s __coro_fn__ before its first call
|
|
to __push_coro_op__ will be re-thrown by the __pull_coro__ constructor. After a
|
|
__pull_coro__'s __coro_fn__'s first call to __push_coro_op__, any subsequent
|
|
exception inside that __coro_fn__ will be re-thrown by __pull_coro_op__.
|
|
__pull_coro_get__ does not throw.
|
|
|
|
An exception thrown inside a __push_coro__'s __coro_fn__ will be re-thrown by
|
|
__push_coro_op__.
|
|
|
|
[important Code executed by coroutine must not prevent the propagation of the
|
|
__forced_unwind__ exception. Absorbing that exception will cause stack
|
|
unwinding to fail. Thus, any code that catches all exceptions must re-throw the
|
|
pending exception.]
|
|
|
|
try {
|
|
// code that might throw
|
|
} catch(const forced_unwind&) {
|
|
throw;
|
|
} catch(...) {
|
|
// possibly not re-throw pending exception
|
|
}
|
|
|
|
|
|
[heading Stack unwinding]
|
|
Sometimes it is necessary to unwind the stack of an unfinished coroutine to
|
|
destroy local stack variables so they can release allocated resources (RAII
|
|
pattern). The third argument of the coroutine constructor, `do_unwind`,
|
|
indicates whether the destructor should unwind the stack (stack is unwound by
|
|
default).
|
|
|
|
Stack unwinding assumes the following preconditions:
|
|
|
|
* The coroutine is not __not_a_coro__
|
|
* The coroutine is not complete
|
|
* The coroutine is not running
|
|
* The coroutine owns a stack
|
|
|
|
After unwinding, a __coro__ is complete.
|
|
|
|
struct X {
|
|
X(){
|
|
std::cout<<"X()"<<std::endl;
|
|
}
|
|
|
|
~X(){
|
|
std::cout<<"~X()"<<std::endl;
|
|
}
|
|
};
|
|
|
|
{
|
|
boost::coroutines::coroutine<void>::push_type sink(
|
|
[&](boost::coroutines::coroutine<void>::pull_type& source){
|
|
X x;
|
|
for(int=0;;++i){
|
|
std::cout<<"fn(): "<<i<<std::endl;
|
|
// transfer execution control back to main()
|
|
source();
|
|
}
|
|
});
|
|
|
|
sink();
|
|
sink();
|
|
sink();
|
|
sink();
|
|
sink();
|
|
|
|
std::cout<<"c is complete: "<<std::boolalpha<<c.is_complete()<<"\n";
|
|
}
|
|
|
|
std::cout<<"Done"<<std::endl;
|
|
|
|
output:
|
|
X()
|
|
fn(): 0
|
|
fn(): 1
|
|
fn(): 2
|
|
fn(): 3
|
|
fn(): 4
|
|
fn(): 5
|
|
c is complete: false
|
|
~X()
|
|
Done
|
|
|
|
|
|
[heading Range iterators]
|
|
__boost_coroutine__ provides output- and input-iterators using __boost_range__.
|
|
__pull_coro__ can be used via input-iterators using __begin__ and __end__.
|
|
|
|
int number=2,exponent=8;
|
|
boost::coroutines::coroutine< int >::pull_type source(
|
|
[&]( boost::coroutines::coroutine< int >::push_type & sink){
|
|
int counter=0,result=1;
|
|
while(counter++<exponent){
|
|
result=result*number;
|
|
sink(result);
|
|
}
|
|
});
|
|
|
|
for (auto i:source)
|
|
std::cout << i << " ";
|
|
|
|
std::cout << "\nDone" << std::endl;
|
|
|
|
output:
|
|
2 4 8 16 32 64 128 256
|
|
Done
|
|
|
|
Output-iterators can be created from __push_coro__.
|
|
|
|
boost::coroutines::coroutine<int>::push_type sink(
|
|
[&](boost::coroutines::coroutine<int>::pull_type& source){
|
|
while(source){
|
|
std::cout << source.get() << " ";
|
|
source();
|
|
}
|
|
});
|
|
|
|
std::vector<int> v{1,1,2,3,5,8,13,21,34,55};
|
|
std::copy(boost::begin(v),boost::end(v),boost::begin(sink));
|
|
|
|
|
|
[heading Exit a __coro_fn__]
|
|
__coro_fn__ is exited with a simple return statement jumping back to the calling
|
|
routine. The __pull_coro__/__push_coro__ becomes complete, e.g. __coro_bool__
|
|
will return 'false'.
|
|
|
|
[important After returning from __coro_fn__ the __coro__ is complete (can not
|
|
resumed with __coro_op__).]
|
|
|
|
|
|
|
|
[section:pull_coro Class `coroutine<>::pull_type`]
|
|
|
|
#include <boost/coroutine/coroutine.hpp>
|
|
|
|
template< typename R >
|
|
class coroutine<>::pull_type
|
|
{
|
|
public:
|
|
pull_type();
|
|
|
|
template<
|
|
typename Fn,
|
|
typename StackAllocator = stack_allocator,
|
|
typename Allocator = std::allocator< coroutine >
|
|
>
|
|
pull_type( Fn fn, attributes const& attr = attributes(),
|
|
StackAllocator const& stack_alloc = StackAllocator(),
|
|
Allocator const& alloc = Allocator() );
|
|
|
|
template<
|
|
typename Fn,
|
|
typename StackAllocator = stack_allocator,
|
|
typename Allocator = std::allocator< coroutine >
|
|
>
|
|
pull_type( Fn && fn, attributes const& attr = attributes(),
|
|
StackAllocator stack_alloc = StackAllocator(),
|
|
Allocator const& alloc = Allocator() );
|
|
|
|
pull_type( pull_type && other);
|
|
|
|
pull_type & operator=( pull_type && other);
|
|
|
|
operator unspecified-bool-type() const;
|
|
|
|
bool operator!() const;
|
|
|
|
void swap( pull_type & other);
|
|
|
|
bool empty() const;
|
|
|
|
pull_type & operator()();
|
|
|
|
bool has_result() const;
|
|
|
|
R get() const;
|
|
};
|
|
|
|
template< typename R >
|
|
void swap( pull_type< R > & l, pull_type< R > & r);
|
|
|
|
template< typename R >
|
|
range_iterator< pull_type< R > >::type begin( pull_type< R > &);
|
|
|
|
template< typename R >
|
|
range_iterator< pull_type< R > >::type end( pull_type< R > &);
|
|
|
|
[heading `pull_type()`]
|
|
[variablelist
|
|
[[Effects:] [Creates a coroutine representing __not_a_coro__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `template< typename Fn, typename StackAllocator, typename Allocator >
|
|
pull_type( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`]
|
|
[variablelist
|
|
[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize()
|
|
when ! is_stack_unbound().]]
|
|
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
|
|
determines stack clean-up and preserving floating-point registers.
|
|
For allocating/deallocating the stack `stack_alloc` is used and internal
|
|
data are allocated by Allocator.]]
|
|
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
|
|
]
|
|
|
|
[heading `template< typename Fn, typename StackAllocator, typename Allocator >
|
|
pull_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`]
|
|
[variablelist
|
|
[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize()
|
|
when ! is_stack_unbound().]]
|
|
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
|
|
determines stack clean-up and preserving floating-point registers.
|
|
For allocating/deallocating the stack `stack_alloc` is used and internal
|
|
data are allocated by Allocator.]]
|
|
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
|
|
]
|
|
|
|
[heading `pull_type( pull_type && other)`]
|
|
[variablelist
|
|
[[Effects:] [Moves the internal data of `other` to `*this`.
|
|
`other` becomes __not_a_coro__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `pull_type & operator=( pull_type && other)`]
|
|
[variablelist
|
|
[[Effects:] [Destroys the internal data of `*this` and moves the
|
|
internal data of `other` to `*this`. `other` becomes __not_a_coro__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `operator unspecified-bool-type() const`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
|
|
has returned (completed), the function returns false. Otherwise true.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `bool operator!() const`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
|
|
has returned (completed), the function returns true. Otherwise false.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `bool empty()`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to __not_a_coro__, the function returns true.
|
|
Otherwise false.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `pull_type<> & operator()()`]
|
|
[variablelist
|
|
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
|
|
[[Effects:] [Execution control is transferred to __coro_fn__ (no parameter are
|
|
passed to the coroutine-function).]]
|
|
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
|
|
]
|
|
|
|
[heading `bool has_result()`]
|
|
[variablelist
|
|
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
|
|
[[Returns:] [If `*this` has a, the function returns true. Otherwise false.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `R get()()`]
|
|
|
|
R coroutine<R>::pull_type::get();
|
|
R& coroutine<R&>::pull_type::get();
|
|
void coroutine<void>pull_type::get()=delete;
|
|
|
|
[variablelist
|
|
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
|
|
[[Returns:] [Returns data transferred from coroutine-function via
|
|
__push_coro_op__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `void swap( pull_type & other)`]
|
|
[variablelist
|
|
[[Effects:] [Swaps the internal data from `*this` with the values
|
|
of `other`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading Non-member function `swap()`]
|
|
|
|
template< typename R >
|
|
void swap( pull_type< R > & l, pull_type< R > & r);
|
|
|
|
[variablelist
|
|
[[Effects:] [As if 'l.swap( r)'.]]
|
|
]
|
|
|
|
[heading Non-member function `begin( pull_type< R > &)`]
|
|
template< typename R >
|
|
range_iterator< pull_type< R > >::type begin( pull_type< R > &);
|
|
|
|
[variablelist
|
|
[[Returns:] [Returns a range-iterator (input-iterator).]]
|
|
]
|
|
|
|
[heading Non-member function `end( pull_type< R > &)`]
|
|
template< typename R >
|
|
range_iterator< pull_type< R > >::type end( pull_type< R > &);
|
|
|
|
[variablelist
|
|
[[Returns:] [Returns a end range-iterator (input-iterator).]]
|
|
]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section:push_coro Class `coroutine<>::push_type`]
|
|
|
|
#include <boost/coroutine/coroutine.hpp>
|
|
|
|
template< typename Arg >
|
|
class coroutine<>::push_type
|
|
{
|
|
public:
|
|
push_type();
|
|
|
|
template<
|
|
typename Fn,
|
|
typename StackAllocator = stack_allocator,
|
|
typename Allocator = std::allocator< coroutine >
|
|
>
|
|
push_type( Fn fn, attributes const& attr = attributes(),
|
|
StackAllocator const& stack_alloc = StackAllocator(),
|
|
Allocator const& alloc = Allocator() );
|
|
|
|
template<
|
|
typename Fn,
|
|
typename StackAllocator = stack_allocator,
|
|
typename Allocator = std::allocator< coroutine >
|
|
>
|
|
push_type( Fn && fn, attributes const& attr = attributes(),
|
|
StackAllocator stack_alloc = StackAllocator(),
|
|
Allocator const& alloc = Allocator() );
|
|
|
|
push_type( push_type && other);
|
|
|
|
push_type & operator=( push_type && other);
|
|
|
|
operator unspecified-bool-type() const;
|
|
|
|
bool operator!() const;
|
|
|
|
void swap( push_type & other);
|
|
|
|
bool empty() const;
|
|
|
|
push_type & operator()( Arg&& arg);
|
|
};
|
|
|
|
template< typename Arg >
|
|
void swap( push_type< Arg > & l, push_type< Arg > & r);
|
|
|
|
template< typename Arg >
|
|
range_iterator< push_type< Arg > >::type begin( push_type< Arg > &);
|
|
|
|
template< typename Arg >
|
|
range_iterator< push_type< Arg > >::type end( push_type< Arg > &);
|
|
|
|
[heading `push_type()`]
|
|
[variablelist
|
|
[[Effects:] [Creates a coroutine representing __not_a_coro__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `template< typename Fn, typename StackAllocator, typename Allocator >
|
|
push_type( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`]
|
|
[variablelist
|
|
[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize()
|
|
when ! is_stack_unbound().]]
|
|
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
|
|
determines stack clean-up and preserving floating-point registers.
|
|
For allocating/deallocating the stack `stack_alloc` is used and internal
|
|
data are allocated by Allocator.]]
|
|
]
|
|
|
|
[heading `template< typename Fn, typename StackAllocator, typename Allocator >
|
|
push_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`]
|
|
[variablelist
|
|
[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize()
|
|
when ! is_stack_unbound().]]
|
|
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
|
|
determines stack clean-up and preserving floating-point registers.
|
|
For allocating/deallocating the stack `stack_alloc` is used and internal
|
|
data are allocated by Allocator.]]
|
|
]
|
|
|
|
[heading `push_type( push_type && other)`]
|
|
[variablelist
|
|
[[Effects:] [Moves the internal data of `other` to `*this`.
|
|
`other` becomes __not_a_coro__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `push_type & operator=( push_type && other)`]
|
|
[variablelist
|
|
[[Effects:] [Destroys the internal data of `*this` and moves the
|
|
internal data of `other` to `*this`. `other` becomes __not_a_coro__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `operator unspecified-bool-type() const`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
|
|
has returned (completed), the function returns false. Otherwise true.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `bool operator!() const`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
|
|
has returned (completed), the function returns true. Otherwise false.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `bool empty()`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to __not_a_coro__, the function returns true.
|
|
Otherwise false.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `push_type<> & operator()(Arg&& arg)`]
|
|
|
|
push_type& coroutine<Arg>::push_type::operator()(const Arg&);
|
|
push_type& coroutine<Arg>::push_type::operator()(Arg&&);
|
|
push_type& coroutine<Arg&>::push_type::operator()(Arg&);
|
|
push_type& coroutine<void>::push_type::operator()();
|
|
|
|
[variablelist
|
|
[[Preconditions:] [operator unspecified-bool-type() returns true for `*this`.]]
|
|
[[Effects:] [Execution control is transferred to __coro_fn__ and the argument
|
|
`arg` is passed to the coroutine-function.]]
|
|
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
|
|
]
|
|
|
|
[heading `void swap( push_type & other)`]
|
|
[variablelist
|
|
[[Effects:] [Swaps the internal data from `*this` with the values
|
|
of `other`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading `T caller_type::operator()( R)`]
|
|
[variablelist
|
|
[[Effects:] [Gives execution control back to calling context by returning
|
|
a value of type R. The return type of this function is a __tuple__ containing
|
|
the arguments passed to __coro_op__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading Non-member function `swap()`]
|
|
|
|
template< typename Arg >
|
|
void swap( push_type< Arg > & l, push_type< Arg > & r);
|
|
|
|
[variablelist
|
|
[[Effects:] [As if 'l.swap( r)'.]]
|
|
]
|
|
|
|
[heading Non-member function `begin( push_type< Arg > &)`]
|
|
template< typename Arg >
|
|
range_iterator< push_type< Arg > >::type begin( push_type< Arg > &);
|
|
|
|
[variablelist
|
|
[[Returns:] [Returns a range-iterator (output-iterator).]]
|
|
]
|
|
|
|
[heading Non-member function `end( push_type< Arg > &)`]
|
|
template< typename Arg >
|
|
range_iterator< push_type< Arg > >::type end( push_type< Arg > &);
|
|
|
|
[variablelist
|
|
[[Returns:] [Returns a end range-iterator (output-iterator).]]
|
|
]
|
|
|
|
[endsect]
|
|
|
|
|
|
|
|
[endsect]
|