[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

13
libs/coroutine2/README.md Normal file
View File

@@ -0,0 +1,13 @@
boost.coroutine2
===============
boost.coroutine2 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.
boost.coroutine2 requires C++11!

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 coroutine2/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 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
]
[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 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
]
[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,638 @@
[/
Copyright 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
]
[section:asymmetric Asymmetric coroutine]
Two asymmetric coroutine types - __push_coro__ and __pull_coro__ - provide a
unidirectional transfer of data.
[note ['asymmetric_coroutine<>] is a typedef of __coro__.]
[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.
typedef boost::coroutines2::coroutine<int> coro_t;
coro_t::pull_type source(
[&](coro_t::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.
typedef boost::coroutines2::coroutine<std::string> coro_t;
struct FinalEOL{
~FinalEOL(){
std::cout << std::endl;
}
};
const int num=5, width=15;
coro_t::push_type writer(
[&](coro_t::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(begin(words),end(words),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__.
typedef boost::coroutines2::coroutine<int> coro_t;
coro_t::pull_type source( // constructor enters coroutine-function
[&](coro_t::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__.
typedef boost::coroutines2::coroutine<int> coro_t;
coro_t::push_type sink( // constructor does NOT enter coroutine-function
[&](coro_t::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.
typedef boost::coroutines2::coroutine<boost::tuple<int,int>> coro_t;
coro_t::push_type sink(
[&](coro_t::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::coroutines2::detail::forced_unwind&) {
throw;
} catch(...) {
// possibly not re-throw pending exception
}
[important Do not jump from inside a catch block and than 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;
}
};
{
typedef boost::coroutines2::coroutine<void>::push_type coro_t;
coro_t::push_type sink(
[&](coro_t::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__.
typedef boost::coroutines2::coroutine< int > coro_t;
int number=2,exponent=8;
coro_t::pull_type source(
[&](coro_t::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
['coroutine<>::pull_type::iterator::operator++()] corresponds to
__pull_coro_op__; ['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
['coroutine<T>::pull_type::iterator] may only be dereferenced once
before it is incremented again.]
Output-iterators can be created from __push_coro__.
typedef boost::coroutines2::coroutine<int> coro_t;
coro_t::push_type sink(
[&](coro_t::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(begin(v),end(v),begin(sink));
['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 `coroutine<>::pull_type`]
#include <boost/coroutine2/coroutine.hpp>
template< typename R >
class coroutine<>::pull_type
{
public:
template< typename Fn >
pull_type( Fn && fn);
template< typename StackAllocator, typename Fn >
pull_type( StackAllocator stack_alloc, Fn && fn);
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;
pull_coroutine & operator()();
explicit operator bool() const noexcept;
bool operator!() const noexcept;
R get() noexcept;
};
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 `template< typename Fn >
pull_type( Fn && fn)`]
[variablelist
[[Effects:] [Creates a coroutine which will execute `fn`, and enters it.]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]
[heading `template< typename StackAllocator, typename Fn >
pull_type( StackAllocator const& stack_alloc, Fn && fn)`]
[variablelist
[[Effects:] [Creates a coroutine which will execute `fn`.
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 `explicit operator bool() const noexcept`]
[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 noexcept`]
[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() noexcept`]
R coroutine<R,StackAllocator>::pull_type::get();
R& coroutine<R&,StackAllocator>::pull_type::get();
void 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 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 `coroutine<>::push_type`]
#include <boost/coroutine2/coroutine.hpp>
template< typename Arg >
class coroutine<>::push_type
{
public:
template< typename Fn >
push_type( Fn && fn);
template< typename StackAllocator, typename Fn >
push_type( StackAllocator stack_alloc, Fn && fn);
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;
explicit operator bool() const noexcept;
bool operator!() const noexcept;
push_type & operator()( Arg arg);
};
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 `template< typename Fn >
push_type( Fn && fn)`]
[variablelist
[[Effects:] [Creates a coroutine which will execute `fn`.]]
]
[heading `template< typename StackAllocator, typename Fn >
push_type( StackAllocator const& stack_alloc, Fn && fn)`]
[variablelist
[[Effects:] [Creates a coroutine which will execute `fn`.
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) noexcept`]
[variablelist
[[Effects:] [Moves the internal data of `other` to `*this`.
`other` becomes __not_a_coro__.]]
[[Throws:] [Nothing.]]
]
[heading `push_type & operator=( push_type && other) noexcept`]
[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 `explicit operator bool() const noexcept`]
[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 noexcept`]
[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& coroutine<Arg>::push_type::operator()(Arg);
push_type& coroutine<Arg&>::push_type::operator()(Arg&);
push_type& coroutine<void>::push_type::operator()();
[variablelist
[[Preconditions:] [operator unspecified-bool-type() returns `true` for `*this`.]]
[[Effects:] [Execution control is transferred to __coro_fn__ and the argument
`arg` is passed to the coroutine-function.]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]
[heading 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,89 @@
[/
Copyright 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
]
[library Coroutine2
[quickbook 1.5]
[authors [Kowalke, Oliver]]
[copyright 2014 Oliver Kowalke]
[purpose C++11 Library providing coroutine facility]
[id coroutine2]
[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.Coroutine2]]
[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__ ['coroutine<>]]
[def __attrs__ ['attributes]]
[def __begin__ ['std::begin()]]
[def __bind__ ['boost::bind()]]
[def __coro_allocator__ ['stack_allocator]]
[def __coro_ns__ ['boost::coroutines2]]
[def __econtext__ ['execution_context]]
[def __end__ ['std::end()]]
[def __fcontext__ [@boost:/libs/context/doc/html/context/cc.html#implementation fcontext_t]]
[def __fetch__ ['inbuf::fetch()]]
[def __fixedsize__ ['fixedsize_stack]]
[def __forced_unwind__ ['detail::forced_unwind]]
[def __getline__ ['std::getline()]]
[def __handle_read__ ['session::handle_read()]]
[def __io_service__ ['boost::asio::io_sevice]]
[def __pooled_fixedsize__ ['pooled_fixedsize_stack]]
[def __protected_allocator__ ['protected_fixedsize]]
[def __protected_fixedsize__ ['protected_fixedsize_stack]]
[def __pull_coro__ ['coroutine<>::pull_type]]
[def __pull_coro_bool__ ['coroutine<>::pull_type::operator bool]]
[def __pull_coro_get__ ['coroutine<>::pull_type::get()]]
[def __pull_coro_it__ ['coroutine<>::pull_type::iterator]]
[def __pull_coro_op__ ['coroutine<>::pull_type::operator()]]
[def __push_coro__ ['coroutine<>::push_type]]
[def __push_coro_bool__ ['coroutine<>::push_type::operator bool]]
[def __push_coro_it__ ['coroutine<>::push_type::iterator]]
[def __push_coro_op__ ['coroutine<>::push_type::operator()]]
[def __segmented_allocator__ ['segmented]]
[def __segmented__ ['segmented_stack]]
[def __server__ ['server]]
[def __session__ ['session]]
[def __stack_context__ ['stack_context]]
[def __standard_allocator__ ['fixedsize]]
[def __start__ ['session::start()]]
[def __terminate__ ['std::terminate()]]
[def __ucontext__ ['ucontext_t]]
[def __winfib__ ['WinFiber]]
[def __cc__ ['call/cc]]
[def __underflow__ ['stream_buf::underflow()]]
[def __yield_context__ ['boost::asio::yield_context]]
[include overview.qbk]
[include intro.qbk]
[include motivation.qbk]
[include coroutine.qbk]
[include stack.qbk]
[include performance.qbk]
[include architectures.qbk]
[include acknowledgements.qbk]

View File

@@ -0,0 +1,123 @@
[/
Copyright 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
]
[section:coroutine Coroutine]
__boost_coroutine__ provides asymmetric coroutines.
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]
__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 [link segmented ['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__).
A context switch is done via __push_coro_op__ and __pull_coro_op__.
[warning Calling __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::coroutines2::coroutine<void>::push_type coro(
[&](boost::coroutines2::coroutine<void>::pull_type& yield){
yield();
});
coro();
[include asymmetric.qbk]
[section Implementations: fcontext_t, ucontext_t and WinFiber]
[heading fcontext_t]
The implementation uses __fcontext__ per default. fcontext_t is based on
assembler and not available for all platforms. It provides a much better
performance than __ucontext__
(the context switch takes two magnitudes of order less CPU cycles) and __winfib__.
[heading ucontext_t]
As an alternative, [@https://en.wikipedia.org/wiki/Setcontext __ucontext__]
can be used by compiling with `BOOST_USE_UCONTEXT` and b2 property `context-impl=ucontext`.
__ucontext__ might be available on a broader range of POSIX-platforms but has
some (for instance deprecated since POSIX.1-2003, not C99 conform).
[note __cc__ supports [link segmented ['Segmented stacks]] only with
__ucontext__ as its implementation.]
[heading WinFiber]
With `BOOST_USE_WINFIB` and b2 property `context-impl=winfib` Win32-Fibers are used
as implementation for __cc__.
Because the TIB (thread information block) is not fully described in the MSDN,
it might be possible that not all required TIB-parts are swapped.
[note The first call of __cc__ converts the thread into a Windows fiber by
invoking `ConvertThreadToFiber()`. If desired, `ConvertFiberToThread()` has
to be called by the user explicitly in order to release resources allocated
by `ConvertThreadToFiber()` (e.g. after using boost.context). ]
[endsect]
[endsect]

View File

@@ -0,0 +1,20 @@
index.html
coroutine2/overview.html
coroutine2/intro.html
coroutine2/motivation.html
coroutine2/coroutine.html
coroutine2/coroutine/asymmetric.html
coroutine2/coroutine/asymmetric/pull_coro.html
coroutine2/coroutine/asymmetric/push_coro.html
coroutine2/coroutine/implementations__fcontext_t__ucontext_t_and_winfiber.html
coroutine2/stack.html
coroutine2/stack/protected_fixedsize.html
coroutine2/stack/pooled_fixedsize.html
coroutine2/stack/fixedsize.html
coroutine2/stack/segmented.html
coroutine2/stack/stack_traits.html
coroutine2/stack/stack_context.html
coroutine2/stack/valgrind.html
coroutine2/performance.html
coroutine2/architectures.html
coroutine2/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;Coroutine2">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<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="coroutine2.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; 2014 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;Coroutine2">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<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="coroutine2.architectures"></a><a class="link" href="architectures.html" title="Architectures">Architectures</a>
</h2></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine2</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; 2014 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,171 @@
<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;Coroutine2">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<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="coroutine2.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">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">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/implementations__fcontext_t__ucontext_t_and_winfiber.html">Implementations:
fcontext_t, ucontext_t and WinFiber</a></span></dt>
</dl></div>
<p>
<span class="bold"><strong>Boost.Coroutine2</strong></span> provides asymmetric coroutines.
</p>
<p>
Implementations that produce sequences of values typically use asymmetric coroutines.
<a href="#ftn.coroutine2.coroutine.f0" class="footnote" name="coroutine2.coroutine.f0"><sup class="footnote">[5]</sup></a>
</p>
<h4>
<a name="coroutine2.coroutine.h0"></a>
<span class="phrase"><a name="coroutine2.coroutine.stackful"></a></span><a class="link" href="coroutine.html#coroutine2.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="coroutine2.coroutine.h1"></a>
<span class="phrase"><a name="coroutine2.coroutine.move_only"></a></span><a class="link" href="coroutine.html#coroutine2.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="coroutine2.coroutine.h2"></a>
<span class="phrase"><a name="coroutine2.coroutine.clean_up"></a></span><a class="link" href="coroutine.html#coroutine2.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="coroutine2.coroutine.h3"></a>
<span class="phrase"><a name="coroutine2.coroutine.segmented_stack"></a></span><a class="link" href="coroutine.html#coroutine2.coroutine.segmented_stack">segmented
stack</a>
</h4>
<p>
<span class="emphasis"><em>coroutine&lt;&gt;::push_type</em></span> and <span class="emphasis"><em>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.coroutine2.coroutine.f1" class="footnote" name="coroutine2.coroutine.f1"><sup class="footnote">[6]</sup></a> is known to support segmented stacks. With version 1.54 <span class="bold"><strong>Boost.Coroutine2</strong></span> provides support for <a class="link" href="stack/segmented.html#segmented"><span class="emphasis"><em>segmented
stacks</em></span></a>.
</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="coroutine2.coroutine.h4"></a>
<span class="phrase"><a name="coroutine2.coroutine.context_switch"></a></span><a class="link" href="coroutine.html#coroutine2.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>
A context switch is done via <span class="emphasis"><em>coroutine&lt;&gt;::push_type::operator()</em></span>
and <span class="emphasis"><em>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>coroutine&lt;&gt;::push_type::operator()</em></span> and
<span class="emphasis"><em>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">coroutines2</span><span class="special">::</span><span class="identifier">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">coro</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">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">yield</span><span class="special">){</span>
<span class="identifier">yield</span><span class="special">();</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.coroutine2.coroutine.f0" class="footnote"><p><a href="#coroutine2.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.coroutine2.coroutine.f1" class="footnote"><p><a href="#coroutine2.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; 2014 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,555 @@
<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;Coroutine2">
<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 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="coroutine2.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">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">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>coroutine&lt;&gt;::push_type</em></span>
and <span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span> - provide a unidirectional
transfer of data.
</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>
<span class="emphasis"><em>asymmetric_coroutine&lt;&gt;</em></span> is a typedef of <span class="emphasis"><em>coroutine</em></span>.
</p></td></tr>
</table></div>
<h5>
<a name="coroutine2.coroutine.asymmetric.h0"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric._emphasis_coroutine_lt__gt___pull_type__emphasis_"></a></span><a class="link" href="asymmetric.html#coroutine2.coroutine.asymmetric._emphasis_coroutine_lt__gt___pull_type__emphasis_"><span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span></a>
</h5>
<p>
<span class="emphasis"><em>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>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>coroutine&lt;&gt;::push_type</em></span> as argument. Instantiating
an <span class="emphasis"><em>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>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>coroutine&lt;&gt;::pull_type::operator()</em></span>.
This method only switches context; it transfers no data.
</p>
<p>
<span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span> provides input iterators
(<span class="emphasis"><em>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="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">source</span><span class="special">(</span>
<span class="special">[&amp;](</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="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>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>coroutine&lt;&gt;::pull_type</em></span>.
An <span class="emphasis"><em>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>coroutine&lt;&gt;::push_type::operator()</em></span>
with another Fibonacci number, <span class="emphasis"><em>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>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="coroutine2.coroutine.asymmetric.h1"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric._emphasis_coroutine_lt__gt___push_type__emphasis_"></a></span><a class="link" href="asymmetric.html#coroutine2.coroutine.asymmetric._emphasis_coroutine_lt__gt___push_type__emphasis_"><span class="emphasis"><em>coroutine&lt;&gt;::push_type</em></span></a>
</h5>
<p>
<span class="emphasis"><em>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>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>coroutine&lt;&gt;::pull_type</em></span> as argument. In contrast
to <span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span>, instantiating an <span class="emphasis"><em>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>coroutine&lt;&gt;::push_type::operator()</em></span>
synthesizes a complementary <span class="emphasis"><em>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>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>coroutine&lt;&gt;::push_type</em></span> provides output iterators
(<span class="emphasis"><em>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">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">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="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">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">writer</span><span class="special">(</span>
<span class="special">[&amp;](</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">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">begin</span><span class="special">(</span><span class="identifier">words</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">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>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>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>coroutine&lt;&gt;::push_type::operator()</em></span>.
An <span class="emphasis"><em>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>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>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="coroutine2.coroutine.asymmetric.h2"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.coroutine_function"></a></span><a class="link" href="asymmetric.html#coroutine2.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>coroutine&lt;&gt;::pull_type</em></span>
the <span class="emphasis"><em>coroutine-function</em></span> is entered at <span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span>
construction. For <span class="emphasis"><em>coroutine&lt;&gt;::push_type</em></span> the
<span class="emphasis"><em>coroutine-function</em></span> is not entered at <span class="emphasis"><em>coroutine&lt;&gt;::push_type</em></span>
construction but entered by the first invocation of <span class="emphasis"><em>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>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="coroutine2.coroutine.asymmetric.h3"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.passing_data_from_a_pull_coroutine_to_main_context"></a></span><a class="link" href="asymmetric.html#coroutine2.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>coroutine&lt;&gt;::pull_type</em></span>
to the main-context the framework synthesizes an <span class="emphasis"><em>coroutine&lt;&gt;::push_type</em></span>
associated with the <span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span> instance
in the main-context. The synthesized <span class="emphasis"><em>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>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>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>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>coroutine&lt;&gt;::pull_type::get()</em></span>.
</p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>
<span class="identifier">coro_t</span><span class="special">::</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">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">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="coroutine2.coroutine.asymmetric.h4"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.passing_data_from_main_context_to_a_push_coroutine"></a></span><a class="link" href="asymmetric.html#coroutine2.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>coroutine&lt;&gt;::push_type</em></span>
from the main-context the framework synthesizes an <span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span>
associated with the <span class="emphasis"><em>coroutine&lt;&gt;::push_type</em></span> instance
in the main-context. The synthesized <span class="emphasis"><em>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>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>coroutine&lt;&gt;::pull_type::get()</em></span>.
</p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>
<span class="identifier">coro_t</span><span class="special">::</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">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">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="coroutine2.coroutine.asymmetric.h5"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.accessing_parameters"></a></span><a class="link" href="asymmetric.html#coroutine2.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>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>coroutine&lt;&gt;::pull_type</em></span> is valid after
return from <span class="emphasis"><em>coroutine&lt;&gt;::pull_type::operator()</em></span>,
e.g. <span class="emphasis"><em>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="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">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">coro_t</span><span class="special">;</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">sink</span><span class="special">(</span>
<span class="special">[&amp;](</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">// 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="coroutine2.coroutine.asymmetric.h6"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.exceptions"></a></span><a class="link" href="asymmetric.html#coroutine2.coroutine.asymmetric.exceptions">exceptions</a>
</h5>
<p>
An exception thrown inside an <span class="emphasis"><em>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>coroutine&lt;&gt;::push_type::operator()</em></span>
will be re-thrown by the <span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span>
constructor. After an <span class="emphasis"><em>coroutine&lt;&gt;::pull_type</em></span>'s
<span class="emphasis"><em>coroutine-function</em></span>'s first call to <span class="emphasis"><em>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>coroutine&lt;&gt;::pull_type::operator()</em></span>.
<span class="emphasis"><em>coroutine&lt;&gt;::pull_type::get()</em></span> does not throw.
</p>
<p>
An exception thrown inside an <span class="emphasis"><em>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>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">coroutines2</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 than re-throw the exception in
another execution context.
</p></td></tr>
</table></div>
<h5>
<a name="coroutine2.coroutine.asymmetric.h7"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.stack_unwinding"></a></span><a class="link" href="asymmetric.html#coroutine2.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="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">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">coro_t</span><span class="special">;</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">sink</span><span class="special">(</span>
<span class="special">[&amp;](</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">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="coroutine2.coroutine.asymmetric.h8"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.range_iterators"></a></span><a class="link" href="asymmetric.html#coroutine2.coroutine.asymmetric.range_iterators">Range
iterators</a>
</h5>
<p>
<span class="bold"><strong>Boost.Coroutine2</strong></span> provides output- and input-iterators
using __boost_range__. <span class="emphasis"><em>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">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">coroutine</span><span class="special">&lt;</span> <span class="keyword">int</span> <span class="special">&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>
<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">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">source</span><span class="special">(</span>
<span class="special">[&amp;](</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="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>coroutine&lt;&gt;::pull_type::iterator::operator++()</em></span>
corresponds to <span class="emphasis"><em>coroutine&lt;&gt;::pull_type::operator()</em></span>;
<span class="emphasis"><em>coroutine&lt;&gt;::pull_type::iterator::operator*()</em></span>
roughly corresponds to <span class="emphasis"><em>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>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>coroutine&lt;&gt;::pull_type</em></span>
instance when its <span class="emphasis"><em>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>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>coroutine&lt;&gt;::push_type</em></span>.
</p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">coroutine</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">sink</span><span class="special">(</span>
<span class="special">[&amp;](</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">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">begin</span><span class="special">(</span><span class="identifier">v</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">begin</span><span class="special">(</span><span class="identifier">sink</span><span class="special">));</span>
</pre>
<p>
<span class="emphasis"><em>coroutine&lt;&gt;::push_type::iterator::operator*()</em></span>
roughly corresponds to <span class="emphasis"><em>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>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>coroutine&lt;&gt;::push_type</em></span>
instance when its <span class="emphasis"><em>coroutine&lt;&gt;::push_type::operator bool</em></span>
would return <code class="computeroutput"><span class="keyword">false</span></code>.
</p>
<h5>
<a name="coroutine2.coroutine.asymmetric.h9"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.exit_a__emphasis_coroutine_function__emphasis_"></a></span><a class="link" href="asymmetric.html#coroutine2.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>coroutine&lt;&gt;::pull_type</em></span>,
<span class="emphasis"><em>coroutine&lt;&gt;::push_type</em></span> becomes complete, e.g.
<span class="emphasis"><em>coroutine&lt;&gt;::pull_type::operator bool</em></span>, <span class="emphasis"><em>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>coroutine&lt;&gt;::push_type::operator()</em></span>,
<span class="emphasis"><em>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; 2014 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,323 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class 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;Coroutine2">
<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 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="coroutine2.coroutine.asymmetric.pull_coro"></a><a class="link" href="pull_coro.html" title="Class coroutine&lt;&gt;::pull_type">Class <code class="computeroutput"><span class="identifier">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">coroutine2</span><span class="special">/</span><span class="identifier">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">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="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="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span><span class="special">,</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">StackAllocator</span> <span class="identifier">stack_alloc</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">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="identifier">pull_coroutine</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">()();</span>
<span class="keyword">explicit</span> <span class="keyword">operator</span> <span class="keyword">bool</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="identifier">R</span> <span class="identifier">get</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">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="coroutine2.coroutine.asymmetric.pull_coro.h0"></a>
<span class="phrase"><a name="coroutine2.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___code_"></a></span><a class="link" href="pull_coro.html#coroutine2.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___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></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 which will execute <code class="computeroutput"><span class="identifier">fn</span></code>,
and enters it.
</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="coroutine2.coroutine.asymmetric.pull_coro.h1"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase__phrase_role__special_____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__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__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___code_"></a></span><a class="link" href="pull_coro.html#coroutine2.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase__phrase_role__special_____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__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__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___code_"><code class="computeroutput"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span><span class="special">,</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">StackAllocator</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">stack_alloc</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></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 which will execute <code class="computeroutput"><span class="identifier">fn</span></code>.
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="coroutine2.coroutine.asymmetric.pull_coro.h2"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.coroutine.asymmetric.pull_coro.h3"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.coroutine.asymmetric.pull_coro.h4"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.coroutine.asymmetric.pull_coro.h5"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__explicit__phrase___phrase_role__keyword__operator__phrase___phrase_role__keyword__bool__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___phrase_role__keyword__noexcept__phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine2.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__explicit__phrase___phrase_role__keyword__operator__phrase___phrase_role__keyword__bool__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___phrase_role__keyword__noexcept__phrase___code_"><code class="computeroutput"><span class="keyword">explicit</span> <span class="keyword">operator</span>
<span class="keyword">bool</span><span class="special">()</span>
<span class="keyword">const</span> <span class="keyword">noexcept</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="coroutine2.coroutine.asymmetric.pull_coro.h6"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___phrase_role__keyword__noexcept__phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine2.coroutine.asymmetric.pull_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___phrase_role__keyword__noexcept__phrase___code_"><code class="computeroutput"><span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span> <span class="keyword">noexcept</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="coroutine2.coroutine.asymmetric.pull_coro.h7"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.coroutine.asymmetric.pull_coro.h8"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__r__phrase___phrase_role__identifier__get__phrase__phrase_role__special______phrase___phrase_role__keyword__noexcept__phrase___code_"></a></span><a class="link" href="pull_coro.html#coroutine2.coroutine.asymmetric.pull_coro._code__phrase_role__identifier__r__phrase___phrase_role__identifier__get__phrase__phrase_role__special______phrase___phrase_role__keyword__noexcept__phrase___code_"><code class="computeroutput"><span class="identifier">R</span> <span class="identifier">get</span><span class="special">()</span> <span class="keyword">noexcept</span></code></a>
</h6>
<pre class="programlisting"><span class="identifier">R</span> <span class="identifier">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">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">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>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>coroutine&lt;&gt;::pull_type::operator()</em></span>
call.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine2.coroutine.asymmetric.pull_coro.h9"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.coroutine.asymmetric.pull_coro.h10"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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>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; 2014 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,287 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class 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;Coroutine2">
<link rel="up" href="../asymmetric.html" title="Asymmetric coroutine">
<link rel="prev" href="pull_coro.html" title="Class coroutine&lt;&gt;::pull_type">
<link rel="next" href="../implementations__fcontext_t__ucontext_t_and_winfiber.html" title="Implementations: fcontext_t, ucontext_t and WinFiber">
</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="../implementations__fcontext_t__ucontext_t_and_winfiber.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="coroutine2.coroutine.asymmetric.push_coro"></a><a class="link" href="push_coro.html" title="Class coroutine&lt;&gt;::push_type">Class <code class="computeroutput"><span class="identifier">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">coroutine2</span><span class="special">/</span><span class="identifier">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">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="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="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span><span class="special">,</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">StackAllocator</span> <span class="identifier">stack_alloc</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">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">explicit</span> <span class="keyword">operator</span> <span class="keyword">bool</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="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="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="coroutine2.coroutine.asymmetric.push_coro.h0"></a>
<span class="phrase"><a name="coroutine2.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___code_"></a></span><a class="link" href="push_coro.html#coroutine2.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___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></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 which will execute <code class="computeroutput"><span class="identifier">fn</span></code>.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine2.coroutine.asymmetric.push_coro.h1"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.push_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase__phrase_role__special_____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__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__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___code_"></a></span><a class="link" href="push_coro.html#coroutine2.coroutine.asymmetric.push_coro._code__phrase_role__keyword__template__phrase__phrase_role__special___lt___phrase___phrase_role__keyword__typename__phrase___phrase_role__identifier__stackallocator__phrase__phrase_role__special_____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__stackallocator__phrase___phrase_role__keyword__const__phrase__phrase_role__special___amp___phrase___phrase_role__identifier__stack_alloc__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___code_"><code class="computeroutput"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">StackAllocator</span><span class="special">,</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">StackAllocator</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">stack_alloc</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></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 which will execute <code class="computeroutput"><span class="identifier">fn</span></code>.
For allocating/deallocating the stack <code class="computeroutput"><span class="identifier">stack_alloc</span></code>
is used.
</p></dd>
</dl>
</div>
<h6>
<a name="coroutine2.coroutine.asymmetric.push_coro.h2"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.coroutine.asymmetric.push_coro.h3"></a>
<span class="phrase"><a name="coroutine2.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___phrase_role__keyword__noexcept__phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine2.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___phrase_role__keyword__noexcept__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>
<span class="keyword">noexcept</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="coroutine2.coroutine.asymmetric.push_coro.h4"></a>
<span class="phrase"><a name="coroutine2.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___phrase_role__keyword__noexcept__phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine2.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___phrase_role__keyword__noexcept__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>
<span class="keyword">noexcept</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="coroutine2.coroutine.asymmetric.push_coro.h5"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.push_coro._code__phrase_role__keyword__explicit__phrase___phrase_role__keyword__operator__phrase___phrase_role__keyword__bool__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___phrase_role__keyword__noexcept__phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine2.coroutine.asymmetric.push_coro._code__phrase_role__keyword__explicit__phrase___phrase_role__keyword__operator__phrase___phrase_role__keyword__bool__phrase__phrase_role__special______phrase___phrase_role__keyword__const__phrase___phrase_role__keyword__noexcept__phrase___code_"><code class="computeroutput"><span class="keyword">explicit</span> <span class="keyword">operator</span>
<span class="keyword">bool</span><span class="special">()</span>
<span class="keyword">const</span> <span class="keyword">noexcept</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="coroutine2.coroutine.asymmetric.push_coro.h6"></a>
<span class="phrase"><a name="coroutine2.coroutine.asymmetric.push_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___phrase_role__keyword__noexcept__phrase___code_"></a></span><a class="link" href="push_coro.html#coroutine2.coroutine.asymmetric.push_coro._code__phrase_role__keyword__bool__phrase___phrase_role__keyword__operator__phrase__phrase_role__special_______phrase___phrase_role__keyword__const__phrase___phrase_role__keyword__noexcept__phrase___code_"><code class="computeroutput"><span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!()</span> <span class="keyword">const</span> <span class="keyword">noexcept</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="coroutine2.coroutine.asymmetric.push_coro.h7"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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">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">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">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="coroutine2.coroutine.asymmetric.push_coro.h8"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.coroutine.asymmetric.push_coro.h9"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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>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; 2014 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="../implementations__fcontext_t__ucontext_t_and_winfiber.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,101 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Implementations: fcontext_t, ucontext_t and WinFiber</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;Coroutine2">
<link rel="up" href="../coroutine.html" title="Coroutine">
<link rel="prev" href="asymmetric/push_coro.html" title="Class coroutine&lt;&gt;::push_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="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="../stack.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="coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber"></a><a class="link" href="implementations__fcontext_t__ucontext_t_and_winfiber.html" title="Implementations: fcontext_t, ucontext_t and WinFiber">Implementations:
fcontext_t, ucontext_t and WinFiber</a>
</h3></div></div></div>
<h5>
<a name="coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.h0"></a>
<span class="phrase"><a name="coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.fcontext_t"></a></span><a class="link" href="implementations__fcontext_t__ucontext_t_and_winfiber.html#coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.fcontext_t">fcontext_t</a>
</h5>
<p>
The implementation uses <a href="../../../../../../libs/context/doc/html/context/cc.html#implementation" target="_top">fcontext_t</a>
per default. fcontext_t is based on assembler and not available for all platforms.
It provides a much better performance than <span class="emphasis"><em>ucontext_t</em></span>
(the context switch takes two magnitudes of order less CPU cycles) and <span class="emphasis"><em>WinFiber</em></span>.
</p>
<h5>
<a name="coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.h1"></a>
<span class="phrase"><a name="coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.ucontext_t"></a></span><a class="link" href="implementations__fcontext_t__ucontext_t_and_winfiber.html#coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.ucontext_t">ucontext_t</a>
</h5>
<p>
As an alternative, <a href="https://en.wikipedia.org/wiki/Setcontext" target="_top"><span class="emphasis"><em>ucontext_t</em></span></a>
can be used by compiling with <code class="computeroutput"><span class="identifier">BOOST_USE_UCONTEXT</span></code>
and b2 property <code class="computeroutput"><span class="identifier">context</span><span class="special">-</span><span class="identifier">impl</span><span class="special">=</span><span class="identifier">ucontext</span></code>.
<span class="emphasis"><em>ucontext_t</em></span> might be available on a broader range of
POSIX-platforms but has some (for instance deprecated since POSIX.1-2003,
not C99 conform).
</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>
<span class="emphasis"><em>call/cc</em></span> supports <a class="link" href="../stack/segmented.html#segmented"><span class="emphasis"><em>Segmented
stacks</em></span></a> only with <span class="emphasis"><em>ucontext_t</em></span> as its
implementation.
</p></td></tr>
</table></div>
<h5>
<a name="coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.h2"></a>
<span class="phrase"><a name="coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.winfiber"></a></span><a class="link" href="implementations__fcontext_t__ucontext_t_and_winfiber.html#coroutine2.coroutine.implementations__fcontext_t__ucontext_t_and_winfiber.winfiber">WinFiber</a>
</h5>
<p>
With <code class="computeroutput"><span class="identifier">BOOST_USE_WINFIB</span></code> and
b2 property <code class="computeroutput"><span class="identifier">context</span><span class="special">-</span><span class="identifier">impl</span><span class="special">=</span><span class="identifier">winfib</span></code>
Win32-Fibers are used as implementation for <span class="emphasis"><em>call/cc</em></span>.
</p>
<p>
Because the TIB (thread information block) is not fully described in the
MSDN, it might be possible that not all required TIB-parts are swapped.
</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 first call of <span class="emphasis"><em>call/cc</em></span> converts the thread into
a Windows fiber by invoking <code class="computeroutput"><span class="identifier">ConvertThreadToFiber</span><span class="special">()</span></code>. If desired, <code class="computeroutput"><span class="identifier">ConvertFiberToThread</span><span class="special">()</span></code> has to be called by the user explicitly
in order to release resources allocated by <code class="computeroutput"><span class="identifier">ConvertThreadToFiber</span><span class="special">()</span></code> (e.g. after using boost.context).
</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; 2014 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="../stack.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,187 @@
<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;Coroutine2">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<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="coroutine2.intro"></a><a class="link" href="intro.html" title="Introduction">Introduction</a>
</h2></div></div></div>
<h4>
<a name="coroutine2.intro.h0"></a>
<span class="phrase"><a name="coroutine2.intro.definition"></a></span><a class="link" href="intro.html#coroutine2.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.coroutine2.intro.f0" class="footnote" name="coroutine2.intro.f0"><sup class="footnote">[1]</sup></a>), are a generalization of routines (Donald Knuth <a href="#ftn.coroutine2.intro.f1" class="footnote" name="coroutine2.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="coroutine2.intro.h1"></a>
<span class="phrase"><a name="coroutine2.intro.how_it_works"></a></span><a class="link" href="intro.html#coroutine2.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/coroutine2/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 (<a href="../../../../../libs/context/doc/html/context/cc.html#implementation" target="_top">fcontext_t</a>
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="coroutine2.intro.h2"></a>
<span class="phrase"><a name="coroutine2.intro.characteristics"></a></span><a class="link" href="intro.html#coroutine2.intro.characteristics">characteristics</a>
</h4>
<p>
Characteristics <a href="#ftn.coroutine2.intro.f2" class="footnote" name="coroutine2.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="coroutine2.intro.h3"></a>
<span class="phrase"><a name="coroutine2.intro.execution_transfer_mechanism"></a></span><a class="link" href="intro.html#coroutine2.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/coroutine2/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.
</p>
<h4>
<a name="coroutine2.intro.h4"></a>
<span class="phrase"><a name="coroutine2.intro.stackfulness"></a></span><a class="link" href="intro.html#coroutine2.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="coroutine2.intro.h5"></a>
<span class="phrase"><a name="coroutine2.intro.first_class_continuation"></a></span><a class="link" href="intro.html#coroutine2.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.coroutine2.intro.f0" class="footnote"><p><a href="#coroutine2.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.coroutine2.intro.f1" class="footnote"><p><a href="#coroutine2.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.coroutine2.intro.f2" class="footnote"><p><a href="#coroutine2.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; 2014 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,653 @@
<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;Coroutine2">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<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="coroutine2.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>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="coroutine2.motivation.h0"></a>
<span class="phrase"><a name="coroutine2.motivation.event_driven_model"></a></span><a class="link" href="motivation.html#coroutine2.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/coroutine2/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="coroutine2.motivation.h1"></a>
<span class="phrase"><a name="coroutine2.motivation.event_based_asynchronous_paradigm"></a></span><a class="link" href="motivation.html#coroutine2.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.coroutine2.motivation.f0" class="footnote" name="coroutine2.motivation.f0"><sup class="footnote">[4]</sup></a>.
</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="coroutine2.motivation.h2"></a>
<span class="phrase"><a name="coroutine2.motivation.recursive_descent_parsing"></a></span><a class="link" href="motivation.html#coroutine2.motivation.recursive_descent_parsing">recursive
descent parsing</a>
</h4>
<p>
Coroutines let you invert the flow of control so you can ask a recursive descent
parser for parsed symbols.
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">Parser</span><span class="special">{</span>
<span class="keyword">char</span> <span class="identifier">next</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">is</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">(</span><span class="keyword">char</span><span class="special">)&gt;</span> <span class="identifier">cb</span><span class="special">;</span>
<span class="keyword">char</span> <span class="identifier">pull</span><span class="special">(){</span>
<span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">char_traits</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">&gt;::</span><span class="identifier">to_char_type</span><span class="special">(</span><span class="identifier">is</span><span class="special">.</span><span class="identifier">get</span><span class="special">());</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">scan</span><span class="special">(){</span>
<span class="keyword">do</span><span class="special">{</span>
<span class="identifier">next</span><span class="special">=</span><span class="identifier">pull</span><span class="special">();</span>
<span class="special">}</span>
<span class="keyword">while</span><span class="special">(</span><span class="identifier">isspace</span><span class="special">(</span><span class="identifier">next</span><span class="special">));</span>
<span class="special">}</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">Parser</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">is_</span><span class="special">,</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">(</span><span class="keyword">char</span><span class="special">)&gt;</span> <span class="identifier">cb_</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">next</span><span class="special">(),</span> <span class="identifier">is</span><span class="special">(</span><span class="identifier">is_</span><span class="special">),</span> <span class="identifier">cb</span><span class="special">(</span><span class="identifier">cb_</span><span class="special">)</span>
<span class="special">{}</span>
<span class="keyword">void</span> <span class="identifier">run</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">scan</span><span class="special">();</span>
<span class="identifier">E</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">E</span><span class="special">(){</span>
<span class="identifier">T</span><span class="special">();</span>
<span class="keyword">while</span> <span class="special">(</span><span class="identifier">next</span><span class="special">==</span><span class="char">'+'</span><span class="special">||</span><span class="identifier">next</span><span class="special">==</span><span class="char">'-'</span><span class="special">){</span>
<span class="identifier">cb</span><span class="special">(</span><span class="identifier">next</span><span class="special">);</span>
<span class="identifier">scan</span><span class="special">();</span>
<span class="identifier">T</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">T</span><span class="special">(){</span>
<span class="identifier">S</span><span class="special">();</span>
<span class="keyword">while</span> <span class="special">(</span><span class="identifier">next</span><span class="special">==</span><span class="char">'*'</span><span class="special">||</span><span class="identifier">next</span><span class="special">==</span><span class="char">'/'</span><span class="special">){</span>
<span class="identifier">cb</span><span class="special">(</span><span class="identifier">next</span><span class="special">);</span>
<span class="identifier">scan</span><span class="special">();</span>
<span class="identifier">S</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">S</span><span class="special">(){</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">isdigit</span><span class="special">(</span><span class="identifier">next</span><span class="special">)){</span>
<span class="identifier">cb</span><span class="special">(</span><span class="identifier">next</span><span class="special">);</span>
<span class="identifier">scan</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">next</span><span class="special">==</span><span class="char">'('</span><span class="special">){</span>
<span class="identifier">cb</span><span class="special">(</span><span class="identifier">next</span><span class="special">);</span>
<span class="identifier">scan</span><span class="special">();</span>
<span class="identifier">E</span><span class="special">();</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">next</span><span class="special">==</span><span class="char">')'</span><span class="special">){</span>
<span class="identifier">cb</span><span class="special">(</span><span class="identifier">next</span><span class="special">);</span>
<span class="identifier">scan</span><span class="special">();</span>
<span class="special">}</span><span class="keyword">else</span><span class="special">{</span>
<span class="keyword">throw</span> <span class="identifier">parser_error</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">else</span><span class="special">{</span>
<span class="keyword">throw</span> <span class="identifier">parser_error</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">coroutine</span><span class="special">&lt;</span> <span class="keyword">char</span> <span class="special">&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">is</span><span class="special">(</span><span class="string">"1+1"</span><span class="special">);</span>
<span class="comment">// invert control flow</span>
<span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">seq</span><span class="special">(</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">fixedsize_stack</span><span class="special">(),</span>
<span class="special">[&amp;</span><span class="identifier">is</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">yield</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// create parser with callback function</span>
<span class="identifier">Parser</span> <span class="identifier">p</span><span class="special">(</span> <span class="identifier">is</span><span class="special">,</span>
<span class="special">[&amp;</span><span class="identifier">yield</span><span class="special">](</span><span class="keyword">char</span> <span class="identifier">ch</span><span class="special">){</span>
<span class="comment">// resume user-code</span>
<span class="identifier">yield</span><span class="special">(</span><span class="identifier">ch</span><span class="special">);</span>
<span class="special">});</span>
<span class="comment">// start recursive parsing</span>
<span class="identifier">p</span><span class="special">.</span><span class="identifier">run</span><span class="special">();</span>
<span class="special">});</span>
<span class="comment">// user-code pulls parsed data from parser</span>
<span class="comment">// invert control flow</span>
<span class="keyword">for</span><span class="special">(</span><span class="keyword">char</span> <span class="identifier">c</span><span class="special">:</span><span class="identifier">seq</span><span class="special">){</span>
<span class="identifier">printf</span><span class="special">(</span><span class="string">"Parsed: %c\n"</span><span class="special">,</span><span class="identifier">c</span><span class="special">);</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>
There's yet another advantage to using coroutines. This recursive descent 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="coroutine2.motivation.h3"></a>
<span class="phrase"><a name="coroutine2.motivation._same_fringe__problem"></a></span><a class="link" href="motivation.html#coroutine2.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/coroutine2/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>coroutine&lt;&gt;::push_type</em></span>. <span class="emphasis"><em>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>coroutine&lt;&gt;::pull_type::iterator</em></span>,
created from <span class="emphasis"><em>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>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">std</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="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines2</span><span class="special">::</span><span class="identifier">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">// 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">coro_t</span><span class="special">::</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">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">left_d_reader</span><span class="special">([&amp;](</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">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">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">right_b_reader</span><span class="special">([&amp;](</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">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">begin</span><span class="special">(</span><span class="identifier">left_d_reader</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">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">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">left_d_reader</span><span class="special">([&amp;](</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">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">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">right_x_reader</span><span class="special">([&amp;](</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">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">begin</span><span class="special">(</span><span class="identifier">left_d_reader</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">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="coroutine2.motivation.h4"></a>
<span class="phrase"><a name="coroutine2.motivation.chaining_coroutines"></a></span><a class="link" href="motivation.html#coroutine2.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">coroutines2</span><span class="special">::</span><span class="identifier">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="keyword">for</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="keyword">for</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="keyword">for</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">std</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">std</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">std</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">std</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">std</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">std</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">std</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">std</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="keyword">for</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">std</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">std</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">std</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">std</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">std</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">std</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">std</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="keyword">for</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">std</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">std</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">std</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">std</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">std</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">std</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">std</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="keyword">for</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.coroutine2.motivation.f0" class="footnote"><p><a href="#coroutine2.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; 2014 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;Coroutine2">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<link rel="prev" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<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="coroutine2.overview"></a><a class="link" href="overview.html" title="Overview">Overview</a>
</h2></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine2</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">coroutine2</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::coroutines2</em></span>.
</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>
This library requires C++11!
</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; 2014 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,83 @@
<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;Coroutine2">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<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="coroutine2.performance"></a><a class="link" href="performance.html" title="Performance">Performance</a>
</h2></div></div></div>
<p>
Performance measurements were taken using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">highresolution_clock</span></code>,
with overhead corrections. The code was compiled with gcc-6.3.1, using build
options: variant = release, optimization = speed. Tests were executed on dual
Intel XEON E5 2620v4 2.2GHz, 16C/32T, 64GB RAM, running Linux (x86_64).
</p>
<div class="table">
<a name="coroutine2.performance.performance_of_context_switch"></a><p class="title"><b>Table&#160;1.1.&#160;Performance of context switch</b></p>
<div class="table-contents"><table class="table" summary="Performance of context switch">
<colgroup>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
using <a href="../../../../../libs/context/doc/html/context/cc.html#implementation" target="_top">fcontext_t</a>
</p>
</th>
<th>
<p>
using <a href="../../../../../libs/context/doc/html/context/cc.html#implementation" target="_top">ucontext_t</a>
</p>
</th>
</tr></thead>
<tbody><tr>
<td>
<p>
26 ns / 56 CPU cycles
</p>
</td>
<td>
<p>
542 ns / 1146 CPU 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; 2014 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,185 @@
<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;Coroutine2">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Coroutine2">
<link rel="prev" href="coroutine/implementations__fcontext_t__ucontext_t_and_winfiber.html" title="Implementations: fcontext_t, ucontext_t and WinFiber">
<link rel="next" href="stack/protected_fixedsize.html" title="Class protected_fixedsize">
</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/implementations__fcontext_t__ucontext_t_and_winfiber.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_fixedsize.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="coroutine2.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_fixedsize.html">Class <span class="emphasis"><em>protected_fixedsize</em></span></a></span></dt>
<dt><span class="section"><a href="stack/pooled_fixedsize.html">Class <span class="emphasis"><em>pooled_fixedsize_stack</em></span></a></span></dt>
<dt><span class="section"><a href="stack/fixedsize.html">Class <span class="emphasis"><em>fixedsize_stack</em></span></a></span></dt>
<dt><span class="section"><a href="stack/segmented.html">Class
<span class="emphasis"><em>segmented_stack</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>
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="coroutine2.stack.h0"></a>
<span class="phrase"><a name="coroutine2.stack._emphasis_stack_allocator_concept__emphasis_"></a></span><a class="link" href="stack.html#coroutine2.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">size</span><span class="special">)</span></code>
</p>
</td>
<td>
</td>
<td>
<p>
creates a stack allocator
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">allocate</span><span class="special">()</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">stack_context</span></code>
</p>
</td>
<td>
<p>
creates a stack
</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>execution_context</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>
</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; 2014 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/implementations__fcontext_t__ucontext_t_and_winfiber.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_fixedsize.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,104 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class fixedsize_stack</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;Coroutine2">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="pooled_fixedsize.html" title="Class pooled_fixedsize_stack">
<link rel="next" href="segmented.html" title="Class segmented_stack">
</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="pooled_fixedsize.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.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="coroutine2.stack.fixedsize"></a><a class="link" href="fixedsize.html" title="Class fixedsize_stack">Class <span class="emphasis"><em>fixedsize_stack</em></span></a>
</h3></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine2</strong></span> provides the class <span class="emphasis"><em>fixedsize_stack</em></span>
which models the <span class="emphasis"><em>stack-allocator concept</em></span>. In contrast
to <span class="emphasis"><em>protected_fixedsize_stack</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>
<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">context</span><span class="special">/</span><span class="identifier">fixedsize_stack</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">fixedsize_stack</span> <span class="special">{</span>
<span class="identifier">fixedsize_stack</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">traits_type</span><span class="special">::</span><span class="identifier">default_size</span><span class="special">());</span>
<span class="identifier">stack_context</span> <span class="identifier">allocate</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>
</pre>
<h5>
<a name="coroutine2.stack.fixedsize.h0"></a>
<span class="phrase"><a name="coroutine2.stack.fixedsize._code__phrase_role__identifier__stack_context__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="fixedsize.html#coroutine2.stack.fixedsize._code__phrase_role__identifier__stack_context__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">stack_context</span> <span class="identifier">allocate</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</span><span class="special">:</span><span class="identifier">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</span><span class="special">:</span><span class="identifier">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="coroutine2.stack.fixedsize.h1"></a>
<span class="phrase"><a name="coroutine2.stack.fixedsize._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="fixedsize.html#coroutine2.stack.fixedsize._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</span><span class="special">:</span><span class="identifier">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</span><span class="special">:</span><span class="identifier">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; 2014 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="pooled_fixedsize.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.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 pooled_fixedsize_stack</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;Coroutine2">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="protected_fixedsize.html" title="Class protected_fixedsize">
<link rel="next" href="fixedsize.html" title="Class fixedsize_stack">
</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_fixedsize.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="fixedsize.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="coroutine2.stack.pooled_fixedsize"></a><a class="link" href="pooled_fixedsize.html" title="Class pooled_fixedsize_stack">Class <span class="emphasis"><em>pooled_fixedsize_stack</em></span></a>
</h3></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine2</strong></span> provides the class <span class="emphasis"><em>pooled_fixedsize_stack</em></span>
which models the <span class="emphasis"><em>stack-allocator concept</em></span>. In contrast
to <span class="emphasis"><em>protected_fixedsize_stack</em></span> it does not append a guard
page at the end of each stack. The memory is managed internally by <a href="http://www.boost.org/doc/libs/release/libs/pool/doc/html/boost/pool.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">pool</span><span class="special">&lt;&gt;</span></code></a>.
</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">coroutine2</span><span class="special">/</span><span class="identifier">pooled_fixedsize_stack</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">pooled_fixedsize_stack</span> <span class="special">{</span>
<span class="identifier">pooled_fixedsize_stack</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">traits_type</span><span class="special">::</span><span class="identifier">default_size</span><span class="special">());</span>
<span class="identifier">stack_context</span> <span class="identifier">allocate</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>
</pre>
<h5>
<a name="coroutine2.stack.pooled_fixedsize.h0"></a>
<span class="phrase"><a name="coroutine2.stack.pooled_fixedsize._code__phrase_role__identifier__pooled_fixedsize_stack__phrase__phrase_role__special_____phrase__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__stack_size__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__next_size__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__max_size__phrase__phrase_role__special_____phrase___code_"></a></span><a class="link" href="pooled_fixedsize.html#coroutine2.stack.pooled_fixedsize._code__phrase_role__identifier__pooled_fixedsize_stack__phrase__phrase_role__special_____phrase__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__stack_size__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__next_size__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__max_size__phrase__phrase_role__special_____phrase___code_"><code class="computeroutput"><span class="identifier">pooled_fixedsize_stack</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
<span class="identifier">stack_size</span><span class="special">,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">next_size</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">max_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="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</span><span class="special">:</span><span class="identifier">size</span><span class="special">()</span> <span class="special">&gt;=</span> <span class="identifier">stack_size</span><span class="special">)</span></code>
and <code class="computeroutput"><span class="number">0</span> <span class="special">&lt;</span>
<span class="identifier">nest_size</span></code>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Allocates memory of at least <code class="computeroutput"><span class="identifier">stack_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. Argument <code class="computeroutput"><span class="identifier">next_size</span></code>
determines the number of stacks to request from the system the first
time that <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
needs to allocate system memory. The third argument <code class="computeroutput"><span class="identifier">max_size</span></code>
controls how many memory might be allocated for stacks - a value of
zero means no uper limit.
</p></dd>
</dl>
</div>
<h5>
<a name="coroutine2.stack.pooled_fixedsize.h1"></a>
<span class="phrase"><a name="coroutine2.stack.pooled_fixedsize._code__phrase_role__identifier__stack_context__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="pooled_fixedsize.html#coroutine2.stack.pooled_fixedsize._code__phrase_role__identifier__stack_context__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">stack_context</span> <span class="identifier">allocate</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="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</span><span class="special">:</span><span class="identifier">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="coroutine2.stack.pooled_fixedsize.h2"></a>
<span class="phrase"><a name="coroutine2.stack.pooled_fixedsize._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="pooled_fixedsize.html#coroutine2.stack.pooled_fixedsize._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="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</span><span class="special">:</span><span class="identifier">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; 2014 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_fixedsize.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="fixedsize.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,127 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class protected_fixedsize</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;Coroutine2">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="../stack.html" title="Stack allocation">
<link rel="next" href="pooled_fixedsize.html" title="Class pooled_fixedsize_stack">
</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="pooled_fixedsize.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="coroutine2.stack.protected_fixedsize"></a><a class="link" href="protected_fixedsize.html" title="Class protected_fixedsize">Class <span class="emphasis"><em>protected_fixedsize</em></span></a>
</h3></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine2</strong></span> provides the class <span class="emphasis"><em>protected_fixedsize_stack</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_fixedsize_stack</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">coroutine2</span><span class="special">/</span><span class="identifier">protected_fixedsize</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">protected_fixedsize</span> <span class="special">{</span>
<span class="identifier">protected_fixesize</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">traits_type</span><span class="special">::</span><span class="identifier">default_size</span><span class="special">());</span>
<span class="identifier">stack_context</span> <span class="identifier">allocate</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>
</pre>
<h5>
<a name="coroutine2.stack.protected_fixedsize.h0"></a>
<span class="phrase"><a name="coroutine2.stack.protected_fixedsize._code__phrase_role__identifier__stack_context__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="protected_fixedsize.html#coroutine2.stack.protected_fixedsize._code__phrase_role__identifier__stack_context__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">stack_context</span> <span class="identifier">allocate</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</span><span class="special">:</span><span class="identifier">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</span><span class="special">:</span><span class="identifier">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="coroutine2.stack.protected_fixedsize.h1"></a>
<span class="phrase"><a name="coroutine2.stack.protected_fixedsize._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_fixedsize.html#coroutine2.stack.protected_fixedsize._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</span><span class="special">:</span><span class="identifier">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</span><span class="special">:</span><span class="identifier">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; 2014 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="pooled_fixedsize.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,134 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Class segmented_stack</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;Coroutine2">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="fixedsize.html" title="Class fixedsize_stack">
<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="fixedsize.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="coroutine2.stack.segmented"></a><a name="segmented"></a><a class="link" href="segmented.html" title="Class segmented_stack">Class
<span class="emphasis"><em>segmented_stack</em></span></a>
</h3></div></div></div>
<p>
<span class="bold"><strong>Boost.Coroutine2</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</em></span>
models the <span class="emphasis"><em>stack-allocator concept</em></span>. In contrast to
<span class="emphasis"><em>protected_fixedsize_stack</em></span> and <span class="emphasis"><em>fixedsize_stack</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> <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.Context</strong></span>
must be built with property <code class="computeroutput"><span class="identifier">segmented</span><span class="special">-</span><span class="identifier">stacks</span></code>,
e.g. <span class="bold"><strong>toolset=gcc segmented-stacks=on</strong></span> and
applying <code class="computeroutput"><span class="identifier">BOOST_USE_SEGMENTED_STACKS</span></code>
and <code class="computeroutput"><span class="identifier">BOOST_USE_UCONTEXT</span></code>
at b2/bjam command line.
</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">coroutine2</span><span class="special">/</span><span class="identifier">segmented_stack</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">segmented_stack</span> <span class="special">{</span>
<span class="identifier">segmented_stack</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">traits_type</span><span class="special">::</span><span class="identifier">default_size</span><span class="special">());</span>
<span class="identifier">stack_context</span> <span class="identifier">allocate</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>
</pre>
<h5>
<a name="coroutine2.stack.segmented.h0"></a>
<span class="phrase"><a name="coroutine2.stack.segmented._code__phrase_role__identifier__stack_context__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="segmented.html#coroutine2.stack.segmented._code__phrase_role__identifier__stack_context__phrase___phrase_role__identifier__allocate__phrase__phrase_role__special______phrase___code_"><code class="computeroutput"><span class="identifier">stack_context</span> <span class="identifier">allocate</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</span><span class="special">:</span><span class="identifier">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</span><span class="special">:</span><span class="identifier">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="coroutine2.stack.segmented.h1"></a>
<span class="phrase"><a name="coroutine2.stack.segmented._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.html#coroutine2.stack.segmented._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</span><span class="special">:</span><span class="identifier">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</span><span class="special">:</span><span class="identifier">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 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 the library is compiled for segmented stacks, <span class="emphasis"><em>segmented-stack</em></span>
is the only available stack allocator.
</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; 2014 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="fixedsize.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;Coroutine2">
<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="coroutine2.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.Coroutine2</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 segmented stacks</span>
<span class="special">}</span>
</pre>
<h5>
<a name="coroutine2.stack.stack_context.h0"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.stack.stack_context.h1"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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; 2014 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,156 @@
<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;Coroutine2">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="segmented.html" title="Class segmented_stack">
<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.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="coroutine2.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="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="coroutine2.stack.stack_traits.h0"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.stack.stack_traits.h1"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.stack.stack_traits.h2"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.stack.stack_traits.h3"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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="coroutine2.stack.stack_traits.h4"></a>
<span class="phrase"><a name="coroutine2.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#coroutine2.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; 2014 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.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,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;Coroutine2">
<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="coroutine2.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; 2014 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,76 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Chapter&#160;1.&#160;Coroutine2</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;Coroutine2">
<link rel="next" href="coroutine2/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="coroutine2/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="coroutine2"></a>Chapter&#160;1.&#160;Coroutine2</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; 2014 Oliver Kowalke</p></div>
<div><div class="legalnotice">
<a name="coroutine2.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="coroutine2/overview.html">Overview</a></span></dt>
<dt><span class="section"><a href="coroutine2/intro.html">Introduction</a></span></dt>
<dt><span class="section"><a href="coroutine2/motivation.html">Motivation</a></span></dt>
<dt><span class="section"><a href="coroutine2/coroutine.html">Coroutine</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine2/coroutine/asymmetric.html">Asymmetric coroutine</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine2/coroutine/asymmetric/pull_coro.html">Class <code class="computeroutput"><span class="identifier">coroutine</span><span class="special">&lt;&gt;::</span><span class="identifier">pull_type</span></code></a></span></dt>
<dt><span class="section"><a href="coroutine2/coroutine/asymmetric/push_coro.html">Class <code class="computeroutput"><span class="identifier">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="coroutine2/coroutine/implementations__fcontext_t__ucontext_t_and_winfiber.html">Implementations:
fcontext_t, ucontext_t and WinFiber</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="coroutine2/stack.html">Stack allocation</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="coroutine2/stack/protected_fixedsize.html">Class <span class="emphasis"><em>protected_fixedsize</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine2/stack/pooled_fixedsize.html">Class <span class="emphasis"><em>pooled_fixedsize_stack</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine2/stack/fixedsize.html">Class <span class="emphasis"><em>fixedsize_stack</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine2/stack/segmented.html">Class
<span class="emphasis"><em>segmented_stack</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine2/stack/stack_traits.html">Class <span class="emphasis"><em>stack_traits</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine2/stack/stack_context.html">Class <span class="emphasis"><em>stack_context</em></span></a></span></dt>
<dt><span class="section"><a href="coroutine2/stack/valgrind.html">Support for valgrind</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="coroutine2/performance.html">Performance</a></span></dt>
<dt><span class="section"><a href="coroutine2/architectures.html">Architectures</a></span></dt>
<dt><span class="section"><a href="coroutine2/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:17 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
<hr>
<div class="spirit-nav"><a accesskey="n" href="coroutine2/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,106 @@
[/
Copyright 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
]
[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/coroutine2/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/coroutine2/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.
[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,567 @@
[/
Copyright 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
]
[section:motivation Motivation]
In order to support a broad range of execution control behaviour the coroutine
types of __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/coroutine2/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]].
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 descent parsing]
Coroutines let you invert the flow of control so you can ask a recursive descent
parser for parsed symbols.
class Parser{
char next;
std::istream& is;
std::function<void(char)> cb;
char pull(){
return std::char_traits<char>::to_char_type(is.get());
}
void scan(){
do{
next=pull();
}
while(isspace(next));
}
public:
Parser(std::istream& is_,std::function<void(char)> cb_) :
next(), is(is_), cb(cb_)
{}
void run() {
scan();
E();
}
private:
void E(){
T();
while (next=='+'||next=='-'){
cb(next);
scan();
T();
}
}
void T(){
S();
while (next=='*'||next=='/'){
cb(next);
scan();
S();
}
}
void S(){
if (std::isdigit(next)){
cb(next);
scan();
}
else if(next=='('){
cb(next);
scan();
E();
if (next==')'){
cb(next);
scan();
}else{
throw parser_error();
}
}
else{
throw parser_error();
}
}
};
typedef boost::coroutines2::coroutine< char > coro_t;
int main() {
std::istringstream is("1+1");
// invert control flow
coro_t::pull_type seq(
boost::coroutines2::fixedsize_stack(),
[&is](coro_t::push_type & yield) {
// create parser with callback function
Parser p( is,
[&yield](char ch){
// resume user-code
yield(ch);
});
// start recursive parsing
p.run();
});
// user-code pulls parsed data from parser
// invert control flow
for(char c:seq){
printf("Parsed: %c\n",c);
}
}
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.
There's yet another advantage to using coroutines. This recursive descent 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/coroutine2/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 std::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")));
}
typedef boost::coroutines2::coroutine<std::string> coro_t;
// recursively walk the tree, delivering values in order
void traverse(node::ptr_t n,
coro_t::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"));
coro_t::pull_type left_d_reader([&](coro_t::push_type & out){
traverse(left_d,out);
});
node::ptr_t right_b(create_right_tree_from("b"));
coro_t::pull_type right_b_reader([&](coro_t::push_type & out){
traverse(right_b,out);
});
std::cout << "left tree from d == right tree from b? "
<< std::boolalpha
<< std::equal(begin(left_d_reader),
end(left_d_reader),
begin(right_b_reader))
<< std::endl;
}
{
node::ptr_t left_d(create_left_tree_from("d"));
coro_t::pull_type left_d_reader([&](coro_t::push_type & out){
traverse(left_d,out);
});
node::ptr_t right_x(create_right_tree_from("x"));
coro_t::pull_type right_x_reader([&](coro_t::push_type & out){
traverse(right_x,out);
});
std::cout << "left tree from d == right tree from x? "
<< std::boolalpha
<< std::equal(begin(left_d_reader),
end(left_d_reader),
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 chaining coroutines]
This code shows how coroutines could be chained.
typedef boost::coroutines2::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.
for(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){
for(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){
for(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(std::bind(readlines, _1, std::ref(infile)));
coro_t::pull_type tokenizer(std::bind(tokenize, _1, std::ref(reader)));
coro_t::pull_type filter(std::bind(only_words, _1, std::ref(tokenizer)));
coro_t::pull_type tracer(std::bind(trace, _1, std::ref(filter)));
for(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(std::bind(readlines, _1, std::ref(infile)));
coro_t::pull_type tokenizer(std::bind(tokenize, _1, std::ref(reader)));
coro_t::pull_type filter(std::bind(only_words, _1, std::ref(tokenizer)));
coro_t::push_type writer(std::bind(layout, _1, 5, 15));
for(std::string token:filter){
writer(token);
}
}
{
std::cout << "\nfiltering output:\n";
std::istringstream infile(data);
coro_t::pull_type reader(std::bind(readlines,_1,std::ref(infile)));
coro_t::pull_type tokenizer(std::bind(tokenize,_1,std::ref(reader)));
coro_t::push_type writer(std::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(std::bind(only_words,std::ref(writer),_1));
for(std::string token:tokenizer){
filter(token);
}
}
[endsect]

View File

@@ -0,0 +1,36 @@
[/
Copyright 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
]
[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/coroutine2/all.hpp>
which includes all the other headers in turn.
All functions and classes are contained in the namespace __coro_ns__.
[note This library requires C++11!]
[endsect]

View File

@@ -0,0 +1,25 @@
[/
Copyright 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
]
[section:performance Performance]
Performance measurements were taken using `std::chrono::highresolution_clock`,
with overhead corrections.
The code was compiled with gcc-6.3.1, using build options:
variant = release, optimization = speed.
Tests were executed on dual Intel XEON E5 2620v4 2.2GHz, 16C/32T, 64GB RAM,
running Linux (x86_64).
[table Performance of context switch
[[using __fcontext__] [using [@boost:/libs/context/doc/html/context/cc.html#implementation ucontext_t]]]
[
[26 ns / 56 CPU cycles]
[542 ns / 1146 CPU cycles]
]
]
[endsect]

View File

@@ -0,0 +1,336 @@
[/
Copyright 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
]
[section:stack Stack allocation]
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(size)`]
[]
[creates a stack allocator]
]
[
[`a.allocate()`]
[`stack_context`]
[creates a stack]
]
[
[`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
__econtext__.]
[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).]
[section:protected_fixedsize Class ['protected_fixedsize]]
__boost_coroutine__ provides the class __protected_fixedsize__ 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_fixedsize__ 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/coroutine2/protected_fixedsize.hpp>
struct protected_fixedsize {
protected_fixesize(std::size_t size = traits_type::default_size());
stack_context allocate();
void deallocate( stack_context &);
}
[heading `stack_context allocate()`]
[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:pooled_fixedsize Class ['pooled_fixedsize_stack]]
__boost_coroutine__ provides the class __pooled_fixedsize__ which models
the __stack_allocator_concept__.
In contrast to __protected_fixedsize__ it does not append a guard page at the
end of each stack. The memory is managed internally by
[@http://www.boost.org/doc/libs/release/libs/pool/doc/html/boost/pool.html `boost::pool<>`].
#include <boost/coroutine2/pooled_fixedsize_stack.hpp>
struct pooled_fixedsize_stack {
pooled_fixedsize_stack(std::size_t size = traits_type::default_size());
stack_context allocate();
void deallocate( stack_context &);
}
[heading `pooled_fixedsize_stack(std::size_t stack_size, std::size_t next_size, std::size_t max_size)`]
[variablelist
[[Preconditions:] [`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= stack_size)`
and `0 < nest_size`.]]
[[Effects:] [Allocates memory of at least `stack_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. Argument `next_size` determines the number of stacks to
request from the system the first time that `*this` needs to allocate system
memory. The third argument `max_size` controls how many memory might be
allocated for stacks - a value of zero means no uper limit.]]
]
[heading `stack_context allocate()`]
[variablelist
[[Preconditions:] [`! 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::is_unbounded() && ( traits_type::maximum:size() >= sctx.size)`.]]
[[Effects:] [Deallocates the stack space.]]
]
[endsect]
[section:fixedsize Class ['fixedsize_stack]]
__boost_coroutine__ provides the class __fixedsize__ which models
the __stack_allocator_concept__.
In contrast to __protected_fixedsize__ it does not append a guard page at the
end of each stack. The memory is simply managed by `std::malloc()` and
`std::free()`.
#include <boost/context/fixedsize_stack.hpp>
struct fixedsize_stack {
fixedsize_stack(std::size_t size = traits_type::default_size());
stack_context allocate();
void deallocate( stack_context &);
}
[heading `stack_context allocate()`]
[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]
[#segmented]
[section:segmented Class ['segmented_stack]]
__boost_coroutine__ supports usage of a __segmented__, 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__ models the __stack_allocator_concept__.
In contrast to __protected_fixedsize__ and __fixedsize__ it creates a
stack which grows on demand.
[note Segmented stacks are currently only supported by [*gcc] from version
[*4.7] [*clang] from version [*3.4] onwards. In order to use a
__segmented_stack__ __boost_context__ must be built with
property `segmented-stacks`, e.g. [*toolset=gcc segmented-stacks=on] and
applying `BOOST_USE_SEGMENTED_STACKS` and `BOOST_USE_UCONTEXT` at b2/bjam
command line.]
#include <boost/coroutine2/segmented_stack.hpp>
struct segmented_stack {
segmented_stack(std::size_t size = traits_type::default_size());
stack_context allocate();
void deallocate( stack_context &);
}
[heading `stack_context allocate()`]
[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.]]
]
[note If the library is compiled for segmented stacks, __segmented_stack__ is the only
available stack allocator.]
[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.
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_context__ contains some extra control
structures.
struct stack_context
{
void * sp;
std::size_t size;
// might contain additional control structures
// 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,45 @@
# Copyright 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine2/example
: requirements
<library>/boost/context//boost_context
<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 fibonacci
: fibonacci.cpp
;
exe same_fringe
: same_fringe.cpp
;
exe layout
: layout.cpp
;
exe parser
: parser.cpp
;
exe segmented
: segmented.cpp
;

View File

@@ -0,0 +1,30 @@
// Copyright 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/coroutine2/all.hpp>
int main() {
boost::coroutines2::coroutine< int >::pull_type source(
[]( boost::coroutines2::coroutine< int >::push_type & sink) {
int first = 1, second = 1;
sink( first);
sink( second);
for ( int i = 0; i < 8; ++i) {
int third = first + second;
first = second;
second = third;
sink( third);
}
});
for ( auto i : source) {
std::cout << i << " ";
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,50 @@
// 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/coroutine2/all.hpp>
struct FinalEOL{
~FinalEOL(){
std::cout << std::endl;
}
};
int main(int argc,char* argv[]){
using std::begin;
using std::end;
std::vector<std::string> words{
"peas", "porridge", "hot", "peas",
"porridge", "cold", "peas", "porridge",
"in", "the", "pot", "nine",
"days", "old" };
int num=5,width=15;
boost::coroutines2::coroutine<std::string>::push_type writer(
[&](boost::coroutines2::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::copy(begin(words),end(words),begin(writer));
std::cout << "\nDone";
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,122 @@
// Copyright 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 <cctype>
#include <cstdio>
#include <exception>
#include <functional>
#include <iostream>
#include <sstream>
#include <boost/coroutine2/all.hpp>
class parser_error : public std::runtime_error {
public:
parser_error() :
std::runtime_error("parsing failed") {
}
};
/*
* grammar:
* P ---> E '\0'
* E ---> T {('+'|'-') T}
* T ---> S {('*'|'/') S}
* S ---> digit | '(' E ')'
*/
class Parser{
char next;
std::istream& is;
std::function<void(char)> cb;
char pull(){
return std::char_traits<char>::to_char_type(is.get());
}
void scan(){
do{
next=pull();
}
while(isspace(next));
}
public:
Parser(std::istream& is_,std::function<void(char)> cb_) :
next(), is(is_), cb(cb_)
{}
void run() {
scan();
E();
}
private:
void E(){
T();
while (next=='+'||next=='-'){
cb(next);
scan();
T();
}
}
void T(){
S();
while (next=='*'||next=='/'){
cb(next);
scan();
S();
}
}
void S(){
if (std::isdigit(next)){
cb(next);
scan();
}
else if(next=='('){
cb(next);
scan();
E();
if (next==')'){
cb(next);
scan();
}else{
throw parser_error();
}
}
else{
throw parser_error();
}
}
};
typedef boost::coroutines2::coroutine< char > coro_t;
int main() {
try {
std::istringstream is("1+1");
// invert control flow
coro_t::pull_type seq(
[&is]( coro_t::push_type & yield) {
Parser p( is,
[&yield](char ch){
yield(ch);
});
p.run();
});
// user-code pulls parsed data from parser
for(char c:seq){
printf("Parsed: %c\n",c);
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
} catch ( std::exception const& ex) {
std::cerr << "exception: " << ex.what() << std::endl;
}
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,172 @@
// Copyright Nat Goodspeed 2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSEstd::placeholders::_1_0.txt or copy at
// http://www.boost.org/LICENSEstd::placeholders::_1_0.txt)
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <string>
#include <utility>
#include <boost/coroutine2/all.hpp>
struct node {
typedef std::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::coroutines2::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"));
node::ptr_t right_b(create_right_tree_from("b"));
node::ptr_t right_x(create_right_tree_from("x"));
{
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
std::cout << "left tree from d:\n";
std::copy(begin(left_d_reader),
end(left_d_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_b,out);
});
std::cout << "right tree from b:\n";
std::copy(begin(right_b_reader),
end(right_b_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_x,out);
});
std::cout << "right tree from x:\n";
std::copy(begin(right_x_reader),
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"));
node::ptr_t right_b(create_right_tree_from("b"));
{
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_b,out);
});
std::cout << "left tree from d == right tree from b? "
<< std::boolalpha
<< std::equal(begin(left_d_reader),
end(left_d_reader),
begin(right_b_reader))
<< std::endl;
}
}
{
node::ptr_t left_d(create_left_tree_from("d"));
node::ptr_t right_x(create_right_tree_from("x"));
{
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_x,out);
});
std::cout << "left tree from d == right tree from x? "
<< std::boolalpha
<< std::equal(begin(left_d_reader),
end(left_d_reader),
begin(right_x_reader))
<< std::endl;
}
}
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,48 @@
// Copyright 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 <memory>
#include <boost/coroutine2/all.hpp>
#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);
}
}
int main() {
int count = 384;
#if defined(BOOST_USE_SEGMENTED_STACKS)
std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
std::cout << "initial stack size = " << boost::context::segmented_stack::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::context::fixedsize_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
std::cout << "application might fail" << std::endl;
#endif
boost::coroutines2::coroutine< void >::pull_type coro{
[count](boost::coroutines2::coroutine< void >::push_type & coro){
bar( count);
}};
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,97 @@
// Copyright 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)
#ifndef TREE_H
#define TREE_H
#include <cstddef>
#include <string>
#include <boost/assert.hpp>
#include <boost/config.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; }
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif // TREE_H

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,14 @@
{
"key": "coroutine2",
"name": "Coroutine2",
"authors": [
"Oliver Kowalke"
],
"description": "(C++11) Coroutine library.",
"category": [
"Concurrent"
],
"maintainers": [
"Oliver Kowalke <oliver.kowalke -at- gmail.com>"
]
}

View File

@@ -0,0 +1,67 @@
# Copyright 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine2/performance
: requirements
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<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
: sources
performance.cpp
;

View File

@@ -0,0 +1,12 @@
// Copyright 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)
#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 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 "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 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 "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 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 "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 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 "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 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 "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 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 "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,45 @@
// Copyright 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)
//
#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();
}
};
inline
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 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)
#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 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)
#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 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)
#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,98 @@
// Copyright 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 <stdexcept>
#include <string>
#include <boost/chrono.hpp>
#include <boost/coroutine2/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "bind_processor.hpp"
#include "clock.hpp"
#include "cycle.hpp"
boost::uint64_t jobs = 1000;
void fn( boost::coroutines2::coroutine< void >::push_type & c) {
while ( true) {
c();
}
}
duration_type measure_time_void( duration_type overhead) {
boost::coroutines2::coroutine< void >::pull_type c{ fn };
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::coroutines2::coroutine< void >::pull_type c{ fn };
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 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")
("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 ( bind) {
bind_to_processor( 0);
}
duration_type overhead_c = overhead_clock();
boost::uint64_t res = measure_time_void( overhead_c).count();
std::cout << "average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
cycle_type overhead_y = overhead_cycle();
res = measure_cycles_void( 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,73 @@
# Copyright 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/coroutine2/performance/segmented_stack
: requirements
<library>/boost/chrono//boost_chrono
<library>/boost/coroutine//boost_coroutine
<library>/boost/program_options//boost_program_options
<segmented-stacks>on
<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
;
exe performance_switch
: sources
performance_switch.cpp
;

View File

@@ -0,0 +1,105 @@
// Copyright 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 <stdexcept>
#include <boost/chrono.hpp>
#include <boost/coroutine2/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
typedef boost::coroutines2::segmented_stack stack_allocator;
typedef boost::coroutines2::coroutine< void > coro_type;
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( stack_alloc, fn);
}
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( stack_alloc, fn);
}
cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement
total /= jobs; // loops
return total;
}
# endif
int main( int argc, char * argv[])
{
try
{
bool 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")
("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 ( 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,202 @@
// Copyright 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 <stdexcept>
#include <string>
#include <boost/chrono.hpp>
#include <boost/coroutine2/all.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../bind_processor.hpp"
#include "../clock.hpp"
#include "../cycle.hpp"
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::coroutines2::coroutine< void >::push_type & c)
{ while ( true) c(); }
void fn_int( boost::coroutines2::coroutine< int >::push_type & c)
{ while ( true) c( 7); }
void fn_x( boost::coroutines2::coroutine< X >::push_type & c)
{
while ( true) c( x);
}
duration_type measure_time_void( duration_type overhead)
{
boost::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< void >::pull_type c( stack_alloc, fn_void);
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::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< int >::pull_type c( stack_alloc, fn_int);
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::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< X >::pull_type c( stack_alloc, fn_x);
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::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< void >::pull_type c( stack_alloc, fn_void);
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::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< int >::pull_type c( stack_alloc, fn_int);
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::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< X >::pull_type c( stack_alloc, fn_x);
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 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")
("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 ( 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,84 @@
# Copyright 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)
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import path ;
import testing ;
import toolset ;
import ../../config/checks/config : requires ;
project boost/coroutine2/test
: requirements
<library>../../test/build//boost_unit_test_framework
<library>/boost/context//boost_context
<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
<optimization>speed
<variant>release
;
rule configure-impl ( properties * )
{
local result ;
if ( ! ( <target-os>windows in $(properties) ) )
{
result = <context-impl>ucontext ;
}
else
{
result = <context-impl>winfib ;
}
return $(result) ;
}
test-suite minimal :
[ run test_coroutine.cpp :
: :
<context-impl>fcontext
[ requires cxx11_auto_declarations
cxx11_constexpr
cxx11_defaulted_functions
cxx11_final
cxx11_hdr_tuple
cxx11_lambdas
cxx11_noexcept
cxx11_nullptr
cxx11_rvalue_references
cxx11_template_aliases
cxx11_variadic_templates ]
: test_coroutine_asm ]
[ run test_coroutine.cpp :
: :
<conditional>@configure-impl
[ requires cxx11_auto_declarations
cxx11_constexpr
cxx11_defaulted_functions
cxx11_final
cxx11_hdr_tuple
cxx11_lambdas
cxx11_noexcept
cxx11_nullptr
cxx11_rvalue_references
cxx11_template_aliases
cxx11_variadic_templates ]
: test_coroutine_native ] ;
test-suite full :
minimal ;
test-suite extra ;
explicit minimal ;
explicit extra ;

View File

@@ -0,0 +1,679 @@
// Copyright 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 <algorithm>
#include <cstdio>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <tuple>
#include <vector>
#include <boost/assert.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/coroutine2/coroutine.hpp>
namespace coro = boost::coroutines2;
int value1 = 0;
std::string value2 = "";
bool value3 = false;
double value4 = .0;
int * value5 = nullptr;
int& value6 = value1;
int& value7 = value1;
int value8 = 0;
int value9 = 0;
struct X
{
X() { value1 = 7; }
~X() { value1 = 0; }
X( X const&) = delete;
X & operator=( X const&) = delete;
};
class copyable
{
public:
bool state;
copyable() :
state( false)
{}
copyable( int) :
state( true)
{}
void operator()( coro::coroutine< int >::push_type &)
{ value3 = state; }
};
class moveable
{
public:
bool state;
moveable() :
state( false)
{}
moveable( int) :
state( true)
{}
moveable( moveable const&) = delete;
moveable & operator=( moveable const&) = delete;
moveable( moveable && other) :
state( false)
{ std::swap( state, other.state); }
moveable & operator=( moveable && other)
{
if ( this != & other) {
state = other.state;
other.state = false;
}
return * this;
}
void operator()( coro::coroutine< int >::push_type &)
{ value3 = state; }
};
class movedata
{
public:
int i;
movedata( int i_) :
i( i_)
{}
movedata( movedata const&) = delete;
movedata & operator=( movedata const&) = delete;
movedata( movedata && other) :
i( 0)
{ std::swap( i, other.i); }
movedata & operator=( movedata && other)
{
if ( this != & other) {
i = other.i;
other.i = 0;
}
return * this;
}
};
struct my_exception {};
void f1( coro::coroutine< void >::push_type & c)
{
while ( c)
c();
}
void f2( coro::coroutine< void >::push_type &)
{ ++value1; }
void f3( coro::coroutine< void >::push_type & c)
{
++value1;
c();
++value1;
}
void f4( coro::coroutine< int >::push_type & c)
{
c( 3);
c( 7);
}
void f5( coro::coroutine< std::string >::push_type & c)
{
std::string res("abc");
c( res);
res = "xyz";
c( res);
}
void f6( coro::coroutine< int >::pull_type & c)
{ value1 = c.get(); }
void f7( coro::coroutine< std::string >::pull_type & c)
{ value2 = c.get(); }
void f8( coro::coroutine< std::tuple< double, double > >::pull_type & c)
{
double x = 0, y = 0;
std::tie( x, y) = c.get();
value4 = x + y;
c();
std::tie( x, y) = c.get();
value4 = x + y;
}
void f9( coro::coroutine< int * >::pull_type & c)
{ value5 = c.get(); }
void f91( coro::coroutine< int const* >::pull_type & c)
{ value5 = const_cast< int * >( c.get() ); }
void f10( coro::coroutine< int & >::pull_type & c)
{
int & i = c.get();
value5 = const_cast< int * >( & i);
}
void f101( coro::coroutine< int const& >::pull_type & c)
{
int const& i = c.get();
value5 = const_cast< int * >( & i);
}
void f11( coro::coroutine< std::tuple< int, int > >::pull_type & c)
{
std::tie( value8, value9) = c.get();
}
void f12( coro::coroutine< void >::pull_type & c)
{
value1 = 7;
X x_;
c();
c();
}
void f16( coro::coroutine< int >::push_type & c)
{
c( 1);
c( 2);
c( 3);
c( 4);
c( 5);
}
void f17( coro::coroutine< int >::pull_type & c, std::vector< int > & vec)
{
int x = c.get();
while ( 5 > x)
{
vec.push_back( x);
x = c().get();
}
}
void f20( coro::coroutine< int >::push_type &)
{}
void f21( coro::coroutine< int >::pull_type & c)
{
while ( c)
{
value1 = c.get();
c();
}
}
void f22( coro::coroutine< movedata >::pull_type & c)
{
movedata mv( c.get() );
value1 = mv.i;
}
void test_move()
{
{
coro::coroutine< int >::pull_type coro1( f20);
coro::coroutine< int >::pull_type coro2( f16);
BOOST_CHECK( ! coro1);
BOOST_CHECK( coro2);
BOOST_CHECK_EQUAL( 1, coro2.get() );
coro2();
BOOST_CHECK_EQUAL( 2, coro2.get() );
coro1 = std::move( coro2);
BOOST_CHECK( coro1);
BOOST_CHECK( ! coro2);
coro1();
BOOST_CHECK_EQUAL( 3, coro1.get() );
BOOST_CHECK( ! coro2);
}
{
value3 = false;
copyable cp( 3);
BOOST_CHECK( cp.state);
BOOST_CHECK( ! value3);
coro::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::coroutine< int >::pull_type coro( std::move( mv) );
BOOST_CHECK( ! mv.state);
BOOST_CHECK( value3);
}
{
value1 = 0;
movedata mv( 7);
BOOST_CHECK_EQUAL( 0, value1);
BOOST_CHECK_EQUAL( 7, mv.i);
coro::coroutine< movedata >::push_type coro( f22);
coro( std::move( mv) );
BOOST_CHECK_EQUAL( 7, value1);
BOOST_CHECK_EQUAL( 0, mv.i);
}
}
void test_complete()
{
value1 = 0;
coro::coroutine< void >::pull_type coro( f2);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( int)1, value1);
}
void test_bind()
{
value1 = 0;
coro::coroutine< void >::pull_type coro( std::bind( f2, std::placeholders::_1) );
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( int)1, value1);
}
void test_jump()
{
value1 = 0;
coro::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::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::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::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::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::coroutine< std::tuple< double, double > >::push_type coro( f8);
BOOST_CHECK( coro);
coro( std::make_tuple( 7.35, 3.14) );
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( double) 10.49, value4);
value4 = 0;
coro( std::make_tuple( 1.15, 3.14) );
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( double) 4.29, value4);
}
void test_ptr()
{
value5 = nullptr;
int a = 3;
coro::coroutine< int * >::push_type coro( f9);
BOOST_CHECK( coro);
coro( & a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_const_ptr()
{
value5 = nullptr;
int a = 3;
coro::coroutine< int const* >::push_type coro( f91);
BOOST_CHECK( coro);
coro( & a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_ref()
{
value5 = nullptr;
int a_ = 3;
int & a = a_;
coro::coroutine< int & >::push_type coro( f10);
BOOST_CHECK( coro);
coro( std::ref( a) );
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_const_ref()
{
value5 = nullptr;
int a = 3;
coro::coroutine< int const& >::push_type coro( f101);
BOOST_CHECK( coro);
coro( a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_no_result()
{
coro::coroutine< int >::pull_type coro( f20);
BOOST_CHECK( ! coro);
}
void test_tuple()
{
value8 = 0;
value9 = 0;
int a = 3, b = 7;
std::tuple< int, int > tpl( a, b);
BOOST_CHECK_EQUAL( a, std::get< 0 >( tpl) );
BOOST_CHECK_EQUAL( b, std::get< 1 >( tpl) );
coro::coroutine< std::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::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);
int i = 0;
{
coro::coroutine< void >::push_type coro(
[&i](coro::coroutine< void >::pull_type &) mutable {
i = 7;
});
}
{
BOOST_CHECK_EQUAL( ( int) 0, value1);
auto * coro = new coro::coroutine< void >::pull_type(
[](coro::coroutine< void >::push_type & coro) mutable {
X x;
coro();
});
BOOST_CHECK_EQUAL( ( int) 7, value1);
delete coro;
BOOST_CHECK_EQUAL( ( int) 0, value1);
}
{
BOOST_CHECK_EQUAL( ( int) 0, value1);
auto * coro = new coro::coroutine< void >::push_type(
[](coro::coroutine< void >::pull_type & coro) mutable {
X x;
coro();
});
( * coro)();
BOOST_CHECK_EQUAL( ( int) 7, value1);
delete coro;
BOOST_CHECK_EQUAL( ( int) 0, value1);
}
}
void test_exceptions()
{
std::string msg("abc"), value;
std::runtime_error ex( msg);
try
{
coro::coroutine< void >::push_type coro(
[&msg]( coro::coroutine< void >::pull_type &) {
throw std::runtime_error( msg);
});
BOOST_CHECK( coro);
coro();
BOOST_CHECK( ! coro);
BOOST_CHECK( false);
}
catch ( std::runtime_error const& ex)
{ value = ex.what(); }
BOOST_CHECK_EQUAL( value, msg);
}
void test_input_iterator()
{
{
using std::begin;
using std::end;
std::vector< int > vec;
coro::coroutine< int >::pull_type coro( f16);
coro::coroutine< int >::pull_type::iterator e = end( coro);
for (
coro::coroutine< int >::pull_type::iterator i = 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] );
}
{
std::vector< int > vec;
coro::coroutine< int >::pull_type coro( f16);
for ( auto 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] );
}
{
int i1 = 1, i2 = 2, i3 = 3;
coro::coroutine< int& >::pull_type coro(
[&i1,&i2,&i3](coro::coroutine< int& >::push_type & c){
c( i1);
c( i2);
c( i3);
});
int counter = 1;
for ( int & i : coro) {
switch ( counter) {
case 1:
BOOST_CHECK_EQUAL( & i1, & i);
break;
case 2:
BOOST_CHECK_EQUAL( & i2, & i);
break;
case 3:
BOOST_CHECK_EQUAL( & i3, & i);
break;
default:
BOOST_ASSERT( false);
}
++counter;
}
}
}
void test_output_iterator()
{
using std::begin;
using std::end;
int counter = 0;
std::vector< int > vec;
coro::coroutine< int >::push_type coro(
[&vec]( coro::coroutine< int >::pull_type & c) {
int x = c.get();
while ( 5 > x)
{
vec.push_back( x);
x = c().get();
}
});
coro::coroutine< int >::push_type::iterator e( end( coro) );
for ( coro::coroutine< int >::push_type::iterator i( 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] );
}
std::vector< int > vec;
coro::coroutine< void >::pull_type * child = nullptr;
void start_child_coroutine() {
child = new coro::coroutine< void >::pull_type([](coro::coroutine< void >::push_type & yield) {
vec.push_back( 2);
yield();
vec.push_back( 2);
yield();
vec.push_back( 2);
yield();
vec.push_back( 2);
yield();
vec.push_back( 2);
yield();
vec.push_back( 2);
});
}
coro::coroutine< void >::pull_type start_parent_coroutine() {
return coro::coroutine< void >::pull_type([=](coro::coroutine< void >::push_type & yield) {
vec.push_back( 1);
start_child_coroutine();
yield();
vec.push_back( 1);
});
}
void test_chaining()
{
auto parent = start_parent_coroutine();
while ( * child) {
( * child)();
}
BOOST_CHECK_EQUAL( 7, vec.size() );
BOOST_CHECK_EQUAL( 1, vec[0]);
BOOST_CHECK_EQUAL( 2, vec[1]);
BOOST_CHECK_EQUAL( 2, vec[2]);
BOOST_CHECK_EQUAL( 2, vec[3]);
BOOST_CHECK_EQUAL( 2, vec[4]);
BOOST_CHECK_EQUAL( 2, vec[5]);
BOOST_CHECK_EQUAL( 2, vec[6]);
}
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
{
boost::unit_test::test_suite * test =
BOOST_TEST_SUITE("Boost.Coroutine2: coroutine test suite");
test->add( BOOST_TEST_CASE( & test_move) );
test->add( BOOST_TEST_CASE( & test_complete) );
test->add( BOOST_TEST_CASE( & test_bind) );
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_no_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_exceptions) );
test->add( BOOST_TEST_CASE( & test_input_iterator) );
test->add( BOOST_TEST_CASE( & test_output_iterator) );
test->add( BOOST_TEST_CASE( & test_chaining) );
return test;
}