[DEV] add v1.66.0

This commit is contained in:
2018-01-12 21:47:58 +01:00
parent 87059bb1af
commit a97e9ae7d4
49032 changed files with 7668950 additions and 0 deletions

11
libs/coroutine/README.md Normal file
View File

@@ -0,0 +1,11 @@
boost.coroutine
===============
boost.coroutine provides templates for generalized subroutines which allow multiple entry points for
suspending and resuming execution at certain locations. It preserves the local state of execution and
allows re-entering subroutines more than once (useful if state must be kept across function calls).
Coroutines can be viewed as a language-level construct providing a special kind of control flow.
In contrast to threads, which are pre-emptive, coroutines switches are cooperative (programmer controls
when a switch will happen). The kernel is not involved in the coroutine switches.

View File

@@ -0,0 +1,47 @@
# 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)
import feature ;
import modules ;
import toolset ;
project boost/coroutine
: requirements
<library>/boost/context//boost_context
<library>/boost/system//boost_system
<library>/boost/thread//boost_thread
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>shared:<define>BOOST_COROUTINES_DYN_LINK=1
<define>BOOST_COROUTINES_SOURCE
: usage-requirements
<link>shared:<define>BOOST_COROUTINES_DYN_LINK=1
: source-location ../src
;
alias stack_traits_sources
: windows/stack_traits.cpp
: <target-os>windows
;
alias stack_traits_sources
: posix/stack_traits.cpp
;
explicit stack_traits_sources ;
lib boost_coroutine
: detail/coroutine_context.cpp
exceptions.cpp
stack_traits_sources
: <link>shared:<library>../../context/build//boost_context
<link>shared:<library>../../system/build//boost_system
<link>shared:<library>../../thread/build//boost_thread
;
boost-install boost_coroutine ;

View File

@@ -0,0 +1,39 @@
# (C) Copyright 2008 Anthony Williams
#
# 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)
project coroutine/doc ;
import boostbook ;
import quickbook ;
import modules ;
path-constant here : . ;
boostbook coro
:
coro.qbk
:
# Path for links to Boost:
<xsl:param>boost.root=../../../..
# HTML options first:
# How far down we chunk nested sections, basically all of them:
<xsl:param>chunk.section.depth=3
# Don't put the first section on the same page as the TOC:
<xsl:param>chunk.first.sections=1
# How far down sections get TOC's
<xsl:param>toc.section.depth=10
# Max depth in each TOC:
<xsl:param>toc.max.depth=3
# How far down we go with TOC's
<xsl:param>generate.section.toc.level=10
# Absolute path for images:
<format>pdf:<xsl:param>img.src.path=$(here)/html/
;
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : coro ;
explicit boostrelease ;

View File

@@ -0,0 +1,17 @@
[/
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:acknowledgements Acknowledgments]
I'd like to thank Alex Hagen-Zanker, Christopher Kormanyos, Conrad Poelman,
Eugene Yakubovich, Giovanni Piero Deretta, Hartmut Kaiser, Jeffrey Lee Hellrung,
[*Nat Goodspeed], Robert Stewart, Vicente J. Botet Escriba and Yuriy Krasnoschek.
Especially Eugene Yakubovich, Giovanni Piero Deretta and Vicente J. Botet
Escriba contributed many good ideas during the review.
[endsect]

View File

@@ -0,0 +1,13 @@
[/
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:architectures Architectures]
__boost_coroutine__ depends on __boost_context__ which supports these
[@boost:/libs/context/doc/html/context/architectures.html architectures].
[endsect]

View File

@@ -0,0 +1,691 @@
[/
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:asymmetric Asymmetric coroutine]
Two asymmetric coroutine types - __push_coro__ and __pull_coro__ - provide a
unidirectional transfer of data.
[heading __pull_coro__]
__pull_coro__ transfers data from another execution context (== pulled-from).
The template parameter defines the transferred parameter type.
The constructor of __pull_coro__ takes a function (__coro_fn__) accepting a
reference to an __push_coro__ as argument. Instantiating an __pull_coro__ passes
the control of execution to __coro_fn__ and a complementary __push_coro__ is
synthesized by the library 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::asymmetric_coroutine<int>::pull_type source(
[&](boost::coroutines::asymmetric_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 << " ";
output:
1 1 2 3 5 8 13 21 34 55
In this example an __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__.
An __push_coro__ is automatically generated by the library 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 template parameter defines the transferred parameter type.
The constructor of __push_coro__ takes a function (__coro_fn__) accepting a
reference to an __pull_coro__ as argument. In contrast to __pull_coro__,
instantiating an __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 __push_coro__ 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_it__) 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::asymmetric_coroutine<std::string>::push_type writer(
[&](boost::coroutines::asymmetric_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 an __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__.
An __pull_coro__ instance is automatically generated by the library 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 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 the first
template parameter 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 an __pull_coro__ to the main-context the framework
synthesizes an __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::asymmetric_coroutine<int>::pull_type source( // constructor enters coroutine-function
[&](boost::coroutines::asymmetric_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 an __push_coro__ from the main-context the framework
synthesizes an __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::asymmetric_coroutine<int>::push_type sink( // constructor does NOT enter coroutine-function
[&](boost::coroutines::asymmetric_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::asymmetric_coroutine<boost::tuple<int,int>>::push_type sink(
[&](boost::coroutines::asymmetric_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 an __pull_coro__'s __coro_fn__ before its first call
to __push_coro_op__ will be re-thrown by the __pull_coro__ constructor. After an
__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 an __push_coro__'s __coro_fn__ will be re-thrown by
__push_coro_op__.
[important Code executed by __coro_fn__ 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 any
pending __forced_unwind__ exception.]
try {
// code that might throw
} catch(const boost::coroutines::detail::forced_unwind&) {
throw;
} catch(...) {
// possibly not re-throw pending exception
}
[important Do not jump from inside a catch block and then re-throw the
exception in another execution context.]
[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 `attributes` argument of the coroutine constructor
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::asymmetric_coroutine<void>::push_type sink(
[&](boost::coroutines::asymmetric_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<<"sink is complete: "<<std::boolalpha<<!sink<<"\n";
}
output:
X()
fn(): 0
fn(): 1
fn(): 2
fn(): 3
fn(): 4
fn(): 5
sink is complete: false
~X()
[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::asymmetric_coroutine< int >::pull_type source(
[&]( boost::coroutines::asymmetric_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 << " ";
output:
2 4 8 16 32 64 128 256
['asymmetric_coroutine<>::pull_type::iterator::operator++()] corresponds to
__pull_coro_op__; ['asymmetric_coroutine<>::pull_type::iterator::operator*()]
roughly corresponds to __pull_coro_get__. An iterator originally obtained from
__begin__ of an __pull_coro__ compares equal to an iterator obtained from
__end__ of that same __pull_coro__ instance when its __pull_coro_bool__ would
return `false`].
[note If `T` is a move-only type, then
['asymmetric_coroutine<T>::pull_type::iterator] may only be dereferenced once
before it is incremented again.]
Output-iterators can be created from __push_coro__.
boost::coroutines::asymmetric_coroutine<int>::push_type sink(
[&](boost::coroutines::asymmetric_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));
['asymmetric_coroutine<>::push_type::iterator::operator*()] roughly
corresponds to __push_coro_op__. An iterator originally obtained from
__begin__ of an __push_coro__ compares equal to an iterator obtained from
__end__ of that same __push_coro__ instance when its __push_coro_bool__ would
return `false`.
[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. __pull_coro_bool__,
__push_coro_bool__ will return `false`.
[important After returning from __coro_fn__ the __coro__ is complete (can not
resumed with __push_coro_op__, __pull_coro_op__).]
[section:pull_coro Class `asymmetric_coroutine<>::pull_type`]
#include <boost/coroutine/asymmetric_coroutine.hpp>
template< typename R >
class asymmetric_coroutine<>::pull_type
{
public:
pull_type() noexcept;
template< typename Fn >
pull_type( Fn && fn, attributes const& attr = attributes() );
template< typename Fn, typename StackAllocator >
pull_type( Fn && fn, attributes const& attr, StackAllocator stack_alloc);
pull_type( pull_type const& other)=delete;
pull_type & operator=( pull_type const& other)=delete;
~pull_type();
pull_type( pull_type && other) noexcept;
pull_type & operator=( pull_type && other) noexcept;
operator unspecified-bool-type() const noexcept;
bool operator!() const noexcept;
void swap( pull_type & other) noexcept;
pull_type & operator()();
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 >
pull_type( Fn && fn, attributes const& attr)`]
[variablelist
[[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize()
when ! is_stack_unbounded().]]
[[Effects:] [Creates a coroutine which will execute `fn`, and enters it.
Argument `attr` determines stack clean-up.]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]
[heading `template< typename Fn, typename StackAllocator >
pull_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`]
[variablelist
[[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize()
when ! is_stack_unbounded().]]
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
determines stack clean-up.
For allocating/deallocating the stack `stack_alloc` is used.]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]
[heading `~pull_type()`]
[variablelist
[[Effects:] [Destroys the context and deallocates the stack.]]
]
[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 `pull_type<> & operator()()`]
[variablelist
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
[[Effects:] [Execution control is transferred to __coro_fn__ (no parameter is
passed to the coroutine-function).]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]
[heading `R get()`]
R asymmetric_coroutine<R,StackAllocator>::pull_type::get();
R& asymmetric_coroutine<R&,StackAllocator>::pull_type::get();
void asymmetric_coroutine<void,StackAllocator>::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:] [`invalid_result`]]
[[Note:] [If `R` is a move-only type, you may only call `get()` once before
the next __pull_coro_op__ call.]]
]
[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 an end range-iterator (input-iterator).]]
[[Note:] [When first obtained from `begin( pull_type< R > &)`, or after some
number of increment operations, an iterator will compare equal to the iterator
returned by `end( pull_type< R > &)` when the corresponding __pull_coro_bool__
would return `false`.]]
]
[endsect]
[section:push_coro Class `asymmetric_coroutine<>::push_type`]
#include <boost/coroutine/asymmetric_coroutine.hpp>
template< typename Arg >
class asymmetric_coroutine<>::push_type
{
public:
push_type() noexcept;
template< typename Fn >
push_type( Fn && fn, attributes const& attr = attributes() );
template< typename Fn, typename StackAllocator >
push_type( Fn && fn, attributes const& attr, StackAllocator stack_alloc);
push_type( push_type const& other)=delete;
push_type & operator=( push_type const& other)=delete;
~push_type();
push_type( push_type && other) noexcept;
push_type & operator=( push_type && other) noexcept;
operator unspecified-bool-type() const noexcept;
bool operator!() const noexcept;
void swap( push_type & other) noexcept;
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 >
push_type( Fn && fn, attributes const& attr)`]
[variablelist
[[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize()
when ! is_stack_unbounded().]]
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
determines stack clean-up.]]
]
[heading `template< typename Fn, typename StackAllocator >
push_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`]
[variablelist
[[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize()
when ! is_stack_unbounded().]]
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
determines stack clean-up.
For allocating/deallocating the stack `stack_alloc` is used.]]
]
[heading `~push_type()`]
[variablelist
[[Effects:] [Destroys the context and deallocates the stack.]]
]
[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 `push_type & operator()(Arg arg)`]
push_type& asymmetric_coroutine<Arg>::push_type::operator()(Arg);
push_type& asymmetric_coroutine<Arg&>::push_type::operator()(Arg&);
push_type& asymmetric_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 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).]]
[[Note:] [When first obtained from `begin( push_type< R > &)`, or after some
number of increment operations, an iterator will compare equal to the iterator
returned by `end( push_type< R > &)` when the corresponding __push_coro_bool__
would return `false`.]]
]
[endsect]
[endsect]

View File

@@ -0,0 +1,60 @@
[/
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:attributes Attributes]
Class `attributes` is used to specify parameters required to setup a
coroutine's context.
enum flag_unwind_t
{
stack_unwind,
no_stack_unwind
};
struct attributes
{
std::size_t size;
flag_unwind_t do_unwind;
attributes() noexcept;
explicit attributes( std::size_t size_) noexcept;
explicit attributes( flag_unwind_t do_unwind_) noexcept;
explicit attributes( std::size_t size_, flag_unwind_t do_unwind_) noexcept;
};
[heading `attributes()`]
[variablelist
[[Effects:] [Default constructor using `boost::context::default_stacksize()`, does unwind
the stack after coroutine/generator is complete.]]
[[Throws:] [Nothing.]]
]
[heading `attributes( std::size_t size)`]
[variablelist
[[Effects:] [Argument `size` defines stack size of the new coroutine.
Stack unwinding after termination.]]
[[Throws:] [Nothing.]]
]
[heading `attributes( flag_unwind_t do_unwind)`]
[variablelist
[[Effects:] [Argument `do_unwind` determines if stack will be unwound after
termination or not. The default stacksize is used for the new coroutine.]]
[[Throws:] [Nothing.]]
]
[heading `attributes( std::size_t size, flag_unwind_t do_unwind)`]
[variablelist
[[Effects:] [Arguments `size` and `do_unwind` are given by the user.]]
[[Throws:] [Nothing.]]
]
[endsect]

108
libs/coroutine/doc/coro.qbk Normal file
View File

@@ -0,0 +1,108 @@
[/
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
]
[library Coroutine
[quickbook 1.5]
[authors [Kowalke, Oliver]]
[copyright 2009 Oliver Kowalke]
[purpose C++ Library providing coroutine facility]
[id coroutine]
[category text]
[license
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])
]
]
[def __boost_asio__ [*Boost.Asio]]
[def __boost_build__ [*Boost.Build]]
[def __boost_context__ [*Boost.Context]]
[def __boost_coroutine__ [*Boost.Coroutine]]
[def __boost_exception__ [*Boost.Exception]]
[def __boost_function_types__ [*Boost.FunctionTypes]]
[def __boost_move__ [*Boost.Move]]
[def __boost_mpl__ [*Boost.MPL]]
[def __boost_optional__ [*Boost.Optional]]
[def __boost_preprocessor__ [*Boost.Preprocessor]]
[def __boost_range__ [*Boost.Range]]
[def __boost_result_of__ [*Boost.ResultOf]]
[def __boost_smart_ptr__ [*Boost.SmartPtr]]
[def __boost_static_assert__ [*Boost.StaticAssert]]
[def __boost_tuple__ [*Boost.Tuple]]
[def __boost_type_traits__ [*Boost.TypeTraits]]
[def __boost_utility__ [*Boost.Utility]]
[def __boost_version__ [*Boost-1.52.0]]
[def __coro__ ['coroutine]]
[def __coro_fn__ ['coroutine-function]]
[def __coros__ ['coroutines]]
[def __ctx__ ['context]]
[def __not_a_coro__ ['not-a-coroutine]]
[def __segmented_stack__ ['segmented-stack]]
[def __signature__ ['Signature]]
[def __stack_allocator_concept__ ['stack-allocator concept]]
[def __stack_allocator__ ['stack-allocator]]
[def __stack_traits__ ['stack-traits]]
[def __stack__ ['stack]]
[def __tls__ ['thread-local-storage]]
[def __acoro__ ['asymmetric_coroutine<>]]
[def __attrs__ ['attributes]]
[def __begin__ ['std::begin()]]
[def __bind__ ['boost::bind()]]
[def __call_coro_bool__ ['symmetric_coroutine<>::call_type::operator bool]]
[def __call_coro_op__ ['symmetric_coroutine<>::call_type::operator()]]
[def __call_coro__ ['symmetric_coroutine<>::call_type]]
[def __coro_allocator__ ['stack_allocator]]
[def __coro_ns__ ['boost::coroutines]]
[def __end__ ['std::end()]]
[def __fcontext__ ['boost::contexts::fcontext_t]]
[def __fetch__ ['inbuf::fetch()]]
[def __forced_unwind__ ['detail::forced_unwind]]
[def __getline__ ['std::getline()]]
[def __handle_read__ ['session::handle_read()]]
[def __io_service__ ['boost::asio::io_sevice]]
[def __protected_allocator__ ['protected_stack_allocator]]
[def __pull_coro__ ['asymmetric_coroutine<>::pull_type]]
[def __pull_coro_bool__ ['asymmetric_coroutine<>::pull_type::operator bool]]
[def __pull_coro_get__ ['asymmetric_coroutine<>::pull_type::get()]]
[def __pull_coro_it__ ['asymmetric_coroutine<>::pull_type::iterator]]
[def __pull_coro_op__ ['asymmetric_coroutine<>::pull_type::operator()]]
[def __push_coro__ ['asymmetric_coroutine<>::push_type]]
[def __push_coro_bool__ ['asymmetric_coroutine<>::push_type::operator bool]]
[def __push_coro_it__ ['asymmetric_coroutine<>::push_type::iterator]]
[def __push_coro_op__ ['asymmetric_coroutine<>::push_type::operator()]]
[def __scoro__ ['symmetric_coroutine<>]]
[def __segmented_allocator__ ['segmented_stack_allocator]]
[def __server__ ['server]]
[def __session__ ['session]]
[def __stack_context__ ['stack_context]]
[def __segmented_allocator__ ['segmented_stack_allocator]]
[def __standard_allocator__ ['standard_stack_allocator]]
[def __start__ ['session::start()]]
[def __terminate__ ['std::terminate()]]
[def __thread__ ['boost::thread]]
[def __tie__ ['boost::tie]]
[def __tuple__ ['boost::tuple<>]]
[def __underflow__ ['stream_buf::underflow()]]
[def __yield_context__ ['boost::asio::yield_context]]
[def __yield_coro_bool__ ['symmetric_coroutine<>::yield_type::operator bool]]
[def __yield_coro_get__ ['symmetric_coroutine<>::yield_type::get()]]
[def __yield_coro_op__ ['symmetric_coroutine<>::yield_type::operator()]]
[def __yield_coro__ ['symmetric_coroutine<>::yield_type]]
[include overview.qbk]
[include intro.qbk]
[include motivation.qbk]
[include coroutine.qbk]
[include attributes.qbk]
[include stack.qbk]
[include performance.qbk]
[include architectures.qbk]
[include acknowledgements.qbk]

View File

@@ -0,0 +1,101 @@
[/
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:coroutine Coroutine]
__boost_coroutine__ provides two implementations - asymmetric and symmetric
coroutines.
Symmetric coroutines occur usually in the context of concurrent programming
in order to represent independent units of execution.
Implementations that produce sequences of values typically use asymmetric
coroutines.
[footnote Moura, Ana Lucia De and Ierusalimschy, Roberto.
"Revisiting coroutines". ACM Trans. Program. Lang. Syst., Volume 31 Issue 2,
February 2009, Article No. 6]
[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 behaviour.
[heading clean-up]
On coroutine destruction the associated stack will be unwound.
The constructor of coroutine allows you to pass a customized ['stack-allocator].
['stack-allocator] is free to deallocate the stack or cache it for future usage
(for coroutines created later).
[heading segmented stack]
__call_coro__, __push_coro__ and __pull_coro__ support segmented stacks
(growing on demand).
It is not always possible to accurately estimate 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)
[footnote [@http://gcc.gnu.org/wiki/SplitStacks Ian Lance Taylor, Split Stacks in GCC]]
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 (using __boost_context__).
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 __call_coro_op__, __push_coro_op__ and
__pull_coro_op__.
[warning Calling __call_coro_op__, __push_coro_op__ and __pull_coro_op__ from
inside the [_same] coroutine results in undefined behaviour.]
As an example, the code below will result in undefined behaviour:
boost::coroutines::symmetric_coroutine<void>::call_type coro(
[&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield){
yield(coro); // yield to same symmetric_coroutine
});
coro();
[include asymmetric.qbk]
[include symmetric.qbk]
[endsect]

View File

@@ -0,0 +1,22 @@
index.html
coroutine/overview.html
coroutine/intro.html
coroutine/motivation.html
coroutine/coroutine.html
coroutine/coroutine/asymmetric.html
coroutine/coroutine/asymmetric/pull_coro.html
coroutine/coroutine/asymmetric/push_coro.html
coroutine/coroutine/symmetric.html
coroutine/coroutine/symmetric/symmetric_coro.html
coroutine/coroutine/symmetric/yield_coro.html
coroutine/attributes.html
coroutine/stack.html
coroutine/stack/protected_stack_allocator.html
coroutine/stack/standard_stack_allocator.html
coroutine/stack/segmented_stack_allocator.html
coroutine/stack/stack_traits.html
coroutine/stack/stack_context.html
coroutine/stack/valgrind.html
coroutine/performance.html
coroutine/architectures.html
coroutine/acknowledgements.html

View File

@@ -0,0 +1,52 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Acknowledgments</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="architectures.html" title="Architectures">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="architectures.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.acknowledgements"></a><a class="link" href="acknowledgements.html" title="Acknowledgments">Acknowledgments</a>
</h2></div></div></div>
<p>
I'd like to thank Alex Hagen-Zanker, Christopher Kormanyos, Conrad Poelman,
Eugene Yakubovich, Giovanni Piero Deretta, Hartmut Kaiser, Jeffrey Lee Hellrung,
<span class="bold"><strong>Nat Goodspeed</strong></span>, Robert Stewart, Vicente J.
Botet Escriba and Yuriy Krasnoschek.
</p>
<p>
Especially Eugene Yakubovich, Giovanni Piero Deretta and Vicente J. Botet Escriba
contributed many good ideas during the review.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="architectures.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,47 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Architectures</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="performance.html" title="Performance">
<link rel="next" href="acknowledgements.html" title="Acknowledgments">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="performance.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="acknowledgements.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.architectures"></a><a class="link" href="architectures.html" title="Architectures">Architectures</a>
</h2></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine</strong></span> depends on <span class="bold"><strong>Boost.Context</strong></span>
which supports these <a href="../../../../../libs/context/doc/html/context/architectures.html" target="_top">architectures</a>.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="performance.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="acknowledgements.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,141 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Attributes</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="coroutine/symmetric/yield_coro.html" title="Class symmetric_coroutine&lt;&gt;::yield_type">
<link rel="next" href="stack.html" title="Stack allocation">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="coroutine/symmetric/yield_coro.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.attributes"></a><a class="link" href="attributes.html" title="Attributes">Attributes</a>
</h2></div></div></div>
<p>
Class <code class="computeroutput"><span class="identifier">attributes</span></code> is used to
specify parameters required to setup a coroutine's context.
</p>
<pre class="programlisting"><span class="keyword">enum</span> <span class="identifier">flag_unwind_t</span>
<span class="special">{</span>
<span class="identifier">stack_unwind</span><span class="special">,</span>
<span class="identifier">no_stack_unwind</span>
<span class="special">};</span>
<span class="keyword">struct</span> <span class="identifier">attributes</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">;</span>
<span class="identifier">flag_unwind_t</span> <span class="identifier">do_unwind</span><span class="special">;</span>
<span class="identifier">attributes</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">explicit</span> <span class="identifier">attributes</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size_</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">explicit</span> <span class="identifier">attributes</span><span class="special">(</span> <span class="identifier">flag_unwind_t</span> <span class="identifier">do_unwind_</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">explicit</span> <span class="identifier">attributes</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size_</span><span class="special">,</span> <span class="identifier">flag_unwind_t</span> <span class="identifier">do_unwind_</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<h4>
<a name="coroutine.attributes.h0"></a>
<span class="phrase"><a name="coroutine.attributes._code__phrase_role__identifier__attributes__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="attributes.html#coroutine.attributes._code__phrase_role__identifier__attributes__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">attributes</span><span class="special">()</span></code></a>
</h4>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Default constructor using <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">default_stacksize</span><span class="special">()</span></code>, does unwind the stack after coroutine/generator
is complete.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h4>
<a name="coroutine.attributes.h1"></a>
<span class="phrase"><a name="coroutine.attributes._code__phrase_role__identifier__attributes__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="attributes.html#coroutine.attributes._code__phrase_role__identifier__attributes__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">attributes</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
<span class="identifier">size</span><span class="special">)</span></code></a>
</h4>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Argument <code class="computeroutput"><span class="identifier">size</span></code> defines
stack size of the new coroutine. Stack unwinding after termination.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h4>
<a name="coroutine.attributes.h2"></a>
<span class="phrase"><a name="coroutine.attributes._code__phrase_role__identifier__attributes__phrase__phrase_role__special_____phrase___phrase_role__identifier__flag_unwind_t__phrase___phrase_role__identifier__do_unwind__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="attributes.html#coroutine.attributes._code__phrase_role__identifier__attributes__phrase__phrase_role__special_____phrase___phrase_role__identifier__flag_unwind_t__phrase___phrase_role__identifier__do_unwind__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">attributes</span><span class="special">(</span> <span class="identifier">flag_unwind_t</span> <span class="identifier">do_unwind</span><span class="special">)</span></code></a>
</h4>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Argument <code class="computeroutput"><span class="identifier">do_unwind</span></code> determines
if stack will be unwound after termination or not. The default stacksize
is used for the new coroutine.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h4>
<a name="coroutine.attributes.h3"></a>
<span class="phrase"><a name="coroutine.attributes._code__phrase_role__identifier__attributes__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___phrase_role__identifier__flag_unwind_t__phrase___phrase_role__identifier__do_unwind__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="attributes.html#coroutine.attributes._code__phrase_role__identifier__attributes__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___phrase_role__identifier__flag_unwind_t__phrase___phrase_role__identifier__do_unwind__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">attributes</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
<span class="identifier">size</span><span class="special">,</span> <span class="identifier">flag_unwind_t</span> <span class="identifier">do_unwind</span><span class="special">)</span></code></a>
</h4>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Arguments <code class="computeroutput"><span class="identifier">size</span></code> and <code class="computeroutput"><span class="identifier">do_unwind</span></code> are given by the user.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="coroutine/symmetric/yield_coro.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,196 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Coroutine</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="motivation.html" title="Motivation">
<link rel="next" href="coroutine/asymmetric.html" title="Asymmetric coroutine">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="motivation.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="coroutine/asymmetric.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.coroutine"></a><a class="link" href="coroutine.html" title="Coroutine">Coroutine</a>
</h2></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="coroutine/asymmetric.html">Asymmetric coroutine</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine/asymmetric/pull_coro.html">Class <code class="computeroutput"><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">pull_type</span></code></a></span></dt>
<dt><span class="section"><a href="coroutine/asymmetric/push_coro.html">Class <code class="computeroutput"><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">push_type</span></code></a></span></dt>
</dl></dd>
<dt><span class="section"><a href="coroutine/symmetric.html">Symmetric coroutine</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine/symmetric/symmetric_coro.html">Class
<code class="computeroutput"><span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">call_type</span></code></a></span></dt>
<dt><span class="section"><a href="coroutine/symmetric/yield_coro.html">Class <code class="computeroutput"><span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">yield_type</span></code></a></span></dt>
</dl></dd>
</dl></div>
<p>
<span class="bold"><strong>Boost.Coroutine</strong></span> provides two implementations
- asymmetric and symmetric coroutines.
</p>
<p>
Symmetric coroutines occur usually in the context of concurrent programming
in order to represent independent units of execution. Implementations that
produce sequences of values typically use asymmetric coroutines. <a href="#ftn.coroutine.coroutine.f0" class="footnote" name="coroutine.coroutine.f0"><sup class="footnote">[5]</sup></a>
</p>
<h4>
<a name="coroutine.coroutine.h0"></a>
<span class="phrase"><a name="coroutine.coroutine.stackful"></a></span><a class="link" href="coroutine.html#coroutine.coroutine.stackful">stackful</a>
</h4>
<p>
Each instance of a coroutine has its own stack.
</p>
<p>
In contrast to stackless coroutines, stackful coroutines allow invoking the
suspend operation out of arbitrary sub-stackframes, enabling escape-and-reenter
recursive operations.
</p>
<h4>
<a name="coroutine.coroutine.h1"></a>
<span class="phrase"><a name="coroutine.coroutine.move_only"></a></span><a class="link" href="coroutine.html#coroutine.coroutine.move_only">move-only</a>
</h4>
<p>
A coroutine is moveable-only.
</p>
<p>
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 behaviour.
</p>
<h4>
<a name="coroutine.coroutine.h2"></a>
<span class="phrase"><a name="coroutine.coroutine.clean_up"></a></span><a class="link" href="coroutine.html#coroutine.coroutine.clean_up">clean-up</a>
</h4>
<p>
On coroutine destruction the associated stack will be unwound.
</p>
<p>
The constructor of coroutine allows you to pass a customized <span class="emphasis"><em>stack-allocator</em></span>.
<span class="emphasis"><em>stack-allocator</em></span> is free to deallocate the stack or cache
it for future usage (for coroutines created later).
</p>
<h4>
<a name="coroutine.coroutine.h3"></a>
<span class="phrase"><a name="coroutine.coroutine.segmented_stack"></a></span><a class="link" href="coroutine.html#coroutine.coroutine.segmented_stack">segmented
stack</a>
</h4>
<p>
<span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>, <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
and <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> support segmented
stacks (growing on demand).
</p>
<p>
It is not always possible to accurately estimate the required stack size -
in most cases too much memory is allocated (waste of virtual address-space).
</p>
<p>
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).
</p>
<p>
At this time of writing only GCC (4.7) <a href="#ftn.coroutine.coroutine.f1" class="footnote" name="coroutine.coroutine.f1"><sup class="footnote">[6]</sup></a> is known to support segmented stacks. With version 1.54 <span class="bold"><strong>Boost.Coroutine</strong></span> provides support for segmented stacks.
</p>
<p>
The destructor releases the associated stack. The implementer is free to deallocate
the stack or to cache it for later usage.
</p>
<h4>
<a name="coroutine.coroutine.h4"></a>
<span class="phrase"><a name="coroutine.coroutine.context_switch"></a></span><a class="link" href="coroutine.html#coroutine.coroutine.context_switch">context
switch</a>
</h4>
<p>
A coroutine saves and restores registers according to the underlying ABI on
each context switch (using <span class="bold"><strong>Boost.Context</strong></span>).
</p>
<p>
Some applications do not use floating-point registers and can disable preserving
FPU registers for performance reasons.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
According to the calling convention the FPU registers are preserved by default.
</p></td></tr>
</table></div>
<p>
On POSIX systems, the coroutine context switch does not preserve signal masks
for performance reasons.
</p>
<p>
A context switch is done via <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>,
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span> and
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator()</em></span>.
</p>
<div class="warning"><table border="0" summary="Warning">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="../../../../../doc/src/images/warning.png"></td>
<th align="left">Warning</th>
</tr>
<tr><td align="left" valign="top"><p>
Calling <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>,
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>
and <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator()</em></span>
from inside the <span class="underline">same</span> coroutine results
in undefined behaviour.
</p></td></tr>
</table></div>
<p>
As an example, the code below will result in undefined behaviour:
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">){</span>
<span class="identifier">yield</span><span class="special">(</span><span class="identifier">coro</span><span class="special">);</span> <span class="comment">// yield to same symmetric_coroutine</span>
<span class="special">});</span>
<span class="identifier">coro</span><span class="special">();</span>
</pre>
<div class="footnotes">
<br><hr style="width:100; text-align:left;margin-left: 0">
<div id="ftn.coroutine.coroutine.f0" class="footnote"><p><a href="#coroutine.coroutine.f0" class="para"><sup class="para">[5] </sup></a>
Moura, Ana Lucia De and Ierusalimschy, Roberto. "Revisiting coroutines".
ACM Trans. Program. Lang. Syst., Volume 31 Issue 2, February 2009, Article
No. 6
</p></div>
<div id="ftn.coroutine.coroutine.f1" class="footnote"><p><a href="#coroutine.coroutine.f1" class="para"><sup class="para">[6] </sup></a>
<a href="http://gcc.gnu.org/wiki/SplitStacks" target="_top">Ian Lance Taylor, Split
Stacks in GCC</a>
</p></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="motivation.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="coroutine/asymmetric.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,536 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Asymmetric coroutine</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../coroutine.html" title="Coroutine">
<link rel="prev" href="../coroutine.html" title="Coroutine">
<link rel="next" href="asymmetric/pull_coro.html" title="Class asymmetric_coroutine&lt;&gt;::pull_type">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../coroutine.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../coroutine.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="asymmetric/pull_coro.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="coroutine.coroutine.asymmetric"></a><a class="link" href="asymmetric.html" title="Asymmetric coroutine">Asymmetric coroutine</a>
</h3></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="asymmetric/pull_coro.html">Class <code class="computeroutput"><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">pull_type</span></code></a></span></dt>
<dt><span class="section"><a href="asymmetric/push_coro.html">Class <code class="computeroutput"><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">push_type</span></code></a></span></dt>
</dl></div>
<p>
Two asymmetric coroutine types - <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
and <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> - provide
a unidirectional transfer of data.
</p>
<h5>
<a name="coroutine.coroutine.asymmetric.h0"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric._emphasis_asymmetric_coroutine_lt__gt___pull_type__emphasis_"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric._emphasis_asymmetric_coroutine_lt__gt___pull_type__emphasis_"><span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span></a>
</h5>
<p>
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> transfers data
from another execution context (== pulled-from). The template parameter defines
the transferred parameter type. The constructor of <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
takes a function (<span class="emphasis"><em>coroutine-function</em></span>) accepting a reference
to an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span> as argument.
Instantiating an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
passes the control of execution to <span class="emphasis"><em>coroutine-function</em></span>
and a complementary <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
is synthesized by the library and passed as reference to <span class="emphasis"><em>coroutine-function</em></span>.
</p>
<p>
This kind of coroutine provides <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator()</em></span>.
This method only switches context; it transfers no data.
</p>
<p>
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> provides input
iterators (<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::iterator</em></span>)
and <span class="emphasis"><em>std::begin()</em></span>/<span class="emphasis"><em>std::end()</em></span> are
overloaded. The increment-operation switches the context and transfers data.
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">source</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">){</span>
<span class="keyword">int</span> <span class="identifier">first</span><span class="special">=</span><span class="number">1</span><span class="special">,</span><span class="identifier">second</span><span class="special">=</span><span class="number">1</span><span class="special">;</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">first</span><span class="special">);</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">second</span><span class="special">);</span>
<span class="keyword">for</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span><span class="special">=</span><span class="number">0</span><span class="special">;</span><span class="identifier">i</span><span class="special">&lt;</span><span class="number">8</span><span class="special">;++</span><span class="identifier">i</span><span class="special">){</span>
<span class="keyword">int</span> <span class="identifier">third</span><span class="special">=</span><span class="identifier">first</span><span class="special">+</span><span class="identifier">second</span><span class="special">;</span>
<span class="identifier">first</span><span class="special">=</span><span class="identifier">second</span><span class="special">;</span>
<span class="identifier">second</span><span class="special">=</span><span class="identifier">third</span><span class="special">;</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">third</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="keyword">for</span><span class="special">(</span><span class="keyword">auto</span> <span class="identifier">i</span><span class="special">:</span><span class="identifier">source</span><span class="special">)</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">i</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span><span class="special">;</span>
<span class="identifier">output</span><span class="special">:</span>
<span class="number">1</span> <span class="number">1</span> <span class="number">2</span> <span class="number">3</span> <span class="number">5</span> <span class="number">8</span> <span class="number">13</span> <span class="number">21</span> <span class="number">34</span> <span class="number">55</span>
</pre>
<p>
In this example an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
is created in the main execution context taking a lambda function (== <span class="emphasis"><em>coroutine-function</em></span>)
which calculates Fibonacci numbers in a simple <span class="emphasis"><em>for</em></span>-loop.
The <span class="emphasis"><em>coroutine-function</em></span> is executed in a newly created
execution context which is managed by the instance of <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>.
An <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span> is automatically
generated by the library and passed as reference to the lambda function.
Each time the lambda function calls <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>
with another Fibonacci number, <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
transfers it back to the main execution context. The local state of <span class="emphasis"><em>coroutine-function</em></span>
is preserved and will be restored upon transferring execution control back
to <span class="emphasis"><em>coroutine-function</em></span> to calculate the next Fibonacci
number. Because <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
provides input iterators and <span class="emphasis"><em>std::begin()</em></span>/<span class="emphasis"><em>std::end()</em></span>
are overloaded, a <span class="emphasis"><em>range-based for</em></span>-loop can be used to
iterate over the generated Fibonacci numbers.
</p>
<h5>
<a name="coroutine.coroutine.asymmetric.h1"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric._emphasis_asymmetric_coroutine_lt__gt___push_type__emphasis_"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric._emphasis_asymmetric_coroutine_lt__gt___push_type__emphasis_"><span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span></a>
</h5>
<p>
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span> transfers data
to the other execution context (== pushed-to). The template parameter defines
the transferred parameter type. The constructor of <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
takes a function (<span class="emphasis"><em>coroutine-function</em></span>) accepting a reference
to an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> as argument.
In contrast to <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>,
instantiating an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
does not pass the control of execution to <span class="emphasis"><em>coroutine-function</em></span>
- instead the first call of <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>
synthesizes a complementary <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
and passes it as reference to <span class="emphasis"><em>coroutine-function</em></span>.
</p>
<p>
The <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span> interface
does not contain a <span class="emphasis"><em>get()</em></span>-function: you can not retrieve
values from another execution context with this kind of coroutine.
</p>
<p>
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span> provides output
iterators (<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::iterator</em></span>)
and <span class="emphasis"><em>std::begin()</em></span>/<span class="emphasis"><em>std::end()</em></span> are
overloaded. The increment-operation switches the context and transfers data.
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">FinalEOL</span><span class="special">{</span>
<span class="special">~</span><span class="identifier">FinalEOL</span><span class="special">(){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="keyword">const</span> <span class="keyword">int</span> <span class="identifier">num</span><span class="special">=</span><span class="number">5</span><span class="special">,</span> <span class="identifier">width</span><span class="special">=</span><span class="number">15</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="identifier">writer</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">in</span><span class="special">){</span>
<span class="comment">// finish the last line when we leave by whatever means</span>
<span class="identifier">FinalEOL</span> <span class="identifier">eol</span><span class="special">;</span>
<span class="comment">// pull values from upstream, lay them out 'num' to a line</span>
<span class="keyword">for</span> <span class="special">(;;){</span>
<span class="keyword">for</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span><span class="special">=</span><span class="number">0</span><span class="special">;</span><span class="identifier">i</span><span class="special">&lt;</span><span class="identifier">num</span><span class="special">;++</span><span class="identifier">i</span><span class="special">){</span>
<span class="comment">// when we exhaust the input, stop</span>
<span class="keyword">if</span><span class="special">(!</span><span class="identifier">in</span><span class="special">)</span> <span class="keyword">return</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setw</span><span class="special">(</span><span class="identifier">width</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">in</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="comment">// now that we've handled this item, advance to next</span>
<span class="identifier">in</span><span class="special">();</span>
<span class="special">}</span>
<span class="comment">// after 'num' items, line break</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;</span> <span class="identifier">words</span><span class="special">{</span>
<span class="string">"peas"</span><span class="special">,</span> <span class="string">"porridge"</span><span class="special">,</span> <span class="string">"hot"</span><span class="special">,</span> <span class="string">"peas"</span><span class="special">,</span>
<span class="string">"porridge"</span><span class="special">,</span> <span class="string">"cold"</span><span class="special">,</span> <span class="string">"peas"</span><span class="special">,</span> <span class="string">"porridge"</span><span class="special">,</span>
<span class="string">"in"</span><span class="special">,</span> <span class="string">"the"</span><span class="special">,</span> <span class="string">"pot"</span><span class="special">,</span> <span class="string">"nine"</span><span class="special">,</span>
<span class="string">"days"</span><span class="special">,</span> <span class="string">"old"</span> <span class="special">};</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">copy</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">words</span><span class="special">),</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">end</span><span class="special">(</span><span class="identifier">words</span><span class="special">),</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">writer</span><span class="special">));</span>
<span class="identifier">output</span><span class="special">:</span>
<span class="identifier">peas</span> <span class="identifier">porridge</span> <span class="identifier">hot</span> <span class="identifier">peas</span> <span class="identifier">porridge</span>
<span class="identifier">cold</span> <span class="identifier">peas</span> <span class="identifier">porridge</span> <span class="identifier">in</span> <span class="identifier">the</span>
<span class="identifier">pot</span> <span class="identifier">nine</span> <span class="identifier">days</span> <span class="identifier">old</span>
</pre>
<p>
In this example an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
is created in the main execution context accepting a lambda function (==
<span class="emphasis"><em>coroutine-function</em></span>) 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 <span class="emphasis"><em>coroutine-function</em></span>, 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 <span class="emphasis"><em>coroutine-function</em></span>
is executed in a newly created execution context which is managed by the
instance of <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>.
The main execution context passes the strings to the <span class="emphasis"><em>coroutine-function</em></span>
by calling <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>.
An <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> instance
is automatically generated by the library and passed as reference to the
lambda function. The <span class="emphasis"><em>coroutine-function</em></span> accesses the
strings passed from the main execution context by calling <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::get()</em></span>
and lays those strings out on <span class="emphasis"><em>std::cout</em></span> according the
parameters 'num' and 'width'. The local state of <span class="emphasis"><em>coroutine-function</em></span>
is preserved and will be restored after transferring execution control back
to <span class="emphasis"><em>coroutine-function</em></span>. Because <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
provides output iterators and <span class="emphasis"><em>std::begin()</em></span>/<span class="emphasis"><em>std::end()</em></span>
are overloaded, the <span class="emphasis"><em>std::copy</em></span> algorithm can be used
to iterate over the vector containing the strings and pass them one by one
to the coroutine.
</p>
<h5>
<a name="coroutine.coroutine.asymmetric.h2"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.coroutine_function"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric.coroutine_function">coroutine-function</a>
</h5>
<p>
The <span class="emphasis"><em>coroutine-function</em></span> returns <span class="emphasis"><em>void</em></span>
and takes its counterpart-coroutine as argument, so that using the coroutine
passed as argument to <span class="emphasis"><em>coroutine-function</em></span> is the only
way to transfer data and execution control back to the caller. Both coroutine
types take the same template argument. For <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
the <span class="emphasis"><em>coroutine-function</em></span> is entered at <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
construction. For <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
the <span class="emphasis"><em>coroutine-function</em></span> is not entered at <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
construction but entered by the first invocation of <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>.
After execution control is returned from <span class="emphasis"><em>coroutine-function</em></span>
the state of the coroutine can be checked via <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator
bool</em></span> returning <code class="computeroutput"><span class="keyword">true</span></code>
if the coroutine is still valid (<span class="emphasis"><em>coroutine-function</em></span>
has not terminated). Unless the first template parameter is <code class="computeroutput"><span class="keyword">void</span></code>, <code class="computeroutput"><span class="keyword">true</span></code>
also implies that a data value is available.
</p>
<h5>
<a name="coroutine.coroutine.asymmetric.h3"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.passing_data_from_a_pull_coroutine_to_main_context"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric.passing_data_from_a_pull_coroutine_to_main_context">passing
data from a pull-coroutine to main-context</a>
</h5>
<p>
In order to transfer data from an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
to the main-context the framework synthesizes an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
associated with the <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
instance in the main-context. The synthesized <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
is passed as argument to <span class="emphasis"><em>coroutine-function</em></span>. The <span class="emphasis"><em>coroutine-function</em></span>
must call this <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>
in order to transfer each data value back to the main-context. In the main-context,
the <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator bool</em></span>
determines whether the coroutine is still valid and a data value is available
or <span class="emphasis"><em>coroutine-function</em></span> has terminated (<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
is invalid; no data value available). Access to the transferred data value
is given by <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::get()</em></span>.
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">source</span><span class="special">(</span> <span class="comment">// constructor enters coroutine-function</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">){</span>
<span class="identifier">sink</span><span class="special">(</span><span class="number">1</span><span class="special">);</span> <span class="comment">// push {1} back to main-context</span>
<span class="identifier">sink</span><span class="special">(</span><span class="number">1</span><span class="special">);</span> <span class="comment">// push {1} back to main-context</span>
<span class="identifier">sink</span><span class="special">(</span><span class="number">2</span><span class="special">);</span> <span class="comment">// push {2} back to main-context</span>
<span class="identifier">sink</span><span class="special">(</span><span class="number">3</span><span class="special">);</span> <span class="comment">// push {3} back to main-context</span>
<span class="identifier">sink</span><span class="special">(</span><span class="number">5</span><span class="special">);</span> <span class="comment">// push {5} back to main-context</span>
<span class="identifier">sink</span><span class="special">(</span><span class="number">8</span><span class="special">);</span> <span class="comment">// push {8} back to main-context</span>
<span class="special">});</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">source</span><span class="special">){</span> <span class="comment">// test if pull-coroutine is valid</span>
<span class="keyword">int</span> <span class="identifier">ret</span><span class="special">=</span><span class="identifier">source</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span> <span class="comment">// access data value</span>
<span class="identifier">source</span><span class="special">();</span> <span class="comment">// context-switch to coroutine-function</span>
<span class="special">}</span>
</pre>
<h5>
<a name="coroutine.coroutine.asymmetric.h4"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.passing_data_from_main_context_to_a_push_coroutine"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric.passing_data_from_main_context_to_a_push_coroutine">passing
data from main-context to a push-coroutine</a>
</h5>
<p>
In order to transfer data to an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
from the main-context the framework synthesizes an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
associated with the <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
instance in the main-context. The synthesized <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
is passed as argument to <span class="emphasis"><em>coroutine-function</em></span>. The main-context
must call this <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>
in order to transfer each data value into the <span class="emphasis"><em>coroutine-function</em></span>.
Access to the transferred data value is given by <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::get()</em></span>.
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="identifier">sink</span><span class="special">(</span> <span class="comment">// constructor does NOT enter coroutine-function</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span><span class="special">:</span><span class="identifier">source</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">i</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">v</span><span class="special">{</span><span class="number">1</span><span class="special">,</span><span class="number">1</span><span class="special">,</span><span class="number">2</span><span class="special">,</span><span class="number">3</span><span class="special">,</span><span class="number">5</span><span class="special">,</span><span class="number">8</span><span class="special">,</span><span class="number">13</span><span class="special">,</span><span class="number">21</span><span class="special">,</span><span class="number">34</span><span class="special">,</span><span class="number">55</span><span class="special">};</span>
<span class="keyword">for</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">i</span><span class="special">:</span><span class="identifier">v</span><span class="special">){</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">i</span><span class="special">);</span> <span class="comment">// push {i} to coroutine-function</span>
<span class="special">}</span>
</pre>
<h5>
<a name="coroutine.coroutine.asymmetric.h5"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.accessing_parameters"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric.accessing_parameters">accessing
parameters</a>
</h5>
<p>
Parameters returned from or transferred to the <span class="emphasis"><em>coroutine-function</em></span>
can be accessed with <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::get()</em></span>.
</p>
<p>
Splitting-up the access of parameters from context switch function enables
to check if <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
is valid after return from <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator()</em></span>,
e.g. <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> has values
and <span class="emphasis"><em>coroutine-function</em></span> has not terminated.
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span><span class="keyword">int</span><span class="special">&gt;&gt;::</span><span class="identifier">push_type</span> <span class="identifier">sink</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span><span class="keyword">int</span><span class="special">&gt;&gt;::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
<span class="comment">// access tuple {7,11}; x==7 y==1</span>
<span class="keyword">int</span> <span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">tie</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">)=</span><span class="identifier">source</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">});</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_tuple</span><span class="special">(</span><span class="number">7</span><span class="special">,</span><span class="number">11</span><span class="special">));</span>
</pre>
<h5>
<a name="coroutine.coroutine.asymmetric.h6"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.exceptions"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric.exceptions">exceptions</a>
</h5>
<p>
An exception thrown inside an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>'s
<span class="emphasis"><em>coroutine-function</em></span> before its first call to <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>
will be re-thrown by the <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
constructor. After an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>'s
<span class="emphasis"><em>coroutine-function</em></span>'s first call to <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>,
any subsequent exception inside that <span class="emphasis"><em>coroutine-function</em></span>
will be re-thrown by <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator()</em></span>.
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::get()</em></span> does
not throw.
</p>
<p>
An exception thrown inside an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>'s
<span class="emphasis"><em>coroutine-function</em></span> will be re-thrown by <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>.
</p>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Code executed by <span class="emphasis"><em>coroutine-function</em></span> must not prevent
the propagation of the <span class="emphasis"><em>detail::forced_unwind</em></span> exception.
Absorbing that exception will cause stack unwinding to fail. Thus, any
code that catches all exceptions must re-throw any pending <span class="emphasis"><em>detail::forced_unwind</em></span>
exception.
</p></td></tr>
</table></div>
<pre class="programlisting"><span class="keyword">try</span> <span class="special">{</span>
<span class="comment">// code that might throw</span>
<span class="special">}</span> <span class="keyword">catch</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">forced_unwind</span><span class="special">&amp;)</span> <span class="special">{</span>
<span class="keyword">throw</span><span class="special">;</span>
<span class="special">}</span> <span class="keyword">catch</span><span class="special">(...)</span> <span class="special">{</span>
<span class="comment">// possibly not re-throw pending exception</span>
<span class="special">}</span>
</pre>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Do not jump from inside a catch block and then re-throw the exception in
another execution context.
</p></td></tr>
</table></div>
<h5>
<a name="coroutine.coroutine.asymmetric.h7"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.stack_unwinding"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric.stack_unwinding">Stack
unwinding</a>
</h5>
<p>
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 <code class="computeroutput"><span class="identifier">attributes</span></code>
argument of the coroutine constructor indicates whether the destructor should
unwind the stack (stack is unwound by default).
</p>
<p>
Stack unwinding assumes the following preconditions:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
The coroutine is not <span class="emphasis"><em>not-a-coroutine</em></span>
</li>
<li class="listitem">
The coroutine is not complete
</li>
<li class="listitem">
The coroutine is not running
</li>
<li class="listitem">
The coroutine owns a stack
</li>
</ul></div>
<p>
After unwinding, a <span class="emphasis"><em>coroutine</em></span> is complete.
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">X</span> <span class="special">{</span>
<span class="identifier">X</span><span class="special">(){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="string">"X()"</span><span class="special">&lt;&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">~</span><span class="identifier">X</span><span class="special">(){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="string">"~X()"</span><span class="special">&lt;&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="identifier">sink</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
<span class="identifier">X</span> <span class="identifier">x</span><span class="special">;</span>
<span class="keyword">for</span><span class="special">(</span><span class="keyword">int</span><span class="special">=</span><span class="number">0</span><span class="special">;;++</span><span class="identifier">i</span><span class="special">){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="string">"fn(): "</span><span class="special">&lt;&lt;</span><span class="identifier">i</span><span class="special">&lt;&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// transfer execution control back to main()</span>
<span class="identifier">source</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="identifier">sink</span><span class="special">();</span>
<span class="identifier">sink</span><span class="special">();</span>
<span class="identifier">sink</span><span class="special">();</span>
<span class="identifier">sink</span><span class="special">();</span>
<span class="identifier">sink</span><span class="special">();</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="string">"sink is complete: "</span><span class="special">&lt;&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">boolalpha</span><span class="special">&lt;&lt;!</span><span class="identifier">sink</span><span class="special">&lt;&lt;</span><span class="string">"\n"</span><span class="special">;</span>
<span class="special">}</span>
<span class="identifier">output</span><span class="special">:</span>
<span class="identifier">X</span><span class="special">()</span>
<span class="identifier">fn</span><span class="special">():</span> <span class="number">0</span>
<span class="identifier">fn</span><span class="special">():</span> <span class="number">1</span>
<span class="identifier">fn</span><span class="special">():</span> <span class="number">2</span>
<span class="identifier">fn</span><span class="special">():</span> <span class="number">3</span>
<span class="identifier">fn</span><span class="special">():</span> <span class="number">4</span>
<span class="identifier">fn</span><span class="special">():</span> <span class="number">5</span>
<span class="identifier">sink</span> <span class="identifier">is</span> <span class="identifier">complete</span><span class="special">:</span> <span class="keyword">false</span>
<span class="special">~</span><span class="identifier">X</span><span class="special">()</span>
</pre>
<h5>
<a name="coroutine.coroutine.asymmetric.h8"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.range_iterators"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric.range_iterators">Range
iterators</a>
</h5>
<p>
<span class="bold"><strong>Boost.Coroutine</strong></span> provides output- and input-iterators
using <span class="bold"><strong>Boost.Range</strong></span>. <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>
can be used via input-iterators using <span class="emphasis"><em>std::begin()</em></span> and
<span class="emphasis"><em>std::end()</em></span>.
</p>
<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">number</span><span class="special">=</span><span class="number">2</span><span class="special">,</span><span class="identifier">exponent</span><span class="special">=</span><span class="number">8</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span> <span class="keyword">int</span> <span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">source</span><span class="special">(</span>
<span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span> <span class="keyword">int</span> <span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">){</span>
<span class="keyword">int</span> <span class="identifier">counter</span><span class="special">=</span><span class="number">0</span><span class="special">,</span><span class="identifier">result</span><span class="special">=</span><span class="number">1</span><span class="special">;</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">counter</span><span class="special">++&lt;</span><span class="identifier">exponent</span><span class="special">){</span>
<span class="identifier">result</span><span class="special">=</span><span class="identifier">result</span><span class="special">*</span><span class="identifier">number</span><span class="special">;</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">result</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">auto</span> <span class="identifier">i</span><span class="special">:</span><span class="identifier">source</span><span class="special">)</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">i</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span><span class="special">;</span>
<span class="identifier">output</span><span class="special">:</span>
<span class="number">2</span> <span class="number">4</span> <span class="number">8</span> <span class="number">16</span> <span class="number">32</span> <span class="number">64</span> <span class="number">128</span> <span class="number">256</span>
</pre>
<p>
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::iterator::operator++()</em></span>
corresponds to <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator()</em></span>;
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::iterator::operator*()</em></span>
roughly corresponds to <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::get()</em></span>.
An iterator originally obtained from <span class="emphasis"><em>std::begin()</em></span> of
an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> compares
equal to an iterator obtained from <span class="emphasis"><em>std::end()</em></span> of that
same <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span> instance
when its <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator bool</em></span>
would return <code class="computeroutput"><span class="keyword">false</span></code>].
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
If <code class="computeroutput"><span class="identifier">T</span></code> is a move-only type,
then <span class="emphasis"><em>asymmetric_coroutine&lt;T&gt;::pull_type::iterator</em></span>
may only be dereferenced once before it is incremented again.
</p></td></tr>
</table></div>
<p>
Output-iterators can be created from <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>.
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="identifier">sink</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">source</span><span class="special">){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">source</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span><span class="special">;</span>
<span class="identifier">source</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">v</span><span class="special">{</span><span class="number">1</span><span class="special">,</span><span class="number">1</span><span class="special">,</span><span class="number">2</span><span class="special">,</span><span class="number">3</span><span class="special">,</span><span class="number">5</span><span class="special">,</span><span class="number">8</span><span class="special">,</span><span class="number">13</span><span class="special">,</span><span class="number">21</span><span class="special">,</span><span class="number">34</span><span class="special">,</span><span class="number">55</span><span class="special">};</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">copy</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">v</span><span class="special">),</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">end</span><span class="special">(</span><span class="identifier">v</span><span class="special">),</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">sink</span><span class="special">));</span>
</pre>
<p>
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::iterator::operator*()</em></span>
roughly corresponds to <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>.
An iterator originally obtained from <span class="emphasis"><em>std::begin()</em></span> of
an <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span> compares
equal to an iterator obtained from <span class="emphasis"><em>std::end()</em></span> of that
same <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span> instance
when its <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator bool</em></span>
would return <code class="computeroutput"><span class="keyword">false</span></code>.
</p>
<h5>
<a name="coroutine.coroutine.asymmetric.h9"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.exit_a__emphasis_coroutine_function__emphasis_"></a></span><a class="link" href="asymmetric.html#coroutine.coroutine.asymmetric.exit_a__emphasis_coroutine_function__emphasis_">Exit
a <span class="emphasis"><em>coroutine-function</em></span></a>
</h5>
<p>
<span class="emphasis"><em>coroutine-function</em></span> is exited with a simple return statement
jumping back to the calling routine. The <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>,
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span> becomes complete,
e.g. <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator bool</em></span>,
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator bool</em></span>
will return <code class="computeroutput"><span class="keyword">false</span></code>.
</p>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
After returning from <span class="emphasis"><em>coroutine-function</em></span> the <span class="emphasis"><em>coroutine</em></span>
is complete (can not resumed with <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>,
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator()</em></span>).
</p></td></tr>
</table></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../coroutine.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../coroutine.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="asymmetric/pull_coro.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,400 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class asymmetric_coroutine&lt;&gt;::pull_type</title>
<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../asymmetric.html" title="Asymmetric coroutine">
<link rel="prev" href="../asymmetric.html" title="Asymmetric coroutine">
<link rel="next" href="push_coro.html" title="Class asymmetric_coroutine&lt;&gt;::push_type">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../asymmetric.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../asymmetric.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="push_coro.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="coroutine.coroutine.asymmetric.pull_coro"></a><a class="link" href="pull_coro.html" title="Class asymmetric_coroutine&lt;&gt;::pull_type">Class <code class="computeroutput"><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">pull_type</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">asymmetric_coroutine</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">pull_type</span>
<span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">pull_type</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span> <span class="special">&gt;</span>
<span class="identifier">pull_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span> <span class="special">=</span> <span class="identifier">attributes</span><span class="special">()</span> <span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span> <span class="special">&gt;</span>
<span class="identifier">pull_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">,</span> <span class="identifier">StackAllocator</span> <span class="identifier">stack_alloc</span><span class="special">);</span>
<span class="identifier">pull_type</span><span class="special">(</span> <span class="identifier">pull_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">pull_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">pull_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="special">~</span><span class="identifier">pull_type</span><span class="special">();</span>
<span class="identifier">pull_type</span><span class="special">(</span> <span class="identifier">pull_type</span> <span class="special">&amp;&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">pull_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">pull_type</span> <span class="special">&amp;&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">operator</span> <span class="identifier">unspecified</span><span class="special">-</span><span class="keyword">bool</span><span class="special">-</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">pull_type</span> <span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">pull_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()();</span>
<span class="identifier">R</span> <span class="identifier">get</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">r</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="identifier">range_iterator</span><span class="special">&lt;</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">begin</span><span class="special">(</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&amp;);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="identifier">range_iterator</span><span class="special">&lt;</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">end</span><span class="special">(</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&amp;);</span>
</pre>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h0"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__pull_type__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__pull_type__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">pull_type</span><span class="special">()</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine representing <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h1"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__pull_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__pull_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span>
<span class="special">&gt;</span> <span class="identifier">pull_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span>
<span class="keyword">const</span><span class="special">&amp;</span>
<span class="identifier">attr</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">size</span></code> &gt;= minimum_stacksize(),
<code class="computeroutput"><span class="identifier">size</span></code> &lt;= maximum_stacksize()
when ! is_stack_unbounded().
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine which will execute <code class="computeroutput"><span class="identifier">fn</span></code>,
and enters it. Argument <code class="computeroutput"><span class="identifier">attr</span></code>
determines stack clean-up.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Exceptions thrown inside <span class="emphasis"><em>coroutine-function</em></span>.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h2"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__pull_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__pull_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span> <span class="special">&gt;</span>
<span class="identifier">pull_type</span><span class="special">(</span>
<span class="identifier">Fn</span> <span class="special">&amp;&amp;</span>
<span class="identifier">fn</span><span class="special">,</span>
<span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">,</span> <span class="identifier">StackAllocator</span>
<span class="keyword">const</span><span class="special">&amp;</span>
<span class="identifier">stack_alloc</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">size</span></code> &gt;= minimum_stacksize(),
<code class="computeroutput"><span class="identifier">size</span></code> &lt;= maximum_stacksize()
when ! is_stack_unbounded().
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine which will execute <code class="computeroutput"><span class="identifier">fn</span></code>.
Argument <code class="computeroutput"><span class="identifier">attr</span></code> determines
stack clean-up. For allocating/deallocating the stack <code class="computeroutput"><span class="identifier">stack_alloc</span></code> is used.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Exceptions thrown inside <span class="emphasis"><em>coroutine-function</em></span>.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h3"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__special_____phrase__phrase_role__identifier__pull_type__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__special_____phrase__phrase_role__identifier__pull_type__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="special">~</span><span class="identifier">pull_type</span><span class="special">()</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Destroys the context and deallocates the stack.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h4"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__pull_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__pull_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__pull_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__pull_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">pull_type</span><span class="special">(</span>
<span class="identifier">pull_type</span> <span class="special">&amp;&amp;</span>
<span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Moves the internal data of <code class="computeroutput"><span class="identifier">other</span></code>
to <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
<code class="computeroutput"><span class="identifier">other</span></code> becomes <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h5"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__pull_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special______phrase___phrase_role__identifier__pull_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__pull_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special______phrase___phrase_role__identifier__pull_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">pull_type</span> <span class="special">&amp;</span>
<span class="keyword">operator</span><span class="special">=(</span>
<span class="identifier">pull_type</span> <span class="special">&amp;&amp;</span>
<span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Destroys the internal data of <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> and moves the internal data of
<code class="computeroutput"><span class="identifier">other</span></code> to <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
<code class="computeroutput"><span class="identifier">other</span></code> becomes <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h6"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__operator__phrase___phrase_role__identifier__unspecified__phrase__phrase_role__special_____phrase__phrase_role__keyword__bool__phrase__phrase_role__special_____phrase__phrase_role__identifier__type__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__operator__phrase___phrase_role__identifier__unspecified__phrase__phrase_role__special_____phrase__phrase_role__keyword__bool__phrase__phrase_role__special_____phrase__phrase_role__identifier__type__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___code_"><code class="computeroutput"><span class="keyword">operator</span> <span class="identifier">unspecified</span><span class="special">-</span><span class="keyword">bool</span><span class="special">-</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to <span class="emphasis"><em>not-a-coroutine</em></span> or the coroutine-function
has returned (completed), the function returns <code class="computeroutput"><span class="keyword">false</span></code>.
Otherwise <code class="computeroutput"><span class="keyword">true</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h7"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___code_"><code class="computeroutput"><span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to <span class="emphasis"><em>not-a-coroutine</em></span> or the coroutine-function
has returned (completed), the function returns <code class="computeroutput"><span class="keyword">true</span></code>.
Otherwise <code class="computeroutput"><span class="keyword">false</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h8"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__pull_type__phrase__phrase_role__special___lt__gt___phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special________phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__pull_type__phrase__phrase_role__special___lt__gt___phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special________phrase___code_"><code class="computeroutput"><span class="identifier">pull_type</span><span class="special">&lt;&gt;</span>
<span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()()</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
is not a <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Execution control is transferred to <span class="emphasis"><em>coroutine-function</em></span>
(no parameter is passed to the coroutine-function).
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Exceptions thrown inside <span class="emphasis"><em>coroutine-function</em></span>.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h9"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__r__phrase___phrase_role__identifier__get__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__r__phrase___phrase_role__identifier__get__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">R</span> <span class="identifier">get</span><span class="special">()</span></code></a>
</h6>
<pre class="programlisting"><span class="identifier">R</span> <span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">,</span><span class="identifier">StackAllocator</span><span class="special">&gt;::</span><span class="identifier">pull_type</span><span class="special">::</span><span class="identifier">get</span><span class="special">();</span>
<span class="identifier">R</span><span class="special">&amp;</span> <span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&amp;,</span><span class="identifier">StackAllocator</span><span class="special">&gt;::</span><span class="identifier">pull_type</span><span class="special">::</span><span class="identifier">get</span><span class="special">();</span>
<span class="keyword">void</span> <span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">,</span><span class="identifier">StackAllocator</span><span class="special">&gt;::</span><span class="identifier">pull_type</span><span class="special">::</span><span class="identifier">get</span><span class="special">()=</span><span class="keyword">delete</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
is not a <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns data transferred from coroutine-function via <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator()</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">invalid_result</span></code>
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="identifier">R</span></code> is a move-only
type, you may only call <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code> once before the next <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator()</em></span>
call.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h10"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__void__phrase___phrase_role__identifier__swap__phrase__phrase_role__special_____phrase___phrase_role__identifier__pull_type__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__void__phrase___phrase_role__identifier__swap__phrase__phrase_role__special_____phrase___phrase_role__identifier__pull_type__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">pull_type</span>
<span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Swaps the internal data from <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> with the values of <code class="computeroutput"><span class="identifier">other</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h11"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro.non_member_function__code__phrase_role__identifier__swap__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro.non_member_function__code__phrase_role__identifier__swap__phrase__phrase_role__special______phrase___code_">Non-member
function <code class="computeroutput"><span class="identifier">swap</span><span class="special">()</span></code></a>
</h6>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">r</span><span class="special">);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
As if 'l.swap( r)'.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h12"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__pull_type__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__r__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__pull_type__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__r__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
function <code class="computeroutput"><span class="identifier">begin</span><span class="special">(</span>
<span class="identifier">pull_type</span><span class="special">&lt;</span>
<span class="identifier">R</span> <span class="special">&gt;</span>
<span class="special">&amp;)</span></code></a>
</h6>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="identifier">range_iterator</span><span class="special">&lt;</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">begin</span><span class="special">(</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&amp;);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns a range-iterator (input-iterator).
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.pull_coro.h13"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.pull_coro.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__pull_type__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__r__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine.coroutine.asymmetric.pull_coro.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__pull_type__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__r__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
function <code class="computeroutput"><span class="identifier">end</span><span class="special">(</span>
<span class="identifier">pull_type</span><span class="special">&lt;</span>
<span class="identifier">R</span> <span class="special">&gt;</span>
<span class="special">&amp;)</span></code></a>
</h6>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="identifier">range_iterator</span><span class="special">&lt;</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">end</span><span class="special">(</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span> <span class="special">&gt;</span> <span class="special">&amp;);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns an end range-iterator (input-iterator).
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
When first obtained from <code class="computeroutput"><span class="identifier">begin</span><span class="special">(</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span>
<span class="special">&gt;</span> <span class="special">&amp;)</span></code>,
or after some number of increment operations, an iterator will compare
equal to the iterator returned by <code class="computeroutput"><span class="identifier">end</span><span class="special">(</span> <span class="identifier">pull_type</span><span class="special">&lt;</span> <span class="identifier">R</span>
<span class="special">&gt;</span> <span class="special">&amp;)</span></code>
when the corresponding <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::operator
bool</em></span> would return <code class="computeroutput"><span class="keyword">false</span></code>.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../asymmetric.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../asymmetric.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="push_coro.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,363 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class asymmetric_coroutine&lt;&gt;::push_type</title>
<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../asymmetric.html" title="Asymmetric coroutine">
<link rel="prev" href="pull_coro.html" title="Class asymmetric_coroutine&lt;&gt;::pull_type">
<link rel="next" href="../symmetric.html" title="Symmetric coroutine">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="pull_coro.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../asymmetric.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../symmetric.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="coroutine.coroutine.asymmetric.push_coro"></a><a class="link" href="push_coro.html" title="Class asymmetric_coroutine&lt;&gt;::push_type">Class <code class="computeroutput"><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">push_type</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">asymmetric_coroutine</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">push_type</span>
<span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">push_type</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span> <span class="special">&gt;</span>
<span class="identifier">push_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span> <span class="special">=</span> <span class="identifier">attributes</span><span class="special">()</span> <span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span> <span class="special">&gt;</span>
<span class="identifier">push_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">,</span> <span class="identifier">StackAllocator</span> <span class="identifier">stack_alloc</span><span class="special">);</span>
<span class="identifier">push_type</span><span class="special">(</span> <span class="identifier">push_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">push_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="special">~</span><span class="identifier">push_type</span><span class="special">();</span>
<span class="identifier">push_type</span><span class="special">(</span> <span class="identifier">push_type</span> <span class="special">&amp;&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">push_type</span> <span class="special">&amp;&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">operator</span> <span class="identifier">unspecified</span><span class="special">-</span><span class="keyword">bool</span><span class="special">-</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">Arg</span> <span class="identifier">arg</span><span class="special">);</span>
<span class="special">};</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">r</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="identifier">range_iterator</span><span class="special">&lt;</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">begin</span><span class="special">(</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&amp;);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="identifier">range_iterator</span><span class="special">&lt;</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">end</span><span class="special">(</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&amp;);</span>
</pre>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h0"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__identifier__push_type__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__identifier__push_type__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">push_type</span><span class="special">()</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine representing <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h1"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__push_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__push_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span>
<span class="special">&gt;</span> <span class="identifier">push_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span>
<span class="keyword">const</span><span class="special">&amp;</span>
<span class="identifier">attr</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">size</span></code> &gt;= minimum_stacksize(),
<code class="computeroutput"><span class="identifier">size</span></code> &lt;= maximum_stacksize()
when ! is_stack_unbounded().
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine which will execute <code class="computeroutput"><span class="identifier">fn</span></code>.
Argument <code class="computeroutput"><span class="identifier">attr</span></code> determines
stack clean-up.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h2"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__push_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__push_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span> <span class="special">&gt;</span>
<span class="identifier">push_type</span><span class="special">(</span>
<span class="identifier">Fn</span> <span class="special">&amp;&amp;</span>
<span class="identifier">fn</span><span class="special">,</span>
<span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">,</span> <span class="identifier">StackAllocator</span>
<span class="keyword">const</span><span class="special">&amp;</span>
<span class="identifier">stack_alloc</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">size</span></code> &gt;= minimum_stacksize(),
<code class="computeroutput"><span class="identifier">size</span></code> &lt;= maximum_stacksize()
when ! is_stack_unbounded().
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine which will execute <code class="computeroutput"><span class="identifier">fn</span></code>.
Argument <code class="computeroutput"><span class="identifier">attr</span></code> determines
stack clean-up. For allocating/deallocating the stack <code class="computeroutput"><span class="identifier">stack_alloc</span></code> is used.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h3"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__special_____phrase__phrase_role__identifier__push_type__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__special_____phrase__phrase_role__identifier__push_type__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="special">~</span><span class="identifier">push_type</span><span class="special">()</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Destroys the context and deallocates the stack.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h4"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__identifier__push_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__push_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__identifier__push_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__push_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">push_type</span><span class="special">(</span>
<span class="identifier">push_type</span> <span class="special">&amp;&amp;</span>
<span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Moves the internal data of <code class="computeroutput"><span class="identifier">other</span></code>
to <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
<code class="computeroutput"><span class="identifier">other</span></code> becomes <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h5"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__identifier__push_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special______phrase___phrase_role__identifier__push_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__identifier__push_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special______phrase___phrase_role__identifier__push_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">push_type</span> <span class="special">&amp;</span>
<span class="keyword">operator</span><span class="special">=(</span>
<span class="identifier">push_type</span> <span class="special">&amp;&amp;</span>
<span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Destroys the internal data of <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> and moves the internal data of
<code class="computeroutput"><span class="identifier">other</span></code> to <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
<code class="computeroutput"><span class="identifier">other</span></code> becomes <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h6"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__operator__phrase___phrase_role__identifier__unspecified__phrase__phrase_role__special_____phrase__phrase_role__keyword__bool__phrase__phrase_role__special_____phrase__phrase_role__identifier__type__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__operator__phrase___phrase_role__identifier__unspecified__phrase__phrase_role__special_____phrase__phrase_role__keyword__bool__phrase__phrase_role__special_____phrase__phrase_role__identifier__type__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___code_"><code class="computeroutput"><span class="keyword">operator</span> <span class="identifier">unspecified</span><span class="special">-</span><span class="keyword">bool</span><span class="special">-</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to <span class="emphasis"><em>not-a-coroutine</em></span> or the coroutine-function
has returned (completed), the function returns <code class="computeroutput"><span class="keyword">false</span></code>.
Otherwise <code class="computeroutput"><span class="keyword">true</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h7"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___code_"><code class="computeroutput"><span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to <span class="emphasis"><em>not-a-coroutine</em></span> or the coroutine-function
has returned (completed), the function returns <code class="computeroutput"><span class="keyword">true</span></code>.
Otherwise <code class="computeroutput"><span class="keyword">false</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h8"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__identifier__push_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase__phrase_role__identifier__arg__phrase___phrase_role__identifier__arg__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__identifier__push_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase__phrase_role__identifier__arg__phrase___phrase_role__identifier__arg__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">push_type</span> <span class="special">&amp;</span>
<span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Arg</span> <span class="identifier">arg</span><span class="special">)</span></code></a>
</h6>
<pre class="programlisting"><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">Arg</span><span class="special">&gt;::</span><span class="identifier">push_type</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Arg</span><span class="special">);</span>
<span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">Arg</span><span class="special">&amp;&gt;::</span><span class="identifier">push_type</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Arg</span><span class="special">&amp;);</span>
<span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">push_type</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()();</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
operator unspecified-bool-type() returns <code class="computeroutput"><span class="keyword">true</span></code>
for <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Execution control is transferred to <span class="emphasis"><em>coroutine-function</em></span>
and the argument <code class="computeroutput"><span class="identifier">arg</span></code>
is passed to the coroutine-function.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Exceptions thrown inside <span class="emphasis"><em>coroutine-function</em></span>.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h9"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__void__phrase___phrase_role__identifier__swap__phrase__phrase_role__special_____phrase___phrase_role__identifier__push_type__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro._code__phrase_role__keyword__void__phrase___phrase_role__identifier__swap__phrase__phrase_role__special_____phrase___phrase_role__identifier__push_type__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">push_type</span>
<span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Swaps the internal data from <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> with the values of <code class="computeroutput"><span class="identifier">other</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h10"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro.non_member_function__code__phrase_role__identifier__swap__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro.non_member_function__code__phrase_role__identifier__swap__phrase__phrase_role__special______phrase___code_">Non-member
function <code class="computeroutput"><span class="identifier">swap</span><span class="special">()</span></code></a>
</h6>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">r</span><span class="special">);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
As if 'l.swap( r)'.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h11"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__push_type__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__arg__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__push_type__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__arg__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
function <code class="computeroutput"><span class="identifier">begin</span><span class="special">(</span>
<span class="identifier">push_type</span><span class="special">&lt;</span>
<span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="special">&amp;)</span></code></a>
</h6>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="identifier">range_iterator</span><span class="special">&lt;</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">begin</span><span class="special">(</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&amp;);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns a range-iterator (output-iterator).
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.asymmetric.push_coro.h12"></a>
<span class="phrase"><a name="coroutine.coroutine.asymmetric.push_coro.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__push_type__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__arg__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine.coroutine.asymmetric.push_coro.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__push_type__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__arg__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
function <code class="computeroutput"><span class="identifier">end</span><span class="special">(</span>
<span class="identifier">push_type</span><span class="special">&lt;</span>
<span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="special">&amp;)</span></code></a>
</h6>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="identifier">range_iterator</span><span class="special">&lt;</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">end</span><span class="special">(</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;</span> <span class="special">&amp;);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns a end range-iterator (output-iterator).
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
When first obtained from <code class="computeroutput"><span class="identifier">begin</span><span class="special">(</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">R</span>
<span class="special">&gt;</span> <span class="special">&amp;)</span></code>,
or after some number of increment operations, an iterator will compare
equal to the iterator returned by <code class="computeroutput"><span class="identifier">end</span><span class="special">(</span> <span class="identifier">push_type</span><span class="special">&lt;</span> <span class="identifier">R</span>
<span class="special">&gt;</span> <span class="special">&amp;)</span></code>
when the corresponding <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type::operator
bool</em></span> would return <code class="computeroutput"><span class="keyword">false</span></code>.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="pull_coro.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../asymmetric.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../symmetric.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,352 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Symmetric coroutine</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../coroutine.html" title="Coroutine">
<link rel="prev" href="asymmetric/push_coro.html" title="Class asymmetric_coroutine&lt;&gt;::push_type">
<link rel="next" href="symmetric/symmetric_coro.html" title="Class symmetric_coroutine&lt;&gt;::call_type">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="asymmetric/push_coro.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../coroutine.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="symmetric/symmetric_coro.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="coroutine.coroutine.symmetric"></a><a class="link" href="symmetric.html" title="Symmetric coroutine">Symmetric coroutine</a>
</h3></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="symmetric/symmetric_coro.html">Class
<code class="computeroutput"><span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">call_type</span></code></a></span></dt>
<dt><span class="section"><a href="symmetric/yield_coro.html">Class <code class="computeroutput"><span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">yield_type</span></code></a></span></dt>
</dl></div>
<p>
In contrast to asymmetric coroutines, where the relationship between caller
and callee is fixed, symmetric coroutines are able to transfer execution
control to any other (symmetric) coroutine. E.g. a symmetric coroutine is
not required to return to its direct caller.
</p>
<h5>
<a name="coroutine.coroutine.symmetric.h0"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric._emphasis_symmetric_coroutine_lt__gt___call_type__emphasis_"></a></span><a class="link" href="symmetric.html#coroutine.coroutine.symmetric._emphasis_symmetric_coroutine_lt__gt___call_type__emphasis_"><span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span></a>
</h5>
<p>
<span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span> starts a symmetric
coroutine and transfers its parameter to its <span class="emphasis"><em>coroutine-function</em></span>.
The template parameter defines the transferred parameter type. The constructor
of <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span> takes a function
(<span class="emphasis"><em>coroutine-function</em></span>) accepting a reference to a <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type</em></span>
as argument. Instantiating a <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>
does not pass the control of execution to <span class="emphasis"><em>coroutine-function</em></span>
- instead the first call of <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>
synthesizes a <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type</em></span>
and passes it as reference to <span class="emphasis"><em>coroutine-function</em></span>.
</p>
<p>
The <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span> interface
does not contain a <span class="emphasis"><em>get()</em></span>-function: you can not retrieve
values from another execution context with this kind of coroutine object.
</p>
<h5>
<a name="coroutine.coroutine.symmetric.h1"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric._emphasis_symmetric_coroutine_lt__gt___yield_type__emphasis_"></a></span><a class="link" href="symmetric.html#coroutine.coroutine.symmetric._emphasis_symmetric_coroutine_lt__gt___yield_type__emphasis_"><span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type</em></span></a>
</h5>
<p>
<span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::operator()</em></span>
is used to transfer data and execution control to another context by calling
<span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::operator()</em></span>
with another <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>
as first argument. Alternatively, you may transfer control back to the code
that called <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>
by calling <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::operator()</em></span>
without a <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span> argument.
</p>
<p>
The class has only one template parameter defining the transferred parameter
type. Data transferred to the coroutine are accessed through <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::get()</em></span>.
</p>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
<span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type</em></span> can only be
created by the framework.
</p></td></tr>
</table></div>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">merge</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&amp;</span> <span class="identifier">a</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&amp;</span> <span class="identifier">b</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">c</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">idx_a</span><span class="special">=</span><span class="number">0</span><span class="special">,</span><span class="identifier">idx_b</span><span class="special">=</span><span class="number">0</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span><span class="special">*</span> <span class="identifier">other_a</span><span class="special">=</span><span class="number">0</span><span class="special">,*</span> <span class="identifier">other_b</span><span class="special">=</span><span class="number">0</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro_a</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_a</span><span class="special">&lt;</span><span class="identifier">a</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
<span class="special">{</span>
<span class="keyword">if</span><span class="special">(</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">]&lt;</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">])</span> <span class="comment">// test if element in array b is less than in array a</span>
<span class="identifier">yield</span><span class="special">(*</span><span class="identifier">other_b</span><span class="special">);</span> <span class="comment">// yield to coroutine coro_b</span>
<span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">++]);</span> <span class="comment">// add element to final array</span>
<span class="special">}</span>
<span class="comment">// add remaining elements of array b</span>
<span class="keyword">while</span> <span class="special">(</span> <span class="identifier">idx_b</span> <span class="special">&lt;</span> <span class="identifier">b</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
<span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span> <span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">++]);</span>
<span class="special">});</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro_b</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_b</span><span class="special">&lt;</span><span class="identifier">b</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
<span class="special">{</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">]&lt;</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">])</span> <span class="comment">// test if element in array a is less than in array b</span>
<span class="identifier">yield</span><span class="special">(*</span><span class="identifier">other_a</span><span class="special">);</span> <span class="comment">// yield to coroutine coro_a</span>
<span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">++]);</span> <span class="comment">// add element to final array</span>
<span class="special">}</span>
<span class="comment">// add remaining elements of array a</span>
<span class="keyword">while</span> <span class="special">(</span> <span class="identifier">idx_a</span> <span class="special">&lt;</span> <span class="identifier">a</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
<span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span> <span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">++]);</span>
<span class="special">});</span>
<span class="identifier">other_a</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="identifier">coro_a</span><span class="special">;</span>
<span class="identifier">other_b</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="identifier">coro_b</span><span class="special">;</span>
<span class="identifier">coro_a</span><span class="special">();</span> <span class="comment">// enter coroutine-fn of coro_a</span>
<span class="keyword">return</span> <span class="identifier">c</span><span class="special">;</span>
<span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span> <span class="keyword">int</span> <span class="special">&gt;</span> <span class="identifier">a</span> <span class="special">=</span> <span class="special">{</span><span class="number">1</span><span class="special">,</span><span class="number">5</span><span class="special">,</span><span class="number">6</span><span class="special">,</span><span class="number">10</span><span class="special">};</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span> <span class="keyword">int</span> <span class="special">&gt;</span> <span class="identifier">b</span> <span class="special">=</span> <span class="special">{</span><span class="number">2</span><span class="special">,</span><span class="number">4</span><span class="special">,</span><span class="number">7</span><span class="special">,</span><span class="number">8</span><span class="special">,</span><span class="number">9</span><span class="special">,</span><span class="number">13</span><span class="special">};</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span> <span class="keyword">int</span> <span class="special">&gt;</span> <span class="identifier">c</span> <span class="special">=</span> <span class="identifier">merge</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span><span class="identifier">b</span><span class="special">);</span>
<span class="identifier">print</span><span class="special">(</span><span class="identifier">a</span><span class="special">);</span>
<span class="identifier">print</span><span class="special">(</span><span class="identifier">b</span><span class="special">);</span>
<span class="identifier">print</span><span class="special">(</span><span class="identifier">c</span><span class="special">);</span>
<span class="identifier">output</span><span class="special">:</span>
<span class="identifier">a</span> <span class="special">:</span> <span class="number">1</span> <span class="number">5</span> <span class="number">6</span> <span class="number">10</span>
<span class="identifier">b</span> <span class="special">:</span> <span class="number">2</span> <span class="number">4</span> <span class="number">7</span> <span class="number">8</span> <span class="number">9</span> <span class="number">13</span>
<span class="identifier">c</span> <span class="special">:</span> <span class="number">1</span> <span class="number">2</span> <span class="number">4</span> <span class="number">5</span> <span class="number">6</span> <span class="number">7</span> <span class="number">8</span> <span class="number">9</span> <span class="number">10</span> <span class="number">13</span>
</pre>
<p>
In this example two <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>
are created in the main execution context accepting a lambda function (==
<span class="emphasis"><em>coroutine-function</em></span>) which merges elements of two sorted
arrays into a third array. <code class="computeroutput"><span class="identifier">coro_a</span><span class="special">()</span></code> enters the <span class="emphasis"><em>coroutine-function</em></span>
of <code class="computeroutput"><span class="identifier">coro_a</span></code> cycling through
the array and testing if the actual element in the other array is less than
the element in the local one. If so, the coroutine yields to the other coroutine
<code class="computeroutput"><span class="identifier">coro_b</span></code> using <code class="computeroutput"><span class="identifier">yield</span><span class="special">(*</span><span class="identifier">other_b</span><span class="special">)</span></code>.
If the current element of the local array is less than the element of the
other array, it is put to the third array. Because the coroutine jumps back
to <code class="computeroutput"><span class="identifier">coro_a</span><span class="special">()</span></code>
(returning from this method) after leaving the <span class="emphasis"><em>coroutine-function</em></span>,
the elements of the other array will appended at the end of the third array
if all element of the local array are processed.
</p>
<h5>
<a name="coroutine.coroutine.symmetric.h2"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.coroutine_function"></a></span><a class="link" href="symmetric.html#coroutine.coroutine.symmetric.coroutine_function">coroutine-function</a>
</h5>
<p>
The <span class="emphasis"><em>coroutine-function</em></span> returns <span class="emphasis"><em>void</em></span>
and takes <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type</em></span>, providing
coroutine functionality inside the <span class="emphasis"><em>coroutine-function</em></span>,
as argument. Using this instance is the only way to transfer data and execution
control. <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span> does
not enter the <span class="emphasis"><em>coroutine-function</em></span> at <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>
construction but at the first invocation of <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>.
</p>
<p>
Unless the template parameter is <code class="computeroutput"><span class="keyword">void</span></code>,
the <span class="emphasis"><em>coroutine-function</em></span> of a <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>
can assume that (a) upon initial entry and (b) after every <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::operator()</em></span>
call, its <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::get()</em></span>
has a new value available.
</p>
<p>
However, if the template parameter is a move-only type, <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::get()</em></span>
may only be called once before the next <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::operator()</em></span>
call.
</p>
<h5>
<a name="coroutine.coroutine.symmetric.h3"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.passing_data_from_main_context_to_a_symmetric_coroutine"></a></span><a class="link" href="symmetric.html#coroutine.coroutine.symmetric.passing_data_from_main_context_to_a_symmetric_coroutine">passing
data from main-context to a symmetric-coroutine</a>
</h5>
<p>
In order to transfer data to a <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>
from the main-context the framework synthesizes a <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type</em></span>
associated with the <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>
instance. The synthesized <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type</em></span>
is passed as argument to <span class="emphasis"><em>coroutine-function</em></span>. The main-context
must call <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>
in order to transfer each data value into the <span class="emphasis"><em>coroutine-function</em></span>.
Access to the transferred data value is given by <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::yield_type::get()</em></span>.
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro</span><span class="special">(</span> <span class="comment">// constructor does NOT enter coroutine-function</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">){</span>
<span class="keyword">for</span> <span class="special">(;;)</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">yield</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span><span class="special">;</span>
<span class="identifier">yield</span><span class="special">();</span> <span class="comment">// jump back to starting context</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="identifier">coro</span><span class="special">(</span><span class="number">1</span><span class="special">);</span> <span class="comment">// transfer {1} to coroutine-function</span>
<span class="identifier">coro</span><span class="special">(</span><span class="number">2</span><span class="special">);</span> <span class="comment">// transfer {2} to coroutine-function</span>
<span class="identifier">coro</span><span class="special">(</span><span class="number">3</span><span class="special">);</span> <span class="comment">// transfer {3} to coroutine-function</span>
<span class="identifier">coro</span><span class="special">(</span><span class="number">4</span><span class="special">);</span> <span class="comment">// transfer {4} to coroutine-function</span>
<span class="identifier">coro</span><span class="special">(</span><span class="number">5</span><span class="special">);</span> <span class="comment">// transfer {5} to coroutine-function</span>
</pre>
<h5>
<a name="coroutine.coroutine.symmetric.h4"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.exceptions"></a></span><a class="link" href="symmetric.html#coroutine.coroutine.symmetric.exceptions">exceptions</a>
</h5>
<p>
An uncaught exception inside a <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span>'s
<span class="emphasis"><em>coroutine-function</em></span> will call <span class="emphasis"><em>std::terminate()</em></span>.
</p>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Code executed by coroutine must not prevent the propagation of the <span class="emphasis"><em>detail::forced_unwind</em></span>
exception. Absorbing that exception will cause stack unwinding to fail.
Thus, any code that catches all exceptions must re-throw any pending <span class="emphasis"><em>detail::forced_unwind</em></span>
exception.
</p></td></tr>
</table></div>
<pre class="programlisting"><span class="keyword">try</span> <span class="special">{</span>
<span class="comment">// code that might throw</span>
<span class="special">}</span> <span class="keyword">catch</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">forced_unwind</span><span class="special">&amp;)</span> <span class="special">{</span>
<span class="keyword">throw</span><span class="special">;</span>
<span class="special">}</span> <span class="keyword">catch</span><span class="special">(...)</span> <span class="special">{</span>
<span class="comment">// possibly not re-throw pending exception</span>
<span class="special">}</span>
</pre>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Do not jump from inside a catch block and then re-throw the exception in
another execution context.
</p></td></tr>
</table></div>
<h5>
<a name="coroutine.coroutine.symmetric.h5"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.stack_unwinding"></a></span><a class="link" href="symmetric.html#coroutine.coroutine.symmetric.stack_unwinding">Stack
unwinding</a>
</h5>
<p>
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 <code class="computeroutput"><span class="identifier">attributes</span></code>
argument of the coroutine constructor indicates whether the destructor should
unwind the stack (stack is unwound by default).
</p>
<p>
Stack unwinding assumes the following preconditions:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
The coroutine is not <span class="emphasis"><em>not-a-coroutine</em></span>
</li>
<li class="listitem">
The coroutine is not complete
</li>
<li class="listitem">
The coroutine is not running
</li>
<li class="listitem">
The coroutine owns a stack
</li>
</ul></div>
<p>
After unwinding, a <span class="emphasis"><em>coroutine</em></span> is complete.
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">X</span> <span class="special">{</span>
<span class="identifier">X</span><span class="special">(){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="string">"X()"</span><span class="special">&lt;&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">~</span><span class="identifier">X</span><span class="special">(){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="string">"~X()"</span><span class="special">&lt;&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">other_coro</span><span class="special">(...);</span>
<span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">){</span>
<span class="identifier">X</span> <span class="identifier">x</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="string">"fn()"</span><span class="special">&lt;&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// transfer execution control to other coroutine</span>
<span class="identifier">yield</span><span class="special">(</span> <span class="identifier">other_coro</span><span class="special">,</span> <span class="number">7</span><span class="special">);</span>
<span class="special">});</span>
<span class="identifier">coro</span><span class="special">();</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="string">"coro is complete: "</span><span class="special">&lt;&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">boolalpha</span><span class="special">&lt;&lt;!</span><span class="identifier">coro</span><span class="special">&lt;&lt;</span><span class="string">"\n"</span><span class="special">;</span>
<span class="special">}</span>
<span class="identifier">output</span><span class="special">:</span>
<span class="identifier">X</span><span class="special">()</span>
<span class="identifier">fn</span><span class="special">()</span>
<span class="identifier">coro</span> <span class="identifier">is</span> <span class="identifier">complete</span><span class="special">:</span> <span class="keyword">false</span>
<span class="special">~</span><span class="identifier">X</span><span class="special">()</span>
</pre>
<h5>
<a name="coroutine.coroutine.symmetric.h6"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.exit_a__emphasis_coroutine_function__emphasis_"></a></span><a class="link" href="symmetric.html#coroutine.coroutine.symmetric.exit_a__emphasis_coroutine_function__emphasis_">Exit
a <span class="emphasis"><em>coroutine-function</em></span></a>
</h5>
<p>
<span class="emphasis"><em>coroutine-function</em></span> is exited with a simple return statement.
This jumps back to the calling <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>
at the start of symmetric coroutine chain. That is, symmetric coroutines
do not have a strong, fixed relationship to the caller as do asymmetric coroutines.
The <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type</em></span> becomes complete,
e.g. <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator bool</em></span>
will return <code class="computeroutput"><span class="keyword">false</span></code>.
</p>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
After returning from <span class="emphasis"><em>coroutine-function</em></span> the <span class="emphasis"><em>coroutine</em></span>
is complete (can not be resumed with <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>).
</p></td></tr>
</table></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="asymmetric/push_coro.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../coroutine.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="symmetric/symmetric_coro.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,306 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class symmetric_coroutine&lt;&gt;::call_type</title>
<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../symmetric.html" title="Symmetric coroutine">
<link rel="prev" href="../symmetric.html" title="Symmetric coroutine">
<link rel="next" href="yield_coro.html" title="Class symmetric_coroutine&lt;&gt;::yield_type">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../symmetric.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../symmetric.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="yield_coro.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="coroutine.coroutine.symmetric.symmetric_coro"></a><a class="link" href="symmetric_coro.html" title="Class symmetric_coroutine&lt;&gt;::call_type">Class
<code class="computeroutput"><span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">call_type</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">symmetric_coroutine</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">call_type</span>
<span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">call_type</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span> <span class="special">&gt;</span>
<span class="identifier">call_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span> <span class="special">=</span> <span class="identifier">attributes</span><span class="special">()</span> <span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span> <span class="special">&gt;</span>
<span class="identifier">call_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">,</span> <span class="identifier">StackAllocator</span> <span class="identifier">stack_alloc</span><span class="special">);</span>
<span class="special">~</span><span class="identifier">call_type</span><span class="special">();</span>
<span class="identifier">call_type</span><span class="special">(</span> <span class="identifier">call_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">call_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">call_type</span><span class="special">(</span> <span class="identifier">call_type</span> <span class="special">&amp;&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">call_type</span> <span class="special">&amp;&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">operator</span> <span class="identifier">unspecified</span><span class="special">-</span><span class="keyword">bool</span><span class="special">-</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">Arg</span> <span class="identifier">arg</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">r</span><span class="special">);</span>
</pre>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h0"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__identifier__call_type__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__identifier__call_type__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">call_type</span><span class="special">()</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine representing <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h1"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__call_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__call_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span>
<span class="special">&gt;</span> <span class="identifier">call_type</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">size</span></code> &gt;= minimum_stacksize(),
<code class="computeroutput"><span class="identifier">size</span></code> &lt;= maximum_stacksize()
when ! is_stack_unbounded().
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine which will execute <code class="computeroutput"><span class="identifier">fn</span></code>.
Argument <code class="computeroutput"><span class="identifier">attr</span></code> determines
stack clean-up. For allocating/deallocating the stack <code class="computeroutput"><span class="identifier">stack_alloc</span></code> is used.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h2"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__call_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__special___gt___phrase_____________phrase_role__identifier__call_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__fn__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__fn__phrase__phrase_role__special_____phrase___phrase_role__identifier__attributes__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__attr__phrase__phrase_role__special_____phrase___phrase_role__identifier__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span> <span class="special">&gt;</span>
<span class="identifier">call_type</span><span class="special">(</span>
<span class="identifier">Fn</span> <span class="special">&amp;&amp;</span>
<span class="identifier">fn</span><span class="special">,</span>
<span class="identifier">attributes</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">,</span> <span class="identifier">StackAllocator</span>
<span class="keyword">const</span><span class="special">&amp;</span>
<span class="identifier">stack_alloc</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">size</span></code> &gt;= minimum_stacksize(),
<code class="computeroutput"><span class="identifier">size</span></code> &lt;= maximum_stacksize()
when ! is_stack_unbounded().
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Creates a coroutine which will execute <code class="computeroutput"><span class="identifier">fn</span></code>.
Argument <code class="computeroutput"><span class="identifier">attr</span></code> determines
stack clean-up. For allocating/deallocating the stack <code class="computeroutput"><span class="identifier">stack_alloc</span></code> is used.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h3"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__special_____phrase__phrase_role__identifier__call_type__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__special_____phrase__phrase_role__identifier__call_type__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="special">~</span><span class="identifier">call_type</span><span class="special">()</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Destroys the context and deallocates the stack.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h4"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__identifier__call_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__call_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__identifier__call_type__phrase__phrase_role__special_____phrase___phrase_role__identifier__call_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">call_type</span><span class="special">(</span>
<span class="identifier">call_type</span> <span class="special">&amp;&amp;</span>
<span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Moves the internal data of <code class="computeroutput"><span class="identifier">other</span></code>
to <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
<code class="computeroutput"><span class="identifier">other</span></code> becomes <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h5"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__identifier__call_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special______phrase___phrase_role__identifier__call_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__identifier__call_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special______phrase___phrase_role__identifier__call_type__phrase___phrase_role__special___amp__amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">call_type</span> <span class="special">&amp;</span>
<span class="keyword">operator</span><span class="special">=(</span>
<span class="identifier">call_type</span> <span class="special">&amp;&amp;</span>
<span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Destroys the internal data of <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> and moves the internal data of
<code class="computeroutput"><span class="identifier">other</span></code> to <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
<code class="computeroutput"><span class="identifier">other</span></code> becomes <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h6"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__operator__phrase___phrase_role__identifier__unspecified__phrase__phrase_role__special_____phrase__phrase_role__keyword__bool__phrase__phrase_role__special_____phrase__phrase_role__identifier__type__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__operator__phrase___phrase_role__identifier__unspecified__phrase__phrase_role__special_____phrase__phrase_role__keyword__bool__phrase__phrase_role__special_____phrase__phrase_role__identifier__type__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___code_"><code class="computeroutput"><span class="keyword">operator</span> <span class="identifier">unspecified</span><span class="special">-</span><span class="keyword">bool</span><span class="special">-</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to <span class="emphasis"><em>not-a-coroutine</em></span> or the coroutine-function
has returned (completed), the function returns <code class="computeroutput"><span class="keyword">false</span></code>.
Otherwise <code class="computeroutput"><span class="keyword">true</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h7"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___code_"><code class="computeroutput"><span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to <span class="emphasis"><em>not-a-coroutine</em></span> or the coroutine-function
has returned (completed), the function returns <code class="computeroutput"><span class="keyword">true</span></code>.
Otherwise <code class="computeroutput"><span class="keyword">false</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h8"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__void__phrase___phrase_role__identifier__swap__phrase__phrase_role__special_____phrase___phrase_role__identifier__call_type__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__keyword__void__phrase___phrase_role__identifier__swap__phrase__phrase_role__special_____phrase___phrase_role__identifier__call_type__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__other__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">call_type</span>
<span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
Swaps the internal data from <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> with the values of <code class="computeroutput"><span class="identifier">other</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h9"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__identifier__call_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase__phrase_role__identifier__arg__phrase___phrase_role__identifier__arg__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro._code__phrase_role__identifier__call_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase__phrase_role__identifier__arg__phrase___phrase_role__identifier__arg__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">call_type</span> <span class="special">&amp;</span>
<span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Arg</span> <span class="identifier">arg</span><span class="special">)</span></code></a>
</h6>
<pre class="programlisting"><span class="identifier">symmetric_coroutine</span><span class="special">::</span><span class="identifier">call_type</span><span class="special">&amp;</span> <span class="identifier">coroutine</span><span class="special">&lt;</span><span class="identifier">Arg</span><span class="special">,</span><span class="identifier">StackAllocator</span><span class="special">&gt;::</span><span class="identifier">call_type</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Arg</span><span class="special">);</span>
<span class="identifier">symmetric_coroutine</span><span class="special">::</span><span class="identifier">call_type</span><span class="special">&amp;</span> <span class="identifier">coroutine</span><span class="special">&lt;</span><span class="identifier">Arg</span><span class="special">&amp;,</span><span class="identifier">StackAllocator</span><span class="special">&gt;::</span><span class="identifier">call_type</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Arg</span><span class="special">&amp;);</span>
<span class="identifier">symmetric_coroutine</span><span class="special">::</span><span class="identifier">call_type</span><span class="special">&amp;</span> <span class="identifier">coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">,</span><span class="identifier">StackAllocator</span><span class="special">&gt;::</span><span class="identifier">call_type</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()();</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
operator unspecified-bool-type() returns <code class="computeroutput"><span class="keyword">true</span></code>
for <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Execution control is transferred to <span class="emphasis"><em>coroutine-function</em></span>
and the argument <code class="computeroutput"><span class="identifier">arg</span></code>
is passed to the coroutine-function.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.symmetric_coro.h10"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.symmetric_coro.non_member_function__code__phrase_role__identifier__swap__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="symmetric_coro.html#coroutine.coroutine.symmetric.symmetric_coro.non_member_function__code__phrase_role__identifier__swap__phrase__phrase_role__special______phrase___code_">Non-member
function <code class="computeroutput"><span class="identifier">swap</span><span class="special">()</span></code></a>
</h6>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span> <span class="identifier">Arg</span> <span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">r</span><span class="special">);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Effects:</span></dt>
<dd><p>
As if 'l.swap( r)'.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../symmetric.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../symmetric.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="yield_coro.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,174 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class symmetric_coroutine&lt;&gt;::yield_type</title>
<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../symmetric.html" title="Symmetric coroutine">
<link rel="prev" href="symmetric_coro.html" title="Class symmetric_coroutine&lt;&gt;::call_type">
<link rel="next" href="../../attributes.html" title="Attributes">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="symmetric_coro.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../symmetric.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../../attributes.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="coroutine.coroutine.symmetric.yield_coro"></a><a class="link" href="yield_coro.html" title="Class symmetric_coroutine&lt;&gt;::yield_type">Class <code class="computeroutput"><span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">yield_type</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">symmetric_coroutine</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">yield_type</span>
<span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">yield_type</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">yield_type</span><span class="special">(</span> <span class="identifier">yield_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">yield_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">yield_type</span><span class="special">(</span> <span class="identifier">yield_type</span> <span class="special">&amp;&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">yield_type</span> <span class="special">&amp;&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="identifier">other</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">operator</span> <span class="identifier">unspecified</span><span class="special">-</span><span class="keyword">bool</span><span class="special">-</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()();</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">X</span> <span class="special">&gt;</span>
<span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span> <span class="identifier">X</span> <span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">other</span><span class="special">,</span> <span class="identifier">X</span> <span class="special">&amp;</span> <span class="identifier">x</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">X</span> <span class="special">&gt;</span>
<span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span> <span class="identifier">X</span> <span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">other</span><span class="special">);</span>
<span class="identifier">R</span> <span class="identifier">get</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<h6>
<a name="coroutine.coroutine.symmetric.yield_coro.h0"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.yield_coro._code__phrase_role__keyword__operator__phrase___phrase_role__identifier__unspecified__phrase__phrase_role__special_____phrase__phrase_role__keyword__bool__phrase__phrase_role__special_____phrase__phrase_role__identifier__type__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___code_"></a></span><a class="link" href="yield_coro.html#coroutine.coroutine.symmetric.yield_coro._code__phrase_role__keyword__operator__phrase___phrase_role__identifier__unspecified__phrase__phrase_role__special_____phrase__phrase_role__keyword__bool__phrase__phrase_role__special_____phrase__phrase_role__identifier__type__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___code_"><code class="computeroutput"><span class="keyword">operator</span> <span class="identifier">unspecified</span><span class="special">-</span><span class="keyword">bool</span><span class="special">-</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to <span class="emphasis"><em>not-a-coroutine</em></span>, the function returns
<code class="computeroutput"><span class="keyword">false</span></code>. Otherwise <code class="computeroutput"><span class="keyword">true</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.yield_coro.h1"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.yield_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___code_"></a></span><a class="link" href="yield_coro.html#coroutine.coroutine.symmetric.yield_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___code_"><code class="computeroutput"><span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span></code></a>
</h6>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to <span class="emphasis"><em>not-a-coroutine</em></span>, the function returns
<code class="computeroutput"><span class="keyword">true</span></code>. Otherwise <code class="computeroutput"><span class="keyword">false</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.yield_coro.h2"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.yield_coro._code__phrase_role__identifier__yield_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special________phrase___code_"></a></span><a class="link" href="yield_coro.html#coroutine.coroutine.symmetric.yield_coro._code__phrase_role__identifier__yield_type__phrase___phrase_role__special___amp___phrase___phrase_role__keyword__operator__phrase__phrase_role__special________phrase___code_"><code class="computeroutput"><span class="identifier">yield_type</span> <span class="special">&amp;</span>
<span class="keyword">operator</span><span class="special">()()</span></code></a>
</h6>
<pre class="programlisting"><span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()();</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">X</span> <span class="special">&gt;</span>
<span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span> <span class="identifier">X</span> <span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">other</span><span class="special">,</span> <span class="identifier">X</span> <span class="special">&amp;</span> <span class="identifier">x</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;&gt;</span>
<span class="identifier">yield_type</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">&amp;</span> <span class="identifier">other</span><span class="special">);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
is not a <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
The first function transfers execution control back to the starting
point, e.g. invocation of <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>.
The last two functions transfer the execution control to another
symmetric coroutine. Parameter <code class="computeroutput"><span class="identifier">x</span></code>
is passed as value into <code class="computeroutput"><span class="identifier">other</span></code>'s
context.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<span class="emphasis"><em>detail::forced_unwind</em></span>
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine.coroutine.symmetric.yield_coro.h3"></a>
<span class="phrase"><a name="coroutine.coroutine.symmetric.yield_coro._code__phrase_role__identifier__r__phrase___phrase_role__identifier__get__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="yield_coro.html#coroutine.coroutine.symmetric.yield_coro._code__phrase_role__identifier__r__phrase___phrase_role__identifier__get__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">R</span> <span class="identifier">get</span><span class="special">()</span></code></a>
</h6>
<pre class="programlisting"><span class="identifier">R</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">::</span><span class="identifier">get</span><span class="special">();</span>
<span class="identifier">R</span><span class="special">&amp;</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&amp;&gt;::</span><span class="identifier">yield_type</span><span class="special">::</span><span class="identifier">get</span><span class="special">();</span>
<span class="keyword">void</span> <span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span><span class="identifier">yield_type</span><span class="special">::</span><span class="identifier">get</span><span class="special">()=</span><span class="keyword">delete</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
is not a <span class="emphasis"><em>not-a-coroutine</em></span>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns data transferred from coroutine-function via <span class="emphasis"><em>symmetric_coroutine&lt;&gt;::call_type::operator()</em></span>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">invalid_result</span></code>
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="symmetric_coro.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../symmetric.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../../attributes.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,188 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Introduction</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="overview.html" title="Overview">
<link rel="next" href="motivation.html" title="Motivation">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="overview.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="motivation.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.intro"></a><a class="link" href="intro.html" title="Introduction">Introduction</a>
</h2></div></div></div>
<h4>
<a name="coroutine.intro.h0"></a>
<span class="phrase"><a name="coroutine.intro.definition"></a></span><a class="link" href="intro.html#coroutine.intro.definition">Definition</a>
</h4>
<p>
In computer science routines are defined as a sequence of operations. The execution
of routines forms a parent-child relationship and the child terminates always
before the parent. Coroutines (the term was introduced by Melvin Conway <a href="#ftn.coroutine.intro.f0" class="footnote" name="coroutine.intro.f0"><sup class="footnote">[1]</sup></a>), are a generalization of routines (Donald Knuth <a href="#ftn.coroutine.intro.f1" class="footnote" name="coroutine.intro.f1"><sup class="footnote">[2]</sup></a>. The principal difference between coroutines and routines is that
a coroutine enables explicit suspend and resume of its progress via additional
operations by preserving execution state and thus provides an <span class="bold"><strong>enhanced
control flow</strong></span> (maintaining the execution context).
</p>
<h4>
<a name="coroutine.intro.h1"></a>
<span class="phrase"><a name="coroutine.intro.how_it_works"></a></span><a class="link" href="intro.html#coroutine.intro.how_it_works">How
it works</a>
</h4>
<p>
Functions foo() and bar() are supposed to alternate their execution (leave
and enter function body).
</p>
<p>
<span class="inlinemediaobject"><img src="../../../../../libs/coroutine/doc/images/foo_bar.png" align="middle" alt="foo_bar"></span>
</p>
<p>
If coroutines were called exactly like routines, the stack would grow with
every call and would never be popped. A jump into the middle of a coroutine
would not be possible, because the return address would be on top of stack
entries.
</p>
<p>
The solution is that each coroutine has its own stack and control-block (<span class="emphasis"><em>boost::contexts::fcontext_t</em></span>
from <span class="bold"><strong>Boost.Context</strong></span>). Before the coroutine
gets suspended, the non-volatile registers (including stack and instruction/program
pointer) of the currently active coroutine are stored in the coroutine's control-block.
The registers of the newly activated coroutine must be restored from its associated
control-block before it is resumed.
</p>
<p>
The context switch requires no system privileges and provides cooperative multitasking
convenient to C++. Coroutines provide quasi parallelism. When a program is
supposed to do several things at the same time, coroutines help to do this
much more simply and elegantly than with only a single flow of control. The
advantages can be seen particularly clearly with the use of a recursive function,
such as traversal of binary trees (see example 'same fringe').
</p>
<h4>
<a name="coroutine.intro.h2"></a>
<span class="phrase"><a name="coroutine.intro.characteristics"></a></span><a class="link" href="intro.html#coroutine.intro.characteristics">characteristics</a>
</h4>
<p>
Characteristics <a href="#ftn.coroutine.intro.f2" class="footnote" name="coroutine.intro.f2"><sup class="footnote">[3]</sup></a> of a coroutine are:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
values of local data persist between successive calls (context switches)
</li>
<li class="listitem">
execution is suspended as control leaves coroutine and is resumed at certain
time later
</li>
<li class="listitem">
symmetric or asymmetric control-transfer mechanism; see below
</li>
<li class="listitem">
first-class object (can be passed as argument, returned by procedures,
stored in a data structure to be used later or freely manipulated by the
developer)
</li>
<li class="listitem">
stackful or stackless
</li>
</ul></div>
<p>
Coroutines are useful in simulation, artificial intelligence, concurrent programming,
text processing and data manipulation, supporting the implementation of components
such as cooperative tasks (fibers), iterators, generators, infinite lists,
pipes etc.
</p>
<h4>
<a name="coroutine.intro.h3"></a>
<span class="phrase"><a name="coroutine.intro.execution_transfer_mechanism"></a></span><a class="link" href="intro.html#coroutine.intro.execution_transfer_mechanism">execution-transfer
mechanism</a>
</h4>
<p>
Two categories of coroutines exist: symmetric and asymmetric coroutines.
</p>
<p>
An asymmetric coroutine knows its invoker, using a special operation to implicitly
yield control specifically to its invoker. By contrast, all symmetric coroutines
are equivalent; one symmetric coroutine may pass control to any other symmetric
coroutine. Because of this, a symmetric coroutine <span class="emphasis"><em>must</em></span>
specify the coroutine to which it intends to yield control.
</p>
<p>
<span class="inlinemediaobject"><img src="../../../../../libs/coroutine/doc/images/foo_bar_seq.png" align="middle" alt="foo_bar_seq"></span>
</p>
<p>
Both concepts are equivalent and a fully-general coroutine library can provide
either symmetric or asymmetric coroutines. For convenience, Boost.Coroutine
provides both.
</p>
<h4>
<a name="coroutine.intro.h4"></a>
<span class="phrase"><a name="coroutine.intro.stackfulness"></a></span><a class="link" href="intro.html#coroutine.intro.stackfulness">stackfulness</a>
</h4>
<p>
In contrast to a stackless coroutine a stackful coroutine can be suspended
from within a nested stackframe. Execution resumes at exactly the same point
in the code where it was suspended before. With a stackless coroutine, only
the top-level routine may be suspended. Any routine called by that top-level
routine may not itself suspend. This prohibits providing suspend/resume operations
in routines within a general-purpose library.
</p>
<h4>
<a name="coroutine.intro.h5"></a>
<span class="phrase"><a name="coroutine.intro.first_class_continuation"></a></span><a class="link" href="intro.html#coroutine.intro.first_class_continuation">first-class
continuation</a>
</h4>
<p>
A first-class continuation can be passed as an argument, returned by a function
and stored in a data structure to be used later. In some implementations (for
instance C# <span class="emphasis"><em>yield</em></span>) the continuation can not be directly
accessed or directly manipulated.
</p>
<p>
Without stackfulness and first-class semantics, some useful execution control
flows cannot be supported (for instance cooperative multitasking or checkpointing).
</p>
<div class="footnotes">
<br><hr style="width:100; text-align:left;margin-left: 0">
<div id="ftn.coroutine.intro.f0" class="footnote"><p><a href="#coroutine.intro.f0" class="para"><sup class="para">[1] </sup></a>
Conway, Melvin E.. "Design of a Separable Transition-Diagram Compiler".
Commun. ACM, Volume 6 Issue 7, July 1963, Article No. 7
</p></div>
<div id="ftn.coroutine.intro.f1" class="footnote"><p><a href="#coroutine.intro.f1" class="para"><sup class="para">[2] </sup></a>
Knuth, Donald Ervin (1997). "Fundamental Algorithms. The Art of Computer
Programming 1", (3rd ed.)
</p></div>
<div id="ftn.coroutine.intro.f2" class="footnote"><p><a href="#coroutine.intro.f2" class="para"><sup class="para">[3] </sup></a>
Moura, Ana Lucia De and Ierusalimschy, Roberto. "Revisiting coroutines".
ACM Trans. Program. Lang. Syst., Volume 31 Issue 2, February 2009, Article
No. 6
</p></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="overview.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="motivation.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,786 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Motivation</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="intro.html" title="Introduction">
<link rel="next" href="coroutine.html" title="Coroutine">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="intro.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="coroutine.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.motivation"></a><a class="link" href="motivation.html" title="Motivation">Motivation</a>
</h2></div></div></div>
<p>
In order to support a broad range of execution control behaviour the coroutine
types of <span class="emphasis"><em>symmetric_coroutine&lt;&gt;</em></span> and <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;</em></span>
can be used to <span class="emphasis"><em>escape-and-reenter</em></span> loops, to <span class="emphasis"><em>escape-and-reenter</em></span>
recursive computations and for <span class="emphasis"><em>cooperative</em></span> multitasking
helping to solve problems in a much simpler and more elegant way than with
only a single flow of control.
</p>
<h4>
<a name="coroutine.motivation.h0"></a>
<span class="phrase"><a name="coroutine.motivation.event_driven_model"></a></span><a class="link" href="motivation.html#coroutine.motivation.event_driven_model">event-driven
model</a>
</h4>
<p>
The event-driven model is a programming paradigm where the flow of a program
is determined by events. The events are generated by multiple independent sources
and an event-dispatcher, waiting on all external sources, triggers callback
functions (event-handlers) whenever one of those events is detected (event-loop).
The application is divided into event selection (detection) and event handling.
</p>
<p>
<span class="inlinemediaobject"><img src="../../../../../libs/coroutine/doc/images/event_model.png" align="middle" alt="event_model"></span>
</p>
<p>
The resulting applications are highly scalable, flexible, have high responsiveness
and the components are loosely coupled. This makes the event-driven model suitable
for user interface applications, rule-based productions systems or applications
dealing with asynchronous I/O (for instance network servers).
</p>
<h4>
<a name="coroutine.motivation.h1"></a>
<span class="phrase"><a name="coroutine.motivation.event_based_asynchronous_paradigm"></a></span><a class="link" href="motivation.html#coroutine.motivation.event_based_asynchronous_paradigm">event-based
asynchronous paradigm</a>
</h4>
<p>
A classic synchronous console program issues an I/O request (e.g. for user
input or filesystem data) and blocks until the request is complete.
</p>
<p>
In contrast, an asynchronous I/O function initiates the physical operation
but immediately returns to its caller, even though the operation is not yet
complete. A program written to leverage this functionality does not block:
it can proceed with other work (including other I/O requests in parallel) while
the original operation is still pending. When the operation completes, the
program is notified. Because asynchronous applications spend less overall time
waiting for operations, they can outperform synchronous programs.
</p>
<p>
Events are one of the paradigms for asynchronous execution, but not all asynchronous
systems use events. Although asynchronous programming can be done using threads,
they come with their own costs:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
hard to program (traps for the unwary)
</li>
<li class="listitem">
memory requirements are high
</li>
<li class="listitem">
large overhead with creation and maintenance of thread state
</li>
<li class="listitem">
expensive context switching between threads
</li>
</ul></div>
<p>
The event-based asynchronous model avoids those issues:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
simpler because of the single stream of instructions
</li>
<li class="listitem">
much less expensive context switches
</li>
</ul></div>
<p>
The downside of this paradigm consists in a sub-optimal program structure.
An event-driven program is required to split its code into multiple small callback
functions, i.e. the code is organized in a sequence of small steps that execute
intermittently. An algorithm that would usually be expressed as a hierarchy
of functions and loops must be transformed into callbacks. The complete state
has to be stored into a data structure while the control flow returns to the
event-loop. As a consequence, event-driven applications are often tedious and
confusing to write. Each callback introduces a new scope, error callback etc.
The sequential nature of the algorithm is split into multiple callstacks, making
the application hard to debug. Exception handlers are restricted to local handlers:
it is impossible to wrap a sequence of events into a single try-catch block.
The use of local variables, while/for loops, recursions etc. together with
the event-loop is not possible. The code becomes less expressive.
</p>
<p>
In the past, code using asio's <span class="emphasis"><em>asynchronous operations</em></span>
was convoluted by callback functions.
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">session</span>
<span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">session</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">&amp;</span> <span class="identifier">io_service</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">socket_</span><span class="special">(</span><span class="identifier">io_service</span><span class="special">)</span> <span class="comment">// construct a TCP-socket from io_service</span>
<span class="special">{}</span>
<span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span><span class="special">&amp;</span> <span class="identifier">socket</span><span class="special">(){</span>
<span class="keyword">return</span> <span class="identifier">socket_</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">start</span><span class="special">(){</span>
<span class="comment">// initiate asynchronous read; handle_read() is callback-function</span>
<span class="identifier">socket_</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data_</span><span class="special">,</span><span class="identifier">max_length</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&amp;</span><span class="identifier">session</span><span class="special">::</span><span class="identifier">handle_read</span><span class="special">,</span><span class="keyword">this</span><span class="special">,</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">error</span><span class="special">,</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">bytes_transferred</span><span class="special">));</span>
<span class="special">}</span>
<span class="keyword">private</span><span class="special">:</span>
<span class="keyword">void</span> <span class="identifier">handle_read</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">error</span><span class="special">,</span>
<span class="identifier">size_t</span> <span class="identifier">bytes_transferred</span><span class="special">){</span>
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">error</span><span class="special">)</span>
<span class="comment">// initiate asynchronous write; handle_write() is callback-function</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">socket_</span><span class="special">,</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data_</span><span class="special">,</span><span class="identifier">bytes_transferred</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&amp;</span><span class="identifier">session</span><span class="special">::</span><span class="identifier">handle_write</span><span class="special">,</span><span class="keyword">this</span><span class="special">,</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">error</span><span class="special">));</span>
<span class="keyword">else</span>
<span class="keyword">delete</span> <span class="keyword">this</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">handle_write</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">error</span><span class="special">){</span>
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">error</span><span class="special">)</span>
<span class="comment">// initiate asynchronous read; handle_read() is callback-function</span>
<span class="identifier">socket_</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data_</span><span class="special">,</span><span class="identifier">max_length</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&amp;</span><span class="identifier">session</span><span class="special">::</span><span class="identifier">handle_read</span><span class="special">,</span><span class="keyword">this</span><span class="special">,</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">error</span><span class="special">,</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">bytes_transferred</span><span class="special">));</span>
<span class="keyword">else</span>
<span class="keyword">delete</span> <span class="keyword">this</span><span class="special">;</span>
<span class="special">}</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span> <span class="identifier">socket_</span><span class="special">;</span>
<span class="keyword">enum</span> <span class="special">{</span> <span class="identifier">max_length</span><span class="special">=</span><span class="number">1024</span> <span class="special">};</span>
<span class="keyword">char</span> <span class="identifier">data_</span><span class="special">[</span><span class="identifier">max_length</span><span class="special">];</span>
<span class="special">};</span>
</pre>
<p>
In this example, a simple echo server, the logic is split into three member
functions - local state (such as data buffer) is moved to member variables.
</p>
<p>
<span class="bold"><strong>Boost.Asio</strong></span> provides with its new <span class="emphasis"><em>asynchronous
result</em></span> feature a new framework combining event-driven model and
coroutines, hiding the complexity of event-driven programming and permitting
the style of classic sequential code. The application is not required to pass
callback functions to asynchronous operations and local state is kept as local
variables. Therefore the code is much easier to read and understand. <a href="#ftn.coroutine.motivation.f0" class="footnote" name="coroutine.motivation.f0"><sup class="footnote">[4]</sup></a>. <span class="emphasis"><em>boost::asio::yield_context</em></span> internally uses
<span class="bold"><strong>Boost.Coroutine</strong></span>:
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">session</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">&amp;</span> <span class="identifier">io_service</span><span class="special">){</span>
<span class="comment">// construct TCP-socket from io_service</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span> <span class="identifier">socket</span><span class="special">(</span><span class="identifier">io_service</span><span class="special">);</span>
<span class="keyword">try</span><span class="special">{</span>
<span class="keyword">for</span><span class="special">(;;){</span>
<span class="comment">// local data-buffer</span>
<span class="keyword">char</span> <span class="identifier">data</span><span class="special">[</span><span class="identifier">max_length</span><span class="special">];</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">;</span>
<span class="comment">// read asynchronous data from socket</span>
<span class="comment">// execution context will be suspended until</span>
<span class="comment">// some bytes are read from socket</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">length</span><span class="special">=</span><span class="identifier">socket</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">ec</span><span class="special">==</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">error</span><span class="special">::</span><span class="identifier">eof</span><span class="special">)</span>
<span class="keyword">break</span><span class="special">;</span> <span class="comment">//connection closed cleanly by peer</span>
<span class="keyword">else</span> <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
<span class="keyword">throw</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">system_error</span><span class="special">(</span><span class="identifier">ec</span><span class="special">);</span> <span class="comment">//some other error</span>
<span class="comment">// write some bytes asynchronously</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span>
<span class="identifier">socket</span><span class="special">,</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data</span><span class="special">,</span><span class="identifier">length</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">ec</span><span class="special">==</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">error</span><span class="special">::</span><span class="identifier">eof</span><span class="special">)</span>
<span class="keyword">break</span><span class="special">;</span> <span class="comment">//connection closed cleanly by peer</span>
<span class="keyword">else</span> <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
<span class="keyword">throw</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">system_error</span><span class="special">(</span><span class="identifier">ec</span><span class="special">);</span> <span class="comment">//some other error</span>
<span class="special">}</span>
<span class="special">}</span> <span class="keyword">catch</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">e</span><span class="special">){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cerr</span><span class="special">&lt;&lt;</span><span class="string">"Exception: "</span><span class="special">&lt;&lt;</span><span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">()&lt;&lt;</span><span class="string">"\n"</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">}</span>
</pre>
<p>
In contrast to the previous example this one gives the impression of sequential
code and local data (<span class="emphasis"><em>data</em></span>) while using asynchronous operations
(<span class="emphasis"><em>async_read()</em></span>, <span class="emphasis"><em>async_write()</em></span>). The
algorithm is implemented in one function and error handling is done by one
try-catch block.
</p>
<h4>
<a name="coroutine.motivation.h2"></a>
<span class="phrase"><a name="coroutine.motivation.recursive_sax_parsing"></a></span><a class="link" href="motivation.html#coroutine.motivation.recursive_sax_parsing">recursive
SAX parsing</a>
</h4>
<p>
To someone who knows SAX, the phrase "recursive SAX parsing" might
sound nonsensical. You get callbacks from SAX; you have to manage the element
stack yourself. If you want recursive XML processing, you must first read the
entire DOM into memory, then walk the tree.
</p>
<p>
But coroutines let you invert the flow of control so you can ask for SAX events.
Once you can do that, you can process them recursively.
</p>
<pre class="programlisting"><span class="comment">// Represent a subset of interesting SAX events</span>
<span class="keyword">struct</span> <span class="identifier">BaseEvent</span><span class="special">{</span>
<span class="identifier">BaseEvent</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">BaseEvent</span><span class="special">&amp;)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">BaseEvent</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> <span class="identifier">BaseEvent</span><span class="special">&amp;)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="special">};</span>
<span class="comment">// End of document or element</span>
<span class="keyword">struct</span> <span class="identifier">CloseEvent</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">BaseEvent</span><span class="special">{</span>
<span class="comment">// CloseEvent binds (without copying) the TagType reference.</span>
<span class="identifier">CloseEvent</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">):</span>
<span class="identifier">mName</span><span class="special">(</span><span class="identifier">name</span><span class="special">)</span>
<span class="special">{}</span>
<span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">mName</span><span class="special">;</span>
<span class="special">};</span>
<span class="comment">// Start of document or element</span>
<span class="keyword">struct</span> <span class="identifier">OpenEvent</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">CloseEvent</span><span class="special">{</span>
<span class="comment">// In addition to CloseEvent's TagType, OpenEvent binds AttributeIterator.</span>
<span class="identifier">OpenEvent</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">,</span>
<span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">AttributeIterator</span><span class="special">&amp;</span> <span class="identifier">attrs</span><span class="special">):</span>
<span class="identifier">CloseEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">),</span>
<span class="identifier">mAttrs</span><span class="special">(</span><span class="identifier">attrs</span><span class="special">)</span>
<span class="special">{}</span>
<span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">AttributeIterator</span><span class="special">&amp;</span> <span class="identifier">mAttrs</span><span class="special">;</span>
<span class="special">};</span>
<span class="comment">// text within an element</span>
<span class="keyword">struct</span> <span class="identifier">TextEvent</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">BaseEvent</span><span class="special">{</span>
<span class="comment">// TextEvent binds the CharIterator.</span>
<span class="identifier">TextEvent</span><span class="special">(</span><span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">CharIterator</span><span class="special">&amp;</span> <span class="identifier">text</span><span class="special">):</span>
<span class="identifier">mText</span><span class="special">(</span><span class="identifier">text</span><span class="special">)</span>
<span class="special">{}</span>
<span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">CharIterator</span><span class="special">&amp;</span> <span class="identifier">mText</span><span class="special">;</span>
<span class="special">};</span>
<span class="comment">// The parsing coroutine instantiates BaseEvent subclass instances and</span>
<span class="comment">// successively shows them to the main program. It passes a reference so we</span>
<span class="comment">// don't slice the BaseEvent subclass.</span>
<span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">BaseEvent</span><span class="special">&amp;&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">parser</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span><span class="special">&amp;</span> <span class="identifier">in</span><span class="special">){</span>
<span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span> <span class="identifier">xparser</span><span class="special">;</span>
<span class="comment">// startDocument() will send OpenEvent</span>
<span class="identifier">xparser</span><span class="special">.</span><span class="identifier">startDocument</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">,</span>
<span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">AttributeIterator</span><span class="special">&amp;</span> <span class="identifier">attrs</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">OpenEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span><span class="identifier">attrs</span><span class="special">));</span>
<span class="special">});</span>
<span class="comment">// startTag() will likewise send OpenEvent</span>
<span class="identifier">xparser</span><span class="special">.</span><span class="identifier">startTag</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">,</span>
<span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">AttributeIterator</span><span class="special">&amp;</span> <span class="identifier">attrs</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">OpenEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span><span class="identifier">attrs</span><span class="special">));</span>
<span class="special">});</span>
<span class="comment">// endTag() will send CloseEvent</span>
<span class="identifier">xparser</span><span class="special">.</span><span class="identifier">endTag</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">CloseEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">));</span>
<span class="special">});</span>
<span class="comment">// endDocument() will likewise send CloseEvent</span>
<span class="identifier">xparser</span><span class="special">.</span><span class="identifier">endDocument</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">CloseEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">));</span>
<span class="special">});</span>
<span class="comment">// characters() will send TextEvent</span>
<span class="identifier">xparser</span><span class="special">.</span><span class="identifier">characters</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">CharIterator</span><span class="special">&amp;</span> <span class="identifier">text</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">TextEvent</span><span class="special">(</span><span class="identifier">text</span><span class="special">));</span>
<span class="special">});</span>
<span class="keyword">try</span>
<span class="special">{</span>
<span class="comment">// parse the document, firing all the above</span>
<span class="identifier">xparser</span><span class="special">.</span><span class="identifier">parse</span><span class="special">(</span><span class="identifier">in</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">catch</span> <span class="special">(</span><span class="identifier">xml</span><span class="special">::</span><span class="identifier">Exception</span> <span class="identifier">e</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">// xml::sax::Parser throws xml::Exception. Helpfully translate the</span>
<span class="comment">// name and provide it as the what() string.</span>
<span class="keyword">throw</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">runtime_error</span><span class="special">(</span><span class="identifier">exception_name</span><span class="special">(</span><span class="identifier">e</span><span class="special">));</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="comment">// Recursively traverse the incoming XML document on the fly, pulling</span>
<span class="comment">// BaseEvent&amp; references from 'events'.</span>
<span class="comment">// 'indent' illustrates the level of recursion.</span>
<span class="comment">// Each time we're called, we've just retrieved an OpenEvent from 'events';</span>
<span class="comment">// accept that as a param.</span>
<span class="comment">// Return the CloseEvent that ends this element.</span>
<span class="keyword">const</span> <span class="identifier">CloseEvent</span><span class="special">&amp;</span> <span class="identifier">process</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">events</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">&amp;</span> <span class="identifier">context</span><span class="special">,</span>
<span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">indent</span><span class="special">=</span><span class="string">""</span><span class="special">){</span>
<span class="comment">// Capture OpenEvent's tag name: as soon as we advance the parser, the</span>
<span class="comment">// TagType&amp; reference bound in this OpenEvent will be invalidated.</span>
<span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span> <span class="identifier">tagName</span> <span class="special">=</span> <span class="identifier">context</span><span class="special">.</span><span class="identifier">mName</span><span class="special">;</span>
<span class="comment">// Since the OpenEvent is still the current value from 'events', pass</span>
<span class="comment">// control back to 'events' until the next event. Of course, each time we</span>
<span class="comment">// come back we must check for the end of the results stream.</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">events</span><span class="special">()){</span>
<span class="comment">// Another event is pending; retrieve it.</span>
<span class="keyword">const</span> <span class="identifier">BaseEvent</span><span class="special">&amp;</span> <span class="identifier">event</span><span class="special">=</span><span class="identifier">events</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">*</span> <span class="identifier">oe</span><span class="special">;</span>
<span class="keyword">const</span> <span class="identifier">CloseEvent</span><span class="special">*</span> <span class="identifier">ce</span><span class="special">;</span>
<span class="keyword">const</span> <span class="identifier">TextEvent</span><span class="special">*</span> <span class="identifier">te</span><span class="special">;</span>
<span class="keyword">if</span><span class="special">((</span><span class="identifier">oe</span><span class="special">=</span><span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">*&gt;(&amp;</span><span class="identifier">event</span><span class="special">))){</span>
<span class="comment">// When we see OpenEvent, recursively process it.</span>
<span class="identifier">process</span><span class="special">(</span><span class="identifier">events</span><span class="special">,*</span><span class="identifier">oe</span><span class="special">,</span><span class="identifier">indent</span><span class="special">+</span><span class="string">" "</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">else</span> <span class="keyword">if</span><span class="special">((</span><span class="identifier">ce</span><span class="special">=</span><span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">CloseEvent</span><span class="special">*&gt;(&amp;</span><span class="identifier">event</span><span class="special">))){</span>
<span class="comment">// When we see CloseEvent, validate its tag name and then return</span>
<span class="comment">// it. (This assert is really a check on xml::sax::Parser, since</span>
<span class="comment">// it already validates matching open/close tags.)</span>
<span class="identifier">assert</span><span class="special">(</span><span class="identifier">ce</span><span class="special">-&gt;</span><span class="identifier">mName</span> <span class="special">==</span> <span class="identifier">tagName</span><span class="special">);</span>
<span class="keyword">return</span> <span class="special">*</span><span class="identifier">ce</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">else</span> <span class="keyword">if</span><span class="special">((</span><span class="identifier">te</span><span class="special">=</span><span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">TextEvent</span><span class="special">*&gt;(&amp;</span><span class="identifier">event</span><span class="special">))){</span>
<span class="comment">// When we see TextEvent, just report its text, along with</span>
<span class="comment">// indentation indicating recursion level.</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="identifier">indent</span><span class="special">&lt;&lt;</span><span class="string">"text: '"</span><span class="special">&lt;&lt;</span><span class="identifier">te</span><span class="special">-&gt;</span><span class="identifier">mText</span><span class="special">.</span><span class="identifier">getText</span><span class="special">()&lt;&lt;</span><span class="string">"'\n"</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="comment">// pretend we have an XML file of arbitrary size</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">in</span><span class="special">(</span><span class="identifier">doc</span><span class="special">);</span>
<span class="keyword">try</span>
<span class="special">{</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">events</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">parser</span><span class="special">,</span><span class="identifier">_1</span><span class="special">,</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">in</span><span class="special">)));</span>
<span class="comment">// We fully expect at least ONE event.</span>
<span class="identifier">assert</span><span class="special">(</span><span class="identifier">events</span><span class="special">);</span>
<span class="comment">// This dynamic_cast&lt;&amp;&gt; is itself an assertion that the first event is an</span>
<span class="comment">// OpenEvent.</span>
<span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">&amp;</span> <span class="identifier">context</span><span class="special">=</span><span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">&amp;&gt;(</span><span class="identifier">events</span><span class="special">.</span><span class="identifier">get</span><span class="special">());</span>
<span class="identifier">process</span><span class="special">(</span><span class="identifier">events</span><span class="special">,</span> <span class="identifier">context</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">catch</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span><span class="special">&amp;</span> <span class="identifier">e</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Parsing error: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="char">'\n'</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
This problem does not map at all well to communicating between independent
threads. It makes no sense for either side to proceed independently of the
other. You want them to pass control back and forth.
</p>
<p>
The solution involves a small polymorphic class event hierarchy, to which we're
passing references. The actual instances are temporaries on the coroutine's
stack; the coroutine passes each reference in turn to the main logic. Copying
them as base-class values would slice them.
</p>
<p>
If we were trying to let the SAX parser proceed independently of the consuming
logic, one could imagine allocating event-subclass instances on the heap, passing
them along on a thread-safe queue of pointers. But that doesn't work either,
because these event classes bind references passed by the SAX parser. The moment
the parser moves on, those references become invalid.
</p>
<p>
Instead of binding a <span class="emphasis"><em>TagType&amp;</em></span> reference, we could
store a copy of the <span class="emphasis"><em>TagType</em></span> in <span class="emphasis"><em>CloseEvent</em></span>.
But that doesn't solve the whole problem. For attributes, we get an <span class="emphasis"><em>AttributeIterator&amp;</em></span>;
for text we get a <span class="emphasis"><em>CharIterator&amp;</em></span>. Storing a copy of
those iterators is pointless: once the parser moves on, those iterators are
invalidated. You must process the attribute iterator (or character iterator)
during the SAX callback for that event.
</p>
<p>
Naturally we could retrieve and store a copy of every attribute and its value;
we could store a copy of every chunk of text. That would effectively be all
the text in the document -- a heavy price to pay, if the reason we're using
SAX is concern about fitting the entire DOM into memory.
</p>
<p>
There's yet another advantage to using coroutines. This SAX parser throws an
exception when parsing fails. With a coroutine implementation, you need only
wrap the calling code in try/catch.
</p>
<p>
With communicating threads, you would have to arrange to catch the exception
and pass along the exception pointer on the same queue you're using to deliver
the other events. You would then have to rethrow the exception to unwind the
recursive document processing.
</p>
<p>
The coroutine solution maps very naturally to the problem space.
</p>
<h4>
<a name="coroutine.motivation.h3"></a>
<span class="phrase"><a name="coroutine.motivation._same_fringe__problem"></a></span><a class="link" href="motivation.html#coroutine.motivation._same_fringe__problem">'same
fringe' problem</a>
</h4>
<p>
The advantages of suspending at an arbitrary call depth can be seen particularly
clearly with the use of a recursive function, such as traversal of trees. If
traversing two different trees in the same deterministic order produces the
same list of leaf nodes, then both trees have the same fringe.
</p>
<p>
<span class="inlinemediaobject"><img src="../../../../../libs/coroutine/doc/images/same_fringe.png" align="middle" alt="same_fringe"></span>
</p>
<p>
Both trees in the picture have the same fringe even though the structure of
the trees is different.
</p>
<p>
The same fringe problem could be solved using coroutines by iterating over
the leaf nodes and comparing this sequence via <span class="emphasis"><em>std::equal()</em></span>.
The range of data values is generated by function <span class="emphasis"><em>traverse()</em></span>
which recursively traverses the tree and passes each node's data value to its
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>. <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
suspends the recursive computation and transfers the data value to the main
execution context. <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::iterator</em></span>,
created from <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>,
steps over those data values and delivers them to <span class="emphasis"><em>std::equal()</em></span>
for comparison. Each increment of <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::iterator</em></span>
resumes <span class="emphasis"><em>traverse()</em></span>. Upon return from <span class="emphasis"><em>iterator::operator++()</em></span>,
either a new data value is available, or tree traversal is finished (iterator
is invalidated).
</p>
<p>
In effect, the coroutine iterator presents a flattened view of the recursive
data structure.
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">node</span><span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;</span> <span class="identifier">ptr_t</span><span class="special">;</span>
<span class="comment">// Each tree node has an optional left subtree,</span>
<span class="comment">// an optional right subtree and a value of its own.</span>
<span class="comment">// The value is considered to be between the left</span>
<span class="comment">// subtree and the right.</span>
<span class="identifier">ptr_t</span> <span class="identifier">left</span><span class="special">,</span><span class="identifier">right</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">value</span><span class="special">;</span>
<span class="comment">// construct leaf</span>
<span class="identifier">node</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">):</span>
<span class="identifier">left</span><span class="special">(),</span><span class="identifier">right</span><span class="special">(),</span><span class="identifier">value</span><span class="special">(</span><span class="identifier">v</span><span class="special">)</span>
<span class="special">{}</span>
<span class="comment">// construct nonleaf</span>
<span class="identifier">node</span><span class="special">(</span><span class="identifier">ptr_t</span> <span class="identifier">l</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">,</span><span class="identifier">ptr_t</span> <span class="identifier">r</span><span class="special">):</span>
<span class="identifier">left</span><span class="special">(</span><span class="identifier">l</span><span class="special">),</span><span class="identifier">right</span><span class="special">(</span><span class="identifier">r</span><span class="special">),</span><span class="identifier">value</span><span class="special">(</span><span class="identifier">v</span><span class="special">)</span>
<span class="special">{}</span>
<span class="keyword">static</span> <span class="identifier">ptr_t</span> <span class="identifier">create</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">){</span>
<span class="keyword">return</span> <span class="identifier">ptr_t</span><span class="special">(</span><span class="keyword">new</span> <span class="identifier">node</span><span class="special">(</span><span class="identifier">v</span><span class="special">));</span>
<span class="special">}</span>
<span class="keyword">static</span> <span class="identifier">ptr_t</span> <span class="identifier">create</span><span class="special">(</span><span class="identifier">ptr_t</span> <span class="identifier">l</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">,</span><span class="identifier">ptr_t</span> <span class="identifier">r</span><span class="special">){</span>
<span class="keyword">return</span> <span class="identifier">ptr_t</span><span class="special">(</span><span class="keyword">new</span> <span class="identifier">node</span><span class="special">(</span><span class="identifier">l</span><span class="special">,</span><span class="identifier">v</span><span class="special">,</span><span class="identifier">r</span><span class="special">));</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">create_left_tree_from</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">root</span><span class="special">){</span>
<span class="comment">/* --------
root
/ \
b e
/ \
a c
-------- */</span>
<span class="keyword">return</span> <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"a"</span><span class="special">),</span>
<span class="string">"b"</span><span class="special">,</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"c"</span><span class="special">)),</span>
<span class="identifier">root</span><span class="special">,</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"e"</span><span class="special">));</span>
<span class="special">}</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">create_right_tree_from</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">root</span><span class="special">){</span>
<span class="comment">/* --------
root
/ \
a d
/ \
c e
-------- */</span>
<span class="keyword">return</span> <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"a"</span><span class="special">),</span>
<span class="identifier">root</span><span class="special">,</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"c"</span><span class="special">),</span>
<span class="string">"d"</span><span class="special">,</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"e"</span><span class="special">)));</span>
<span class="special">}</span>
<span class="comment">// recursively walk the tree, delivering values in order</span>
<span class="keyword">void</span> <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">n</span><span class="special">,</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
<span class="keyword">if</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">left</span><span class="special">)</span> <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">left</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
<span class="identifier">out</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">);</span>
<span class="keyword">if</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">right</span><span class="special">)</span> <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">right</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">// evaluation</span>
<span class="special">{</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">left_d</span><span class="special">(</span><span class="identifier">create_left_tree_from</span><span class="special">(</span><span class="string">"d"</span><span class="special">));</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">left_d_reader</span><span class="special">(</span>
<span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
<span class="identifier">traverse</span><span class="special">(</span><span class="identifier">left_d</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
<span class="special">});</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">right_b</span><span class="special">(</span><span class="identifier">create_right_tree_from</span><span class="special">(</span><span class="string">"b"</span><span class="special">));</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">right_b_reader</span><span class="special">(</span>
<span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
<span class="identifier">traverse</span><span class="special">(</span><span class="identifier">right_b</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
<span class="special">});</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"left tree from d == right tree from b? "</span>
<span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">boolalpha</span>
<span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">equal</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">left_d_reader</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">end</span><span class="special">(</span><span class="identifier">left_d_reader</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">right_b_reader</span><span class="special">))</span>
<span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">{</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">left_d</span><span class="special">(</span><span class="identifier">create_left_tree_from</span><span class="special">(</span><span class="string">"d"</span><span class="special">));</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">left_d_reader</span><span class="special">(</span>
<span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
<span class="identifier">traverse</span><span class="special">(</span><span class="identifier">left_d</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
<span class="special">});</span>
<span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">right_x</span><span class="special">(</span><span class="identifier">create_right_tree_from</span><span class="special">(</span><span class="string">"x"</span><span class="special">));</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">right_x_reader</span><span class="special">(</span>
<span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
<span class="identifier">traverse</span><span class="special">(</span><span class="identifier">right_x</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
<span class="special">});</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"left tree from d == right tree from x? "</span>
<span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">boolalpha</span>
<span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">equal</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">left_d_reader</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">end</span><span class="special">(</span><span class="identifier">left_d_reader</span><span class="special">),</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">right_x_reader</span><span class="special">))</span>
<span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Done"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="identifier">output</span><span class="special">:</span>
<span class="identifier">left</span> <span class="identifier">tree</span> <span class="identifier">from</span> <span class="identifier">d</span> <span class="special">==</span> <span class="identifier">right</span> <span class="identifier">tree</span> <span class="identifier">from</span> <span class="identifier">b</span><span class="special">?</span> <span class="keyword">true</span>
<span class="identifier">left</span> <span class="identifier">tree</span> <span class="identifier">from</span> <span class="identifier">d</span> <span class="special">==</span> <span class="identifier">right</span> <span class="identifier">tree</span> <span class="identifier">from</span> <span class="identifier">x</span><span class="special">?</span> <span class="keyword">false</span>
<span class="identifier">Done</span>
</pre>
<h4>
<a name="coroutine.motivation.h4"></a>
<span class="phrase"><a name="coroutine.motivation.merging_two_sorted_arrays"></a></span><a class="link" href="motivation.html#coroutine.motivation.merging_two_sorted_arrays">merging
two sorted arrays</a>
</h4>
<p>
This example demonstrates how symmetric coroutines merge two sorted arrays.
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">merge</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&amp;</span> <span class="identifier">a</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&amp;</span> <span class="identifier">b</span><span class="special">){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">c</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">idx_a</span><span class="special">=</span><span class="number">0</span><span class="special">,</span><span class="identifier">idx_b</span><span class="special">=</span><span class="number">0</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">*</span><span class="identifier">other_a</span><span class="special">=</span><span class="number">0</span><span class="special">,*</span><span class="identifier">other_b</span><span class="special">=</span><span class="number">0</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro_a</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">){</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_a</span><span class="special">&lt;</span><span class="identifier">a</span><span class="special">.</span><span class="identifier">size</span><span class="special">()){</span>
<span class="keyword">if</span><span class="special">(</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">]&lt;</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">])</span> <span class="comment">// test if element in array b is less than in array a</span>
<span class="identifier">yield</span><span class="special">(*</span><span class="identifier">other_b</span><span class="special">);</span> <span class="comment">// yield to coroutine coro_b</span>
<span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">++]);</span> <span class="comment">// add element to final array</span>
<span class="special">}</span>
<span class="comment">// add remaining elements of array b</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_b</span><span class="special">&lt;</span><span class="identifier">b</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
<span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">++]);</span>
<span class="special">});</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro_b</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">){</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_b</span><span class="special">&lt;</span><span class="identifier">b</span><span class="special">.</span><span class="identifier">size</span><span class="special">()){</span>
<span class="keyword">if</span><span class="special">(</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">]&lt;</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">])</span> <span class="comment">// test if element in array a is less than in array b</span>
<span class="identifier">yield</span><span class="special">(*</span><span class="identifier">other_a</span><span class="special">);</span> <span class="comment">// yield to coroutine coro_a</span>
<span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">++]);</span> <span class="comment">// add element to final array</span>
<span class="special">}</span>
<span class="comment">// add remaining elements of array a</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_a</span><span class="special">&lt;</span><span class="identifier">a</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
<span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">++]);</span>
<span class="special">});</span>
<span class="identifier">other_a</span><span class="special">=&amp;</span><span class="identifier">coro_a</span><span class="special">;</span>
<span class="identifier">other_b</span><span class="special">=&amp;</span><span class="identifier">coro_b</span><span class="special">;</span>
<span class="identifier">coro_a</span><span class="special">();</span> <span class="comment">// enter coroutine-fn of coro_a</span>
<span class="keyword">return</span> <span class="identifier">c</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<h4>
<a name="coroutine.motivation.h5"></a>
<span class="phrase"><a name="coroutine.motivation.chaining_coroutines"></a></span><a class="link" href="motivation.html#coroutine.motivation.chaining_coroutines">chaining
coroutines</a>
</h4>
<p>
This code shows how coroutines could be chained.
</p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>
<span class="comment">// deliver each line of input stream to sink as a separate string</span>
<span class="keyword">void</span> <span class="identifier">readlines</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span><span class="special">&amp;</span> <span class="identifier">in</span><span class="special">){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">line</span><span class="special">;</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">getline</span><span class="special">(</span><span class="identifier">in</span><span class="special">,</span><span class="identifier">line</span><span class="special">))</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">line</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">tokenize</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span> <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
<span class="comment">// This tokenizer doesn't happen to be stateful: you could reasonably</span>
<span class="comment">// implement it with a single call to push each new token downstream. But</span>
<span class="comment">// I've worked with stateful tokenizers, in which the meaning of input</span>
<span class="comment">// characters depends in part on their position within the input line.</span>
<span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">line</span><span class="special">,</span><span class="identifier">source</span><span class="special">){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">::</span><span class="identifier">size_type</span> <span class="identifier">pos</span><span class="special">=</span><span class="number">0</span><span class="special">;</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">pos</span><span class="special">&lt;</span><span class="identifier">line</span><span class="special">.</span><span class="identifier">length</span><span class="special">()){</span>
<span class="keyword">if</span><span class="special">(</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">]==</span><span class="char">'"'</span><span class="special">){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">;</span>
<span class="special">++</span><span class="identifier">pos</span><span class="special">;</span> <span class="comment">// skip open quote</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">pos</span><span class="special">&lt;</span><span class="identifier">line</span><span class="special">.</span><span class="identifier">length</span><span class="special">()&amp;&amp;</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">]!=</span><span class="char">'"'</span><span class="special">)</span>
<span class="identifier">token</span><span class="special">+=</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">++];</span>
<span class="special">++</span><span class="identifier">pos</span><span class="special">;</span> <span class="comment">// skip close quote</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span> <span class="comment">// pass token downstream</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="keyword">if</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">isspace</span><span class="special">(</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">])){</span>
<span class="special">++</span><span class="identifier">pos</span><span class="special">;</span> <span class="comment">// outside quotes, ignore whitespace</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="keyword">if</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">isalpha</span><span class="special">(</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">])){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">;</span>
<span class="keyword">while</span> <span class="special">(</span><span class="identifier">pos</span> <span class="special">&lt;</span> <span class="identifier">line</span><span class="special">.</span><span class="identifier">length</span><span class="special">()</span> <span class="special">&amp;&amp;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">isalpha</span><span class="special">(</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">]))</span>
<span class="identifier">token</span> <span class="special">+=</span> <span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">++];</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span> <span class="comment">// pass token downstream</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span> <span class="comment">// punctuation</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">(</span><span class="number">1</span><span class="special">,</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">++]));</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">only_words</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
<span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">source</span><span class="special">){</span>
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">token</span><span class="special">.</span><span class="identifier">empty</span><span class="special">()</span> <span class="special">&amp;&amp;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">isalpha</span><span class="special">(</span><span class="identifier">token</span><span class="special">[</span><span class="number">0</span><span class="special">]))</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">trace</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span> <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
<span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">source</span><span class="special">){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"trace: '"</span> <span class="special">&lt;&lt;</span> <span class="identifier">token</span> <span class="special">&lt;&lt;</span> <span class="string">"'\n"</span><span class="special">;</span>
<span class="identifier">sink</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">struct</span> <span class="identifier">FinalEOL</span><span class="special">{</span>
<span class="special">~</span><span class="identifier">FinalEOL</span><span class="special">(){</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="keyword">void</span> <span class="identifier">layout</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">,</span><span class="keyword">int</span> <span class="identifier">num</span><span class="special">,</span><span class="keyword">int</span> <span class="identifier">width</span><span class="special">){</span>
<span class="comment">// Finish the last line when we leave by whatever means</span>
<span class="identifier">FinalEOL</span> <span class="identifier">eol</span><span class="special">;</span>
<span class="comment">// Pull values from upstream, lay them out 'num' to a line</span>
<span class="keyword">for</span> <span class="special">(;;){</span>
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special">&lt;</span> <span class="identifier">num</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span>
<span class="comment">// when we exhaust the input, stop</span>
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">source</span><span class="special">)</span> <span class="keyword">return</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setw</span><span class="special">(</span><span class="identifier">width</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">source</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="comment">// now that we've handled this item, advance to next</span>
<span class="identifier">source</span><span class="special">();</span>
<span class="special">}</span>
<span class="comment">// after 'num' items, line break</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="comment">// For example purposes, instead of having a separate text file in the</span>
<span class="comment">// local filesystem, construct an istringstream to read.</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">data</span><span class="special">(</span>
<span class="string">"This is the first line.\n"</span>
<span class="string">"This, the second.\n"</span>
<span class="string">"The third has \"a phrase\"!\n"</span>
<span class="special">);</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"\nfilter:\n"</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">infile</span><span class="special">(</span><span class="identifier">data</span><span class="special">);</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">reader</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">readlines</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">infile</span><span class="special">)));</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">tokenizer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">tokenize</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">reader</span><span class="special">)));</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">filter</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">only_words</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">tokenizer</span><span class="special">)));</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">tracer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">trace</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">filter</span><span class="special">)));</span>
<span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">tracer</span><span class="special">){</span>
<span class="comment">// just iterate, we're already pulling through tracer</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"\nlayout() as coroutine::push_type:\n"</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">infile</span><span class="special">(</span><span class="identifier">data</span><span class="special">);</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">reader</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">readlines</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">infile</span><span class="special">)));</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">tokenizer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">tokenize</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">reader</span><span class="special">)));</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">filter</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">only_words</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">tokenizer</span><span class="special">)));</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">writer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">layout</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="number">5</span><span class="special">,</span> <span class="number">15</span><span class="special">));</span>
<span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">filter</span><span class="special">){</span>
<span class="identifier">writer</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"\nfiltering output:\n"</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">infile</span><span class="special">(</span><span class="identifier">data</span><span class="special">);</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">reader</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">readlines</span><span class="special">,</span><span class="identifier">_1</span><span class="special">,</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">infile</span><span class="special">)));</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">tokenizer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">tokenize</span><span class="special">,</span><span class="identifier">_1</span><span class="special">,</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">reader</span><span class="special">)));</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">writer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">layout</span><span class="special">,</span><span class="identifier">_1</span><span class="special">,</span><span class="number">5</span><span class="special">,</span><span class="number">15</span><span class="special">));</span>
<span class="comment">// Because of the symmetry of the API, we can use any of these</span>
<span class="comment">// chaining functions in a push_type coroutine chain as well.</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">filter</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">only_words</span><span class="special">,</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">writer</span><span class="special">),</span><span class="identifier">_1</span><span class="special">));</span>
<span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">tokenizer</span><span class="special">){</span>
<span class="identifier">filter</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
</pre>
<div class="footnotes">
<br><hr style="width:100; text-align:left;margin-left: 0">
<div id="ftn.coroutine.motivation.f0" class="footnote"><p><a href="#coroutine.motivation.f0" class="para"><sup class="para">[4] </sup></a>
Christopher Kohlhoff, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3964.pdf" target="_top">N3964
- Library Foundations for Asynchronous Operations, Revision 1</a>
</p></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="intro.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="coroutine.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,84 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Overview</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="next" href="intro.html" title="Introduction">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../index.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="intro.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.overview"></a><a class="link" href="overview.html" title="Overview">Overview</a>
</h2></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine</strong></span> provides templates for generalized
subroutines which allow suspending and resuming execution at certain locations.
It preserves the local state of execution and allows re-entering subroutines
more than once (useful if state must be kept across function calls).
</p>
<p>
Coroutines can be viewed as a language-level construct providing a special
kind of control flow.
</p>
<p>
In contrast to threads, which are pre-emptive, <span class="emphasis"><em>coroutine</em></span>
switches are cooperative (programmer controls when a switch will happen). The
kernel is not involved in the coroutine switches.
</p>
<p>
The implementation uses <span class="bold"><strong>Boost.Context</strong></span> for
context switching.
</p>
<p>
In order to use the classes and functions described here, you can either include
the specific headers specified by the descriptions of each class or function,
or include the master library header:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">all</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
</pre>
<p>
which includes all the other headers in turn.
</p>
<p>
All functions and classes are contained in the namespace <span class="emphasis"><em>boost::coroutines</em></span>.
</p>
<div class="warning"><table border="0" summary="Warning">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="../../../../../doc/src/images/warning.png"></td>
<th align="left">Warning</th>
</tr>
<tr><td align="left" valign="top"><p>
BoostCoroutine is now deprecated. Please use <a href="http://www.boost.org/doc/libs/release/libs/coroutine2/index.html" target="_top">Boost.Coroutine2</a>.
</p></td></tr>
</table></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../index.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="intro.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,241 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Performance</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="stack/valgrind.html" title="Support for valgrind">
<link rel="next" href="architectures.html" title="Architectures">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack/valgrind.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="architectures.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.performance"></a><a class="link" href="performance.html" title="Performance">Performance</a>
</h2></div></div></div>
<p>
Performance of <span class="bold"><strong>Boost.Coroutine</strong></span> was measured
on the platforms shown in the following table. Performance measurements were
taken using <code class="computeroutput"><span class="identifier">rdtsc</span></code> and <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">high_resolution_clock</span></code>,
with overhead corrections, on x86 platforms. In each case, cache warm-up was
accounted for, and the one running thread was pinned to a single CPU.
</p>
<div class="table">
<a name="coroutine.performance.performance_of_asymmetric_coroutines"></a><p class="title"><b>Table&#160;1.1.&#160;Performance of asymmetric coroutines</b></p>
<div class="table-contents"><table class="table" summary="Performance of asymmetric coroutines">
<colgroup>
<col>
<col>
<col>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Platform
</p>
</th>
<th>
<p>
switch
</p>
</th>
<th>
<p>
construction (protected stack-allocator)
</p>
</th>
<th>
<p>
construction (preallocated stack-allocator)
</p>
</th>
<th>
<p>
construction (standard stack-allocator)
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)
</p>
</td>
<td>
<p>
49 ns / 50 cycles
</p>
</td>
<td>
<p>
51 &#181;s / 51407 cycles
</p>
</td>
<td>
<p>
14 &#181;s / 15231 cycles
</p>
</td>
<td>
<p>
14 &#181;s / 15216 cycles
</p>
</td>
</tr>
<tr>
<td>
<p>
x86_64 (Intel Core2 Q6700, Linux 64bit)
</p>
</td>
<td>
<p>
12 ns / 39 cycles
</p>
</td>
<td>
<p>
16 &#181;s / 41802 cycles
</p>
</td>
<td>
<p>
6 &#181;s / 10350 cycles
</p>
</td>
<td>
<p>
6 &#181;s / 18817 cycles
</p>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break"><div class="table">
<a name="coroutine.performance.performance_of_symmetric_coroutines"></a><p class="title"><b>Table&#160;1.2.&#160;Performance of symmetric coroutines</b></p>
<div class="table-contents"><table class="table" summary="Performance of symmetric coroutines">
<colgroup>
<col>
<col>
<col>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Platform
</p>
</th>
<th>
<p>
switch
</p>
</th>
<th>
<p>
construction (protected stack-allocator)
</p>
</th>
<th>
<p>
construction (preallocated stack-allocator)
</p>
</th>
<th>
<p>
construction (standard stack-allocator)
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)
</p>
</td>
<td>
<p>
47 ns / 49 cycles
</p>
</td>
<td>
<p>
27 &#181;s / 28002 cycles
</p>
</td>
<td>
<p>
98 ns / 116 cycles
</p>
</td>
<td>
<p>
319 ns / 328 cycles
</p>
</td>
</tr>
<tr>
<td>
<p>
x86_64 (Intel Core2 Q6700, Linux 64bit)
</p>
</td>
<td>
<p>
10 ns / 33 cycles
</p>
</td>
<td>
<p>
10 &#181;s / 22828 cycles
</p>
</td>
<td>
<p>
42 ns / 710 cycles
</p>
</td>
<td>
<p>
135 ns / 362 cycles
</p>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break">
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack/valgrind.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="architectures.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,177 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Stack allocation</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="prev" href="attributes.html" title="Attributes">
<link rel="next" href="stack/protected_stack_allocator.html" title="Class protected_stack_allocator">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="attributes.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack/protected_stack_allocator.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.stack"></a><a class="link" href="stack.html" title="Stack allocation">Stack allocation</a>
</h2></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="stack/protected_stack_allocator.html">Class <span class="emphasis"><em>protected_stack_allocator</em></span></a></span></dt>
<dt><span class="section"><a href="stack/standard_stack_allocator.html">Class <span class="emphasis"><em>standard_stack_allocator</em></span></a></span></dt>
<dt><span class="section"><a href="stack/segmented_stack_allocator.html">Class <span class="emphasis"><em>segmented_stack_allocator</em></span></a></span></dt>
<dt><span class="section"><a href="stack/stack_traits.html">Class <span class="emphasis"><em>stack_traits</em></span></a></span></dt>
<dt><span class="section"><a href="stack/stack_context.html">Class <span class="emphasis"><em>stack_context</em></span></a></span></dt>
<dt><span class="section"><a href="stack/valgrind.html">Support for valgrind</a></span></dt>
</dl></div>
<p>
A <span class="emphasis"><em>coroutine</em></span> uses internally a <span class="emphasis"><em>context</em></span>
which manages a set of registers and a stack. The memory used by the stack
is allocated/deallocated via a <span class="emphasis"><em>stack-allocator</em></span> which is
required to model a <span class="emphasis"><em>stack-allocator concept</em></span>.
</p>
<h4>
<a name="coroutine.stack.h0"></a>
<span class="phrase"><a name="coroutine.stack._emphasis_stack_allocator_concept__emphasis_"></a></span><a class="link" href="stack.html#coroutine.stack._emphasis_stack_allocator_concept__emphasis_"><span class="emphasis"><em>stack-allocator
concept</em></span></a>
</h4>
<p>
A <span class="emphasis"><em>stack-allocator</em></span> must satisfy the <span class="emphasis"><em>stack-allocator
concept</em></span> requirements shown in the following table, in which <code class="computeroutput"><span class="identifier">a</span></code> is an object of a <span class="emphasis"><em>stack-allocator</em></span>
type, <code class="computeroutput"><span class="identifier">sctx</span></code> is a <code class="computeroutput"><span class="identifier">stack_context</span></code>, and <code class="computeroutput"><span class="identifier">size</span></code>
is a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span></code>:
</p>
<div class="informaltable"><table class="table">
<colgroup>
<col>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
expression
</p>
</th>
<th>
<p>
return type
</p>
</th>
<th>
<p>
notes
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">allocate</span><span class="special">(</span>
<span class="identifier">sctx</span><span class="special">,</span>
<span class="identifier">size</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">void</span></code>
</p>
</td>
<td>
<p>
creates a stack of at least <code class="computeroutput"><span class="identifier">size</span></code>
bytes and stores its pointer and length in <code class="computeroutput"><span class="identifier">sctx</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">deallocate</span><span class="special">(</span>
<span class="identifier">sctx</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">void</span></code>
</p>
</td>
<td>
<p>
deallocates the stack created by <code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">allocate</span><span class="special">()</span></code>
</p>
</td>
</tr>
</tbody>
</table></div>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
The implementation of <code class="computeroutput"><span class="identifier">allocate</span><span class="special">()</span></code> might include logic to protect against
exceeding the context's available stack size rather than leaving it as undefined
behaviour.
</p></td></tr>
</table></div>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Calling <code class="computeroutput"><span class="identifier">deallocate</span><span class="special">()</span></code>
with a <code class="computeroutput"><span class="identifier">stack_context</span></code> not
set by <code class="computeroutput"><span class="identifier">allocate</span><span class="special">()</span></code>
results in undefined behaviour.
</p></td></tr>
</table></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
The stack is not required to be aligned; alignment takes place inside <span class="emphasis"><em>coroutine</em></span>.
</p></td></tr>
</table></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
Depending on the architecture <code class="computeroutput"><span class="identifier">allocate</span><span class="special">()</span></code> stores an address from the top of the stack
(growing downwards) or the bottom of the stack (growing upwards).
</p></td></tr>
</table></div>
<p>
class <span class="emphasis"><em>stack_allocator</em></span> is a typedef of <span class="emphasis"><em>standard_stack_allocator</em></span>.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="attributes.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack/protected_stack_allocator.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,132 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class protected_stack_allocator</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="../stack.html" title="Stack allocation">
<link rel="next" href="standard_stack_allocator.html" title="Class standard_stack_allocator">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../stack.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="standard_stack_allocator.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="coroutine.stack.protected_stack_allocator"></a><a class="link" href="protected_stack_allocator.html" title="Class protected_stack_allocator">Class <span class="emphasis"><em>protected_stack_allocator</em></span></a>
</h3></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine</strong></span> provides the class <span class="emphasis"><em>protected_stack_allocator</em></span>
which models the <span class="emphasis"><em>stack-allocator concept</em></span>. It appends
a guard page at the end of each stack to protect against exceeding the stack.
If the guard page is accessed (read or write operation) a segmentation fault/access
violation is generated by the operating system.
</p>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Using <span class="emphasis"><em>protected_stack_allocator</em></span> is expensive. That
is, launching a new coroutine with a new stack is expensive; the allocated
stack is just as efficient to use as any other stack.
</p></td></tr>
</table></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
The appended <code class="computeroutput"><span class="identifier">guard</span> <span class="identifier">page</span></code>
is <span class="bold"><strong>not</strong></span> mapped to physical memory, only
virtual addresses are used.
</p></td></tr>
</table></div>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">protected_stack_allocator</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">traitsT</span> <span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">basic_protected_stack_allocator</span>
<span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">traitT</span> <span class="identifier">traits_type</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">allocate</span><span class="special">(</span> <span class="identifier">stack_context</span> <span class="special">&amp;,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">);</span>
<span class="keyword">void</span> <span class="identifier">deallocate</span><span class="special">(</span> <span class="identifier">stack_context</span> <span class="special">&amp;);</span>
<span class="special">}</span>
<span class="keyword">typedef</span> <span class="identifier">basic_protected_stack_allocator</span><span class="special">&lt;</span> <span class="identifier">stack_traits</span> <span class="special">&gt;</span> <span class="identifier">protected_stack_allocator</span>
</pre>
<h5>
<a name="coroutine.stack.protected_stack_allocator.h0"></a>
<span class="phrase"><a name="coroutine.stack.protected_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="protected_stack_allocator.html#coroutine.stack.protected_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">allocate</span><span class="special">(</span> <span class="identifier">stack_context</span>
<span class="special">&amp;</span> <span class="identifier">sctx</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">)</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">minimum_size</span><span class="special">()</span>
<span class="special">&lt;=</span> <span class="identifier">size</span></code>
and <code class="computeroutput"><span class="special">!</span> <span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">is_unbounded</span><span class="special">()</span> <span class="special">&amp;&amp;</span>
<span class="special">(</span> <span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">maximum_size</span><span class="special">()</span> <span class="special">&gt;=</span> <span class="identifier">size</span><span class="special">)</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Allocates memory of at least <code class="computeroutput"><span class="identifier">size</span></code>
bytes and stores a pointer to the stack and its actual size in <code class="computeroutput"><span class="identifier">sctx</span></code>. Depending on the architecture
(the stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine.stack.protected_stack_allocator.h1"></a>
<span class="phrase"><a name="coroutine.stack.protected_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__deallocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="protected_stack_allocator.html#coroutine.stack.protected_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__deallocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">deallocate</span><span class="special">(</span> <span class="identifier">stack_context</span>
<span class="special">&amp;</span> <span class="identifier">sctx</span><span class="special">)</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">sctx</span><span class="special">.</span><span class="identifier">sp</span></code> is valid, <code class="computeroutput"><span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">minimum_size</span><span class="special">()</span> <span class="special">&lt;=</span> <span class="identifier">sctx</span><span class="special">.</span><span class="identifier">size</span></code> and <code class="computeroutput"><span class="special">!</span>
<span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">is_unbounded</span><span class="special">()</span>
<span class="special">&amp;&amp;</span> <span class="special">(</span>
<span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">maximum_size</span><span class="special">()</span>
<span class="special">&gt;=</span> <span class="identifier">sctx</span><span class="special">.</span><span class="identifier">size</span><span class="special">)</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Deallocates the stack space.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../stack.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="standard_stack_allocator.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,126 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class segmented_stack_allocator</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="standard_stack_allocator.html" title="Class standard_stack_allocator">
<link rel="next" href="stack_traits.html" title="Class stack_traits">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="standard_stack_allocator.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack_traits.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="coroutine.stack.segmented_stack_allocator"></a><a class="link" href="segmented_stack_allocator.html" title="Class segmented_stack_allocator">Class <span class="emphasis"><em>segmented_stack_allocator</em></span></a>
</h3></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine</strong></span> supports usage of a <span class="emphasis"><em>segmented-stack</em></span>,
e. g. the size of the stack grows on demand. The coroutine is created with
a minimal stack size and will be increased as required. Class <span class="emphasis"><em>segmented_stack_allocator</em></span>
models the <span class="emphasis"><em>stack-allocator concept</em></span>. In contrast to
<span class="emphasis"><em>protected_stack_allocator</em></span> and <span class="emphasis"><em>standard_stack_allocator</em></span>
it creates a stack which grows on demand.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
Segmented stacks are currently only supported by <span class="bold"><strong>gcc</strong></span>
from version <span class="bold"><strong>4.7</strong></span> and <span class="bold"><strong>clang</strong></span>
from version <span class="bold"><strong>3.4</strong></span> onwards. In order to
use a <span class="emphasis"><em>segmented-stack</em></span> <span class="bold"><strong>Boost.Coroutine</strong></span>
must be built with <span class="bold"><strong>toolset=gcc segmented-stacks=on</strong></span>
at b2/bjam command-line. Applications must be compiled with compiler-flags
<span class="bold"><strong>-fsplit-stack -DBOOST_USE_SEGMENTED_STACKS</strong></span>.
</p></td></tr>
</table></div>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">segmented_stack_allocator</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">traitsT</span> <span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">basic_segmented_stack_allocator</span>
<span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">traitT</span> <span class="identifier">traits_type</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">allocate</span><span class="special">(</span> <span class="identifier">stack_context</span> <span class="special">&amp;,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">);</span>
<span class="keyword">void</span> <span class="identifier">deallocate</span><span class="special">(</span> <span class="identifier">stack_context</span> <span class="special">&amp;);</span>
<span class="special">}</span>
<span class="keyword">typedef</span> <span class="identifier">basic_segmented_stack_allocator</span><span class="special">&lt;</span> <span class="identifier">stack_traits</span> <span class="special">&gt;</span> <span class="identifier">segmented_stack_allocator</span><span class="special">;</span>
</pre>
<h5>
<a name="coroutine.stack.segmented_stack_allocator.h0"></a>
<span class="phrase"><a name="coroutine.stack.segmented_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="segmented_stack_allocator.html#coroutine.stack.segmented_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">allocate</span><span class="special">(</span> <span class="identifier">stack_context</span>
<span class="special">&amp;</span> <span class="identifier">sctx</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">)</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">minimum_size</span><span class="special">()</span>
<span class="special">&lt;=</span> <span class="identifier">size</span></code>
and <code class="computeroutput"><span class="special">!</span> <span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">is_unbounded</span><span class="special">()</span> <span class="special">&amp;&amp;</span>
<span class="special">(</span> <span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">maximum_size</span><span class="special">()</span> <span class="special">&gt;=</span> <span class="identifier">size</span><span class="special">)</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Allocates memory of at least <code class="computeroutput"><span class="identifier">size</span></code>
bytes and stores a pointer to the stack and its actual size in <code class="computeroutput"><span class="identifier">sctx</span></code>. Depending on the architecture
(the stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine.stack.segmented_stack_allocator.h1"></a>
<span class="phrase"><a name="coroutine.stack.segmented_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__deallocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="segmented_stack_allocator.html#coroutine.stack.segmented_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__deallocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">deallocate</span><span class="special">(</span> <span class="identifier">stack_context</span>
<span class="special">&amp;</span> <span class="identifier">sctx</span><span class="special">)</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">sctx</span><span class="special">.</span><span class="identifier">sp</span></code> is valid, <code class="computeroutput"><span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">minimum_size</span><span class="special">()</span> <span class="special">&lt;=</span> <span class="identifier">sctx</span><span class="special">.</span><span class="identifier">size</span></code> and <code class="computeroutput"><span class="special">!</span>
<span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">is_unbounded</span><span class="special">()</span>
<span class="special">&amp;&amp;</span> <span class="special">(</span>
<span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">maximum_size</span><span class="special">()</span>
<span class="special">&gt;=</span> <span class="identifier">sctx</span><span class="special">.</span><span class="identifier">size</span><span class="special">)</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Deallocates the stack space.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="standard_stack_allocator.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack_traits.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,85 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class stack_context</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="stack_traits.html" title="Class stack_traits">
<link rel="next" href="valgrind.html" title="Support for valgrind">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack_traits.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="valgrind.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="coroutine.stack.stack_context"></a><a class="link" href="stack_context.html" title="Class stack_context">Class <span class="emphasis"><em>stack_context</em></span></a>
</h3></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine</strong></span> provides the class <span class="emphasis"><em>stack_context</em></span>
which will contain the stack pointer and the size of the stack. In case of
a <span class="emphasis"><em>segmented-stack</em></span>, <span class="emphasis"><em>stack_context</em></span>
contains some extra control structures.
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">stack_context</span>
<span class="special">{</span>
<span class="keyword">void</span> <span class="special">*</span> <span class="identifier">sp</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">;</span>
<span class="comment">// might contain additional control structures</span>
<span class="comment">// for instance for segmented stacks</span>
<span class="special">}</span>
</pre>
<h5>
<a name="coroutine.stack.stack_context.h0"></a>
<span class="phrase"><a name="coroutine.stack.stack_context._code__phrase_role__keyword__void__phrase___phrase_role__special_____phrase___phrase_role__identifier__sp__phrase___code_"></a></span><a class="link" href="stack_context.html#coroutine.stack.stack_context._code__phrase_role__keyword__void__phrase___phrase_role__special_____phrase___phrase_role__identifier__sp__phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="special">*</span> <span class="identifier">sp</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Value:</span></dt>
<dd><p>
Pointer to the beginning of the stack.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine.stack.stack_context.h1"></a>
<span class="phrase"><a name="coroutine.stack.stack_context._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase___code_"></a></span><a class="link" href="stack_context.html#coroutine.stack.stack_context._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase___code_"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
<span class="identifier">size</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Value:</span></dt>
<dd><p>
Actual size of the stack.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack_traits.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="valgrind.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,158 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class stack_traits</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="segmented_stack_allocator.html" title="Class segmented_stack_allocator">
<link rel="next" href="stack_context.html" title="Class stack_context">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="segmented_stack_allocator.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack_context.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="coroutine.stack.stack_traits"></a><a class="link" href="stack_traits.html" title="Class stack_traits">Class <span class="emphasis"><em>stack_traits</em></span></a>
</h3></div></div></div>
<p>
<span class="emphasis"><em>stack_traits</em></span> models a <span class="emphasis"><em>stack-traits</em></span>
providing a way to access certain properites defined by the enironment. Stack
allocators use <span class="emphasis"><em>stack-traits</em></span> to allocate stacks.
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">stack_traits</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">stack_traits</span>
<span class="special">{</span>
<span class="keyword">static</span> <span class="keyword">bool</span> <span class="identifier">is_unbounded</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">page_size</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">default_size</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">minimum_size</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">maximum_size</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<h5>
<a name="coroutine.stack.stack_traits.h0"></a>
<span class="phrase"><a name="coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__keyword__bool__phrase___phrase_role__identifier__is_unbounded__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="stack_traits.html#coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__keyword__bool__phrase___phrase_role__identifier__is_unbounded__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="keyword">static</span> <span class="keyword">bool</span> <span class="identifier">is_unbounded</span><span class="special">()</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns <code class="computeroutput"><span class="keyword">true</span></code> if the environment
defines no limit for the size of a stack.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine.stack.stack_traits.h1"></a>
<span class="phrase"><a name="coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__page_size__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="stack_traits.html#coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__page_size__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">page_size</span><span class="special">()</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns the page size in bytes.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine.stack.stack_traits.h2"></a>
<span class="phrase"><a name="coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__default_size__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="stack_traits.html#coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__default_size__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">default_size</span><span class="special">()</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns a default stack size, which may be platform specific. If the
stack is unbounded then the present implementation returns the maximum
of <code class="computeroutput"><span class="number">64</span> <span class="identifier">kB</span></code>
and <code class="computeroutput"><span class="identifier">minimum_size</span><span class="special">()</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine.stack.stack_traits.h3"></a>
<span class="phrase"><a name="coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__minimum_size__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="stack_traits.html#coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__minimum_size__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">minimum_size</span><span class="special">()</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns the minimum size in bytes of stack defined by the environment
(Win32 4kB/Win64 8kB, defined by rlimit on POSIX).
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine.stack.stack_traits.h4"></a>
<span class="phrase"><a name="coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__maximum_size__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="stack_traits.html#coroutine.stack.stack_traits._code__phrase_role__keyword__static__phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__maximum_size__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">maximum_size</span><span class="special">()</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">is_unbounded</span><span class="special">()</span></code>
returns <code class="computeroutput"><span class="keyword">false</span></code>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
Returns the maximum size in bytes of stack defined by the environment.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="segmented_stack_allocator.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack_context.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,119 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class standard_stack_allocator</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="protected_stack_allocator.html" title="Class protected_stack_allocator">
<link rel="next" href="segmented_stack_allocator.html" title="Class segmented_stack_allocator">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="protected_stack_allocator.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="segmented_stack_allocator.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="coroutine.stack.standard_stack_allocator"></a><a class="link" href="standard_stack_allocator.html" title="Class standard_stack_allocator">Class <span class="emphasis"><em>standard_stack_allocator</em></span></a>
</h3></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine</strong></span> provides the class <span class="emphasis"><em>standard_stack_allocator</em></span>
which models the <span class="emphasis"><em>stack-allocator concept</em></span>. In contrast
to <span class="emphasis"><em>protected_stack_allocator</em></span> it does not append a guard
page at the end of each stack. The memory is simply managed by <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">malloc</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">free</span><span class="special">()</span></code>.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
The <span class="emphasis"><em>standard_stack_allocator</em></span> is the default stack
allocator.
</p></td></tr>
</table></div>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">coroutine</span><span class="special">/</span><span class="identifier">standard_stack_allocator</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">traitsT</span> <span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">standard_stack_allocator</span>
<span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">traitT</span> <span class="identifier">traits_type</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">allocate</span><span class="special">(</span> <span class="identifier">stack_context</span> <span class="special">&amp;,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">);</span>
<span class="keyword">void</span> <span class="identifier">deallocate</span><span class="special">(</span> <span class="identifier">stack_context</span> <span class="special">&amp;);</span>
<span class="special">}</span>
<span class="keyword">typedef</span> <span class="identifier">basic_standard_stack_allocator</span><span class="special">&lt;</span> <span class="identifier">stack_traits</span> <span class="special">&gt;</span> <span class="identifier">standard_stack_allocator</span>
</pre>
<h5>
<a name="coroutine.stack.standard_stack_allocator.h0"></a>
<span class="phrase"><a name="coroutine.stack.standard_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="standard_stack_allocator.html#coroutine.stack.standard_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__size__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">allocate</span><span class="special">(</span> <span class="identifier">stack_context</span>
<span class="special">&amp;</span> <span class="identifier">sctx</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">)</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">minimum_size</span><span class="special">()</span>
<span class="special">&lt;=</span> <span class="identifier">size</span></code>
and <code class="computeroutput"><span class="special">!</span> <span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">is_unbounded</span><span class="special">()</span> <span class="special">&amp;&amp;</span>
<span class="special">(</span> <span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">maximum_size</span><span class="special">()</span> <span class="special">&gt;=</span> <span class="identifier">size</span><span class="special">)</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Allocates memory of at least <code class="computeroutput"><span class="identifier">size</span></code>
bytes and stores a pointer to the stack and its actual size in <code class="computeroutput"><span class="identifier">sctx</span></code>. Depending on the architecture
(the stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine.stack.standard_stack_allocator.h1"></a>
<span class="phrase"><a name="coroutine.stack.standard_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__deallocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="standard_stack_allocator.html#coroutine.stack.standard_stack_allocator._code__phrase_role__keyword__void__phrase___phrase_role__identifier__deallocate__phrase__phrase_role__special_____phrase___phrase_role__identifier__stack_context__phrase___phrase_role__special___amp___phrase___phrase_role__identifier__sctx__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="keyword">void</span> <span class="identifier">deallocate</span><span class="special">(</span> <span class="identifier">stack_context</span>
<span class="special">&amp;</span> <span class="identifier">sctx</span><span class="special">)</span></code></a>
</h5>
<div class="variablelist">
<p class="title"><b></b></p>
<dl class="variablelist">
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">sctx</span><span class="special">.</span><span class="identifier">sp</span></code> is valid, <code class="computeroutput"><span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">minimum_size</span><span class="special">()</span> <span class="special">&lt;=</span> <span class="identifier">sctx</span><span class="special">.</span><span class="identifier">size</span></code> and <code class="computeroutput"><span class="special">!</span>
<span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">is_unbounded</span><span class="special">()</span>
<span class="special">&amp;&amp;</span> <span class="special">(</span>
<span class="identifier">traits_type</span><span class="special">::</span><span class="identifier">maximum_size</span><span class="special">()</span>
<span class="special">&gt;=</span> <span class="identifier">sctx</span><span class="special">.</span><span class="identifier">size</span><span class="special">)</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Deallocates the stack space.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="protected_stack_allocator.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="segmented_stack_allocator.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,48 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Support for valgrind</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="stack_context.html" title="Class stack_context">
<link rel="next" href="../performance.html" title="Performance">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack_context.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../performance.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="coroutine.stack.valgrind"></a><a class="link" href="valgrind.html" title="Support for valgrind">Support for valgrind</a>
</h3></div></div></div>
<p>
Running programs that switch stacks under valgrind causes problems. Property
(b2 command-line) <code class="computeroutput"><span class="identifier">valgrind</span><span class="special">=</span><span class="identifier">on</span></code> let
valgrind treat the memory regions as stack space which suppresses the errors.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2009 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack_context.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../performance.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,79 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Chapter&#160;1.&#160;Coroutine</title>
<link rel="stylesheet" href="../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="index.html" title="Chapter&#160;1.&#160;Coroutine">
<link rel="next" href="coroutine/overview.html" title="Overview">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../boost.png"></td>
<td align="center"><a href="../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav"><a accesskey="n" href="coroutine/overview.html"><img src="../../../../doc/src/images/next.png" alt="Next"></a></div>
<div class="chapter">
<div class="titlepage"><div>
<div><h2 class="title">
<a name="coroutine"></a>Chapter&#160;1.&#160;Coroutine</h2></div>
<div><div class="author"><h3 class="author">
<span class="firstname">Oliver</span> <span class="surname">Kowalke</span>
</h3></div></div>
<div><p class="copyright">Copyright &#169; 2009 Oliver Kowalke</p></div>
<div><div class="legalnotice">
<a name="coroutine.legal"></a><p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></div>
</div></div>
<div class="toc">
<p><b>Table of Contents</b></p>
<dl class="toc">
<dt><span class="section"><a href="coroutine/overview.html">Overview</a></span></dt>
<dt><span class="section"><a href="coroutine/intro.html">Introduction</a></span></dt>
<dt><span class="section"><a href="coroutine/motivation.html">Motivation</a></span></dt>
<dt><span class="section"><a href="coroutine/coroutine.html">Coroutine</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine/coroutine/asymmetric.html">Asymmetric coroutine</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine/coroutine/asymmetric/pull_coro.html">Class <code class="computeroutput"><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">pull_type</span></code></a></span></dt>
<dt><span class="section"><a href="coroutine/coroutine/asymmetric/push_coro.html">Class <code class="computeroutput"><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">push_type</span></code></a></span></dt>
</dl></dd>
<dt><span class="section"><a href="coroutine/coroutine/symmetric.html">Symmetric coroutine</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine/coroutine/symmetric/symmetric_coro.html">Class
<code class="computeroutput"><span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">call_type</span></code></a></span></dt>
<dt><span class="section"><a href="coroutine/coroutine/symmetric/yield_coro.html">Class <code class="computeroutput"><span class="identifier">symmetric_coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">yield_type</span></code></a></span></dt>
</dl></dd>
</dl></dd>
<dt><span class="section"><a href="coroutine/attributes.html">Attributes</a></span></dt>
<dt><span class="section"><a href="coroutine/stack.html">Stack allocation</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine/stack/protected_stack_allocator.html">Class <span class="emphasis"><em>protected_stack_allocator</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine/stack/standard_stack_allocator.html">Class <span class="emphasis"><em>standard_stack_allocator</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine/stack/segmented_stack_allocator.html">Class <span class="emphasis"><em>segmented_stack_allocator</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine/stack/stack_traits.html">Class <span class="emphasis"><em>stack_traits</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine/stack/stack_context.html">Class <span class="emphasis"><em>stack_context</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine/stack/valgrind.html">Support for valgrind</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="coroutine/performance.html">Performance</a></span></dt>
<dt><span class="section"><a href="coroutine/architectures.html">Architectures</a></span></dt>
<dt><span class="section"><a href="coroutine/acknowledgements.html">Acknowledgments</a></span></dt>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><p><small>Last revised: December 14, 2017 at 00:00:18 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
<hr>
<div class="spirit-nav"><a accesskey="n" href="coroutine/overview.html"><img src="../../../../doc/src/images/next.png" alt="Next"></a></div>
</body>
</html>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -0,0 +1,107 @@
[/
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:intro Introduction]
[heading Definition]
In computer science routines are defined as a sequence of operations. The
execution of routines forms a parent-child relationship and the child terminates
always before the parent. Coroutines (the term was introduced by Melvin
Conway [footnote Conway, Melvin E.. "Design of a Separable Transition-Diagram Compiler".
Commun. ACM, Volume 6 Issue 7, July 1963, Article No. 7]),
are a generalization of routines (Donald Knuth [footnote Knuth, Donald Ervin (1997).
"Fundamental Algorithms. The Art of Computer Programming 1", (3rd ed.)].
The principal difference between coroutines and routines
is that a coroutine enables explicit suspend and resume of its progress via
additional operations by preserving execution state and thus provides an
[*enhanced control flow] (maintaining the execution context).
[heading How it works]
Functions foo() and bar() are supposed to alternate their execution (leave and
enter function body).
[$../../../../libs/coroutine/doc/images/foo_bar.png [align center]]
If coroutines were called exactly like routines, the stack would grow with
every call and would never be popped. A jump into the middle of a coroutine
would not be possible, because the return address would be on top of
stack entries.
The solution is that each coroutine has its own stack and control-block
(__fcontext__ from __boost_context__).
Before the coroutine gets suspended, the non-volatile registers (including stack
and instruction/program pointer) of the currently active coroutine are stored in
the coroutine's control-block.
The registers of the newly activated coroutine must be restored from its
associated control-block before it is resumed.
The context switch requires no system privileges and provides cooperative
multitasking convenient to C++. Coroutines provide quasi parallelism.
When a program is supposed to do several things at the same time, coroutines
help to do this much more simply and elegantly than with only a single flow of
control.
The advantages can be seen particularly clearly with the use of a recursive
function, such as traversal of binary trees (see example 'same fringe').
[heading characteristics]
Characteristics [footnote Moura, Ana Lucia De and Ierusalimschy, Roberto.
"Revisiting coroutines". ACM Trans. Program. Lang. Syst., Volume 31 Issue 2,
February 2009, Article No. 6] of a coroutine are:
* values of local data persist between successive calls (context switches)
* execution is suspended as control leaves coroutine and is resumed at certain time later
* symmetric or asymmetric control-transfer mechanism; see below
* first-class object (can be passed as argument, returned by procedures,
stored in a data structure to be used later or freely manipulated by
the developer)
* stackful or stackless
Coroutines are useful in simulation, artificial intelligence, concurrent
programming, text processing and data manipulation, supporting
the implementation of components such as cooperative tasks (fibers), iterators,
generators, infinite lists, pipes etc.
[heading execution-transfer mechanism]
Two categories of coroutines exist: symmetric and asymmetric coroutines.
An asymmetric coroutine knows its invoker, using a special operation to
implicitly yield control specifically to its invoker. By contrast, all symmetric
coroutines are equivalent; one symmetric coroutine may pass control to any
other symmetric coroutine. Because of this, a symmetric coroutine ['must]
specify the coroutine to which it intends to yield control.
[$../../../../libs/coroutine/doc/images/foo_bar_seq.png [align center]]
Both concepts are equivalent and a fully-general coroutine library can provide
either symmetric or asymmetric coroutines. For convenience, Boost.Coroutine
provides both.
[heading stackfulness]
In contrast to a stackless coroutine a stackful coroutine can be suspended
from within a nested stackframe. Execution resumes at exactly the same point
in the code where it was suspended before.
With a stackless coroutine, only the top-level routine may be suspended. Any
routine called by that top-level routine may not itself suspend. This prohibits
providing suspend/resume operations in routines within a general-purpose library.
[heading first-class continuation]
A first-class continuation can be passed as an argument, returned by a
function and stored in a data structure to be used later.
In some implementations (for instance C# ['yield]) the continuation can
not be directly accessed or directly manipulated.
Without stackfulness and first-class semantics, some useful execution control
flows cannot be supported (for instance cooperative multitasking or
checkpointing).
[endsect]

View File

@@ -0,0 +1,691 @@
[/
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:motivation Motivation]
In order to support a broad range of execution control behaviour the coroutine
types of __scoro__ and __acoro__ can be used to ['escape-and-reenter] loops, to
['escape-and-reenter] recursive computations and for ['cooperative] multitasking
helping to solve problems in a much simpler and more elegant way than with only
a single flow of control.
[heading event-driven model]
The event-driven model is a programming paradigm where the flow of a program is
determined by events. The events are generated by multiple independent sources
and an event-dispatcher, waiting on all external sources, triggers callback
functions (event-handlers) whenever one of those events is detected (event-loop).
The application is divided into event selection (detection) and event handling.
[$../../../../libs/coroutine/doc/images/event_model.png [align center]]
The resulting applications are highly scalable, flexible, have high
responsiveness and the components are loosely coupled. This makes the event-driven
model suitable for user interface applications, rule-based productions systems
or applications dealing with asynchronous I/O (for instance network servers).
[heading event-based asynchronous paradigm]
A classic synchronous console program issues an I/O request (e.g. for user
input or filesystem data) and blocks until the request is complete.
In contrast, an asynchronous I/O function initiates the physical operation but
immediately returns to its caller, even though the operation is not yet
complete. A program written to leverage this functionality does not block: it
can proceed with other work (including other I/O requests in parallel) while
the original operation is still pending. When the operation completes, the
program is notified. Because asynchronous applications spend less overall time
waiting for operations, they can outperform synchronous programs.
Events are one of the paradigms for asynchronous execution, but
not all asynchronous systems use events.
Although asynchronous programming can be done using threads, they come with
their own costs:
* hard to program (traps for the unwary)
* memory requirements are high
* large overhead with creation and maintenance of thread state
* expensive context switching between threads
The event-based asynchronous model avoids those issues:
* simpler because of the single stream of instructions
* much less expensive context switches
The downside of this paradigm consists in a sub-optimal program
structure. An event-driven program is required to split its code into
multiple small callback functions, i.e. the code is organized in a sequence of
small steps that execute intermittently. An algorithm that would usually be expressed
as a hierarchy of functions and loops must be transformed into callbacks. The
complete state has to be stored into a data structure while the control flow
returns to the event-loop.
As a consequence, event-driven applications are often tedious and confusing to
write. Each callback introduces a new scope, error callback etc. The
sequential nature of the algorithm is split into multiple callstacks,
making the application hard to debug. Exception handlers are restricted to
local handlers: it is impossible to wrap a sequence of events into a single
try-catch block.
The use of local variables, while/for loops, recursions etc. together with the
event-loop is not possible. The code becomes less expressive.
In the past, code using asio's ['asynchronous operations] was convoluted by
callback functions.
class session
{
public:
session(boost::asio::io_service& io_service) :
socket_(io_service) // construct a TCP-socket from io_service
{}
tcp::socket& socket(){
return socket_;
}
void start(){
// initiate asynchronous read; handle_read() is callback-function
socket_.async_read_some(boost::asio::buffer(data_,max_length),
boost::bind(&session::handle_read,this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
private:
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred){
if (!error)
// initiate asynchronous write; handle_write() is callback-function
boost::asio::async_write(socket_,
boost::asio::buffer(data_,bytes_transferred),
boost::bind(&session::handle_write,this,
boost::asio::placeholders::error));
else
delete this;
}
void handle_write(const boost::system::error_code& error){
if (!error)
// initiate asynchronous read; handle_read() is callback-function
socket_.async_read_some(boost::asio::buffer(data_,max_length),
boost::bind(&session::handle_read,this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
else
delete this;
}
boost::asio::ip::tcp::socket socket_;
enum { max_length=1024 };
char data_[max_length];
};
In this example, a simple echo server, the logic is split into three member
functions - local state (such as data buffer) is moved to member variables.
__boost_asio__ provides with its new ['asynchronous result] feature a new
framework combining event-driven model and coroutines, hiding the complexity
of event-driven programming and permitting the style of classic sequential code.
The application is not required to pass callback functions to asynchronous
operations and local state is kept as local variables. Therefore the code
is much easier to read and understand.
[footnote Christopher Kohlhoff,
[@ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3964.pdf
N3964 - Library Foundations for Asynchronous Operations, Revision 1]].
__yield_context__ internally uses __boost_coroutine__:
void session(boost::asio::io_service& io_service){
// construct TCP-socket from io_service
boost::asio::ip::tcp::socket socket(io_service);
try{
for(;;){
// local data-buffer
char data[max_length];
boost::system::error_code ec;
// read asynchronous data from socket
// execution context will be suspended until
// some bytes are read from socket
std::size_t length=socket.async_read_some(
boost::asio::buffer(data),
boost::asio::yield[ec]);
if (ec==boost::asio::error::eof)
break; //connection closed cleanly by peer
else if(ec)
throw boost::system::system_error(ec); //some other error
// write some bytes asynchronously
boost::asio::async_write(
socket,
boost::asio::buffer(data,length),
boost::asio::yield[ec]);
if (ec==boost::asio::error::eof)
break; //connection closed cleanly by peer
else if(ec)
throw boost::system::system_error(ec); //some other error
}
} catch(std::exception const& e){
std::cerr<<"Exception: "<<e.what()<<"\n";
}
}
In contrast to the previous example this one gives the impression of sequential
code and local data (['data]) while using asynchronous operations
(['async_read()], ['async_write()]). The algorithm is implemented in one
function and error handling is done by one try-catch block.
[heading recursive SAX parsing]
To someone who knows SAX, the phrase "recursive SAX parsing" might sound
nonsensical. You get callbacks from SAX; you have to manage the element stack
yourself. If you want recursive XML processing, you must first read the entire
DOM into memory, then walk the tree.
But coroutines let you invert the flow of control so you can ask for SAX
events. Once you can do that, you can process them recursively.
// Represent a subset of interesting SAX events
struct BaseEvent{
BaseEvent(const BaseEvent&)=delete;
BaseEvent& operator=(const BaseEvent&)=delete;
};
// End of document or element
struct CloseEvent: public BaseEvent{
// CloseEvent binds (without copying) the TagType reference.
CloseEvent(const xml::sax::Parser::TagType& name):
mName(name)
{}
const xml::sax::Parser::TagType& mName;
};
// Start of document or element
struct OpenEvent: public CloseEvent{
// In addition to CloseEvent's TagType, OpenEvent binds AttributeIterator.
OpenEvent(const xml::sax::Parser::TagType& name,
xml::sax::AttributeIterator& attrs):
CloseEvent(name),
mAttrs(attrs)
{}
xml::sax::AttributeIterator& mAttrs;
};
// text within an element
struct TextEvent: public BaseEvent{
// TextEvent binds the CharIterator.
TextEvent(xml::sax::CharIterator& text):
mText(text)
{}
xml::sax::CharIterator& mText;
};
// The parsing coroutine instantiates BaseEvent subclass instances and
// successively shows them to the main program. It passes a reference so we
// don't slice the BaseEvent subclass.
typedef boost::coroutines::asymmetric_coroutine<const BaseEvent&> coro_t;
void parser(coro_t::push_type& sink,std::istream& in){
xml::sax::Parser xparser;
// startDocument() will send OpenEvent
xparser.startDocument([&sink](const xml::sax::Parser::TagType& name,
xml::sax::AttributeIterator& attrs)
{
sink(OpenEvent(name,attrs));
});
// startTag() will likewise send OpenEvent
xparser.startTag([&sink](const xml::sax::Parser::TagType& name,
xml::sax::AttributeIterator& attrs)
{
sink(OpenEvent(name,attrs));
});
// endTag() will send CloseEvent
xparser.endTag([&sink](const xml::sax::Parser::TagType& name)
{
sink(CloseEvent(name));
});
// endDocument() will likewise send CloseEvent
xparser.endDocument([&sink](const xml::sax::Parser::TagType& name)
{
sink(CloseEvent(name));
});
// characters() will send TextEvent
xparser.characters([&sink](xml::sax::CharIterator& text)
{
sink(TextEvent(text));
});
try
{
// parse the document, firing all the above
xparser.parse(in);
}
catch (xml::Exception e)
{
// xml::sax::Parser throws xml::Exception. Helpfully translate the
// name and provide it as the what() string.
throw std::runtime_error(exception_name(e));
}
}
// Recursively traverse the incoming XML document on the fly, pulling
// BaseEvent& references from 'events'.
// 'indent' illustrates the level of recursion.
// Each time we're called, we've just retrieved an OpenEvent from 'events';
// accept that as a param.
// Return the CloseEvent that ends this element.
const CloseEvent& process(coro_t::pull_type& events,const OpenEvent& context,
const std::string& indent=""){
// Capture OpenEvent's tag name: as soon as we advance the parser, the
// TagType& reference bound in this OpenEvent will be invalidated.
xml::sax::Parser::TagType tagName = context.mName;
// Since the OpenEvent is still the current value from 'events', pass
// control back to 'events' until the next event. Of course, each time we
// come back we must check for the end of the results stream.
while(events()){
// Another event is pending; retrieve it.
const BaseEvent& event=events.get();
const OpenEvent* oe;
const CloseEvent* ce;
const TextEvent* te;
if((oe=dynamic_cast<const OpenEvent*>(&event))){
// When we see OpenEvent, recursively process it.
process(events,*oe,indent+" ");
}
else if((ce=dynamic_cast<const CloseEvent*>(&event))){
// When we see CloseEvent, validate its tag name and then return
// it. (This assert is really a check on xml::sax::Parser, since
// it already validates matching open/close tags.)
assert(ce->mName == tagName);
return *ce;
}
else if((te=dynamic_cast<const TextEvent*>(&event))){
// When we see TextEvent, just report its text, along with
// indentation indicating recursion level.
std::cout<<indent<<"text: '"<<te->mText.getText()<<"'\n";
}
}
}
// pretend we have an XML file of arbitrary size
std::istringstream in(doc);
try
{
coro_t::pull_type events(std::bind(parser,_1,std::ref(in)));
// We fully expect at least ONE event.
assert(events);
// This dynamic_cast<&> is itself an assertion that the first event is an
// OpenEvent.
const OpenEvent& context=dynamic_cast<const OpenEvent&>(events.get());
process(events, context);
}
catch (std::exception& e)
{
std::cout << "Parsing error: " << e.what() << '\n';
}
This problem does not map at all well to communicating between independent
threads. It makes no sense for either side to proceed independently of the
other. You want them to pass control back and forth.
The solution involves a small polymorphic class event hierarchy, to which
we're passing references. The actual instances are temporaries on the
coroutine's stack; the coroutine passes each reference in turn to the main
logic. Copying them as base-class values would slice them.
If we were trying to let the SAX parser proceed independently of the consuming
logic, one could imagine allocating event-subclass instances on the heap,
passing them along on a thread-safe queue of pointers. But that doesn't work
either, because these event classes bind references passed by the SAX parser.
The moment the parser moves on, those references become invalid.
Instead of binding a ['TagType&] reference, we could store a copy of
the ['TagType] in ['CloseEvent]. But that doesn't solve the whole
problem. For attributes, we get an ['AttributeIterator&]; for text we get
a ['CharIterator&]. Storing a copy of those iterators is pointless: once
the parser moves on, those iterators are invalidated. You must process the
attribute iterator (or character iterator) during the SAX callback for that
event.
Naturally we could retrieve and store a copy of every attribute and its value;
we could store a copy of every chunk of text. That would effectively be all
the text in the document -- a heavy price to pay, if the reason we're using
SAX is concern about fitting the entire DOM into memory.
There's yet another advantage to using coroutines. This SAX parser throws an
exception when parsing fails. With a coroutine implementation, you need only
wrap the calling code in try/catch.
With communicating threads, you would have to arrange to catch the exception
and pass along the exception pointer on the same queue you're using to deliver
the other events. You would then have to rethrow the exception to unwind the
recursive document processing.
The coroutine solution maps very naturally to the problem space.
[heading 'same fringe' problem]
The advantages of suspending at an arbitrary call depth can be seen
particularly clearly with the use of a recursive function, such as traversal
of trees.
If traversing two different trees in the same deterministic order produces the
same list of leaf nodes, then both trees have the same fringe.
[$../../../../libs/coroutine/doc/images/same_fringe.png [align center]]
Both trees in the picture have the same fringe even though the structure of the
trees is different.
The same fringe problem could be solved using coroutines by iterating over the
leaf nodes and comparing this sequence via ['std::equal()]. The range of data
values is generated by function ['traverse()] which recursively traverses the
tree and passes each node's data value to its __push_coro__.
__push_coro__ suspends the recursive computation and transfers the data value to
the main execution context.
__pull_coro_it__, created from __pull_coro__, steps over those data values and
delivers them to ['std::equal()] for comparison. Each increment of
__pull_coro_it__ resumes ['traverse()]. Upon return from
['iterator::operator++()], either a new data value is available, or tree
traversal is finished (iterator is invalidated).
In effect, the coroutine iterator presents a flattened view of the recursive
data structure.
struct node{
typedef boost::shared_ptr<node> ptr_t;
// Each tree node has an optional left subtree,
// an optional right subtree and a value of its own.
// The value is considered to be between the left
// subtree and the right.
ptr_t left,right;
std::string value;
// construct leaf
node(const std::string& v):
left(),right(),value(v)
{}
// construct nonleaf
node(ptr_t l,const std::string& v,ptr_t r):
left(l),right(r),value(v)
{}
static ptr_t create(const std::string& v){
return ptr_t(new node(v));
}
static ptr_t create(ptr_t l,const std::string& v,ptr_t r){
return ptr_t(new node(l,v,r));
}
};
node::ptr_t create_left_tree_from(const std::string& root){
/* --------
root
/ \
b e
/ \
a c
-------- */
return node::create(
node::create(
node::create("a"),
"b",
node::create("c")),
root,
node::create("e"));
}
node::ptr_t create_right_tree_from(const std::string& root){
/* --------
root
/ \
a d
/ \
c e
-------- */
return node::create(
node::create("a"),
root,
node::create(
node::create("c"),
"d",
node::create("e")));
}
// recursively walk the tree, delivering values in order
void traverse(node::ptr_t n,
boost::coroutines::asymmetric_coroutine<std::string>::push_type& out){
if(n->left) traverse(n->left,out);
out(n->value);
if(n->right) traverse(n->right,out);
}
// evaluation
{
node::ptr_t left_d(create_left_tree_from("d"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines::asymmetric_coroutine<std::string>::push_type & out){
traverse(left_d,out);
});
node::ptr_t right_b(create_right_tree_from("b"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_b_reader(
[&]( boost::coroutines::asymmetric_coroutine<std::string>::push_type & out){
traverse(right_b,out);
});
std::cout << "left tree from d == right tree from b? "
<< std::boolalpha
<< std::equal(boost::begin(left_d_reader),
boost::end(left_d_reader),
boost::begin(right_b_reader))
<< std::endl;
}
{
node::ptr_t left_d(create_left_tree_from("d"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines::asymmetric_coroutine<std::string>::push_type & out){
traverse(left_d,out);
});
node::ptr_t right_x(create_right_tree_from("x"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_x_reader(
[&]( boost::coroutines::asymmetric_coroutine<std::string>::push_type & out){
traverse(right_x,out);
});
std::cout << "left tree from d == right tree from x? "
<< std::boolalpha
<< std::equal(boost::begin(left_d_reader),
boost::end(left_d_reader),
boost::begin(right_x_reader))
<< std::endl;
}
std::cout << "Done" << std::endl;
output:
left tree from d == right tree from b? true
left tree from d == right tree from x? false
Done
[heading merging two sorted arrays]
This example demonstrates how symmetric coroutines merge two sorted arrays.
std::vector<int> merge(const std::vector<int>& a,const std::vector<int>& b){
std::vector<int> c;
std::size_t idx_a=0,idx_b=0;
boost::coroutines::symmetric_coroutine<void>::call_type *other_a=0,*other_b=0;
boost::coroutines::symmetric_coroutine<void>::call_type coro_a(
[&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield){
while(idx_a<a.size()){
if(b[idx_b]<a[idx_a]) // test if element in array b is less than in array a
yield(*other_b); // yield to coroutine coro_b
c.push_back(a[idx_a++]); // add element to final array
}
// add remaining elements of array b
while(idx_b<b.size())
c.push_back(b[idx_b++]);
});
boost::coroutines::symmetric_coroutine<void>::call_type coro_b(
[&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield){
while(idx_b<b.size()){
if(a[idx_a]<b[idx_b]) // test if element in array a is less than in array b
yield(*other_a); // yield to coroutine coro_a
c.push_back(b[idx_b++]); // add element to final array
}
// add remaining elements of array a
while(idx_a<a.size())
c.push_back(a[idx_a++]);
});
other_a=&coro_a;
other_b=&coro_b;
coro_a(); // enter coroutine-fn of coro_a
return c;
}
[heading chaining coroutines]
This code shows how coroutines could be chained.
typedef boost::coroutines::asymmetric_coroutine<std::string> coro_t;
// deliver each line of input stream to sink as a separate string
void readlines(coro_t::push_type& sink,std::istream& in){
std::string line;
while(std::getline(in,line))
sink(line);
}
void tokenize(coro_t::push_type& sink, coro_t::pull_type& source){
// This tokenizer doesn't happen to be stateful: you could reasonably
// implement it with a single call to push each new token downstream. But
// I've worked with stateful tokenizers, in which the meaning of input
// characters depends in part on their position within the input line.
BOOST_FOREACH(std::string line,source){
std::string::size_type pos=0;
while(pos<line.length()){
if(line[pos]=='"'){
std::string token;
++pos; // skip open quote
while(pos<line.length()&&line[pos]!='"')
token+=line[pos++];
++pos; // skip close quote
sink(token); // pass token downstream
} else if (std::isspace(line[pos])){
++pos; // outside quotes, ignore whitespace
} else if (std::isalpha(line[pos])){
std::string token;
while (pos < line.length() && std::isalpha(line[pos]))
token += line[pos++];
sink(token); // pass token downstream
} else { // punctuation
sink(std::string(1,line[pos++]));
}
}
}
}
void only_words(coro_t::push_type& sink,coro_t::pull_type& source){
BOOST_FOREACH(std::string token,source){
if (!token.empty() && std::isalpha(token[0]))
sink(token);
}
}
void trace(coro_t::push_type& sink, coro_t::pull_type& source){
BOOST_FOREACH(std::string token,source){
std::cout << "trace: '" << token << "'\n";
sink(token);
}
}
struct FinalEOL{
~FinalEOL(){
std::cout << std::endl;
}
};
void layout(coro_t::pull_type& source,int num,int width){
// 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 (!source) return;
std::cout << std::setw(width) << source.get();
// now that we've handled this item, advance to next
source();
}
// after 'num' items, line break
std::cout << std::endl;
}
}
// For example purposes, instead of having a separate text file in the
// local filesystem, construct an istringstream to read.
std::string data(
"This is the first line.\n"
"This, the second.\n"
"The third has \"a phrase\"!\n"
);
{
std::cout << "\nfilter:\n";
std::istringstream infile(data);
coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(filter)));
BOOST_FOREACH(std::string token,tracer){
// just iterate, we're already pulling through tracer
}
}
{
std::cout << "\nlayout() as coroutine::push_type:\n";
std::istringstream infile(data);
coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
coro_t::push_type writer(boost::bind(layout, _1, 5, 15));
BOOST_FOREACH(std::string token,filter){
writer(token);
}
}
{
std::cout << "\nfiltering output:\n";
std::istringstream infile(data);
coro_t::pull_type reader(boost::bind(readlines,_1,boost::ref(infile)));
coro_t::pull_type tokenizer(boost::bind(tokenize,_1,boost::ref(reader)));
coro_t::push_type writer(boost::bind(layout,_1,5,15));
// Because of the symmetry of the API, we can use any of these
// chaining functions in a push_type coroutine chain as well.
coro_t::push_type filter(boost::bind(only_words,boost::ref(writer),_1));
BOOST_FOREACH(std::string token,tokenizer){
filter(token);
}
}
[endsect]

View File

@@ -0,0 +1,37 @@
[/
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:overview Overview]
__boost_coroutine__ provides templates for generalized subroutines which allow
suspending and resuming execution at certain locations.
It preserves the local state of execution and allows re-entering subroutines more
than once (useful if state must be kept across function calls).
Coroutines can be viewed as a language-level construct providing a special kind
of control flow.
In contrast to threads, which are pre-emptive, __coro__ switches are
cooperative (programmer controls when a switch will happen). The kernel is not
involved in the coroutine switches.
The implementation uses __boost_context__ for context switching.
In order to use the classes and functions described here, you can either include
the specific headers specified by the descriptions of each class or function, or
include the master library header:
#include <boost/coroutine/all.hpp>
which includes all the other headers in turn.
All functions and classes are contained in the namespace __coro_ns__.
[warning BoostCoroutine is now deprecated. Please use
[@http://www.boost.org/doc/libs/release/libs/coroutine2/index.html Boost.Coroutine2].]
[endsect]

View File

@@ -0,0 +1,65 @@
[/
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:performance Performance]
Performance of __boost_coroutine__ was measured on the platforms shown in the
following table. Performance measurements were taken using `rdtsc` and
`boost::chrono::high_resolution_clock`, with overhead corrections, on x86
platforms. In each case, cache warm-up was accounted for, and the one
running thread was pinned to a single CPU.
[table Performance of asymmetric coroutines
[
[Platform]
[switch]
[construction (protected stack-allocator)]
[construction (preallocated stack-allocator)]
[construction (standard stack-allocator)]
]
[
[i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)]
[49 ns / 50 cycles]
[51 \u00b5s / 51407 cycles]
[14 \u00b5s / 15231 cycles]
[14 \u00b5s / 15216 cycles]
]
[
[x86_64 (Intel Core2 Q6700, Linux 64bit)]
[12 ns / 39 cycles]
[16 \u00b5s / 41802 cycles]
[6 \u00b5s / 10350 cycles]
[6 \u00b5s / 18817 cycles]
]
]
[table Performance of symmetric coroutines
[
[Platform]
[switch]
[construction (protected stack-allocator)]
[construction (preallocated stack-allocator)]
[construction (standard stack-allocator)]
]
[
[i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)]
[47 ns / 49 cycles]
[27 \u00b5s / 28002 cycles]
[98 ns / 116 cycles]
[319 ns / 328 cycles]
]
[
[x86_64 (Intel Core2 Q6700, Linux 64bit)]
[10 ns / 33 cycles]
[10 \u00b5s / 22828 cycles]
[42 ns / 710 cycles]
[135 ns / 362 cycles]
]
]
[endsect]

View File

@@ -0,0 +1,295 @@
[/
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:stack Stack allocation]
A __coro__ uses internally a __ctx__ which manages a set of registers and a stack.
The memory used by the stack is allocated/deallocated via a __stack_allocator__
which is required to model a __stack_allocator_concept__.
[heading __stack_allocator_concept__]
A __stack_allocator__ must satisfy the __stack_allocator_concept__ requirements
shown in the following table, in which `a` is an object of a
__stack_allocator__ type, `sctx` is a `stack_context`, and `size` is a `std::size_t`:
[table
[[expression][return type][notes]]
[
[`a.allocate( sctx, size)`]
[`void`]
[creates a stack of at least `size` bytes and stores its pointer and
length in `sctx`]
]
[
[`a.deallocate( sctx)`]
[`void`]
[deallocates the stack created by `a.allocate()`]
]
]
[important The implementation of `allocate()` might include logic to protect
against exceeding the context's available stack size rather than leaving it as
undefined behaviour.]
[important Calling `deallocate()` with a `stack_context` not set by `allocate()`
results in undefined behaviour.]
[note The stack is not required to be aligned; alignment takes place inside
__coro__.]
[note Depending on the architecture `allocate()` stores an address from the
top of the stack (growing downwards) or the bottom of the stack (growing
upwards).]
class __coro_allocator__ is a typedef of __standard_allocator__.
[section:protected_stack_allocator Class ['protected_stack_allocator]]
__boost_coroutine__ provides the class __protected_allocator__ which models
the __stack_allocator_concept__.
It appends a guard page at the end of each stack to protect against exceeding
the stack. If the guard page is accessed (read or write operation) a
segmentation fault/access violation is generated by the operating system.
[important Using __protected_allocator__ is expensive. That is, launching a
new coroutine with a new stack is expensive; the allocated stack is just as
efficient to use as any other stack.]
[note The appended `guard page` is [*not] mapped to physical memory, only
virtual addresses are used.]
#include <boost/coroutine/protected_stack_allocator.hpp>
template< typename traitsT >
struct basic_protected_stack_allocator
{
typedef traitT traits_type;
void allocate( stack_context &, std::size_t size);
void deallocate( stack_context &);
}
typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator
[heading `void allocate( stack_context & sctx, std::size_t size)`]
[variablelist
[[Preconditions:] [`traits_type::minimum_size() <= size` and
`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= size)`.]]
[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer
to the stack and its actual size in `sctx`. Depending
on the architecture (the stack grows downwards/upwards) the stored address is
the highest/lowest address of the stack.]]
]
[heading `void deallocate( stack_context & sctx)`]
[variablelist
[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and
`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= sctx.size)`.]]
[[Effects:] [Deallocates the stack space.]]
]
[endsect]
[section:standard_stack_allocator Class ['standard_stack_allocator]]
__boost_coroutine__ provides the class __standard_allocator__ which models
the __stack_allocator_concept__.
In contrast to __protected_allocator__ it does not append a guard page at the
end of each stack. The memory is simply managed by `std::malloc()` and
`std::free()`.
[note The __standard_allocator__ is the default stack allocator.]
#include <boost/coroutine/standard_stack_allocator.hpp>
template< typename traitsT >
struct standard_stack_allocator
{
typedef traitT traits_type;
void allocate( stack_context &, std::size_t size);
void deallocate( stack_context &);
}
typedef basic_standard_stack_allocator< stack_traits > standard_stack_allocator
[heading `void allocate( stack_context & sctx, std::size_t size)`]
[variablelist
[[Preconditions:] [`traits_type::minimum_size() <= size` and
`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= size)`.]]
[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer to
the stack and its actual size in `sctx`. Depending on the architecture (the
stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.]]
]
[heading `void deallocate( stack_context & sctx)`]
[variablelist
[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and
`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= sctx.size)`.]]
[[Effects:] [Deallocates the stack space.]]
]
[endsect]
[section:segmented_stack_allocator Class ['segmented_stack_allocator]]
__boost_coroutine__ supports usage of a __segmented_stack__, e. g. the size of
the stack grows on demand. The coroutine is created with a minimal stack size
and will be increased as required.
Class __segmented_allocator__ models the __stack_allocator_concept__.
In contrast to __protected_allocator__ and __standard_allocator__ it creates a
stack which grows on demand.
[note Segmented stacks are currently only supported by [*gcc] from version
[*4.7] and [*clang] from version [*3.4] onwards. In order to use a
__segmented_stack__ __boost_coroutine__ must be built with
[*toolset=gcc segmented-stacks=on] at b2/bjam command-line. Applications
must be compiled with compiler-flags
[*-fsplit-stack -DBOOST_USE_SEGMENTED_STACKS].]
#include <boost/coroutine/segmented_stack_allocator.hpp>
template< typename traitsT >
struct basic_segmented_stack_allocator
{
typedef traitT traits_type;
void allocate( stack_context &, std::size_t size);
void deallocate( stack_context &);
}
typedef basic_segmented_stack_allocator< stack_traits > segmented_stack_allocator;
[heading `void allocate( stack_context & sctx, std::size_t size)`]
[variablelist
[[Preconditions:] [`traits_type::minimum_size() <= size` and
`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= size)`.]]
[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer to
the stack and its actual size in `sctx`. Depending on the architecture (the
stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.]]
]
[heading `void deallocate( stack_context & sctx)`]
[variablelist
[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and
`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= sctx.size)`.]]
[[Effects:] [Deallocates the stack space.]]
]
[endsect]
[section:stack_traits Class ['stack_traits]]
['stack_traits] models a __stack_traits__ providing a way to access certain
properites defined by the enironment. Stack allocators use __stack_traits__ to
allocate stacks.
#include <boost/coroutine/stack_traits.hpp>
struct stack_traits
{
static bool is_unbounded() noexcept;
static std::size_t page_size() noexcept;
static std::size_t default_size() noexcept;
static std::size_t minimum_size() noexcept;
static std::size_t maximum_size() noexcept;
}
[heading `static bool is_unbounded()`]
[variablelist
[[Returns:] [Returns `true` if the environment defines no limit for the size of
a stack.]]
[[Throws:] [Nothing.]]
]
[heading `static std::size_t page_size()`]
[variablelist
[[Returns:] [Returns the page size in bytes.]]
[[Throws:] [Nothing.]]
]
[heading `static std::size_t default_size()`]
[variablelist
[[Returns:] [Returns a default stack size, which may be platform specific.
If the stack is unbounded then the present implementation returns the maximum of
`64 kB` and `minimum_size()`.]]
[[Throws:] [Nothing.]]
]
[heading `static std::size_t minimum_size()`]
[variablelist
[[Returns:] [Returns the minimum size in bytes of stack defined by the
environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]]
[[Throws:] [Nothing.]]
]
[heading `static std::size_t maximum_size()`]
[variablelist
[[Preconditions:] [`is_unbounded()` returns `false`.]]
[[Returns:] [Returns the maximum size in bytes of stack defined by the
environment.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:stack_context Class ['stack_context]]
__boost_coroutine__ provides the class __stack_context__ which will contain
the stack pointer and the size of the stack.
In case of a __segmented_stack__, __stack_context__ contains some extra control
structures.
struct stack_context
{
void * sp;
std::size_t size;
// might contain additional control structures
// for instance for segmented stacks
}
[heading `void * sp`]
[variablelist
[[Value:] [Pointer to the beginning of the stack.]]
]
[heading `std::size_t size`]
[variablelist
[[Value:] [Actual size of the stack.]]
]
[endsect]
[section:valgrind Support for valgrind]
Running programs that switch stacks under valgrind causes problems.
Property (b2 command-line) `valgrind=on` let valgrind treat the memory regions
as stack space which suppresses the errors.
[endsect]
[endsect]

View File

@@ -0,0 +1,439 @@
[/
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:symmetric Symmetric coroutine]
In contrast to asymmetric coroutines, where the relationship between caller and
callee is fixed, symmetric coroutines are able to transfer execution control
to any other (symmetric) coroutine. E.g. a symmetric coroutine is not required
to return to its direct caller.
[heading __call_coro__]
__call_coro__ starts a symmetric coroutine and transfers its parameter to its
__coro_fn__.
The template parameter defines the transferred parameter type.
The constructor of __call_coro__ takes a function (__coro_fn__) accepting a
reference to a __yield_coro__ as argument. Instantiating a __call_coro__ does
not pass the control of execution to __coro_fn__ - instead the first call of
__call_coro_op__ synthesizes a __yield_coro__ and passes it as reference to
__coro_fn__.
The __call_coro__ interface does not contain a ['get()]-function: you can not
retrieve values from another execution context with this kind of coroutine
object.
[heading __yield_coro__]
__yield_coro_op__ is used to transfer data and execution control to another
context by calling __yield_coro_op__ with another __call_coro__ as first argument.
Alternatively, you may transfer control back to the code that called
__call_coro_op__ by calling __yield_coro_op__ without a __call_coro__ argument.
The class has only one template parameter defining the transferred parameter
type.
Data transferred to the coroutine are accessed through __yield_coro_get__.
[important __yield_coro__ can only be created by the framework.]
std::vector<int> merge(const std::vector<int>& a,const std::vector<int>& b)
{
std::vector<int> c;
std::size_t idx_a=0,idx_b=0;
boost::coroutines::symmetric_coroutine<void>::call_type* other_a=0,* other_b=0;
boost::coroutines::symmetric_coroutine<void>::call_type coro_a(
[&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield) {
while(idx_a<a.size())
{
if(b[idx_b]<a[idx_a]) // test if element in array b is less than in array a
yield(*other_b); // yield to coroutine coro_b
c.push_back(a[idx_a++]); // add element to final array
}
// add remaining elements of array b
while ( idx_b < b.size())
c.push_back( b[idx_b++]);
});
boost::coroutines::symmetric_coroutine<void>::call_type coro_b(
[&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield) {
while(idx_b<b.size())
{
if (a[idx_a]<b[idx_b]) // test if element in array a is less than in array b
yield(*other_a); // yield to coroutine coro_a
c.push_back(b[idx_b++]); // add element to final array
}
// add remaining elements of array a
while ( idx_a < a.size())
c.push_back( a[idx_a++]);
});
other_a = & coro_a;
other_b = & coro_b;
coro_a(); // enter coroutine-fn of coro_a
return c;
}
std::vector< int > a = {1,5,6,10};
std::vector< int > b = {2,4,7,8,9,13};
std::vector< int > c = merge(a,b);
print(a);
print(b);
print(c);
output:
a : 1 5 6 10
b : 2 4 7 8 9 13
c : 1 2 4 5 6 7 8 9 10 13
In this example two __call_coro__ are created in the main execution context
accepting a lambda function (== __coro_fn__) which merges elements of two
sorted arrays into a third array.
`coro_a()` enters the __coro_fn__ of `coro_a` cycling through the array and
testing if the actual element in the other array is less than the element in
the local one. If so, the coroutine yields to the other coroutine `coro_b`
using `yield(*other_b)`. If the current element of the local array is less
than the element of the other array, it is put to the third array.
Because the coroutine jumps back to `coro_a()` (returning from this method)
after leaving the __coro_fn__, the elements of the other array will appended
at the end of the third array if all element of the local array are processed.
[heading coroutine-function]
The __coro_fn__ returns ['void] and takes __yield_coro__, providing
coroutine functionality inside the __coro_fn__, as argument. Using this
instance is the only way to transfer data and execution control.
__call_coro__ does not enter the __coro_fn__ at __call_coro__ construction but
at the first invocation of __call_coro_op__.
Unless the template parameter is `void`, the __coro_fn__ of a
__call_coro__ can assume that (a) upon initial entry and (b) after every
__yield_coro_op__ call, its __yield_coro_get__ has a new value available.
However, if the template parameter is a move-only type,
__yield_coro_get__ may only be called once before the next __yield_coro_op__
call.
[heading passing data from main-context to a symmetric-coroutine]
In order to transfer data to a __call_coro__ from the main-context the
framework synthesizes a __yield_coro__ associated with the __call_coro__
instance. The synthesized __yield_coro__ is passed as argument to __coro_fn__.
The main-context must call __call_coro_op__ in order to transfer each data value
into the __coro_fn__.
Access to the transferred data value is given by __yield_coro_get__.
boost::coroutines::symmetric_coroutine<int>::call_type coro( // constructor does NOT enter coroutine-function
[&](boost::coroutines::symmetric_coroutine<int>::yield_type& yield){
for (;;) {
std::cout << yield.get() << " ";
yield(); // jump back to starting context
}
});
coro(1); // transfer {1} to coroutine-function
coro(2); // transfer {2} to coroutine-function
coro(3); // transfer {3} to coroutine-function
coro(4); // transfer {4} to coroutine-function
coro(5); // transfer {5} to coroutine-function
[heading exceptions]
An uncaught exception inside a __call_coro__'s __coro_fn__ will call
__terminate__.
[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 any
pending __forced_unwind__ exception.]
try {
// code that might throw
} catch(const boost::coroutines::detail::forced_unwind&) {
throw;
} catch(...) {
// possibly not re-throw pending exception
}
[important Do not jump from inside a catch block and then re-throw the
exception in another execution context.]
[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 `attributes` argument of the coroutine constructor 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::symmetric_coroutine<int>::call_type other_coro(...);
{
boost::coroutines::symmetric_coroutine<void>::call_type coro(
[&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield){
X x;
std::cout<<"fn()"<<std::endl;
// transfer execution control to other coroutine
yield( other_coro, 7);
});
coro();
std::cout<<"coro is complete: "<<std::boolalpha<<!coro<<"\n";
}
output:
X()
fn()
coro is complete: false
~X()
[heading Exit a __coro_fn__]
__coro_fn__ is exited with a simple return statement. This jumps back to the
calling __call_coro_op__ at the start of symmetric coroutine chain. That is,
symmetric coroutines do not have a strong, fixed relationship to the caller as
do asymmetric coroutines. The __call_coro__ becomes complete, e.g.
__call_coro_bool__ will return `false`.
[important After returning from __coro_fn__ the __coro__ is complete (can not be
resumed with __call_coro_op__).]
[section:symmetric_coro Class `symmetric_coroutine<>::call_type`]
#include <boost/coroutine/symmetric_coroutine.hpp>
template< typename Arg >
class symmetric_coroutine<>::call_type
{
public:
call_type() noexcept;
template< typename Fn >
call_type( Fn && fn, attributes const& attr = attributes() );
template< typename Fn, typename StackAllocator >
call_type( Fn && fn, attributes const& attr, StackAllocator stack_alloc);
~call_type();
call_type( call_type const& other)=delete;
call_type & operator=( call_type const& other)=delete;
call_type( call_type && other) noexcept;
call_type & operator=( call_type && other) noexcept;
operator unspecified-bool-type() const;
bool operator!() const noexcept;
void swap( call_type & other) noexcept;
call_type & operator()( Arg arg) noexcept;
};
template< typename Arg >
void swap( symmetric_coroutine< Arg >::call_type & l, symmetric_coroutine< Arg >::call_type & r);
[heading `call_type()`]
[variablelist
[[Effects:] [Creates a coroutine representing __not_a_coro__.]]
[[Throws:] [Nothing.]]
]
[heading `template< typename Fn >
call_type( Fn fn, attributes const& attr)`]
[variablelist
[[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize()
when ! is_stack_unbounded().]]
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
determines stack clean-up.
For allocating/deallocating the stack `stack_alloc` is used.]]
]
[heading `template< typename Fn, typename StackAllocator >
call_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`]
[variablelist
[[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize()
when ! is_stack_unbounded().]]
[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
determines stack clean-up.
For allocating/deallocating the stack `stack_alloc` is used.]]
]
[heading `~call_type()`]
[variablelist
[[Effects:] [Destroys the context and deallocates the stack.]]
]
[heading `call_type( call_type && other)`]
[variablelist
[[Effects:] [Moves the internal data of `other` to `*this`.
`other` becomes __not_a_coro__.]]
[[Throws:] [Nothing.]]
]
[heading `call_type & operator=( call_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 `void swap( call_type & other)`]
[variablelist
[[Effects:] [Swaps the internal data from `*this` with the values
of `other`.]]
[[Throws:] [Nothing.]]
]
[heading `call_type & operator()(Arg arg)`]
symmetric_coroutine::call_type& coroutine<Arg,StackAllocator>::call_type::operator()(Arg);
symmetric_coroutine::call_type& coroutine<Arg&,StackAllocator>::call_type::operator()(Arg&);
symmetric_coroutine::call_type& coroutine<void,StackAllocator>::call_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:] [Nothing.]]
]
[heading Non-member function `swap()`]
template< typename Arg >
void swap( symmetric_coroutine< Arg >::call_type & l, symmetric_coroutine< Arg >::call_type & r);
[variablelist
[[Effects:] [As if 'l.swap( r)'.]]
]
[endsect]
[section:yield_coro Class `symmetric_coroutine<>::yield_type`]
#include <boost/coroutine/symmetric_coroutine.hpp>
template< typename R >
class symmetric_coroutine<>::yield_type
{
public:
yield_type() noexcept;
yield_type( yield_type const& other)=delete;
yield_type & operator=( yield_type const& other)=delete;
yield_type( yield_type && other) noexcept;
yield_type & operator=( yield_type && other) noexcept;
void swap( yield_type & other) noexcept;
operator unspecified-bool-type() const;
bool operator!() const noexcept;
yield_type & operator()();
template< typename X >
yield_type & operator()( symmetric_coroutine< X >::call_type & other, X & x);
template< typename X >
yield_type & operator()( symmetric_coroutine< X >::call_type & other);
R get() const;
};
[heading `operator unspecified-bool-type() const`]
[variablelist
[[Returns:] [If `*this` refers to __not_a_coro__, the function returns `false`.
Otherwise `true`.]]
[[Throws:] [Nothing.]]
]
[heading `bool operator!() const`]
[variablelist
[[Returns:] [If `*this` refers to __not_a_coro__, the function returns `true`.
Otherwise `false`.]]
[[Throws:] [Nothing.]]
]
[heading `yield_type & operator()()`]
yield_type & operator()();
template< typename X >
yield_type & operator()( symmetric_coroutine< X >::call_type & other, X & x);
template<>
yield_type & operator()( symmetric_coroutine< void >::call_type & other);
[variablelist
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
[[Effects:] [The first function transfers execution control back to the starting point,
e.g. invocation of __call_coro_op__. The last two functions transfer the execution control
to another symmetric coroutine. Parameter `x` is passed as value into `other`'s context.]]
[[Throws:] [__forced_unwind__]]
]
[heading `R get()`]
R symmetric_coroutine<R>::yield_type::get();
R& symmetric_coroutine<R&>::yield_type::get();
void symmetric_coroutine<void>yield_type::get()=delete;
[variablelist
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
[[Returns:] [Returns data transferred from coroutine-function via
__call_coro_op__.]]
[[Throws:] [`invalid_result`]]
]
[endsect]
[endsect]

View File

@@ -0,0 +1,63 @@
# Boost.Coroutine Library Examples Jamfile
# 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine/example
: requirements
<library>/boost/context//boost_context
<library>/boost/coroutine//boost_coroutine
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>shared
<threading>multi
;
exe chaining
: chaining.cpp
;
exe echo
: echo.cpp
;
exe exception
: exception.cpp
;
exe fibonacci
: fibonacci.cpp
;
exe layout
: layout.cpp
;
exe parallel
: parallel.cpp
;
exe power
: power.cpp
;
exe same_fringe
: same_fringe.cpp
;
exe segmented_stack
: segmented_stack.cpp
;
exe simple
: simple.cpp
test.cpp
;
exe unwind
: unwind.cpp
;

View File

@@ -0,0 +1,13 @@
#ifndef X_H
#define X_H
struct X
{
int i;
X( int i_) :
i( i_)
{}
};
#endif // X_H

View File

@@ -0,0 +1,205 @@
// Copyright Nat Goodspeed 2013.
// 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)
#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
#include <sstream>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/foreach.hpp>
typedef boost::coroutines::asymmetric_coroutine<std::string> coro_t;
// deliver each line of input stream to sink as a separate string
void readlines(coro_t::push_type& sink, std::istream& in)
{
std::string line;
while (std::getline(in, line))
sink(line);
}
void tokenize(coro_t::push_type& sink, coro_t::pull_type& source)
{
// This tokenizer doesn't happen to be stateful: you could reasonably
// implement it with a single call to push each new token downstream. But
// I've worked with stateful tokenizers, in which the meaning of input
// characters depends in part on their position within the input line. At
// the time, I wished for a way to resume at the suspend point!
BOOST_FOREACH(std::string line, source)
{
std::string::size_type pos = 0;
while (pos < line.length())
{
if (line[pos] == '"')
{
std::string token;
++pos; // skip open quote
while (pos < line.length() && line[pos] != '"')
token += line[pos++];
++pos; // skip close quote
sink(token); // pass token downstream
}
else if (std::isspace(line[pos]))
{
++pos; // outside quotes, ignore whitespace
}
else if (std::isalpha(line[pos]))
{
std::string token;
while (pos < line.length() && std::isalpha(line[pos]))
token += line[pos++];
sink(token); // pass token downstream
}
else // punctuation
{
sink(std::string(1, line[pos++]));
}
}
}
}
void only_words(coro_t::push_type& sink, coro_t::pull_type& source)
{
BOOST_FOREACH(std::string token, source)
{
if (! token.empty() && std::isalpha(token[0]))
sink(token);
}
}
void trace(coro_t::push_type& sink, coro_t::pull_type& source)
{
BOOST_FOREACH(std::string token, source)
{
std::cout << "trace: '" << token << "'\n";
sink(token);
}
}
struct FinalEOL
{
~FinalEOL() { std::cout << std::endl; }
};
void layout(coro_t::pull_type& source, int num, int width)
{
// 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 (! source)
return;
std::cout << std::setw(width) << source.get();
// now that we've handled this item, advance to next
source();
}
// after 'num' items, line break
std::cout << std::endl;
}
}
int main(int argc, char *argv[])
{
// For example purposes, instead of having a separate text file in the
// local filesystem, construct an istringstream to read.
std::string data(
"This is the first line.\n"
"This, the second.\n"
"The third has \"a phrase\"!\n"
);
{
std::cout << "\nreadlines:\n";
std::istringstream infile(data);
// Each coroutine-function has a small, specific job to do. Instead of
// adding conditional logic to a large, complex input function, the
// caller composes smaller functions into the desired processing
// chain.
coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(reader)));
BOOST_FOREACH(std::string line, tracer)
{
std::cout << "got: " << line << "\n";
}
}
{
std::cout << "\ncompose a chain:\n";
std::istringstream infile(data);
coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(tokenizer)));
BOOST_FOREACH(std::string token, tracer)
{
// just iterate, we're already pulling through tracer
}
}
{
std::cout << "\nfilter:\n";
std::istringstream infile(data);
coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(filter)));
BOOST_FOREACH(std::string token, tracer)
{
// just iterate, we're already pulling through tracer
}
}
{
std::cout << "\nlayout() as coroutine::push_type:\n";
std::istringstream infile(data);
coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
coro_t::push_type writer(boost::bind(layout, _1, 5, 15));
BOOST_FOREACH(std::string token, filter)
{
writer(token);
}
}
{
std::cout << "\ncalling layout() directly:\n";
std::istringstream infile(data);
coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
// Because of the symmetry of the API, we can directly call layout()
// instead of using it as a coroutine-function.
layout(filter, 5, 15);
}
{
std::cout << "\nfiltering output:\n";
std::istringstream infile(data);
coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
coro_t::push_type writer(boost::bind(layout, _1, 5, 15));
// Because of the symmetry of the API, we can use any of these
// chaining functions in a push_type coroutine chain as well.
coro_t::push_type filter(boost::bind(only_words, boost::ref(writer), _1));
BOOST_FOREACH(std::string token, tokenizer)
{
filter(token);
}
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,47 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
typedef boost::coroutines::asymmetric_coroutine< void >::pull_type pull_coro_t;
typedef boost::coroutines::asymmetric_coroutine< void >::push_type push_coro_t;
void echo( pull_coro_t & source, int i)
{
std::cout << i;
source();
}
void runit( push_coro_t & sink1)
{
std::cout << "started! ";
for ( int i = 0; i < 10; ++i)
{
push_coro_t sink2( boost::bind( echo, _1, i) );
while ( sink2)
sink2();
sink1();
}
}
int main( int argc, char * argv[])
{
{
pull_coro_t source( runit);
while ( source) {
std::cout << "-";
source();
}
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,52 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <string>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/throw_exception.hpp>
typedef boost::coroutines::asymmetric_coroutine< int >::pull_type pull_coro_t;
typedef boost::coroutines::asymmetric_coroutine< int >::push_type push_coro_t;
struct my_exception : public std::runtime_error
{
my_exception( std::string const& str) :
std::runtime_error( str)
{}
};
void echo( push_coro_t & sink, int j)
{
for ( int i = 0; i < j; ++i)
{
if ( i == 5) boost::throw_exception( my_exception("abc") );
sink( i);
}
}
int main( int argc, char * argv[])
{
pull_coro_t source( boost::bind( echo, _1, 10) );
try
{
while ( source)
{
std::cout << source.get() << std::endl;
source();
}
}
catch ( my_exception const& ex)
{ std::cout << "exception: " << ex.what() << std::endl; }
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,42 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <boost/range.hpp>
#include <boost/coroutine/all.hpp>
void fibonacci( boost::coroutines::asymmetric_coroutine< int >::push_type & sink)
{
int first = 1, second = 1;
sink( first);
sink( second);
while ( true)
{
int third = first + second;
first = second;
second = third;
sink( third);
}
}
int main()
{
boost::coroutines::asymmetric_coroutine< int >::pull_type source( fibonacci);
boost::range_iterator<
boost::coroutines::asymmetric_coroutine< int >::pull_type
>::type it( boost::begin( source) );
for ( int i = 0; i < 10; ++i)
{
std::cout << * it << " ";
++it;
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,73 @@
// Copyright Nat Goodspeed 2013.
// 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)
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <utility>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/range.hpp>
struct FinalEOL
{
~FinalEOL() { std::cout << std::endl; }
};
void layout(boost::coroutines::asymmetric_coroutine<std::string>::pull_type& in, int num, int width)
{
// 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;
}
}
int main(int argc, char *argv[])
{
std::vector<std::string> words = boost::assign::list_of
("peas")
("porridge")
("hot")
("peas")
("porridge")
("cold")
("peas")
("porridge")
("in")
("the")
("pot")
("nine")
("days")
("old")
;
boost::coroutines::asymmetric_coroutine<std::string>::push_type writer(
boost::bind(layout, _1, 5, 15));
std::copy(boost::begin(words), boost::end(words), boost::begin(writer));
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,49 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
void first( boost::coroutines::asymmetric_coroutine< void >::push_type & sink)
{
std::cout << "started first! ";
for ( int i = 0; i < 10; ++i)
{
sink();
std::cout << "a" << i;
}
}
void second( boost::coroutines::asymmetric_coroutine< void >::push_type & sink)
{
std::cout << "started second! ";
for ( int i = 0; i < 10; ++i)
{
sink();
std::cout << "b" << i;
}
}
int main( int argc, char * argv[])
{
{
boost::coroutines::asymmetric_coroutine< void >::pull_type source1( boost::bind( first, _1) );
boost::coroutines::asymmetric_coroutine< void >::pull_type source2( boost::bind( second, _1) );
while ( source1 && source2) {
source1();
std::cout << " ";
source2();
std::cout << " ";
}
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,47 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/range.hpp>
#include <boost/coroutine/all.hpp>
void power( boost::coroutines::asymmetric_coroutine< int >::push_type & sink, int number, int exponent)
{
int counter = 0;
int result = 1;
while ( counter++ < exponent)
{
result = result * number;
sink( result);
}
}
int main()
{
{
std::cout << "using range functions" << std::endl;
boost::coroutines::asymmetric_coroutine< int >::pull_type source( boost::bind( power, _1, 2, 8) );
boost::coroutines::asymmetric_coroutine< int >::pull_type::iterator e( boost::end( source) );
for ( boost::coroutines::asymmetric_coroutine< int >::pull_type::iterator i( boost::begin( source) );
i != e; ++i)
std::cout << * i << " ";
}
{
std::cout << "\nusing BOOST_FOREACH" << std::endl;
boost::coroutines::asymmetric_coroutine< int >::pull_type source( boost::bind( power, _1, 2, 8) );
BOOST_FOREACH( int i, source)
{ std::cout << i << " "; }
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,161 @@
// Copyright Nat Goodspeed 2013.
// 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)
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <string>
#include <utility>
#include <boost/bind.hpp>
#include <boost/range.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/coroutine/all.hpp>
struct node
{
typedef boost::shared_ptr< node > ptr_t;
// Each tree node has an optional left subtree, an optional right subtree
// and a value of its own. The value is considered to be between the left
// subtree and the right.
ptr_t left, right;
std::string value;
// construct leaf
node(const std::string& v):
left(), right(), value(v)
{}
// construct nonleaf
node(ptr_t l, const std::string& v, ptr_t r):
left(l), right(r), value(v)
{}
static ptr_t create(const std::string& v)
{
return ptr_t(new node(v));
}
static ptr_t create(ptr_t l, const std::string& v, ptr_t r)
{
return ptr_t(new node(l, v, r));
}
};
node::ptr_t create_left_tree_from(const std::string& root)
{
/* --------
root
/ \
b e
/ \
a c
-------- */
return node::create(
node::create(
node::create("a"),
"b",
node::create("c")),
root,
node::create("e"));
}
node::ptr_t create_right_tree_from(const std::string& root)
{
/* --------
root
/ \
a d
/ \
c e
-------- */
return node::create(
node::create("a"),
root,
node::create(
node::create("c"),
"d",
node::create("e")));
}
// recursively walk the tree, delivering values in order
void traverse(node::ptr_t n,boost::coroutines::asymmetric_coroutine<std::string>::push_type& out)
{
if (n->left) traverse(n->left,out);
out(n->value);
if (n->right) traverse(n->right,out);
}
int main()
{
{
node::ptr_t left_d(create_left_tree_from("d"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type left_d_reader(
boost::bind(traverse, left_d, _1));
std::cout << "left tree from d:\n";
std::copy(boost::begin(left_d_reader),
boost::end(left_d_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
node::ptr_t right_b(create_right_tree_from("b"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_b_reader(
boost::bind(traverse, right_b, _1));
std::cout << "right tree from b:\n";
std::copy(boost::begin(right_b_reader),
boost::end(right_b_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
node::ptr_t right_x(create_right_tree_from("x"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_x_reader(
boost::bind(traverse, right_x, _1));
std::cout << "right tree from x:\n";
std::copy(boost::begin(right_x_reader),
boost::end(right_x_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
}
{
node::ptr_t left_d(create_left_tree_from("d"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type left_d_reader(
boost::bind(traverse, left_d, _1));
node::ptr_t right_b(create_right_tree_from("b"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_b_reader(
boost::bind(traverse, right_b, _1));
std::cout << "left tree from d == right tree from b? "
<< std::boolalpha
<< std::equal(boost::begin(left_d_reader),
boost::end(left_d_reader),
boost::begin(right_b_reader))
<< std::endl;
}
{
node::ptr_t left_d(create_left_tree_from("d"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type left_d_reader(
boost::bind(traverse, left_d, _1));
node::ptr_t right_x(create_right_tree_from("x"));
boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_x_reader(
boost::bind(traverse, right_x, _1));
std::cout << "left tree from d == right tree from x? "
<< std::boolalpha
<< std::equal(boost::begin(left_d_reader),
boost::end(left_d_reader),
boost::begin(right_x_reader))
<< std::endl;
}
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,62 @@
// 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)
#include <iostream>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/coroutine/all.hpp>
int count = 384;
#ifdef BOOST_MSVC //MS VisualStudio
__declspec(noinline) void access( char *buf);
#else // GCC
void access( char *buf) __attribute__ ((noinline));
#endif
void access( char *buf)
{
buf[0] = '\0';
}
void bar( int i)
{
char buf[4 * 1024];
if ( i > 0)
{
access( buf);
std::cout << i << ". iteration" << std::endl;
bar( i - 1);
}
}
void foo( boost::coroutines::asymmetric_coroutine< void >::pull_type & source)
{
bar( count);
source();
}
int main( int argc, char * argv[])
{
#if defined(BOOST_USE_SEGMENTED_STACKS)
std::cout << "using segmented stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl;
std::cout << "application should not fail" << std::endl;
#else
std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl;
std::cout << "application might fail" << std::endl;
#endif
boost::coroutines::asymmetric_coroutine< void >::push_type sink( foo);
sink();
std::cout << "Done" << std::endl;
return 0;
}

View File

@@ -0,0 +1,52 @@
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#include "X.h"
typedef boost::coroutines::asymmetric_coroutine< X& >::pull_type pull_coro_t;
typedef boost::coroutines::asymmetric_coroutine< X& >::push_type push_coro_t;
void fn1( push_coro_t & sink)
{
for ( int i = 0; i < 10; ++i)
{
X x( i);
sink( x);
}
}
void fn2( pull_coro_t & source)
{
while ( source) {
X & x = source.get();
std::cout << "i = " << x.i << std::endl;
source();
}
}
int main( int argc, char * argv[])
{
{
pull_coro_t source( fn1);
while ( source) {
X & x = source.get();
std::cout << "i = " << x.i << std::endl;
source();
}
}
{
push_coro_t sink( fn2);
for ( int i = 0; i < 10; ++i)
{
X x( i);
sink( x);
}
}
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,44 @@
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#include "X.h"
typedef boost::coroutines::asymmetric_coroutine< X& >::pull_type pull_coro_t;
typedef boost::coroutines::asymmetric_coroutine< X& >::push_type push_coro_t;
void foo1( push_coro_t & sink)
{
for ( int i = 0; i < 10; ++i)
{
X x( i);
sink( x);
}
}
void foo2( pull_coro_t & source)
{
while ( source) {
X & x = source.get();
source();
}
}
void bar()
{
{
pull_coro_t source( foo1);
while ( source) {
X & x = source.get();
source();
}
}
{
push_coro_t sink( foo2);
for ( int i = 0; i < 10; ++i)
{
X x( i);
sink( x);
}
}
}

View File

@@ -0,0 +1,124 @@
// 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)
#ifndef TREE_H
#define TREE_H
#include <cstddef>
#include <string>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/intrusive_ptr.hpp>
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable:4355)
#endif
struct branch;
struct leaf;
struct visitor
{
virtual ~visitor() {};
virtual void visit( branch & b) = 0;
virtual void visit( leaf & l) = 0;
};
struct node
{
typedef boost::intrusive_ptr< node > ptr_t;
std::size_t use_count;
node() :
use_count( 0)
{}
virtual ~node() {}
virtual void accept( visitor & v) = 0;
friend inline void intrusive_ptr_add_ref( node * p)
{ ++p->use_count; }
friend inline void intrusive_ptr_release( node * p)
{ if ( 0 == --p->use_count) delete p; }
};
struct branch : public node
{
node::ptr_t left;
node::ptr_t right;
static ptr_t create( node::ptr_t left_, node::ptr_t right_)
{ return ptr_t( new branch( left_, right_) ); }
branch( node::ptr_t left_, node::ptr_t right_) :
left( left_), right( right_)
{}
void accept( visitor & v)
{ v.visit( * this); }
};
struct leaf : public node
{
std::string value;
static ptr_t create( std::string const& value_)
{ return ptr_t( new leaf( value_) ); }
leaf( std::string const& value_) :
value( value_)
{}
void accept( visitor & v)
{ v.visit( * this); }
};
inline
bool operator==( leaf const& l, leaf const& r)
{ return l.value == r.value; }
inline
bool operator!=( leaf const& l, leaf const& r)
{ return l.value != r.value; }
class tree_visitor : public visitor
{
private:
boost::coroutines::asymmetric_coroutine< leaf & >::push_type & c_;
public:
tree_visitor( boost::coroutines::asymmetric_coroutine< leaf & >::push_type & c) :
c_( c)
{}
void visit( branch & b)
{
if ( b.left) b.left->accept( * this);
if ( b.right) b.right->accept( * this);
}
void visit( leaf & l)
{ c_( l); }
};
void enumerate_leafs( boost::coroutines::asymmetric_coroutine< leaf & >::push_type & c, node::ptr_t root)
{
tree_visitor v( c);
root->accept( v);
}
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif // TREE_H

View File

@@ -0,0 +1,44 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
struct X : private boost::noncopyable
{
X() { std::cout << "X()" << std::endl; }
~X() { std::cout << "~X()" << std::endl; }
};
void fn( boost::coroutines::asymmetric_coroutine< void >::push_type & sink)
{
X x;
int i = 0;
while ( true)
{
std::cout << "fn() : " << ++i << std::endl;
sink();
}
}
int main( int argc, char * argv[])
{
{
boost::coroutines::asymmetric_coroutine< void >::pull_type source( fn);
for ( int k = 0; k < 3; ++k)
{
source();
}
std::cout << "destroying coroutine and unwinding stack" << std::endl;
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,49 @@
# Boost.Coroutine Library Examples Jamfile
# 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine/example
: requirements
<library>/boost/context//boost_context
<library>/boost/coroutine//boost_coroutine
<library>/boost/program_options//boost_program_options
<library>/boost/random//boost_random
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static
<threading>multi
;
exe simple
: simple.cpp
;
exe dice_game
: dice_game.cpp
;
exe merge_arrays
: merge_arrays.cpp
;
exe unwind
: unwind.cpp
;
exe segmented_stack
: segmented_stack.cpp
;

View File

@@ -0,0 +1,69 @@
// Copyright Keld Helsgaun 2000, Oliver Kowalke 2014.
// 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)
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/move/move.hpp>
#include <boost/random/random_device.hpp>
#include <boost/random/uniform_int_distribution.hpp>
typedef boost::coroutines::symmetric_coroutine< void > coro_t;
class player
{
private:
int die()
{
boost::random::uniform_int_distribution<> dist( 1, 6);
return dist( gen);
}
void run_( coro_t::yield_type & yield)
{
int sum = 0;
while ( ( sum += die() ) < 100)
yield( nxt->coro);
std::cout << "player " << id << " winns" << std::endl;
}
player( player const&);
player & operator=( player const&);
public:
int id;
player * nxt;
coro_t::call_type coro;
boost::random::random_device gen;
player( int id_) :
id( id_), nxt( 0),
coro( boost::bind( & player::run_, this, _1) ),
gen()
{}
void run()
{ coro(); }
};
int main( int argc, char * argv[])
{
player * first = new player( 1);
player * p = first;
for ( int i = 2; i <= 4; ++i)
{
p->nxt = new player( i);
p = p->nxt;
}
p->nxt = first;
first->run();
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,104 @@
// Copyright Keld Helsgaun 2000, Oliver Kowalke 2014.
// 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)
#include <cstdlib>
#include <cstddef>
#include <iostream>
#include <vector>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/foreach.hpp>
typedef boost::coroutines::symmetric_coroutine< void > coro_t;
class merger
{
private:
std::size_t max_;
std::vector< int > & to_;
void run_( coro_t::yield_type & yield)
{
while ( idx < from.size() )
{
if ( other->from[other->idx] < from[idx])
yield( other->coro);
to_.push_back(from[idx++]);
}
while ( to_.size() < max_)
to_.push_back( other->from[other->idx]);
}
merger( merger const&);
merger & operator=( merger const&);
public:
std::vector< int > const& from;
std::size_t idx;
merger * other;
coro_t::call_type coro;
merger( std::vector< int > const& from_, std::vector< int > & to, std::size_t max) :
max_( max),
to_( to),
from( from_),
idx( 0),
other( 0),
coro( boost::bind( & merger::run_, this, _1) )
{}
void run()
{ coro(); }
};
std::vector< int > merge( std::vector< int > const& a, std::vector< int > const& b)
{
std::vector< int > c;
merger ma( a, c, a.size() + b. size() );
merger mb( b, c, a.size() + b. size() );
ma.other = & mb;
mb.other = & ma;
ma.run();
return c;
}
void print( std::string const& name, std::vector< int > const& v)
{
std::cout << name << " : ";
BOOST_FOREACH( int itm, v)
{ std::cout << itm << " "; }
std::cout << "\n";
}
int main( int argc, char * argv[])
{
std::vector< int > a;
a.push_back( 1);
a.push_back( 5);
a.push_back( 6);
a.push_back( 10);
print( "a", a);
std::vector< int > b;
b.push_back( 2);
b.push_back( 4);
b.push_back( 7);
b.push_back( 8);
b.push_back( 9);
b.push_back( 13);
print( "b", b);
std::vector< int > c = merge( a, b);
print( "c", c);
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,66 @@
// 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)
#include <iostream>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/thread.hpp>
int count = 384;
#ifdef BOOST_MSVC //MS VisualStudio
__declspec(noinline) void access( char *buf);
#else // GCC
void access( char *buf) __attribute__ ((noinline));
#endif
void access( char *buf)
{
buf[0] = '\0';
}
void bar( int i)
{
char buf[4 * 1024];
if ( i > 0)
{
access( buf);
std::cout << i << ". iteration" << std::endl;
bar( i - 1);
}
}
void foo( boost::coroutines::symmetric_coroutine< void >::yield_type &)
{
bar( count);
}
void thread_fn()
{
{
boost::coroutines::symmetric_coroutine< void >::call_type coro( foo);
coro();
}
}
int main( int argc, char * argv[])
{
#if defined(BOOST_USE_SEGMENTED_STACKS)
std::cout << "using segmented stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl;
std::cout << "application should not fail" << std::endl;
#else
std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl;
std::cout << "application might fail" << std::endl;
#endif
boost::thread( thread_fn).join();
return 0;
}

View File

@@ -0,0 +1,46 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
typedef boost::coroutines::symmetric_coroutine< void > coro_t;
coro_t::call_type * c1 = 0;
coro_t::call_type * c2 = 0;
void foo( coro_t::yield_type & yield)
{
std::cout << "foo1" << std::endl;
yield( * c2);
std::cout << "foo2" << std::endl;
yield( * c2);
std::cout << "foo3" << std::endl;
}
void bar( coro_t::yield_type & yield)
{
std::cout << "bar1" << std::endl;
yield( * c1);
std::cout << "bar2" << std::endl;
yield( * c1);
std::cout << "bar3" << std::endl;
}
int main( int argc, char * argv[])
{
coro_t::call_type coro1( foo);
coro_t::call_type coro2( bar);
c1 = & coro1;
c2 = & coro2;
coro1();
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,50 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
struct X : private boost::noncopyable
{
X() { std::cout << "X()" << std::endl; }
~X() { std::cout << "~X()" << std::endl; }
};
typedef boost::coroutines::symmetric_coroutine< void > coro_t;
coro_t::call_type * c1 = 0;
coro_t::call_type * c2 = 0;
void foo( coro_t::yield_type & yield)
{
X x;
std::cout << "foo() entered" << std::endl;
yield( * c2);
yield( * c2);
std::cout << "foo() finished" << std::endl;
}
void bar( coro_t::yield_type & yield)
{
std::cout << "bar() entered" << std::endl;
yield( * c1);
std::cout << "bar() finished" << std::endl;
}
int main( int argc, char * argv[])
{
coro_t::call_type coro1( foo);
coro_t::call_type coro2( bar);
c1 = & coro1;
c2 = & coro2;
coro1();
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

14
libs/coroutine/index.html Normal file
View File

@@ -0,0 +1,14 @@
<html>
<head>
<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
</head>
<body>
Automatic redirection failed, please go to
<a href="doc/html/index.html">doc/html/index.html</a>
<hr>
<p>&copy; Copyright Beman Dawes, 2001</p>
<p> Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
www.boost.org/LICENSE_1_0.txt</a>)</p>
</body>
</html>

View File

@@ -0,0 +1,15 @@
{
"key": "coroutine",
"status": "deprecated",
"name": "Coroutine",
"authors": [
"Oliver Kowalke"
],
"description": "Coroutine library.",
"category": [
"Concurrent"
],
"maintainers": [
"Oliver Kowalke <oliver.kowalke -at- gmail.com>"
]
}

View File

@@ -0,0 +1,83 @@
# 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine/performance/asymmetric
: requirements
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<library>/boost/coroutine//boost_coroutine
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static
<threading>multi
<cxxflags>-DBOOST_DISABLE_ASSERTS
<optimization>speed
<variant>release
;
alias sources
: ../bind_processor_aix.cpp
: <target-os>aix
;
alias sources
: ../bind_processor_freebsd.cpp
: <target-os>freebsd
;
alias sources
: ../bind_processor_hpux.cpp
: <target-os>hpux
;
alias sources
: ../bind_processor_linux.cpp
: <target-os>linux
;
alias sources
: ../bind_processor_solaris.cpp
: <target-os>solaris
;
alias sources
: ../bind_processor_windows.cpp
: <target-os>windows
;
explicit sources ;
exe performance_create_protected
: sources
performance_create_protected.cpp
;
exe performance_create_standard
: sources
performance_create_standard.cpp
;
exe performance_create_prealloc
: sources
performance_create_prealloc.cpp
;
exe performance_switch
: sources
performance_switch.cpp
;

View File

@@ -0,0 +1,116 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
#include "../preallocated_stack_allocator.hpp"
typedef preallocated_stack_allocator stack_allocator;
typedef boost::coroutines::asymmetric_coroutine< void > coro_type;
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
boost::uint64_t jobs = 1000;
void fn( coro_type::push_type & c)
{ while ( true) c(); }
duration_type measure_time( duration_type overhead)
{
stack_allocator stack_alloc;
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::pull_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu),
stack_alloc);
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles( cycle_type overhead)
{
stack_allocator stack_alloc;
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::pull_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu),
stack_alloc);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, unwind = true, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles( overhead_y);
std::cout << "average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,113 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
typedef boost::coroutines::protected_stack_allocator stack_allocator;
typedef boost::coroutines::asymmetric_coroutine< void > coro_type;
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
boost::uint64_t jobs = 1000;
void fn( coro_type::push_type & c)
{ while ( true) c(); }
duration_type measure_time( duration_type overhead)
{
stack_allocator stack_alloc;
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::pull_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles( cycle_type overhead)
{
stack_allocator stack_alloc;
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::pull_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, unwind = true, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles( overhead_y);
std::cout << "average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,113 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
typedef boost::coroutines::standard_stack_allocator stack_allocator;
typedef boost::coroutines::asymmetric_coroutine< void > coro_type;
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
boost::uint64_t jobs = 1000;
void fn( coro_type::push_type & c)
{ while ( true) c(); }
duration_type measure_time( duration_type overhead)
{
stack_allocator stack_alloc;
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::pull_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles( cycle_type overhead)
{
stack_allocator stack_alloc;
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::pull_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, unwind = true, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles( overhead_y);
std::cout << "average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,205 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <string>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::uint64_t jobs = 1000;
struct X
{
std::string str;
X( std::string const& str_) :
str( str_)
{}
};
const X x("abc");
void fn_void( boost::coroutines::asymmetric_coroutine< void >::push_type & c)
{ while ( true) c(); }
void fn_int( boost::coroutines::asymmetric_coroutine< int >::push_type & c)
{ while ( true) c( 7); }
void fn_x( boost::coroutines::asymmetric_coroutine< X >::push_type & c)
{
while ( true) c( x);
}
duration_type measure_time_void( duration_type overhead)
{
boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn_void,
boost::coroutines::attributes( preserve_fpu) );
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
c();
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
duration_type measure_time_int( duration_type overhead)
{
boost::coroutines::asymmetric_coroutine< int >::pull_type c( fn_int,
boost::coroutines::attributes( preserve_fpu) );
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
c();
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
duration_type measure_time_x( duration_type overhead)
{
boost::coroutines::asymmetric_coroutine< X >::pull_type c( fn_x,
boost::coroutines::attributes( preserve_fpu) );
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
c();
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles_void( cycle_type overhead)
{
boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn_void,
boost::coroutines::attributes( preserve_fpu) );
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
c();
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
cycle_type measure_cycles_int( cycle_type overhead)
{
boost::coroutines::asymmetric_coroutine< int >::pull_type c( fn_int,
boost::coroutines::attributes( preserve_fpu) );
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
c();
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
cycle_type measure_cycles_x( cycle_type overhead)
{
boost::coroutines::asymmetric_coroutine< X >::pull_type c( fn_x,
boost::coroutines::attributes( preserve_fpu) );
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
c();
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time_void( overhead_c).count();
std::cout << "void: average of " << res << " nano seconds" << std::endl;
res = measure_time_int( overhead_c).count();
std::cout << "int: average of " << res << " nano seconds" << std::endl;
res = measure_time_x( overhead_c).count();
std::cout << "X: average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles_void( overhead_y);
std::cout << "void: average of " << res << " cpu cycles" << std::endl;
res = measure_cycles_int( overhead_y);
std::cout << "int: average of " << res << " cpu cycles" << std::endl;
res = measure_cycles_x( overhead_y);
std::cout << "X: average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,68 @@
# 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine/performance/segmented
: requirements
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<library>/boost/coroutine//boost_coroutine
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static
<threading>multi
<cxxflags>-DBOOST_DISABLE_ASSERTS
<optimization>speed
<variant>release
;
alias sources
: ../../bind_processor_aix.cpp
: <target-os>aix
;
alias sources
: ../../bind_processor_freebsd.cpp
: <target-os>freebsd
;
alias sources
: ../../bind_processor_hpux.cpp
: <target-os>hpux
;
alias sources
: ../../bind_processor_linux.cpp
: <target-os>linux
;
alias sources
: ../../bind_processor_solaris.cpp
: <target-os>solaris
;
alias sources
: ../../bind_processor_windows.cpp
: <target-os>windows
;
explicit sources ;
exe performance_create_segmented
: sources
performance_create_segmented.cpp
;

View File

@@ -0,0 +1,106 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../../bind_processor.hpp"
#include "../../clock.hpp"
#include "../../cycle.hpp"
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
boost::uint64_t jobs = 1000;
void fn( boost::coroutines::asymmetric_coroutine< void >::push_type & c)
{ while ( true) c(); }
duration_type measure_time( duration_type overhead)
{
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu) );
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles( cycle_type overhead)
{
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu) );
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, unwind = true, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles( overhead_y);
std::cout << "average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,12 @@
// 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)
#ifndef BIND_TO_PROCESSOR_H
#define BIND_TO_PROCESSOR_H
void bind_to_processor( unsigned int n);
#endif // BIND_TO_PROCESSOR_H

View File

@@ -0,0 +1,25 @@
// 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)
#include "bind_processor.hpp"
extern "C"
{
#include <sys/processor.h>
#include <sys/thread.h>
}
#include <stdexcept>
#include <boost/config/abi_prefix.hpp>
void bind_to_processor( unsigned int n)
{
if ( ::bindprocessor( BINDTHREAD, ::thread_yield(), static_cast< cpu_t >( n) ) == -1)
throw std::runtime_error("::bindprocessor() failed");
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -0,0 +1,29 @@
// 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)
#include "bind_processor.hpp"
extern "C"
{
#include <sys/param.h>
#include <sys/cpuset.h>
}
#include <stdexcept>
#include <boost/config/abi_prefix.hpp>
void bind_to_processor( unsigned int n)
{
cpuset_t cpuset;
CPU_ZERO( & cpuset);
CPU_SET( n, & cpuset);
if ( ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( cpuset), & cpuset) == -1)
throw std::runtime_error("::cpuset_setaffinity() failed");
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -0,0 +1,31 @@
// 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)
#include "bind_processor.hpp"
extern "C"
{
#include <sys/pthread.h>
}
#include <stdexcept>
#include <boost/config/abi_prefix.hpp>
void bind_to_processor( unsigned int n)
{
::pthread_spu_t spu;
int errno_(
::pthread_processor_bind_np(
PTHREAD_BIND_FORCED_NP,
& spu,
static_cast< pthread_spu_t >( n),
PTHREAD_SELFTID_NP) );
if ( errno_ != 0)
throw std::runtime_error("::pthread_processor_bind_np() failed");
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -0,0 +1,30 @@
// 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)
#include "bind_processor.hpp"
extern "C"
{
#include <pthread.h>
#include <sched.h>
}
#include <stdexcept>
#include <boost/config/abi_prefix.hpp>
void bind_to_processor( unsigned int n)
{
cpu_set_t cpuset;
CPU_ZERO( & cpuset);
CPU_SET( n, & cpuset);
int errno_( ::pthread_setaffinity_np( ::pthread_self(), sizeof( cpuset), & cpuset) );
if ( errno_ != 0)
throw std::runtime_error("::pthread_setaffinity_np() failed");
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -0,0 +1,26 @@
// 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)
#include "bind_processor.hpp"
extern "C"
{
#include <sys/types.h>
#include <sys/processor.h>
#include <sys/procset.h>
}
#include <stdexcept>
#include <boost/config/abi_prefix.hpp>
void bind_to_processor( unsigned int n)
{
if ( ::processor_bind( P_LWPID, P_MYID, static_cast< processorid_t >( n), 0) == -1)
throw std::runtime_error("::processor_bind() failed");
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -0,0 +1,24 @@
// 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)
#include "bind_processor.hpp"
extern "C"
{
#include <windows.h>
}
#include <stdexcept>
#include <boost/config/abi_prefix.hpp>
void bind_to_processor( unsigned int n)
{
if ( ::SetThreadAffinityMask( ::GetCurrentThread(), ( DWORD_PTR)1 << n) == 0)
throw std::runtime_error("::SetThreadAffinityMask() failed");
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -0,0 +1,44 @@
// 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)
//
#ifndef CLOCK_H
#define CLOCK_H
#include <algorithm>
#include <cstddef>
#include <numeric>
#include <vector>
#include <boost/assert.hpp>
#include <boost/chrono.hpp>
#include <boost/cstdint.hpp>
typedef boost::chrono::high_resolution_clock clock_type;
typedef clock_type::duration duration_type;
typedef clock_type::time_point time_point_type;
struct clock_overhead
{
boost::uint64_t operator()()
{
time_point_type start( clock_type::now() );
return ( clock_type::now() - start).count();
}
};
duration_type overhead_clock()
{
std::size_t iterations( 10);
std::vector< boost::uint64_t > overhead( iterations, 0);
for ( std::size_t i = 0; i < iterations; ++i)
std::generate(
overhead.begin(), overhead.end(),
clock_overhead() );
BOOST_ASSERT( overhead.begin() != overhead.end() );
return duration_type( std::accumulate( overhead.begin(), overhead.end(), 0) / iterations);
}
#endif // CLOCK_H

View File

@@ -0,0 +1,26 @@
// 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)
#ifndef CYCLE_H
#define CYCLE_H
// x86_64
// test x86_64 before i386 because icc might
// define __i686__ for x86_64 too
#if defined(__x86_64__) || defined(__x86_64) \
|| defined(__amd64__) || defined(__amd64) \
|| defined(_M_X64) || defined(_M_AMD64)
# include "cycle_x86-64.hpp"
// i386
#elif defined(i386) || defined(__i386__) || defined(__i386) \
|| defined(__i486__) || defined(__i586__) || defined(__i686__) \
|| defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \
|| defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \
|| defined(_M_IX86) || defined(_I86_)
# include "cycle_i386.hpp"
#endif
#endif // CYCLE_H

View File

@@ -0,0 +1,83 @@
// 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)
#ifndef CYCLE_I386_H
#define CYCLE_I386_H
#include <algorithm>
#include <numeric>
#include <cstddef>
#include <vector>
#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#define BOOST_CONTEXT_CYCLE
typedef boost::uint64_t cycle_type;
#if _MSC_VER
inline
cycle_type cycles()
{
cycle_type c;
__asm {
cpuid
rdtsc
mov dword ptr [c + 0], eax
mov dword ptr [c + 4], edx
}
return c;
}
#elif defined(__GNUC__) || \
defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL)
inline
cycle_type cycles()
{
boost::uint32_t lo, hi;
__asm__ __volatile__ (
"xorl %%eax, %%eax\n"
"cpuid\n"
::: "%eax", "%ebx", "%ecx", "%edx"
);
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) );
__asm__ __volatile__ (
"xorl %%eax, %%eax\n"
"cpuid\n"
::: "%eax", "%ebx", "%ecx", "%edx"
);
return ( cycle_type)hi << 32 | lo;
}
#else
# error "this compiler is not supported"
#endif
struct cycle_overhead
{
cycle_type operator()()
{
cycle_type start( cycles() );
return cycles() - start;
}
};
inline
cycle_type overhead_cycle()
{
std::size_t iterations( 10);
std::vector< cycle_type > overhead( iterations, 0);
for ( std::size_t i( 0); i < iterations; ++i)
std::generate(
overhead.begin(), overhead.end(),
cycle_overhead() );
BOOST_ASSERT( overhead.begin() != overhead.end() );
return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
}
#endif // CYCLE_I386_H

View File

@@ -0,0 +1,79 @@
// 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)
#ifndef CYCLE_X86_64_H
#define CYCLE_X86_64_H
#include <algorithm>
#include <numeric>
#include <cstddef>
#include <vector>
#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#define BOOST_CONTEXT_CYCLE
typedef boost::uint64_t cycle_type;
#if _MSC_VER >= 1400
# include <intrin.h>
# pragma intrinsic(__rdtsc)
inline
cycle_type cycles()
{ return __rdtsc(); }
#elif defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL)
inline
cycle_type cycles()
{ return __rdtsc(); }
#elif defined(__GNUC__) || defined(__SUNPRO_C)
inline
cycle_type cycles()
{
boost::uint32_t lo, hi;
__asm__ __volatile__ (
"xorl %%eax, %%eax\n"
"cpuid\n"
::: "%rax", "%rbx", "%rcx", "%rdx"
);
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) );
__asm__ __volatile__ (
"xorl %%eax, %%eax\n"
"cpuid\n"
::: "%rax", "%rbx", "%rcx", "%rdx"
);
return ( cycle_type)hi << 32 | lo;
}
#else
# error "this compiler is not supported"
#endif
struct cycle_overhead
{
cycle_type operator()()
{
cycle_type start( cycles() );
return cycles() - start;
}
};
inline
cycle_type overhead_cycle()
{
std::size_t iterations( 10);
std::vector< cycle_type > overhead( iterations, 0);
for ( std::size_t i( 0); i < iterations; ++i)
std::generate(
overhead.begin(), overhead.end(),
cycle_overhead() );
BOOST_ASSERT( overhead.begin() != overhead.end() );
return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
}
#endif // CYCLE_X86_64_H

View File

@@ -0,0 +1,56 @@
// 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)
#ifndef BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H
#define BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H
#include <cstddef>
#include <cstdlib>
#include <stdexcept>
#include <vector>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/coroutine/standard_stack_allocator.hpp>
#include <boost/coroutine/stack_context.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
class preallocated_stack_allocator
{
private:
boost::coroutines::stack_context stack_ctx_;
public:
preallocated_stack_allocator() :
stack_ctx_()
{
boost::coroutines::standard_stack_allocator allocator;
allocator.allocate(
stack_ctx_,
boost::coroutines::standard_stack_allocator::traits_type::default_size() );
}
void allocate( boost::coroutines::stack_context & ctx, std::size_t size)
{
ctx.sp = stack_ctx_.sp;
ctx.size = stack_ctx_.size;
}
void deallocate( boost::coroutines::stack_context & ctx)
{
}
};
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H

View File

@@ -0,0 +1,83 @@
# 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine/performance/symmetric
: requirements
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<library>/boost/coroutine//boost_coroutine
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static
<threading>multi
<cxxflags>-DBOOST_DISABLE_ASSERTS
<optimization>speed
<variant>release
;
alias sources
: ../bind_processor_aix.cpp
: <target-os>aix
;
alias sources
: ../bind_processor_freebsd.cpp
: <target-os>freebsd
;
alias sources
: ../bind_processor_hpux.cpp
: <target-os>hpux
;
alias sources
: ../bind_processor_linux.cpp
: <target-os>linux
;
alias sources
: ../bind_processor_solaris.cpp
: <target-os>solaris
;
alias sources
: ../bind_processor_windows.cpp
: <target-os>windows
;
explicit sources ;
exe performance_create_protected
: sources
performance_create_protected.cpp
;
exe performance_create_standard
: sources
performance_create_standard.cpp
;
exe performance_create_prealloc
: sources
performance_create_prealloc.cpp
;
exe performance_switch
: sources
performance_switch.cpp
;

View File

@@ -0,0 +1,114 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
#include "../preallocated_stack_allocator.hpp"
typedef preallocated_stack_allocator stack_allocator;
typedef boost::coroutines::symmetric_coroutine< void > coro_type;
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
boost::uint64_t jobs = 1000;
void fn( coro_type::yield_type &) {}
duration_type measure_time( duration_type overhead)
{
stack_allocator stack_alloc;
boost::coroutines::attributes attrs( unwind_stack, preserve_fpu);
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::call_type c( fn, attrs, stack_alloc);
}
duration_type total = clock_type::now() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles( cycle_type overhead)
{
stack_allocator stack_alloc;
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::call_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu),
stack_alloc);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, unwind = true, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles( overhead_y);
std::cout << "average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,112 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
typedef boost::coroutines::protected_stack_allocator stack_allocator;
typedef boost::coroutines::symmetric_coroutine< void > coro_type;
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
boost::uint64_t jobs = 1000;
void fn( coro_type::yield_type &) {}
duration_type measure_time( duration_type overhead)
{
stack_allocator stack_alloc;
boost::coroutines::attributes attrs( unwind_stack, preserve_fpu);
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::call_type c( fn, attrs, stack_alloc);
}
duration_type total = clock_type::now() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles( cycle_type overhead)
{
stack_allocator stack_alloc;
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::call_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, unwind = true, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles( overhead_y);
std::cout << "average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,112 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
typedef boost::coroutines::standard_stack_allocator stack_allocator;
typedef boost::coroutines::symmetric_coroutine< void > coro_type;
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
boost::uint64_t jobs = 1000;
void fn( coro_type::yield_type &) {}
duration_type measure_time( duration_type overhead)
{
stack_allocator stack_alloc;
boost::coroutines::attributes attrs( unwind_stack, preserve_fpu);
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::call_type c( fn, attrs, stack_alloc);
}
duration_type total = clock_type::now() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles( cycle_type overhead)
{
stack_allocator stack_alloc;
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::call_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, unwind = true, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles( overhead_y);
std::cout << "average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,207 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <string>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::uint64_t jobs = 1000;
time_point_type end;
struct X
{
std::string str;
X( std::string const& str_) :
str( str_)
{}
};
const X x("abc");
void fn_void( boost::coroutines::symmetric_coroutine< void >::yield_type & yield)
{ while( true) yield(); }
void fn_int( boost::coroutines::symmetric_coroutine< int >::yield_type & yield)
{ while( true) yield(); }
void fn_x( boost::coroutines::symmetric_coroutine< X >::yield_type & yield)
{ while( true) yield(); }
duration_type measure_time_void( duration_type overhead)
{
boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void,
boost::coroutines::attributes( preserve_fpu) );
c();
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
c();
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
duration_type measure_time_int( duration_type overhead)
{
boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int,
boost::coroutines::attributes( preserve_fpu) );
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
c( i);
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
duration_type measure_time_x( duration_type overhead)
{
boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x,
boost::coroutines::attributes( preserve_fpu) );
X x("abc");
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
c( x);
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles_void( cycle_type overhead)
{
boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void,
boost::coroutines::attributes( preserve_fpu) );
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
c();
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
cycle_type measure_cycles_int( cycle_type overhead)
{
boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int,
boost::coroutines::attributes( preserve_fpu) );
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
c( i);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
cycle_type measure_cycles_x( cycle_type overhead)
{
boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x,
boost::coroutines::attributes( preserve_fpu) );
X x("abc");
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
c( x);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time_void( overhead_c).count();
std::cout << "void: average of " << res << " nano seconds" << std::endl;
res = measure_time_int( overhead_c).count();
std::cout << "int: average of " << res << " nano seconds" << std::endl;
res = measure_time_x( overhead_c).count();
std::cout << "X: average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles_void( overhead_y);
std::cout << "void: average of " << res << " cpu cycles" << std::endl;
res = measure_cycles_int( overhead_y);
std::cout << "int: average of " << res << " cpu cycles" << std::endl;
res = measure_cycles_x( overhead_y);
std::cout << "X: average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,68 @@
# 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine/performance/segmented
: requirements
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<library>/boost/coroutine//boost_coroutine
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static
<threading>multi
<cxxflags>-DBOOST_DISABLE_ASSERTS
<optimization>speed
<variant>release
;
alias sources
: ../../bind_processor_aix.cpp
: <target-os>aix
;
alias sources
: ../../bind_processor_freebsd.cpp
: <target-os>freebsd
;
alias sources
: ../../bind_processor_hpux.cpp
: <target-os>hpux
;
alias sources
: ../../bind_processor_linux.cpp
: <target-os>linux
;
alias sources
: ../../bind_processor_solaris.cpp
: <target-os>solaris
;
alias sources
: ../../bind_processor_windows.cpp
: <target-os>windows
;
explicit sources ;
exe performance_create_segmented
: sources
performance_create_segmented.cpp
;

View File

@@ -0,0 +1,105 @@
// 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)
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../../bind_processor.hpp"
#include "../../clock.hpp"
#include "../../cycle.hpp"
boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
boost::uint64_t jobs = 1000;
void fn( boost::coroutines::symmetric_coroutine< void >::yield_type &) {}
duration_type measure_time( duration_type overhead)
{
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
boost::coroutines::symmetric_coroutine< void >::call_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu) );
}
duration_type total = clock_type::now() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles( cycle_type overhead)
{
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
boost::coroutines::symmetric_coroutine< void >::call_type c( fn,
boost::coroutines::attributes( unwind_stack, preserve_fpu) );
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool preserve = false, unwind = true, bind = false;
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
if ( bind) bind_to_processor( 0);
duration_type overhead_c = overhead_clock();
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
boost::uint64_t res = measure_time( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
res = measure_cycles( overhead_y);
std::cout << "average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,82 @@
// 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)
#include "boost/coroutine/detail/coroutine_context.hpp"
#include "boost/coroutine/detail/data.hpp"
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable:4355)
#endif
#if defined(BOOST_USE_SEGMENTED_STACKS)
extern "C" {
void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]);
void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]);
}
#endif
namespace boost {
namespace coroutines {
namespace detail {
coroutine_context::coroutine_context() :
palloc_(),
ctx_( 0)
{}
coroutine_context::coroutine_context( ctx_fn fn, preallocated const& palloc) :
palloc_( palloc),
ctx_( context::detail::make_fcontext( palloc_.sp, palloc_.size, fn) )
{}
coroutine_context::coroutine_context( coroutine_context const& other) :
palloc_( other.palloc_),
ctx_( other.ctx_)
{}
coroutine_context &
coroutine_context::operator=( coroutine_context const& other)
{
if ( this == & other) return * this;
palloc_ = other.palloc_;
ctx_ = other.ctx_;
return * this;
}
void *
coroutine_context::jump( coroutine_context & other, void * param)
{
#if defined(BOOST_USE_SEGMENTED_STACKS)
__splitstack_getcontext( palloc_.sctx.segments_ctx);
__splitstack_setcontext( other.palloc_.sctx.segments_ctx);
#endif
data_t data = { this, param };
context::detail::transfer_t t = context::detail::jump_fcontext( other.ctx_, & data);
data_t * ret = static_cast< data_t * >( t.data);
ret->from->ctx_ = t.fctx;
return ret->data;
}
}}}
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif

View File

@@ -0,0 +1,37 @@
// 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)
#include "boost/coroutine/exceptions.hpp"
namespace boost {
namespace coroutines {
class coroutine_error_category : public system::error_category
{
public:
virtual const char* name() const BOOST_NOEXCEPT
{ return "coroutine"; }
virtual std::string message( int ev) const
{
switch (BOOST_SCOPED_ENUM_NATIVE(coroutine_errc)(ev))
{
case coroutine_errc::no_data:
return std::string("Operation not permitted because coroutine "
"has no valid result.");
}
return std::string("unspecified coroutine_errc value\n");
}
};
BOOST_COROUTINES_DECL
system::error_category const& coroutine_category() BOOST_NOEXCEPT
{
static coroutines::coroutine_error_category cat;
return cat;
}
}}

View File

@@ -0,0 +1,112 @@
// 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)
#include "boost/coroutine/stack_traits.hpp"
extern "C" {
#include <signal.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>
}
//#if _POSIX_C_SOURCE >= 200112L
#include <algorithm>
#include <cmath>
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#if !defined (SIGSTKSZ)
# define SIGSTKSZ (8 * 1024)
# define UDEF_SIGSTKSZ
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace {
void pagesize_( std::size_t * size)
{
// conform to POSIX.1-2001
* size = ::sysconf( _SC_PAGESIZE);
}
void stacksize_limit_( rlimit * limit)
{
// conforming to POSIX.1-2001
#if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG)
::getrlimit( RLIMIT_STACK, limit);
#else
const int result = ::getrlimit( RLIMIT_STACK, limit);
BOOST_ASSERT( 0 == result);
#endif
}
std::size_t pagesize()
{
static std::size_t size = 0;
static boost::once_flag flag;
boost::call_once( flag, pagesize_, & size);
return size;
}
rlimit stacksize_limit()
{
static rlimit limit;
static boost::once_flag flag;
boost::call_once( flag, stacksize_limit_, & limit);
return limit;
}
}
namespace boost {
namespace coroutines {
bool
stack_traits::is_unbounded() BOOST_NOEXCEPT
{ return RLIM_INFINITY == stacksize_limit().rlim_max; }
std::size_t
stack_traits::page_size() BOOST_NOEXCEPT
{ return pagesize(); }
std::size_t
stack_traits::default_size() BOOST_NOEXCEPT
{
std::size_t size = 8 * minimum_size();
if ( is_unbounded() ) return size;
BOOST_ASSERT( maximum_size() >= minimum_size() );
return maximum_size() == size
? size
: (std::min)( size, maximum_size() );
}
std::size_t
stack_traits::minimum_size() BOOST_NOEXCEPT
{ return SIGSTKSZ; }
std::size_t
stack_traits::maximum_size() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! is_unbounded() );
return static_cast< std::size_t >( stacksize_limit().rlim_max);
}
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#ifdef UDEF_SIGSTKSZ
# undef SIGSTKSZ
#endif

View File

@@ -0,0 +1,114 @@
// 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)
#include "boost/coroutine/stack_traits.hpp"
extern "C" {
#include <windows.h>
}
//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <stdexcept>
#include <boost/assert.hpp>
#include <boost/coroutine/detail/config.hpp>
#include <boost/thread.hpp>
#include <boost/coroutine/stack_context.hpp>
// x86_64
// test x86_64 before i386 because icc might
// define __i686__ for x86_64 too
#if defined(__x86_64__) || defined(__x86_64) \
|| defined(__amd64__) || defined(__amd64) \
|| defined(_M_X64) || defined(_M_AMD64)
// Windows seams not to provide a constant or function
// telling the minimal stacksize
# define MIN_STACKSIZE 8 * 1024
#else
# define MIN_STACKSIZE 4 * 1024
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace {
void system_info_( SYSTEM_INFO * si)
{ ::GetSystemInfo( si); }
SYSTEM_INFO system_info()
{
static SYSTEM_INFO si;
static boost::once_flag flag;
boost::call_once( flag, static_cast< void(*)( SYSTEM_INFO *) >( system_info_), & si);
return si;
}
std::size_t pagesize()
{ return static_cast< std::size_t >( system_info().dwPageSize); }
std::size_t page_count( std::size_t stacksize)
{
return static_cast< std::size_t >(
std::floor(
static_cast< float >( stacksize) / pagesize() ) );
}
}
namespace boost {
namespace coroutines {
// Windows seams not to provide a limit for the stacksize
// libcoco uses 32k+4k bytes as minimum
bool
stack_traits::is_unbounded() BOOST_NOEXCEPT
{ return true; }
std::size_t
stack_traits::page_size() BOOST_NOEXCEPT
{ return pagesize(); }
std::size_t
stack_traits::default_size() BOOST_NOEXCEPT
{
std::size_t size = 64 * 1024; // 64 kB
if ( is_unbounded() )
return (std::max)( size, minimum_size() );
BOOST_ASSERT( maximum_size() >= minimum_size() );
return maximum_size() == minimum_size()
? minimum_size()
: ( std::min)( size, maximum_size() );
}
// because Windows seams not to provide a limit for minimum stacksize
std::size_t
stack_traits::minimum_size() BOOST_NOEXCEPT
{ return MIN_STACKSIZE; }
// because Windows seams not to provide a limit for maximum stacksize
// maximum_size() can never be called (pre-condition ! is_unbounded() )
std::size_t
stack_traits::maximum_size() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! is_unbounded() );
return 1 * 1024 * 1024 * 1024; // 1GB
}
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif

View File

@@ -0,0 +1,33 @@
# Boost.Coroutine Library Tests Jamfile
# 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)
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import testing ;
import toolset ;
project boost/coroutine/test
: requirements
<library>/boost/context//boost_context
<library>/boost/coroutine//boost_coroutine
<library>/boost/program_options//boost_program_options
<library>/boost/test///boost_unit_test_framework
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static
<threading>multi
;
test-suite "coroutine" :
[ run test_asymmetric_coroutine.cpp ]
[ run test_symmetric_coroutine.cpp ]
;

View File

@@ -0,0 +1,627 @@
// 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)
#include <algorithm>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <cstdio>
#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/move/move.hpp>
#include <boost/range.hpp>
#include <boost/ref.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/utility.hpp>
#include <boost/coroutine/asymmetric_coroutine.hpp>
namespace coro = boost::coroutines;
int value1 = 0;
std::string value2 = "";
bool value3 = false;
double value4 = .0;
int * value5 = 0;
int& value6 = value1;
int& value7 = value1;
int value8 = 0;
int value9 = 0;
struct X : private boost::noncopyable
{
X() { value1 = 7; }
~X() { value1 = 0; }
};
class copyable
{
public:
bool state;
copyable() :
state( false)
{}
copyable( int) :
state( true)
{}
void operator()( coro::asymmetric_coroutine< int >::push_type &)
{ value3 = state; }
};
class moveable
{
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable)
public:
bool state;
moveable() :
state( false)
{}
moveable( int) :
state( true)
{}
moveable( BOOST_RV_REF( moveable) other) :
state( false)
{ std::swap( state, other.state); }
moveable & operator=( BOOST_RV_REF( moveable) other)
{
if ( this == & other) return * this;
moveable tmp( boost::move( other) );
std::swap( state, tmp.state);
return * this;
}
void operator()( coro::asymmetric_coroutine< int >::push_type &)
{ value3 = state; }
};
struct my_exception {};
void f1( coro::asymmetric_coroutine< void >::push_type & c)
{
while ( c)
c();
}
void f2( coro::asymmetric_coroutine< void >::push_type &)
{ ++value1; }
void f3( coro::asymmetric_coroutine< void >::push_type & c)
{
++value1;
c();
++value1;
}
void f4( coro::asymmetric_coroutine< int >::push_type & c)
{
c( 3);
c( 7);
}
void f5( coro::asymmetric_coroutine< std::string >::push_type & c)
{
std::string res("abc");
c( res);
res = "xyz";
c( res);
}
void f6( coro::asymmetric_coroutine< int >::pull_type & c)
{ value1 = c.get(); }
void f7( coro::asymmetric_coroutine< std::string >::pull_type & c)
{ value2 = c.get(); }
void f8( coro::asymmetric_coroutine< boost::tuple< double, double > >::pull_type & c)
{
double x = 0, y = 0;
boost::tie( x, y) = c.get();
value4 = x + y;
c();
boost::tie( x, y) = c.get();
value4 = x + y;
}
void f9( coro::asymmetric_coroutine< int * >::pull_type & c)
{ value5 = c.get(); }
void f91( coro::asymmetric_coroutine< int const* >::pull_type & c)
{ value5 = const_cast< int * >( c.get() ); }
void f10( coro::asymmetric_coroutine< int & >::pull_type & c)
{
int const& i = c.get();
value5 = const_cast< int * >( & i);
}
void f101( coro::asymmetric_coroutine< int const& >::pull_type & c)
{
int const& i = c.get();
value5 = const_cast< int * >( & i);
}
void f11( coro::asymmetric_coroutine< boost::tuple< int, int > >::pull_type & c)
{
boost::tie( value8, value9) = c.get();
}
void f12( coro::asymmetric_coroutine< void >::pull_type & c)
{
X x_;
c();
c();
}
template< typename E >
void f14( coro::asymmetric_coroutine< void >::pull_type &, E const& e)
{ throw e; }
void f16( coro::asymmetric_coroutine< int >::push_type & c)
{
c( 1);
c( 2);
c( 3);
c( 4);
c( 5);
}
void f17( coro::asymmetric_coroutine< int >::pull_type & c, std::vector< int > & vec)
{
int x = c.get();
while ( 5 > x)
{
vec.push_back( x);
x = c().get();
}
}
void f19( coro::asymmetric_coroutine< int* >::push_type & c, std::vector< int * > & vec)
{
BOOST_FOREACH( int * ptr, vec)
{ c( ptr); }
}
void f20( coro::asymmetric_coroutine< int >::push_type &)
{}
void f21( coro::asymmetric_coroutine< int >::pull_type & c)
{
while ( c)
{
value1 = c.get();
c();
}
}
void test_move()
{
{
coro::asymmetric_coroutine< void >::pull_type coro1;
coro::asymmetric_coroutine< void >::pull_type coro2( f1);
BOOST_CHECK( ! coro1);
BOOST_CHECK( coro2);
coro2();
coro1 = boost::move( coro2);
BOOST_CHECK( coro1);
coro1();
BOOST_CHECK( ! coro2);
}
{
value3 = false;
copyable cp( 3);
BOOST_CHECK( cp.state);
BOOST_CHECK( ! value3);
coro::asymmetric_coroutine< int >::pull_type coro( cp);
BOOST_CHECK( cp.state);
BOOST_CHECK( value3);
}
{
value3 = false;
moveable mv( 7);
BOOST_CHECK( mv.state);
BOOST_CHECK( ! value3);
coro::asymmetric_coroutine< int >::pull_type coro( boost::move( mv) );
BOOST_CHECK( ! mv.state);
BOOST_CHECK( value3);
}
}
void test_complete()
{
value1 = 0;
coro::asymmetric_coroutine< void >::pull_type coro( f2);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( int)1, value1);
}
void test_jump()
{
value1 = 0;
coro::asymmetric_coroutine< void >::pull_type coro( f3);
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int)1, value1);
coro();
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( int)2, value1);
}
void test_result_int()
{
coro::asymmetric_coroutine< int >::pull_type coro( f4);
BOOST_CHECK( coro);
int result = coro.get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( 3, result);
result = coro().get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( 7, result);
coro();
BOOST_CHECK( ! coro);
}
void test_result_string()
{
coro::asymmetric_coroutine< std::string >::pull_type coro( f5);
BOOST_CHECK( coro);
std::string result = coro.get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( std::string("abc"), result);
result = coro().get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( std::string("xyz"), result);
coro();
BOOST_CHECK( ! coro);
}
void test_arg_int()
{
value1 = 0;
coro::asymmetric_coroutine< int >::push_type coro( f6);
BOOST_CHECK( coro);
coro( 3);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( 3, value1);
}
void test_arg_string()
{
value2 = "";
coro::asymmetric_coroutine< std::string >::push_type coro( f7);
BOOST_CHECK( coro);
coro( std::string("abc") );
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( std::string("abc"), value2);
}
void test_fp()
{
value4 = 0;
coro::asymmetric_coroutine< boost::tuple< double, double > >::push_type coro( f8);
BOOST_CHECK( coro);
coro( boost::make_tuple( 7.35, 3.14) );
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( double) 10.49, value4);
value4 = 0;
coro( boost::make_tuple( 1.15, 3.14) );
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( double) 4.29, value4);
}
void test_ptr()
{
value5 = 0;
int a = 3;
coro::asymmetric_coroutine< int * >::push_type coro( f9);
BOOST_CHECK( coro);
coro( & a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_const_ptr()
{
value5 = 0;
int a = 3;
coro::asymmetric_coroutine< int const* >::push_type coro( f91);
BOOST_CHECK( coro);
coro( & a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_ref()
{
value5 = 0;
int a = 3;
coro::asymmetric_coroutine< int & >::push_type coro( f10);
BOOST_CHECK( coro);
coro( a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_const_ref()
{
value5 = 0;
int a = 3;
coro::asymmetric_coroutine< int const& >::push_type coro( f101);
BOOST_CHECK( coro);
coro( a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_tuple()
{
value8 = 0;
value9 = 0;
int a = 3, b = 7;
boost::tuple< int, int > tpl( a, b);
BOOST_CHECK_EQUAL( a, tpl.get< 0 >() );
BOOST_CHECK_EQUAL( b, tpl.get< 1 >() );
coro::asymmetric_coroutine< boost::tuple< int, int > >::push_type coro( f11);
BOOST_CHECK( coro);
coro( tpl);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( a, value8);
BOOST_CHECK_EQUAL( b, value9);
}
void test_unwind()
{
value1 = 0;
{
coro::asymmetric_coroutine< void >::push_type coro( f12);
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int) 0, value1);
coro();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int) 7, value1);
coro();
BOOST_CHECK_EQUAL( ( int) 7, value1);
}
BOOST_CHECK_EQUAL( ( int) 0, value1);
}
void test_no_unwind()
{
value1 = 0;
{
coro::asymmetric_coroutine< void >::push_type coro(
f12,
coro::attributes(
coro::stack_allocator::traits_type::default_size(),
coro::no_stack_unwind) );
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int) 0, value1);
coro();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int) 7, value1);
coro();
BOOST_CHECK_EQUAL( ( int) 7, value1);
}
BOOST_CHECK_EQUAL( ( int) 7, value1);
}
void test_exceptions()
{
bool thrown = false;
std::runtime_error ex("abc");
try
{
coro::asymmetric_coroutine< void >::push_type coro( boost::bind( f14< std::runtime_error >, _1, ex) );
BOOST_CHECK( coro);
coro();
BOOST_CHECK( ! coro);
BOOST_CHECK( false);
}
catch ( std::runtime_error const&)
{ thrown = true; }
catch ( std::exception const&)
{}
catch (...)
{}
BOOST_CHECK( thrown);
}
void test_input_iterator()
{
{
std::vector< int > vec;
coro::asymmetric_coroutine< int >::pull_type coro( f16);
BOOST_FOREACH( int i, coro)
{ vec.push_back( i); }
BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
BOOST_CHECK_EQUAL( ( int)1, vec[0] );
BOOST_CHECK_EQUAL( ( int)2, vec[1] );
BOOST_CHECK_EQUAL( ( int)3, vec[2] );
BOOST_CHECK_EQUAL( ( int)4, vec[3] );
BOOST_CHECK_EQUAL( ( int)5, vec[4] );
}
{
std::vector< int > vec;
coro::asymmetric_coroutine< int >::pull_type coro( f16);
coro::asymmetric_coroutine< int >::pull_type::iterator e = boost::end( coro);
for (
coro::asymmetric_coroutine< int >::pull_type::iterator i = boost::begin( coro);
i != e; ++i)
{ vec.push_back( * i); }
BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
BOOST_CHECK_EQUAL( ( int)1, vec[0] );
BOOST_CHECK_EQUAL( ( int)2, vec[1] );
BOOST_CHECK_EQUAL( ( int)3, vec[2] );
BOOST_CHECK_EQUAL( ( int)4, vec[3] );
BOOST_CHECK_EQUAL( ( int)5, vec[4] );
}
{
int i1 = 1, i2 = 2, i3 = 3;
std::vector< int* > vec_in;
vec_in.push_back( & i1);
vec_in.push_back( & i2);
vec_in.push_back( & i3);
std::vector< int* > vec_out;
coro::asymmetric_coroutine< int* >::pull_type coro( boost::bind( f19, _1, boost::ref( vec_in) ) );
coro::asymmetric_coroutine< int* >::pull_type::iterator e = boost::end( coro);
for (
coro::asymmetric_coroutine< int* >::pull_type::iterator i = boost::begin( coro);
i != e; ++i)
{
int * p = * i;
vec_out.push_back( p);
}
BOOST_CHECK_EQUAL( ( std::size_t)3, vec_out.size() );
BOOST_CHECK_EQUAL( & i1, vec_out[0] );
BOOST_CHECK_EQUAL( & i2, vec_out[1] );
BOOST_CHECK_EQUAL( & i3, vec_out[2] );
}
}
void test_output_iterator()
{
int counter = 0;
std::vector< int > vec;
coro::asymmetric_coroutine< int >::push_type coro(
boost::bind( f17, _1, boost::ref( vec) ) );
coro::asymmetric_coroutine< int >::push_type::iterator e( boost::end( coro) );
for ( coro::asymmetric_coroutine< int >::push_type::iterator i( boost::begin( coro) );
i != e; ++i)
{
i = ++counter;
}
BOOST_CHECK_EQUAL( ( std::size_t)4, vec.size() );
BOOST_CHECK_EQUAL( ( int)1, vec[0] );
BOOST_CHECK_EQUAL( ( int)2, vec[1] );
BOOST_CHECK_EQUAL( ( int)3, vec[2] );
BOOST_CHECK_EQUAL( ( int)4, vec[3] );
}
void test_invalid_result()
{
bool catched = false;
coro::asymmetric_coroutine< int >::pull_type coro( f20);
BOOST_CHECK( ! coro);
try
{
int i = coro.get();
(void)i;
}
catch ( coro::invalid_result const&)
{
catched = true;
}
BOOST_CHECK( catched);
}
void test_move_coro()
{
value1 = 0;
coro::asymmetric_coroutine< int >::push_type coro1( f21);
coro::asymmetric_coroutine< int >::push_type coro2;
BOOST_CHECK( coro1);
BOOST_CHECK( ! coro2);
coro1( 1);
BOOST_CHECK_EQUAL( ( int)1, value1);
coro2 = boost::move( coro1);
BOOST_CHECK( ! coro1);
BOOST_CHECK( coro2);
coro2( 2);
BOOST_CHECK_EQUAL( ( int)2, value1);
coro1 = boost::move( coro2);
BOOST_CHECK( coro1);
BOOST_CHECK( ! coro2);
coro1( 3);
BOOST_CHECK_EQUAL( ( int)3, value1);
coro2 = boost::move( coro1);
BOOST_CHECK( ! coro1);
BOOST_CHECK( coro2);
coro2( 4);
BOOST_CHECK_EQUAL( ( int)4, value1);
}
void foo( coro::asymmetric_coroutine< int >::push_type & yield)
{
yield( 1);
}
coro::asymmetric_coroutine< int >::pull_type make_range()
{
return coro::asymmetric_coroutine< int >::pull_type( foo);
}
template< typename Range >
void const_func( Range const& r)
{
begin( r);
}
void test_range()
{
const_func( make_range() );
}
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
{
boost::unit_test::test_suite * test =
BOOST_TEST_SUITE("Boost.coroutine: asymmetric coroutine test suite");
test->add( BOOST_TEST_CASE( & test_move) );
test->add( BOOST_TEST_CASE( & test_complete) );
test->add( BOOST_TEST_CASE( & test_jump) );
test->add( BOOST_TEST_CASE( & test_result_int) );
test->add( BOOST_TEST_CASE( & test_result_string) );
test->add( BOOST_TEST_CASE( & test_arg_int) );
test->add( BOOST_TEST_CASE( & test_arg_string) );
test->add( BOOST_TEST_CASE( & test_fp) );
test->add( BOOST_TEST_CASE( & test_ptr) );
test->add( BOOST_TEST_CASE( & test_const_ptr) );
test->add( BOOST_TEST_CASE( & test_invalid_result) );
test->add( BOOST_TEST_CASE( & test_ref) );
test->add( BOOST_TEST_CASE( & test_const_ref) );
test->add( BOOST_TEST_CASE( & test_tuple) );
test->add( BOOST_TEST_CASE( & test_unwind) );
test->add( BOOST_TEST_CASE( & test_no_unwind) );
test->add( BOOST_TEST_CASE( & test_exceptions) );
test->add( BOOST_TEST_CASE( & test_input_iterator) );
test->add( BOOST_TEST_CASE( & test_output_iterator) );
test->add( BOOST_TEST_CASE( & test_range) );
return test;
}

Some files were not shown because too many files have changed in this diff Show More