rename to symmetric_coroutine_call<>
This commit is contained in:
parent
baabddae44
commit
82a78583ff
@ -1,13 +1,13 @@
|
||||
[/
|
||||
Copyright Oliver Kowalke 2009.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt
|
||||
]
|
||||
|
||||
[section:architextues Architectures]
|
||||
|
||||
__boost_coroutine__ depends on __boost_context__ witch supports this
|
||||
[@boost:/libs/context/architectures.html architectures].
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
13
doc/coro.qbk
13
doc/coro.qbk
@ -39,6 +39,7 @@
|
||||
[def __boost_utility__ [*Boost.Utility]]
|
||||
[def __boost_version__ [*Boost-1.52.0]]
|
||||
|
||||
[def __call_coro___ ['symmetric_coroutine<>::call_type]]
|
||||
[def __coro__ ['coroutine]]
|
||||
[def __coro_fn__ ['coroutine-function]]
|
||||
[def __coros__ ['coroutines]]
|
||||
@ -46,19 +47,20 @@
|
||||
[def __not_a_coro__ ['not-a-coroutine]]
|
||||
[def __pull_coro__ ['asymmetric_coroutine<>::pull_type]]
|
||||
[def __push_coro__ ['asymmetric_coroutine<>::push_type]]
|
||||
[def __scoro__ ['symmetric_coroutine<>]]
|
||||
[def __segmented_stack__ ['segemented-stack]]
|
||||
[def __yield_scoro__ ['symmetric_coroutine<>::yield_type]]
|
||||
[def __signature__ ['Signature]]
|
||||
[def __stack_allocator_concept__ ['stack-allocator concept]]
|
||||
[def __stack_allocator__ ['stack-allocator]]
|
||||
[def __stack__ ['stack]]
|
||||
[def __tls__ ['thread-local-storage]]
|
||||
[def __yield_coro__ ['symmetric_coroutine<>::yield_type]]
|
||||
|
||||
[def __args__ ['boost::coroutines::asymmetric_coroutine<>::arguments]]
|
||||
[def __attrs__ ['boost::coroutines::attributes]]
|
||||
[def __begin__ ['boost::begin()]]
|
||||
[def __bind__ ['boost::bind()]]
|
||||
[def __call_coro_bool__ ['boost::coroutines::symmetric_coroutine<>::operator bool]]
|
||||
[def __call_coro_op__ ['boost::coroutines::symmetric_coroutine<>::operator()]]
|
||||
[def __coro_allocator__ ['boost::coroutines::stack_allocator]]
|
||||
[def __coro_ns__ ['boost::coroutines]]
|
||||
[def __end__ ['boost::end()]]
|
||||
@ -75,11 +77,7 @@
|
||||
[def __pull_coro_op__ ['boost::coroutines::asymmetric_coroutine<>::pull_type::operator()]]
|
||||
[def __push_coro_bool__ ['boost::coroutines::asymmetric_coroutine<>::push_type::operator bool]]
|
||||
[def __push_coro_op__ ['boost::coroutines::asymmetric_coroutine<>::push_type::operator()]]
|
||||
[def __scoro_bool__ ['boost::coroutines::symmetric_coroutine<>::operator bool]]
|
||||
[def __scoro_op__ ['boost::coroutines::symmetric_coroutine<>::operator()]]
|
||||
[def __segmented_allocator__ ['boost::coroutines::segmented_stack_allocator]]
|
||||
[def __yield_scoro_get__ ['boost::coroutines::symmetric_coroutine<>::yield_type::get()]]
|
||||
[def __yield_scoro_op__ ['boost::coroutines::symmetric_coroutine<>::yield_type::operator()]]
|
||||
[def __server__ ['server]]
|
||||
[def __session__ ['session]]
|
||||
[def __stack_context__ ['boost::coroutines::stack_context]]
|
||||
@ -91,6 +89,9 @@
|
||||
[def __tuple__ ['boost::tuple<>]]
|
||||
[def __underflow__ ['stream_buf::underflow()]]
|
||||
[def __yield_context__ ['boost::asio::yield_context]]
|
||||
[def __yield_coro_bool__ ['boost::coroutines::symmetric_coroutine<>::yield_type::operator bool]]
|
||||
[def __yield_coro_get__ ['boost::coroutines::symmetric_coroutine<>::yield_type::get()]]
|
||||
[def __yield_coro_op__ ['boost::coroutines::symmetric_coroutine<>::yield_type::operator()]]
|
||||
|
||||
[include overview.qbk]
|
||||
[include intro.qbk]
|
||||
|
@ -1,91 +1,91 @@
|
||||
[/
|
||||
Copyright Oliver Kowalke 2009.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt
|
||||
]
|
||||
|
||||
[section:coroutine Coroutine]
|
||||
|
||||
__boost_coroutine__ provides two classes - implementations of asymmetric and
|
||||
symmetric coroutines.
|
||||
|
||||
'Coroutine mechanisms that support concurrent programming usually provide
|
||||
symmetric coroutines to represent independent units of execution. On the other
|
||||
hand, coroutine mechanisms intended for implementing constructs that produce
|
||||
sequences of values typically provide 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 behavior.
|
||||
|
||||
|
||||
[heading clean-up]
|
||||
On coroutine destruction the associated stack will be unwound.
|
||||
|
||||
The constructor of coroutine allows to pass an customized ['stack-allocator].
|
||||
['stack-allocator] is free to deallocate the stack or cache it for future usage
|
||||
(for coroutines created later).
|
||||
|
||||
|
||||
[heading segmented stack]
|
||||
__scoro__, __push_coro__ and __pull_coro__ does support segmented stacks
|
||||
(growing on demand).
|
||||
|
||||
It is not always possible to estimated the required stack size - in most cases
|
||||
too much memory is allocated (waste of virtual address-space).
|
||||
|
||||
At construction a coroutine starts with a default (minimal) stack size. This
|
||||
minimal stack size is the maximum of page size and the canonical size for signal
|
||||
stack (macro SIGSTKSZ on POSIX).
|
||||
|
||||
At this time of writing only GCC (4.7)\cite{gccsplit} is known to support
|
||||
segmented stacks. With version 1.54 __boost_coroutine__ provides support for
|
||||
segmented stacks.
|
||||
|
||||
The destructor releases the associated stack. The implementer is free to
|
||||
deallocate the stack or to cache it for later usage.
|
||||
|
||||
|
||||
[heading context switch]
|
||||
A coroutine saves and restores registers according to the underlying ABI on
|
||||
each context switch.
|
||||
|
||||
Some applications do not use floating-point registers and can disable preserving
|
||||
fpu registers for performance reasons.
|
||||
|
||||
[note According to the calling convention the FPU registers are preserved by
|
||||
default.]
|
||||
|
||||
On POSIX systems, the coroutine context switch does not preserve signal masks
|
||||
for performance reasons.
|
||||
|
||||
A context switch is done via __push_coro_op__ and __pull_coro_op__.
|
||||
|
||||
[warning Calling __scoro_op__/__push_coro_op__/__pull_coro_op__ from inside the
|
||||
[_same] coroutine results in undefined behaviour.]
|
||||
|
||||
|
||||
[include asymmetric.qbk]
|
||||
[include symmetric.qbk]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
192
doc/intro.qbk
192
doc/intro.qbk
@ -1,107 +1,107 @@
|
||||
[/
|
||||
Copyright Oliver Kowalke 2009.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt
|
||||
]
|
||||
|
||||
[section:intro Introduction]
|
||||
|
||||
[heading Definition]
|
||||
|
||||
In computer science routines are defined as a sequence of operations. The
|
||||
execution of routines forms a parent-child relationship and the child terminates
|
||||
always before the parent. Coroutines (the term was introduced by Melvin
|
||||
Conway [footnote Conway, Melvin E.. "Design of a Separable Transition-Diagram Compiler".
|
||||
Commun. ACM, Volume 6 Issue 7, July 1963, Articale No. 7]),
|
||||
are a generalization of routines (Donald Knuth [footnote Knuth, Donald Ervin (1997).
|
||||
"Fundamental Algorithms. The Art of Computer Programming 1", (3rd ed.)].
|
||||
The principal difference between coroutines and routines
|
||||
is that a coroutine enables explicit suspend and resume of its progress via
|
||||
additional operations by preserving execution state and thus provides an
|
||||
[*enhanced control flow] (maintaining the execution context).
|
||||
|
||||
|
||||
[heading How it works]
|
||||
|
||||
Functions foo() and bar() are supposed to alternate their execution (leave and
|
||||
enter function body).
|
||||
|
||||
[$../../../../libs/coroutine/doc/images/foo_bar.png [align center]]
|
||||
|
||||
If coroutines would be called such as routines, the stack would grow with
|
||||
every call and will never be degraded. A jump into the middle of a coroutine
|
||||
would not be possible, because the return address would have been 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
|
||||
coroutine's control-block.
|
||||
The registers of the newly activated coroutine must be restored from its
|
||||
associated control-block before it can continue with their work.
|
||||
|
||||
The context switch requires no system privileges and provides cooperative
|
||||
multitasking on the level of language. Coroutines provide quasi parallelism.
|
||||
When a program is supposed to do several things at the same time, coroutines
|
||||
help to do this much simpler and more elegant than with only a single flow of
|
||||
control.
|
||||
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 resumed at certain time later
|
||||
* symmetric or asymmetric control-transfer mechanism
|
||||
* 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.
|
||||
A symmetric coroutine transfers the execution control only via one operation.
|
||||
The target coroutine must be explicitly specified in the transfer operation.
|
||||
Asymmetric coroutines provide two transfer operations:
|
||||
the ['suspend]-operation returns to the invoker by preserving the
|
||||
execution context and the ['resume]-operation restores the execution
|
||||
context, e.g. re-enters the coroutine at the same point as it was suspended
|
||||
before.
|
||||
|
||||
[$../../../../libs/coroutine/doc/images/foo_bar_seq.png [align center]]
|
||||
|
||||
Both concepts are equivalent and a coroutine library can provide either
|
||||
symmetric or asymmetric coroutines.
|
||||
|
||||
|
||||
[heading stackfulness]
|
||||
In contrast to a stackless coroutine a stackful coroutine allows to suspend
|
||||
from nested stackframes. The execution resumes at exact the same point in the
|
||||
code as 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 ityield 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]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,39 +1,39 @@
|
||||
[/
|
||||
Copyright Oliver Kowalke 2009.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt
|
||||
]
|
||||
|
||||
[section:overview Overview]
|
||||
|
||||
__boost_coroutine__ provides templates for generalized subroutines which allow
|
||||
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, __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.
|
||||
|
||||
This library is a follow-up on
|
||||
[@http://www.crystalclearsoftware.com/soc/coroutine/ Boost.Coroutine]
|
||||
by Giovanni P. Deretta.
|
||||
|
||||
In order to use the classes and functions described here, you can either include
|
||||
the specific headers specified by the descriptions of each class or function, or
|
||||
include the master library header:
|
||||
|
||||
#include <boost/coroutine/all.hpp>
|
||||
|
||||
which includes all the other headers in turn.
|
||||
|
||||
All functions and classes are contained in the namespace __coro_ns__.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -13,59 +13,49 @@ to any other (symmetric) coroutine. E.g. a symmetric coroutine is not required
|
||||
to return to its caller.
|
||||
|
||||
|
||||
[heading __scoro__]
|
||||
__scoro__ starts a symmetric coroutine and transfers parameter to its __coro_fn__.
|
||||
[heading __call_coro___]
|
||||
__call_coro___ starts a symmetric coroutine and transfers parameter to its
|
||||
__coro_fn__.
|
||||
The first template parameter defining the transferred parameter type.
|
||||
The constructor of __scoro__ takes a function (__coro_fn__) accepting a
|
||||
reference to a __yield_scoro__ as argument. Instantiating a __scoro__ does
|
||||
The constructor of __call_coro___ takes a function (__coro_fn__) accepting a
|
||||
reference to a __yield_coro__ as argument. Instantiating a __call_coro___ does
|
||||
not pass the control of execution to __coro_fn__ - instead the first call of
|
||||
__scoro_op__ synthesizes a __yield_scoro__ passed it as reference to __coro_fn__.
|
||||
__call_coro_op__ synthesizes a __yield_coro__ passed it as reference to
|
||||
__coro_fn__.
|
||||
|
||||
The interface does not contain a ['get()]-function: you can not retrieve
|
||||
values from another execution context with this kind of coroutine.
|
||||
|
||||
|
||||
[heading __yield_scoro__]
|
||||
__yield_scoro_op__ ist used to transfers data to another execution context -
|
||||
which might be a __scoro__ or called with no argument back to the excecution
|
||||
context were the chain of symmetric coroutines has been started (invocation of
|
||||
__scoro_op__).
|
||||
[heading __yield_coro__]
|
||||
__yield_coro_op__ ist used to transfers data and execution control to another
|
||||
context - which might be a __call_coro___ or called with no argument back to the
|
||||
excecution context were the chain of symmetric coroutines has been started
|
||||
(invocation of __call_coro_op__).
|
||||
The class has only one template parameter defining the transferred parameter
|
||||
type.
|
||||
Data transferred to the coroutine are accessed through __yield_scoro_get__.
|
||||
Data transferred to the coroutine are accessed through __yield_coro_get__.
|
||||
|
||||
|
||||
[heading coroutine-function]
|
||||
The __coro_fn__ returns ['void] and takes __yield_scoro__, providing
|
||||
The __coro_fn__ returns ['void] and takes __yield_coro__, providing
|
||||
coroutine functionality inside the coroutine-fn, as argument, so that using this
|
||||
instance passed as argument to __coro_fn__ is the only way to transfer data and
|
||||
execution control.
|
||||
__scoro__ does not enter the __coro_fn__ at __scoro__ construction but entered
|
||||
by the first invocation of __scoro_op__.
|
||||
|
||||
|
||||
[heading passing data from a pull-coroutine to main-context]
|
||||
In order to transfer data from a __pull_coro__ to the main-context the framework
|
||||
synthesizes a __push_coro__ associated with the __pull_coro__ instance in the
|
||||
main-context. The synthesized __push_coro__ is passed as argument to __coro_fn__.\\
|
||||
The __coro_fn__ must call this __push_coro_op__ in order to transfer each
|
||||
data value back to the main-context.
|
||||
In the main-context, the __pull_coro_bool__ determines whether the coroutine is
|
||||
still valid and a data value is available or __coro_fn__ has terminated
|
||||
(__pull_coro__ is invalid; no data value available). Access to the transferred
|
||||
data value is given by __pull_coro_get__.
|
||||
__call_coro___ does not enter the __coro_fn__ at __call_coro___ construction but
|
||||
entered by the first invocation of __call_coro_op__.
|
||||
|
||||
|
||||
[heading passing data from main-context to a symmetric-coroutine]
|
||||
In order to transfer data to a __scoro__ from the main-context the framework
|
||||
synthesizes a __yield_scoro__ associated with the __scoro__ instance in the
|
||||
main-context. The synthesized __yield_scoro__ is passed as argument to
|
||||
In order to transfer data to a __call_coro___ from the main-context the framework
|
||||
synthesizes a __yield_coro__ associated with the __call_coro___ instance in the
|
||||
main-context. The synthesized __yield_coro__ is passed as argument to
|
||||
__coro_fn__.
|
||||
The main-context must call __scoro_op__ in order to transfer each data value
|
||||
The main-context must call __call_coro_op__ in order to transfer each data value
|
||||
into the __coro_fn__.
|
||||
Access to the transferred data value is given by __yield_scoro_get__.
|
||||
Access to the transferred data value is given by __yield_coro_get__.
|
||||
|
||||
boost::coroutines::symmetric_coroutine<int> coro( // constructor does NOT enter coroutine-function
|
||||
boost::coroutines::symmetric_coroutine<int>::call_type coro( // constructor does NOT enter coroutine-function
|
||||
[&](boost::coroutines::symmetric_coroutine<int>::yield_type& yield){
|
||||
for (;;) {
|
||||
std::cout << yield.get() << " ";
|
||||
@ -81,7 +71,7 @@ Access to the transferred data value is given by __yield_scoro_get__.
|
||||
|
||||
|
||||
[heading exceptions]
|
||||
An exception thrown and not catched inside a __scoro__'s __coro_fn__ will call
|
||||
An exception thrown and not catched inside a __call_coro___'s __coro_fn__ will call
|
||||
__terminate__.
|
||||
|
||||
[important Code executed by coroutine must not prevent the propagation of the
|
||||
@ -124,10 +114,10 @@ After unwinding, a __coro__ is complete.
|
||||
}
|
||||
};
|
||||
|
||||
boost::coroutines::symmetric_coroutine<int> other_coro(...);
|
||||
boost::coroutines::symmetric_coroutine<int>::call_type other_coro(...);
|
||||
|
||||
{
|
||||
boost::coroutines::symmetric_coroutine<void> coro(
|
||||
boost::coroutines::symmetric_coroutine<void>::call_type coro(
|
||||
[&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield){
|
||||
X x;
|
||||
std::cout<<"fn()"<<std::endl;
|
||||
@ -152,12 +142,12 @@ After unwinding, a __coro__ is complete.
|
||||
|
||||
[heading Exit a __coro_fn__]
|
||||
__coro_fn__ is exited with a simple return statement jumping back to the calling
|
||||
__scoro_op__ at the start of symmetric coroutine chain. E.g. symmetric coroutines do
|
||||
__call_coro_op__ at the start of symmetric coroutine chain. E.g. symmetric coroutines do
|
||||
not have a strong, fixed relationship to the caller as asymmetric coroutines.
|
||||
The __scoro__ becomes complete, e.g. __scoro_bool__ will return 'false'.
|
||||
The __call_coro___ becomes complete, e.g. __call_coro_bool__ will return 'false'.
|
||||
|
||||
[important After returning from __coro_fn__ the __coro__ is complete (can not
|
||||
resumed with __scoro_op__).]
|
||||
resumed with __call_coro_op__).]
|
||||
|
||||
|
||||
|
||||
@ -224,16 +214,16 @@ Otherwise false.]]
|
||||
[heading `yield_type & operator()()`]
|
||||
[variablelist
|
||||
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
|
||||
[[Effects:] [Execution control is transferred to __coro_fn__ (no parameter are
|
||||
passed to the coroutine-function).]]
|
||||
[[Effects:] [Execution control is transferred back to the starting point,
|
||||
e.g. invocation of __call_coro_op__.]]
|
||||
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
|
||||
]
|
||||
|
||||
[heading `R get()()`]
|
||||
|
||||
R symmetric_oroutine<R>::yield_type::get();
|
||||
R& symmetric_oroutine<R&>::yield_type::get();
|
||||
void symmetric_oroutine<void>yield_type::get()=delete;
|
||||
R symmetric_coroutine<R>::yield_type::get();
|
||||
R& symmetric_coroutine<R&>::yield_type::get();
|
||||
void symmetric_coroutine<void>yield_type::get()=delete;
|
||||
|
||||
[variablelist
|
||||
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
|
||||
@ -266,48 +256,48 @@ of `other`.]]
|
||||
#include <boost/coroutine/symmetric_coroutine.hpp>
|
||||
|
||||
template< typename Arg, typename StackAllocator = standard_stack_allocator >
|
||||
class symmetric_coroutine<>
|
||||
class symmetric_coroutine<>::call_type
|
||||
{
|
||||
public:
|
||||
symmetric_coroutine();
|
||||
call_type();
|
||||
|
||||
template< typename Fn >
|
||||
symmetric_coroutine( Fn fn, attributes const& attr = attributes() );
|
||||
call_type( Fn fn, attributes const& attr = attributes() );
|
||||
|
||||
template< typename Fn >
|
||||
symmetric_coroutine( Fn && fn, attributes const& attr = attributes(),
|
||||
call_type( Fn && fn, attributes const& attr = attributes(),
|
||||
StackAllocator stack_alloc = StackAllocator() );
|
||||
|
||||
symmetric_coroutine( symmetric_coroutine cosnt& other)=delete;
|
||||
call_type( call_type cosnt& other)=delete;
|
||||
|
||||
symmetric_coroutine & operator=( symmetric_coroutine const& other)=delete;
|
||||
call_type & operator=( call_type const& other)=delete;
|
||||
|
||||
symmetric_coroutine( symmetric_coroutine && other);
|
||||
call_type( call_type && other);
|
||||
|
||||
symmetric_coroutine & operator=( symmetric_coroutine && other);
|
||||
call_type & operator=( call_type && other);
|
||||
|
||||
~symmetric_coroutine();
|
||||
~call_type();
|
||||
|
||||
operator unspecified-bool-type() const;
|
||||
|
||||
bool operator!() const;
|
||||
|
||||
void swap( symmetric_coroutine & other);
|
||||
void swap( call_type & other);
|
||||
|
||||
symmetric_coroutine & operator()( Arg&& arg);
|
||||
call_type & operator()( Arg&& arg);
|
||||
};
|
||||
|
||||
template< typename Arg >
|
||||
void swap( symmetric_coroutine< Arg > & l, symmetric_coroutine< Arg > & r);
|
||||
void swap( symmetric_coroutine< Arg >::call_type & l, symmetric_coroutine< Arg >::call_type & r);
|
||||
|
||||
[heading `symmetric_coroutine()`]
|
||||
[heading `call_type()`]
|
||||
[variablelist
|
||||
[[Effects:] [Creates a coroutine representing __not_a_coro__.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
]
|
||||
|
||||
[heading `template< typename Fn, typename StackAllocator >
|
||||
symmetric_coroutine( Fn fn, attributes const& attr, StackAllocator const& stack_alloc)`]
|
||||
call_type( Fn fn, attributes const& attr, StackAllocator const& stack_alloc)`]
|
||||
[variablelist
|
||||
[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize()
|
||||
when ! is_stack_unbound().]]
|
||||
@ -317,7 +307,7 @@ For allocating/deallocating the stack `stack_alloc` is used.]]
|
||||
]
|
||||
|
||||
[heading `template< typename Fn, typename StackAllocator >
|
||||
symmetric_coroutine( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`]
|
||||
call_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`]
|
||||
[variablelist
|
||||
[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize()
|
||||
when ! is_stack_unbound().]]
|
||||
@ -326,14 +316,14 @@ determines stack clean-up and preserving floating-point registers.
|
||||
For allocating/deallocating the stack `stack_alloc` is used.]]
|
||||
]
|
||||
|
||||
[heading `symmetric_coroutine( symmetric_coroutine && other)`]
|
||||
[heading `call_type( call_type && other)`]
|
||||
[variablelist
|
||||
[[Effects:] [Moves the internal data of `other` to `*this`.
|
||||
`other` becomes __not_a_coro__.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
]
|
||||
|
||||
[heading `symmetric_coroutine & operator=( symmetric_coroutine && other)`]
|
||||
[heading `call_type & operator=( call_type && other)`]
|
||||
[variablelist
|
||||
[[Effects:] [Destroys the internal data of `*this` and moves the
|
||||
internal data of `other` to `*this`. `other` becomes __not_a_coro__.]]
|
||||
@ -354,12 +344,12 @@ has returned (completed), the function returns true. Otherwise false.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
]
|
||||
|
||||
[heading `symmetric_coroutine<> & operator()(Arg&& arg)`]
|
||||
[heading `call_type<> & operator()(Arg&& arg)`]
|
||||
|
||||
symmetric_coroutine& coroutine<Arg>::operator()(const Arg&);
|
||||
symmetric_coroutine& coroutine<Arg>::operator()(Arg&&);
|
||||
symmetric_coroutine& coroutine<Arg&>::operator()(Arg&);
|
||||
symmetric_coroutine& coroutine<void>::operator()();
|
||||
symmetric_coroutine::call_type& coroutine<Arg>::call_type::operator()(const Arg&);
|
||||
symmetric_coroutine::call_type& coroutine<Arg>::call_type::operator()(Arg&&);
|
||||
symmetric_coroutine::call_type& coroutine<Arg&>::call_type::operator()(Arg&);
|
||||
symmetric_coroutine::call_type& coroutine<void>::call_type::operator()();
|
||||
|
||||
[variablelist
|
||||
[[Preconditions:] [operator unspecified-bool-type() returns true for `*this`.]]
|
||||
@ -368,7 +358,7 @@ has returned (completed), the function returns true. Otherwise false.]]
|
||||
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
|
||||
]
|
||||
|
||||
[heading `void swap( symmetric_coroutine & other)`]
|
||||
[heading `void swap( call_type & other)`]
|
||||
[variablelist
|
||||
[[Effects:] [Swaps the internal data from `*this` with the values
|
||||
of `other`.]]
|
||||
@ -378,7 +368,7 @@ of `other`.]]
|
||||
[heading Non-member function `swap()`]
|
||||
|
||||
template< typename Arg >
|
||||
void swap( symmetric_coroutine< Arg > & l, symmetric_coroutine< Arg > & r);
|
||||
void swap( symmetric_coroutine< Arg >::call_type & l, symmetric_coroutine< Arg >::call_type & r);
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [As if 'l.swap( r)'.]]
|
||||
|
@ -38,7 +38,7 @@ private:
|
||||
public:
|
||||
int id;
|
||||
player * nxt;
|
||||
coro_t coro;
|
||||
coro_t::call_type coro;
|
||||
boost::random::random_device gen;
|
||||
|
||||
player( int id_) :
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
std::vector< int > const& from;
|
||||
std::size_t idx;
|
||||
merger * other;
|
||||
coro_t coro;
|
||||
coro_t::call_type coro;
|
||||
|
||||
merger( std::vector< int > const& from_, std::vector< int > & to, std::size_t max) :
|
||||
max_( max),
|
||||
|
@ -12,8 +12,8 @@
|
||||
|
||||
typedef boost::coroutines::symmetric_coroutine< void > coro_t;
|
||||
|
||||
coro_t * c1 = 0;
|
||||
coro_t * c2 = 0;
|
||||
coro_t::call_type * c1 = 0;
|
||||
coro_t::call_type * c2 = 0;
|
||||
|
||||
void foo( coro_t::yield_type & yield)
|
||||
{
|
||||
@ -35,8 +35,8 @@ void bar( coro_t::yield_type & yield)
|
||||
|
||||
int main( int argc, char * argv[])
|
||||
{
|
||||
coro_t coro1( foo);
|
||||
coro_t coro2( bar);
|
||||
coro_t::call_type coro1( foo);
|
||||
coro_t::call_type coro2( bar);
|
||||
c1 = & coro1;
|
||||
c2 = & coro2;
|
||||
coro1();
|
||||
|
@ -17,9 +17,9 @@ std::vector< int > merge( std::vector< int > const& a, std::vector< int > const&
|
||||
{
|
||||
std::vector< int > c;
|
||||
std::size_t idx_a = 0, idx_b = 0;
|
||||
coro_t * other_a = 0, * other_b = 0;
|
||||
coro_t::call_type * other_a = 0, * other_b = 0;
|
||||
|
||||
coro_t coro_a(
|
||||
coro_t::call_type coro_a(
|
||||
[&]( coro_t::yield_type & yield) {
|
||||
while ( idx_a < a.size() )
|
||||
{
|
||||
@ -31,7 +31,7 @@ std::vector< int > merge( std::vector< int > const& a, std::vector< int > const&
|
||||
c.push_back( b[idx_b]);
|
||||
});
|
||||
|
||||
coro_t coro_b(
|
||||
coro_t::call_type coro_b(
|
||||
[&]( coro_t::yield_type & yield) {
|
||||
while ( idx_b < b.size() )
|
||||
{
|
||||
|
@ -13,10 +13,10 @@ typedef boost::coroutines::symmetric_coroutine< void > coro_t;
|
||||
|
||||
int main( int argc, char * argv[])
|
||||
{
|
||||
coro_t * other1 = 0;
|
||||
coro_t * other2 = 0;
|
||||
coro_t::call_type * other1 = 0;
|
||||
coro_t::call_type * other2 = 0;
|
||||
|
||||
coro_t coro1(
|
||||
coro_t::call_type coro1(
|
||||
[&]( coro_t::yield_type & yield) {
|
||||
std::cout << "foo1" << std::endl;
|
||||
yield( * other2);
|
||||
@ -24,7 +24,7 @@ int main( int argc, char * argv[])
|
||||
yield( * other2);
|
||||
std::cout << "foo3" << std::endl;
|
||||
});
|
||||
coro_t coro2(
|
||||
coro_t::call_type coro2(
|
||||
[&]( coro_t::yield_type & yield) {
|
||||
std::cout << "bar1" << std::endl;
|
||||
yield( * other1);
|
||||
|
892
include/boost/coroutine/detail/symmetric_coroutine_call.hpp
Normal file
892
include/boost/coroutine/detail/symmetric_coroutine_call.hpp
Normal file
@ -0,0 +1,892 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2009.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H
|
||||
#define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/utility/explicit_operator_bool.hpp>
|
||||
|
||||
#include <boost/coroutine/attributes.hpp>
|
||||
#include <boost/coroutine/detail/config.hpp>
|
||||
#include <boost/coroutine/detail/coroutine_context.hpp>
|
||||
#include <boost/coroutine/detail/parameters.hpp>
|
||||
#include <boost/coroutine/detail/setup.hpp>
|
||||
#include <boost/coroutine/detail/symmetric_coroutine_impl.hpp>
|
||||
#include <boost/coroutine/detail/symmetric_coroutine_yield.hpp>
|
||||
#include <boost/coroutine/detail/trampoline.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace coroutines {
|
||||
namespace detail {
|
||||
|
||||
template< typename Arg, typename StackAllocator >
|
||||
class symmetric_coroutine_call
|
||||
{
|
||||
private:
|
||||
template< typename X >
|
||||
friend class symmetric_coroutine_yield;
|
||||
|
||||
typedef symmetric_coroutine_impl< Arg > impl_type;
|
||||
typedef parameters< Arg > param_type;
|
||||
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call)
|
||||
|
||||
struct dummy {};
|
||||
|
||||
impl_type * impl_;
|
||||
StackAllocator stack_alloc_;
|
||||
stack_context stack_ctx_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
|
||||
public:
|
||||
typedef Arg value_type;
|
||||
typedef symmetric_coroutine_yield< Arg > yield_type;
|
||||
|
||||
symmetric_coroutine_call() BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
# ifdef BOOST_MSVC
|
||||
typedef void ( * coroutine_fn)( yield_type &);
|
||||
|
||||
explicit symmetric_coroutine_call( coroutine_fn fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
explicit symmetric_coroutine_call( coroutine_fn fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
# endif
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#else
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( Fn fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine_call >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine_call >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#endif
|
||||
|
||||
~symmetric_coroutine_call() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( 0 != stack_ctx_.sp)
|
||||
{
|
||||
BOOST_ASSERT( 0 != impl_);
|
||||
impl_->unwind_stack();
|
||||
stack_alloc_.deallocate( stack_ctx_);
|
||||
impl_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{ swap( other); }
|
||||
|
||||
symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT
|
||||
{
|
||||
symmetric_coroutine_call tmp( boost::move( other) );
|
||||
swap( tmp);
|
||||
return * this;
|
||||
}
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL();
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT
|
||||
{ return 0 == impl_ || impl_->is_complete(); }
|
||||
|
||||
void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT
|
||||
{
|
||||
std::swap( impl_, other.impl_);
|
||||
std::swap( stack_alloc_, other.stack_alloc_);
|
||||
std::swap( stack_ctx_, other.stack_ctx_);
|
||||
std::swap( caller_, other.caller_);
|
||||
std::swap( callee_, other.callee_);
|
||||
}
|
||||
|
||||
symmetric_coroutine_call & operator()( Arg arg) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( * this);
|
||||
|
||||
impl_->run( arg);
|
||||
return * this;
|
||||
}
|
||||
|
||||
symmetric_coroutine_call & operator()( BOOST_RV_REF( Arg) arg) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( * this);
|
||||
|
||||
impl_->run( forward< Arg >( arg) );
|
||||
return * this;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Arg, typename StackAllocator >
|
||||
class symmetric_coroutine_call< Arg &, StackAllocator >
|
||||
{
|
||||
private:
|
||||
template< typename X >
|
||||
friend class symmetric_coroutine_yield;
|
||||
|
||||
typedef symmetric_coroutine_impl< Arg & > impl_type;
|
||||
typedef parameters< Arg & > param_type;
|
||||
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call)
|
||||
|
||||
struct dummy {};
|
||||
|
||||
impl_type * impl_;
|
||||
StackAllocator stack_alloc_;
|
||||
stack_context stack_ctx_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
|
||||
public:
|
||||
typedef Arg value_type;
|
||||
typedef symmetric_coroutine_yield< Arg & > yield_type;
|
||||
|
||||
symmetric_coroutine_call() BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
# ifdef BOOST_MSVC
|
||||
typedef void ( * coroutine_fn)( yield_type &);
|
||||
|
||||
explicit symmetric_coroutine_call( coroutine_fn fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
explicit symmetric_coroutine_call( coroutine_fn fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
# endif
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#else
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( Fn fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine_call >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine_call >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#endif
|
||||
|
||||
~symmetric_coroutine_call() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( 0 != stack_ctx_.sp)
|
||||
{
|
||||
BOOST_ASSERT( 0 != impl_);
|
||||
impl_->unwind_stack();
|
||||
stack_alloc_.deallocate( stack_ctx_);
|
||||
impl_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{ swap( other); }
|
||||
|
||||
symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT
|
||||
{
|
||||
symmetric_coroutine_call tmp( boost::move( other) );
|
||||
swap( tmp);
|
||||
return * this;
|
||||
}
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL();
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT
|
||||
{ return 0 == impl_ || impl_->is_complete(); }
|
||||
|
||||
void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT
|
||||
{
|
||||
std::swap( impl_, other.impl_);
|
||||
std::swap( stack_alloc_, other.stack_alloc_);
|
||||
std::swap( stack_ctx_, other.stack_ctx_);
|
||||
std::swap( caller_, other.caller_);
|
||||
std::swap( callee_, other.callee_);
|
||||
}
|
||||
|
||||
symmetric_coroutine_call & operator()( Arg & arg) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( * this);
|
||||
|
||||
impl_->run( arg);
|
||||
return * this;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename StackAllocator >
|
||||
class symmetric_coroutine_call< void, StackAllocator >
|
||||
{
|
||||
private:
|
||||
template< typename X >
|
||||
friend class symmetric_coroutine_yield;
|
||||
|
||||
typedef symmetric_coroutine_impl< void > impl_type;
|
||||
typedef parameters< void > param_type;
|
||||
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call)
|
||||
|
||||
struct dummy {};
|
||||
|
||||
impl_type * impl_;
|
||||
StackAllocator stack_alloc_;
|
||||
stack_context stack_ctx_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
|
||||
public:
|
||||
typedef void value_type;
|
||||
typedef symmetric_coroutine_yield< void > yield_type;
|
||||
|
||||
symmetric_coroutine_call() BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
# ifdef BOOST_MSVC
|
||||
typedef void ( * coroutine_fn)( yield_type &);
|
||||
|
||||
explicit symmetric_coroutine_call( coroutine_fn fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline_void< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
explicit symmetric_coroutine_call( coroutine_fn fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline_void< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
# endif
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#else
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( Fn fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine_call >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine_call >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = coroutine_context(
|
||||
trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#endif
|
||||
|
||||
~symmetric_coroutine_call() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( 0 != stack_ctx_.sp)
|
||||
{
|
||||
BOOST_ASSERT( 0 != impl_);
|
||||
impl_->unwind_stack();
|
||||
stack_alloc_.deallocate( stack_ctx_);
|
||||
impl_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{ swap( other); }
|
||||
|
||||
symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT
|
||||
{
|
||||
symmetric_coroutine_call tmp( boost::move( other) );
|
||||
swap( tmp);
|
||||
return * this;
|
||||
}
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL();
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT
|
||||
{ return 0 == impl_ || impl_->is_complete(); }
|
||||
|
||||
void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT
|
||||
{
|
||||
std::swap( impl_, other.impl_);
|
||||
std::swap( stack_alloc_, other.stack_alloc_);
|
||||
std::swap( stack_ctx_, other.stack_ctx_);
|
||||
std::swap( caller_, other.caller_);
|
||||
std::swap( callee_, other.callee_);
|
||||
}
|
||||
|
||||
symmetric_coroutine_call & operator()() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( * this);
|
||||
|
||||
impl_->run();
|
||||
return * this;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Arg, typename StackAllocator >
|
||||
void swap( symmetric_coroutine_call< Arg, StackAllocator > & l,
|
||||
symmetric_coroutine_call< Arg, StackAllocator > & r)
|
||||
{ l.swap( r); }
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H
|
@ -7,23 +7,10 @@
|
||||
#ifndef BOOST_COROUTINES_SYMMETRIC_COROUTINE_H
|
||||
#define BOOST_COROUTINES_SYMMETRIC_COROUTINE_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/utility/explicit_operator_bool.hpp>
|
||||
|
||||
#include <boost/coroutine/attributes.hpp>
|
||||
#include <boost/coroutine/detail/config.hpp>
|
||||
#include <boost/coroutine/detail/coroutine_context.hpp>
|
||||
#include <boost/coroutine/detail/parameters.hpp>
|
||||
#include <boost/coroutine/detail/setup.hpp>
|
||||
#include <boost/coroutine/detail/symmetric_coroutine_call.hpp>
|
||||
#include <boost/coroutine/detail/symmetric_coroutine_impl.hpp>
|
||||
#include <boost/coroutine/detail/symmetric_coroutine_yield.hpp>
|
||||
#include <boost/coroutine/detail/trampoline.hpp>
|
||||
#include <boost/coroutine/stack_allocator.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
@ -33,849 +20,11 @@
|
||||
namespace boost {
|
||||
namespace coroutines {
|
||||
|
||||
template< typename Arg, typename StackAllocator = standard_stack_allocator >
|
||||
class symmetric_coroutine
|
||||
template< typename T, typename StackAllocator = standard_stack_allocator >
|
||||
struct symmetric_coroutine
|
||||
{
|
||||
private:
|
||||
template< typename X >
|
||||
friend class detail::symmetric_coroutine_yield;
|
||||
|
||||
typedef detail::symmetric_coroutine_impl< Arg > impl_type;
|
||||
typedef detail::parameters< Arg > param_type;
|
||||
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine)
|
||||
|
||||
struct dummy {};
|
||||
|
||||
impl_type * impl_;
|
||||
StackAllocator stack_alloc_;
|
||||
stack_context stack_ctx_;
|
||||
detail::coroutine_context caller_;
|
||||
detail::coroutine_context callee_;
|
||||
|
||||
public:
|
||||
typedef Arg value_type;
|
||||
typedef detail::symmetric_coroutine_yield< Arg > yield_type;
|
||||
|
||||
symmetric_coroutine() BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
# ifdef BOOST_MSVC
|
||||
typedef void ( * coroutine_fn)( yield_type &);
|
||||
|
||||
explicit symmetric_coroutine( coroutine_fn fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
explicit symmetric_coroutine( coroutine_fn fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
# endif
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#else
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( Fn fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#endif
|
||||
|
||||
~symmetric_coroutine() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( 0 != stack_ctx_.sp)
|
||||
{
|
||||
BOOST_ASSERT( 0 != impl_);
|
||||
impl_->unwind_stack();
|
||||
stack_alloc_.deallocate( stack_ctx_);
|
||||
impl_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
symmetric_coroutine( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{ swap( other); }
|
||||
|
||||
symmetric_coroutine & operator=( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT
|
||||
{
|
||||
symmetric_coroutine tmp( boost::move( other) );
|
||||
swap( tmp);
|
||||
return * this;
|
||||
}
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL();
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT
|
||||
{ return 0 == impl_ || impl_->is_complete(); }
|
||||
|
||||
void swap( symmetric_coroutine & other) BOOST_NOEXCEPT
|
||||
{
|
||||
std::swap( impl_, other.impl_);
|
||||
std::swap( stack_alloc_, other.stack_alloc_);
|
||||
std::swap( stack_ctx_, other.stack_ctx_);
|
||||
std::swap( caller_, other.caller_);
|
||||
std::swap( callee_, other.callee_);
|
||||
}
|
||||
|
||||
symmetric_coroutine & operator()( Arg arg) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( * this);
|
||||
|
||||
impl_->run( arg);
|
||||
return * this;
|
||||
}
|
||||
|
||||
symmetric_coroutine & operator()( BOOST_RV_REF( Arg) arg) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( * this);
|
||||
|
||||
impl_->run( forward< Arg >( arg) );
|
||||
return * this;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Arg, typename StackAllocator >
|
||||
class symmetric_coroutine< Arg &, StackAllocator >
|
||||
{
|
||||
private:
|
||||
template< typename X >
|
||||
friend class detail::symmetric_coroutine_yield;
|
||||
|
||||
typedef detail::symmetric_coroutine_impl< Arg & > impl_type;
|
||||
typedef detail::parameters< Arg & > param_type;
|
||||
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine)
|
||||
|
||||
struct dummy {};
|
||||
|
||||
impl_type * impl_;
|
||||
StackAllocator stack_alloc_;
|
||||
stack_context stack_ctx_;
|
||||
detail::coroutine_context caller_;
|
||||
detail::coroutine_context callee_;
|
||||
|
||||
public:
|
||||
typedef Arg value_type;
|
||||
typedef detail::symmetric_coroutine_yield< Arg & > yield_type;
|
||||
|
||||
symmetric_coroutine() BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
# ifdef BOOST_MSVC
|
||||
typedef void ( * coroutine_fn)( yield_type &);
|
||||
|
||||
explicit symmetric_coroutine( coroutine_fn fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
explicit symmetric_coroutine( coroutine_fn fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
# endif
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#else
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( Fn fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#endif
|
||||
|
||||
~symmetric_coroutine() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( 0 != stack_ctx_.sp)
|
||||
{
|
||||
BOOST_ASSERT( 0 != impl_);
|
||||
impl_->unwind_stack();
|
||||
stack_alloc_.deallocate( stack_ctx_);
|
||||
impl_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
symmetric_coroutine( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{ swap( other); }
|
||||
|
||||
symmetric_coroutine & operator=( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT
|
||||
{
|
||||
symmetric_coroutine tmp( boost::move( other) );
|
||||
swap( tmp);
|
||||
return * this;
|
||||
}
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL();
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT
|
||||
{ return 0 == impl_ || impl_->is_complete(); }
|
||||
|
||||
void swap( symmetric_coroutine & other) BOOST_NOEXCEPT
|
||||
{
|
||||
std::swap( impl_, other.impl_);
|
||||
std::swap( stack_alloc_, other.stack_alloc_);
|
||||
std::swap( stack_ctx_, other.stack_ctx_);
|
||||
std::swap( caller_, other.caller_);
|
||||
std::swap( callee_, other.callee_);
|
||||
}
|
||||
|
||||
symmetric_coroutine & operator()( Arg & arg) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( * this);
|
||||
|
||||
impl_->run( arg);
|
||||
return * this;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename StackAllocator >
|
||||
class symmetric_coroutine< void, StackAllocator >
|
||||
{
|
||||
private:
|
||||
template< typename X >
|
||||
friend class detail::symmetric_coroutine_yield;
|
||||
|
||||
typedef detail::symmetric_coroutine_impl< void > impl_type;
|
||||
typedef detail::parameters< void > param_type;
|
||||
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine)
|
||||
|
||||
struct dummy {};
|
||||
|
||||
impl_type * impl_;
|
||||
StackAllocator stack_alloc_;
|
||||
stack_context stack_ctx_;
|
||||
detail::coroutine_context caller_;
|
||||
detail::coroutine_context callee_;
|
||||
|
||||
public:
|
||||
typedef void value_type;
|
||||
typedef detail::symmetric_coroutine_yield< void > yield_type;
|
||||
|
||||
symmetric_coroutine() BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
# ifdef BOOST_MSVC
|
||||
typedef void ( * coroutine_fn)( yield_type &);
|
||||
|
||||
explicit symmetric_coroutine( coroutine_fn fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline_void< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
explicit symmetric_coroutine( coroutine_fn fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline_void< coroutine_fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
# endif
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes() ) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#else
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( Fn fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr = attributes(),
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn,
|
||||
attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, symmetric_coroutine >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
impl_( 0),
|
||||
stack_alloc_( stack_alloc),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{
|
||||
stack_alloc_.allocate( stack_ctx_, attr.size);
|
||||
callee_ = detail::coroutine_context(
|
||||
detail::trampoline_void< Fn, impl_type, yield_type >,
|
||||
& stack_ctx_);
|
||||
detail::setup< Fn > to( fn, & caller_, & callee_, attr);
|
||||
impl_ = reinterpret_cast< impl_type * >(
|
||||
caller_.jump(
|
||||
callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
fpu_preserved == attr.preserve_fpu) );
|
||||
BOOST_ASSERT( impl_);
|
||||
}
|
||||
#endif
|
||||
|
||||
~symmetric_coroutine() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( 0 != stack_ctx_.sp)
|
||||
{
|
||||
BOOST_ASSERT( 0 != impl_);
|
||||
impl_->unwind_stack();
|
||||
stack_alloc_.deallocate( stack_ctx_);
|
||||
impl_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
symmetric_coroutine( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT :
|
||||
impl_( 0),
|
||||
stack_alloc_(),
|
||||
stack_ctx_(),
|
||||
caller_(),
|
||||
callee_()
|
||||
{ swap( other); }
|
||||
|
||||
symmetric_coroutine & operator=( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT
|
||||
{
|
||||
symmetric_coroutine tmp( boost::move( other) );
|
||||
swap( tmp);
|
||||
return * this;
|
||||
}
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL();
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT
|
||||
{ return 0 == impl_ || impl_->is_complete(); }
|
||||
|
||||
void swap( symmetric_coroutine & other) BOOST_NOEXCEPT
|
||||
{
|
||||
std::swap( impl_, other.impl_);
|
||||
std::swap( stack_alloc_, other.stack_alloc_);
|
||||
std::swap( stack_ctx_, other.stack_ctx_);
|
||||
std::swap( caller_, other.caller_);
|
||||
std::swap( callee_, other.callee_);
|
||||
}
|
||||
|
||||
symmetric_coroutine & operator()() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( * this);
|
||||
|
||||
impl_->run();
|
||||
return * this;
|
||||
}
|
||||
typedef detail::symmetric_coroutine_call< T, StackAllocator > call_type;
|
||||
typedef detail::symmetric_coroutine_yield< T > yield_type;
|
||||
};
|
||||
|
||||
}}
|
||||
|
@ -33,7 +33,7 @@ duration_type measure_time( duration_type overhead)
|
||||
|
||||
time_point_type start( clock_type::now() );
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
coro_type c( fn,
|
||||
coro_type::call_type c( fn,
|
||||
boost::coroutines::attributes( stack_allocator::default_stacksize(), unwind_stack, preserve_fpu),
|
||||
stack_alloc);
|
||||
}
|
||||
@ -51,7 +51,7 @@ cycle_type measure_cycles( cycle_type overhead)
|
||||
|
||||
cycle_type start( cycles() );
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
coro_type c( fn,
|
||||
coro_type::call_type c( fn,
|
||||
boost::coroutines::attributes( stack_allocator::default_stacksize(), unwind_stack, preserve_fpu),
|
||||
stack_alloc);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ duration_type measure_time( duration_type overhead)
|
||||
|
||||
time_point_type start( clock_type::now() );
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
coro_type c( fn,
|
||||
coro_type::call_type c( fn,
|
||||
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
|
||||
}
|
||||
duration_type total = clock_type::now() - start;
|
||||
@ -49,7 +49,7 @@ cycle_type measure_cycles( cycle_type overhead)
|
||||
|
||||
cycle_type start( cycles() );
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
coro_type c( fn,
|
||||
coro_type::call_type c( fn,
|
||||
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
|
||||
}
|
||||
cycle_type total = cycles() - start;
|
||||
|
@ -32,7 +32,7 @@ duration_type measure_time( duration_type overhead)
|
||||
|
||||
time_point_type start( clock_type::now() );
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
coro_type c( fn,
|
||||
coro_type::call_type c( fn,
|
||||
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
|
||||
}
|
||||
duration_type total = clock_type::now() - start;
|
||||
@ -49,7 +49,7 @@ cycle_type measure_cycles( cycle_type overhead)
|
||||
|
||||
cycle_type start( cycles() );
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
coro_type c( fn,
|
||||
coro_type::call_type c( fn,
|
||||
boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
|
||||
}
|
||||
cycle_type total = cycles() - start;
|
||||
|
@ -46,7 +46,7 @@ duration_type measure_time_void( duration_type overhead)
|
||||
{
|
||||
duration_type total = duration_type::zero();
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
boost::coroutines::symmetric_coroutine< void > c( fn_void,
|
||||
boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void,
|
||||
boost::coroutines::attributes( preserve_fpu) );
|
||||
time_point_type start( clock_type::now() );
|
||||
c();
|
||||
@ -64,7 +64,7 @@ duration_type measure_time_int( duration_type overhead)
|
||||
int i = 3;
|
||||
duration_type total = duration_type::zero();
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
boost::coroutines::symmetric_coroutine< int > c( fn_int,
|
||||
boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int,
|
||||
boost::coroutines::attributes( preserve_fpu) );
|
||||
time_point_type start( clock_type::now() );
|
||||
c( i);
|
||||
@ -82,7 +82,7 @@ duration_type measure_time_x( duration_type overhead)
|
||||
X x("abc");
|
||||
duration_type total = duration_type::zero();
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
boost::coroutines::symmetric_coroutine< X > c( fn_x,
|
||||
boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x,
|
||||
boost::coroutines::attributes( preserve_fpu) );
|
||||
time_point_type start( clock_type::now() );
|
||||
c( x);
|
||||
@ -100,7 +100,7 @@ cycle_type measure_cycles_void( cycle_type overhead)
|
||||
{
|
||||
cycle_type total = 0;
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
boost::coroutines::symmetric_coroutine< void > c( fn_void,
|
||||
boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void,
|
||||
boost::coroutines::attributes( preserve_fpu) );
|
||||
cycle_type start( cycles() );
|
||||
c();
|
||||
@ -118,7 +118,7 @@ cycle_type measure_cycles_int( cycle_type overhead)
|
||||
int i = 3;
|
||||
cycle_type total = 0;
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
boost::coroutines::symmetric_coroutine< int > c( fn_int,
|
||||
boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int,
|
||||
boost::coroutines::attributes( preserve_fpu) );
|
||||
cycle_type start( cycles() );
|
||||
c( i);
|
||||
@ -136,7 +136,7 @@ cycle_type measure_cycles_x( cycle_type overhead)
|
||||
X x("abc");
|
||||
cycle_type total = 0;
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
boost::coroutines::symmetric_coroutine< X > c( fn_x,
|
||||
boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x,
|
||||
boost::coroutines::attributes( preserve_fpu) );
|
||||
cycle_type start( cycles() );
|
||||
c( x);
|
||||
|
@ -26,7 +26,7 @@ duration_type measure_time( duration_type overhead)
|
||||
{
|
||||
time_point_type start( clock_type::now() );
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
boost::coroutines::symmetric_coroutine< void > c( fn,
|
||||
boost::coroutines::symmetric_coroutine< void >::call_type c( fn,
|
||||
boost::coroutines::attributes( preserve_fpu) );
|
||||
}
|
||||
duration_type total = clock_type::now() - start;
|
||||
@ -41,7 +41,7 @@ cycle_type measure_cycles( cycle_type overhead)
|
||||
{
|
||||
cycle_type start( cycles() );
|
||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||
boost::coroutines::symmetric_coroutine< void > c( fn,
|
||||
boost::coroutines::symmetric_coroutine< void >::call_type c( fn,
|
||||
boost::coroutines::attributes( preserve_fpu) );
|
||||
}
|
||||
cycle_type total = cycles() - start;
|
||||
|
@ -32,7 +32,7 @@ bool value1 = false;
|
||||
int value2 = 0;
|
||||
std::string value3;
|
||||
|
||||
coro::symmetric_coroutine< void > * term_coro = 0;
|
||||
coro::symmetric_coroutine< void >::call_type * term_coro = 0;
|
||||
|
||||
struct X
|
||||
{
|
||||
@ -142,7 +142,7 @@ void f9( coro::symmetric_coroutine< void >::yield_type &, E const& e)
|
||||
{ throw e; }
|
||||
|
||||
void f10( coro::symmetric_coroutine< int >::yield_type & yield,
|
||||
coro::symmetric_coroutine< int > & other)
|
||||
coro::symmetric_coroutine< int >::call_type & other)
|
||||
{
|
||||
int i = yield.get();
|
||||
yield( other, i);
|
||||
@ -153,7 +153,7 @@ void f101( coro::symmetric_coroutine< int >::yield_type & yield)
|
||||
{ value2 = yield.get(); }
|
||||
|
||||
void f11( coro::symmetric_coroutine< void >::yield_type & yield,
|
||||
coro::symmetric_coroutine< void > & other)
|
||||
coro::symmetric_coroutine< void >::call_type & other)
|
||||
{
|
||||
yield( other);
|
||||
value2 = 7;
|
||||
@ -163,7 +163,7 @@ void f111( coro::symmetric_coroutine< void >::yield_type &)
|
||||
{ value2 = 3; }
|
||||
|
||||
void f12( coro::symmetric_coroutine< X& >::yield_type & yield,
|
||||
coro::symmetric_coroutine< X& > & other)
|
||||
coro::symmetric_coroutine< X& >::call_type & other)
|
||||
{
|
||||
yield( other, yield.get());
|
||||
p = & yield.get();
|
||||
@ -173,7 +173,7 @@ void f121( coro::symmetric_coroutine< X& >::yield_type & yield)
|
||||
{ p = & yield.get(); }
|
||||
|
||||
void f14( coro::symmetric_coroutine< int >::yield_type & yield,
|
||||
coro::symmetric_coroutine< std::string > & other)
|
||||
coro::symmetric_coroutine< std::string >::call_type & other)
|
||||
{
|
||||
std::string str( boost::lexical_cast< std::string >( yield.get() ) );
|
||||
yield( other, str);
|
||||
@ -185,7 +185,7 @@ void f141( coro::symmetric_coroutine< std::string >::yield_type & yield)
|
||||
|
||||
void f15( coro::symmetric_coroutine< int >::yield_type & yield,
|
||||
int offset,
|
||||
coro::symmetric_coroutine< int > & other)
|
||||
coro::symmetric_coroutine< int >::call_type & other)
|
||||
{
|
||||
int x = yield.get();
|
||||
value2 += x + offset;
|
||||
@ -208,8 +208,8 @@ void f151( coro::symmetric_coroutine< int >::yield_type & yield,
|
||||
void test_move()
|
||||
{
|
||||
{
|
||||
coro::symmetric_coroutine< void > coro1;
|
||||
coro::symmetric_coroutine< void > coro2( empty);
|
||||
coro::symmetric_coroutine< void >::call_type coro1;
|
||||
coro::symmetric_coroutine< void >::call_type coro2( empty);
|
||||
BOOST_CHECK( ! coro1);
|
||||
BOOST_CHECK( coro2);
|
||||
coro1 = boost::move( coro2);
|
||||
@ -222,7 +222,7 @@ void test_move()
|
||||
copyable cp( 3);
|
||||
BOOST_CHECK( cp.state);
|
||||
BOOST_CHECK( ! value1);
|
||||
coro::symmetric_coroutine< int > coro( cp);
|
||||
coro::symmetric_coroutine< int >::call_type coro( cp);
|
||||
coro( 3);
|
||||
BOOST_CHECK( cp.state);
|
||||
BOOST_CHECK( value1);
|
||||
@ -233,7 +233,7 @@ void test_move()
|
||||
moveable mv( 7);
|
||||
BOOST_CHECK( mv.state);
|
||||
BOOST_CHECK( ! value1);
|
||||
coro::symmetric_coroutine< int > coro( boost::move( mv) );
|
||||
coro::symmetric_coroutine< int >::call_type coro( boost::move( mv) );
|
||||
coro( 7);
|
||||
BOOST_CHECK( ! mv.state);
|
||||
BOOST_CHECK( value1);
|
||||
@ -244,7 +244,7 @@ void test_complete()
|
||||
{
|
||||
value2 = 0;
|
||||
|
||||
coro::symmetric_coroutine< void > coro( f2);
|
||||
coro::symmetric_coroutine< void >::call_type coro( f2);
|
||||
BOOST_CHECK( coro);
|
||||
coro();
|
||||
BOOST_CHECK( ! coro);
|
||||
@ -255,13 +255,13 @@ void test_yield()
|
||||
{
|
||||
value2 = 0;
|
||||
|
||||
coro::symmetric_coroutine< int > coro3(
|
||||
coro::symmetric_coroutine< int >::call_type coro3(
|
||||
boost::bind( f151, _1, 3) );
|
||||
BOOST_CHECK( coro3);
|
||||
coro::symmetric_coroutine< int > coro2(
|
||||
coro::symmetric_coroutine< int >::call_type coro2(
|
||||
boost::bind( f15, _1, 2, boost::ref( coro3) ) );
|
||||
BOOST_CHECK( coro2);
|
||||
coro::symmetric_coroutine< int > coro1(
|
||||
coro::symmetric_coroutine< int >::call_type coro1(
|
||||
boost::bind( f15, _1, 1, boost::ref( coro2) ) );
|
||||
BOOST_CHECK( coro1);
|
||||
|
||||
@ -285,7 +285,7 @@ void test_pass_value()
|
||||
X x(7);
|
||||
BOOST_CHECK_EQUAL( ( int)7, x.i);
|
||||
BOOST_CHECK_EQUAL( 0, value2);
|
||||
coro::symmetric_coroutine< X > coro( f3);
|
||||
coro::symmetric_coroutine< X >::call_type coro( f3);
|
||||
BOOST_CHECK( coro);
|
||||
coro(7);
|
||||
BOOST_CHECK( ! coro);
|
||||
@ -298,7 +298,7 @@ void test_pass_reference()
|
||||
p = 0;
|
||||
|
||||
X x;
|
||||
coro::symmetric_coroutine< X& > coro( f4);
|
||||
coro::symmetric_coroutine< X& >::call_type coro( f4);
|
||||
BOOST_CHECK( coro);
|
||||
coro( x);
|
||||
BOOST_CHECK( ! coro);
|
||||
@ -310,7 +310,7 @@ void test_pass_pointer()
|
||||
p = 0;
|
||||
|
||||
X x;
|
||||
coro::symmetric_coroutine< X* > coro( f5);
|
||||
coro::symmetric_coroutine< X* >::call_type coro( f5);
|
||||
BOOST_CHECK( coro);
|
||||
coro( & x);
|
||||
BOOST_CHECK( ! coro);
|
||||
@ -321,8 +321,8 @@ void test_unwind()
|
||||
{
|
||||
value2 = 0;
|
||||
{
|
||||
coro::symmetric_coroutine< void > coro( f6);
|
||||
coro::symmetric_coroutine< void > coro_e( empty);
|
||||
coro::symmetric_coroutine< void >::call_type coro( f6);
|
||||
coro::symmetric_coroutine< void >::call_type coro_e( empty);
|
||||
BOOST_CHECK( coro);
|
||||
BOOST_CHECK( coro_e);
|
||||
term_coro = & coro_e;
|
||||
@ -338,11 +338,11 @@ void test_no_unwind()
|
||||
{
|
||||
value2 = 0;
|
||||
{
|
||||
coro::symmetric_coroutine< void > coro( f6,
|
||||
coro::symmetric_coroutine< void >::call_type coro( f6,
|
||||
coro::attributes(
|
||||
coro::stack_allocator::default_stacksize(),
|
||||
coro::no_stack_unwind) );
|
||||
coro::symmetric_coroutine< void > coro_e( empty);
|
||||
coro::symmetric_coroutine< void >::call_type coro_e( empty);
|
||||
BOOST_CHECK( coro);
|
||||
BOOST_CHECK( coro_e);
|
||||
term_coro = & coro_e;
|
||||
@ -358,8 +358,8 @@ void test_termination()
|
||||
{
|
||||
value2 = 0;
|
||||
|
||||
coro::symmetric_coroutine< int > coro( f7);
|
||||
coro::symmetric_coroutine< void > coro_e( empty);
|
||||
coro::symmetric_coroutine< int >::call_type coro( f7);
|
||||
coro::symmetric_coroutine< void >::call_type coro_e( empty);
|
||||
BOOST_CHECK( coro);
|
||||
BOOST_CHECK( coro_e);
|
||||
term_coro = & coro_e;
|
||||
@ -376,8 +376,8 @@ void test_yield_to_void()
|
||||
{
|
||||
value2 = 0;
|
||||
|
||||
coro::symmetric_coroutine< void > coro_other( f111);
|
||||
coro::symmetric_coroutine< void > coro( boost::bind( f11, _1, boost::ref( coro_other) ) );
|
||||
coro::symmetric_coroutine< void >::call_type coro_other( f111);
|
||||
coro::symmetric_coroutine< void >::call_type coro( boost::bind( f11, _1, boost::ref( coro_other) ) );
|
||||
BOOST_CHECK( coro_other);
|
||||
BOOST_CHECK( coro);
|
||||
BOOST_CHECK_EQUAL( ( int) 0, value2);
|
||||
@ -395,8 +395,8 @@ void test_yield_to_int()
|
||||
{
|
||||
value2 = 0;
|
||||
|
||||
coro::symmetric_coroutine< int > coro_other( f101);
|
||||
coro::symmetric_coroutine< int > coro( boost::bind( f10, _1, boost::ref( coro_other) ) );
|
||||
coro::symmetric_coroutine< int >::call_type coro_other( f101);
|
||||
coro::symmetric_coroutine< int >::call_type coro( boost::bind( f10, _1, boost::ref( coro_other) ) );
|
||||
BOOST_CHECK( coro_other);
|
||||
BOOST_CHECK( coro);
|
||||
BOOST_CHECK_EQUAL( ( int) 0, value2);
|
||||
@ -414,8 +414,8 @@ void test_yield_to_ref()
|
||||
{
|
||||
p = 0;
|
||||
|
||||
coro::symmetric_coroutine< X& > coro_other( f121);
|
||||
coro::symmetric_coroutine< X& > coro( boost::bind( f12, _1, boost::ref( coro_other) ) );
|
||||
coro::symmetric_coroutine< X& >::call_type coro_other( f121);
|
||||
coro::symmetric_coroutine< X& >::call_type coro( boost::bind( f12, _1, boost::ref( coro_other) ) );
|
||||
BOOST_CHECK( coro_other);
|
||||
BOOST_CHECK( coro);
|
||||
BOOST_CHECK( 0 == p);
|
||||
@ -438,8 +438,8 @@ void test_yield_to_different()
|
||||
value2 = 0;
|
||||
value3 = "";
|
||||
|
||||
coro::symmetric_coroutine< std::string > coro_other( f141);
|
||||
coro::symmetric_coroutine< int > coro( boost::bind( f14, _1, boost::ref( coro_other) ) );
|
||||
coro::symmetric_coroutine< std::string >::call_type coro_other( f141);
|
||||
coro::symmetric_coroutine< int >::call_type coro( boost::bind( f14, _1, boost::ref( coro_other) ) );
|
||||
BOOST_CHECK( coro_other);
|
||||
BOOST_CHECK( coro);
|
||||
BOOST_CHECK_EQUAL( ( int) 0, value2);
|
||||
|
Loading…
Reference in New Issue
Block a user