use of captured_context

This commit is contained in:
Oliver Kowalke 2016-01-02 18:43:39 +01:00
parent 37222c014a
commit 6796caa2c7
12 changed files with 939 additions and 127 deletions

View File

@ -13,7 +13,8 @@
#include <boost/coroutine2/all.hpp>
struct node {
struct node
{
typedef std::shared_ptr< node > ptr_t;
// Each tree node has an optional left subtree, an optional right subtree
@ -24,24 +25,26 @@ struct node {
// construct leaf
node(const std::string& v):
left(),right(),value(v) {
}
left(),right(),value(v)
{}
// construct nonleaf
node(ptr_t l, const std::string& v, ptr_t r):
left(l),right(r),value(v) {
}
left(l),right(r),value(v)
{}
static ptr_t create(const std::string& v) {
static ptr_t create(const std::string& v)
{
return ptr_t(new node(v));
}
static ptr_t create(ptr_t l, const std::string& v, ptr_t r) {
static ptr_t create(ptr_t l, const std::string& v, ptr_t r)
{
return ptr_t(new node(l, v, r));
}
};
node::ptr_t create_left_tree_from(const std::string& root) {
node::ptr_t create_left_tree_from(const std::string& root)
{
/* --------
root
/ \
@ -59,7 +62,8 @@ node::ptr_t create_left_tree_from(const std::string& root) {
node::create("e"));
}
node::ptr_t create_right_tree_from(const std::string& root) {
node::ptr_t create_right_tree_from(const std::string& root)
{
/* --------
root
/ \
@ -78,7 +82,8 @@ node::ptr_t create_right_tree_from(const std::string& root) {
}
// recursively walk the tree, delivering values in order
void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_type& out) {
void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_type& out)
{
if (n->left)
traverse(n->left,out);
out(n->value);
@ -86,81 +91,92 @@ void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_ty
traverse(n->right,out);
}
int main() {
int main()
{
{
node::ptr_t left_d(create_left_tree_from("d"));
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
std::cout << "left tree from d:\n";
std::copy(begin(left_d_reader),
end(left_d_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
node::ptr_t right_b(create_right_tree_from("b"));
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_b,out);
});
std::cout << "right tree from b:\n";
std::copy(begin(right_b_reader),
end(right_b_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
node::ptr_t right_x(create_right_tree_from("x"));
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_x,out);
});
std::cout << "right tree from x:\n";
std::copy(begin(right_x_reader),
end(right_x_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
{
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
std::cout << "left tree from d:\n";
std::copy(begin(left_d_reader),
end(left_d_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_b,out);
});
std::cout << "right tree from b:\n";
std::copy(begin(right_b_reader),
end(right_b_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_x,out);
});
std::cout << "right tree from x:\n";
std::copy(begin(right_x_reader),
end(right_x_reader),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
}
}
{
node::ptr_t left_d(create_left_tree_from("d"));
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
node::ptr_t right_b(create_right_tree_from("b"));
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_b,out);
});
{
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
std::cout << "left tree from d == right tree from b? "
<< std::boolalpha
<< std::equal(begin(left_d_reader),
end(left_d_reader),
begin(right_b_reader))
<< std::endl;
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_b,out);
});
std::cout << "left tree from d == right tree from b? "
<< std::boolalpha
<< std::equal(begin(left_d_reader),
end(left_d_reader),
begin(right_b_reader))
<< std::endl;
}
}
{
node::ptr_t left_d(create_left_tree_from("d"));
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
node::ptr_t right_x(create_right_tree_from("x"));
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_x,out);
});
{
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(left_d,out);
});
std::cout << "left tree from d == right tree from x? "
<< std::boolalpha
<< std::equal(begin(left_d_reader),
end(left_d_reader),
begin(right_x_reader))
<< std::endl;
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
traverse(right_x,out);
});
std::cout << "left tree from d == right tree from x? "
<< std::boolalpha
<< std::equal(begin(left_d_reader),
end(left_d_reader),
begin(right_x_reader))
<< std::endl;
}
}
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -28,14 +28,24 @@ class push_coroutine;
#include <boost/coroutine2/detail/pull_coroutine.hpp>
#include <boost/coroutine2/detail/push_coroutine.hpp>
#include <boost/coroutine2/detail/pull_control_block.hpp>
#include <boost/coroutine2/detail/push_control_block.hpp>
#if ! defined(BOOST_USE_SEGMENTED_STACKS)
#include <boost/coroutine2/detail/pull_control_block_cc.hpp>
#include <boost/coroutine2/detail/push_control_block_cc.hpp>
#else
#include <boost/coroutine2/detail/pull_control_block_ec.hpp>
#include <boost/coroutine2/detail/push_control_block_ec.hpp>
#endif
#include <boost/coroutine2/detail/pull_coroutine.ipp>
#include <boost/coroutine2/detail/push_coroutine.ipp>
#include <boost/coroutine2/detail/pull_control_block.ipp>
#include <boost/coroutine2/detail/push_control_block.ipp>
#if ! defined(BOOST_USE_SEGMENTED_STACKS)
#include <boost/coroutine2/detail/pull_control_block_cc.ipp>
#include <boost/coroutine2/detail/push_control_block_cc.ipp>
#else
#include <boost/coroutine2/detail/pull_control_block_ec.ipp>
#include <boost/coroutine2/detail/push_control_block_ec.ipp>
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX

View File

@ -24,6 +24,12 @@ namespace detail {
struct forced_unwind {};
inline
void * unwind_coroutine( void * data) {
throw forced_unwind{};
return data;
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS

View File

@ -0,0 +1,98 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP
#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP
#include <exception>
#include <type_traits>
#include <boost/config.hpp>
#include <boost/context/captured_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines2 {
namespace detail {
template< typename T >
struct pull_coroutine< T >::control_block {
typename push_coroutine< T >::control_block * other;
boost::context::captured_context ctx;
std::exception_ptr except;
bool bvalid;
typename std::aligned_storage< sizeof( T), alignof( T) >::type storage;
template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&);
control_block( typename push_coroutine< T >::control_block *, boost::context::captured_context &) noexcept;
~control_block();
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;
void resume();
void set( T *);
T & get() noexcept;
bool valid() const noexcept;
};
template< typename T >
struct pull_coroutine< T & >::control_block {
typename push_coroutine< T & >::control_block * other;
boost::context::captured_context ctx;
std::exception_ptr except;
T * t;
template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&);
control_block( typename push_coroutine< T & >::control_block *, boost::context::captured_context &) noexcept;
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;
void resume();
T & get() noexcept;
bool valid() const noexcept;
};
struct pull_coroutine< void >::control_block {
push_coroutine< void >::control_block * other;
boost::context::captured_context ctx;
std::exception_ptr except;
template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&);
control_block( push_coroutine< void >::control_block *, boost::context::captured_context &) noexcept;
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;
void resume();
bool valid() const noexcept;
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP

View File

@ -0,0 +1,332 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
#include <algorithm>
#include <exception>
#include <memory>
#include <tuple>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/captured_context.hpp>
#include <boost/coroutine2/detail/config.hpp>
#include <boost/coroutine2/detail/forced_unwind.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines2 {
namespace detail {
// pull_coroutine< T >
template< typename T >
template< typename StackAllocator, typename Fn >
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
other{ nullptr },
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
ctx{ std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
// create synthesized push_coroutine< T >
typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
push_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb;
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized push_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
},
std::forward< Fn >( fn),
std::placeholders::_1,
std::placeholders::_2))},
#else
ctx{ std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
// create synthesized push_coroutine< T >
typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
push_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb;
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized push_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
}},
#endif
except{},
bvalid{ false },
storage{} {
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
void * data = nullptr;
std::tie( ctx, data) = ctx();
set( static_cast< T * >( data) );
}
template< typename T >
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
boost::context::captured_context & ctx_) noexcept :
other{ cb },
ctx{ std::move( ctx_) },
except{},
bvalid{ false },
storage{} {
}
template< typename T >
pull_coroutine< T >::control_block::~control_block() {
// destroy data if set
if ( bvalid) {
reinterpret_cast< T * >( std::addressof( storage) )->~T();
}
}
template< typename T >
void
pull_coroutine< T >::control_block::resume() {
void * data;
std::tie( ctx, data) = ctx();
set( static_cast< T * >( data) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
void
pull_coroutine< T >::control_block::set( T * t) {
// destroy data if set
if ( bvalid) {
reinterpret_cast< T * >( std::addressof( storage) )->~T();
}
if ( nullptr != t) {
::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( * t) );
bvalid = true;
} else {
bvalid = false;
}
}
template< typename T >
T &
pull_coroutine< T >::control_block::get() noexcept {
return * reinterpret_cast< T * >( std::addressof( storage) );
}
template< typename T >
bool
pull_coroutine< T >::control_block::valid() const noexcept {
return nullptr != other && ctx && bvalid;
}
// pull_coroutine< T & >
template< typename T >
template< typename StackAllocator, typename Fn >
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
other{ nullptr },
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
ctx{ std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
// create synthesized push_coroutine< T >
typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
push_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb;
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized push_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
},
std::forward< Fn >( fn),
std::placeholders::_1,
std::placeholders::_2))},
#else
ctx{ std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
// create synthesized push_coroutine< T >
typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
push_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb;
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized push_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
}},
#endif
except{},
t{ nullptr } {
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
void * data = nullptr;
std::tie( ctx, data) = ctx();
t = static_cast< T * >( data);
}
template< typename T >
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
boost::context::captured_context & ctx_) noexcept :
other{ cb },
ctx{ std::move( ctx_) },
except{},
t{ nullptr } {
}
template< typename T >
void
pull_coroutine< T & >::control_block::resume() {
void * data;
std::tie( ctx, data) = ctx();
t = static_cast< T * >( data);
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
T &
pull_coroutine< T & >::control_block::get() noexcept {
return * static_cast< T * >( t);
}
template< typename T >
bool
pull_coroutine< T & >::control_block::valid() const noexcept {
return nullptr != other && ctx && nullptr != t;
}
// pull_coroutine< void >
template< typename StackAllocator, typename Fn >
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
other{ nullptr },
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
ctx{ std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
// create synthesized push_coroutine< T >
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
push_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized push_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
},
std::forward< Fn >( fn),
std::placeholders::_1,
std::placeholders::_2))},
#else
ctx{ std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
// create synthesized push_coroutine< T >
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
push_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized push_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
}},
#endif
except{} {
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
void * ignored = nullptr;
std::tie( ctx, ignored) = ctx();
}
inline
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
boost::context::captured_context & ctx_) noexcept :
other{ cb },
ctx{ std::move( ctx_) },
except{} {
}
inline
void
pull_coroutine< void >::control_block::resume() {
void * ignored;
std::tie( ctx, ignored) = ctx();
if ( except) {
std::rethrow_exception( except);
}
}
inline
bool
pull_coroutine< void >::control_block::valid() const noexcept {
return nullptr != other && ctx;
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP

View File

@ -38,7 +38,7 @@ struct pull_coroutine< T >::control_block {
control_block( typename push_coroutine< T >::control_block *, boost::context::execution_context const&) noexcept;
~control_block() noexcept;
~control_block();
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;
@ -65,7 +65,7 @@ struct pull_coroutine< T & >::control_block {
control_block( typename push_coroutine< T & >::control_block *, boost::context::execution_context const&) noexcept;
~control_block() noexcept;
~control_block();
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;
@ -88,7 +88,7 @@ struct pull_coroutine< void >::control_block {
control_block( push_coroutine< void >::control_block *, boost::context::execution_context const&) noexcept;
~control_block() noexcept;
~control_block();
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;

View File

@ -108,12 +108,11 @@ pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >:
}
template< typename T >
pull_coroutine< T >::control_block::~control_block() noexcept {
pull_coroutine< T >::control_block::~control_block() {
if ( state_t::none == ( state & state_t::complete) &&
state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag
state |= state_t::early_exit;
ctx();
// unwind coroutine stack
ctx( context::exec_ontop_arg, unwind_coroutine);
}
// destroy data if it set
if ( bvalid) {
@ -129,10 +128,6 @@ pull_coroutine< T >::control_block::resume() {
if ( except) {
std::rethrow_exception( except);
}
// test early-exit-flag
if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind();
}
}
template< typename T >
@ -243,9 +238,8 @@ template< typename T >
pull_coroutine< T & >::control_block::~control_block() noexcept {
if ( state_t::none == ( state & state_t::complete) &&
state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag
state |= state_t::early_exit;
ctx();
// unwind coroutine stack
ctx( context::exec_ontop_arg, unwind_coroutine);
}
}
@ -257,10 +251,6 @@ pull_coroutine< T & >::control_block::resume() {
if ( except) {
std::rethrow_exception( except);
}
// test early-exit-flag
if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind();
}
}
template< typename T >
@ -353,9 +343,8 @@ inline
pull_coroutine< void >::control_block::~control_block() noexcept {
if ( state_t::none == ( state & state_t::complete) &&
state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag
state |= state_t::early_exit;
ctx();
// unwind coroutine stack
ctx( context::exec_ontop_arg, unwind_coroutine);
}
}
@ -367,10 +356,6 @@ pull_coroutine< void >::control_block::resume() {
if ( except) {
std::rethrow_exception( except);
}
// test early-exit-flag
if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind();
}
}
inline

View File

@ -0,0 +1,88 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP
#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP
#include <exception>
#include <boost/config.hpp>
#include <boost/context/captured_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines2 {
namespace detail {
template< typename T >
struct push_coroutine< T >::control_block {
typename pull_coroutine< T >::control_block * other;
boost::context::captured_context ctx;
std::exception_ptr except;
template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&);
control_block( typename pull_coroutine< T >::control_block *, boost::context::captured_context &) noexcept;
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;
void resume( T const&);
void resume( T &&);
bool valid() const noexcept;
};
template< typename T >
struct push_coroutine< T & >::control_block {
typename pull_coroutine< T & >::control_block * other;
boost::context::captured_context ctx;
std::exception_ptr except;
template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&);
control_block( typename pull_coroutine< T & >::control_block *, boost::context::captured_context &) noexcept;
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;
void resume( T &);
bool valid() const noexcept;
};
struct push_coroutine< void >::control_block {
pull_coroutine< void >::control_block * other;
boost::context::captured_context ctx;
std::exception_ptr except;
template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&);
control_block( pull_coroutine< void >::control_block *, boost::context::captured_context &) noexcept;
control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete;
void resume();
bool valid() const noexcept;
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP

View File

@ -0,0 +1,297 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
#include <algorithm>
#include <exception>
#include <memory>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/captured_context.hpp>
#include <boost/coroutine2/detail/config.hpp>
#include <boost/coroutine2/detail/forced_unwind.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines2 {
namespace detail {
// push_coroutine< T >
template< typename T >
template< typename StackAllocator, typename Fn >
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
other{ nullptr },
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
ctx{ std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void * data) mutable {
// create synthesized pull_coroutine< T >
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
pull_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb;
// set transferred value
synthesized_cb.set( static_cast< T * >( data) );
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized pull_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
},
std::forward< Fn >( fn),
std::placeholders::_1,
std::placeholders::_2))},
#else
ctx{ std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void * data) mutable {
// create synthesized pull_coroutine< T >
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
pull_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb;
// set transferred value
synthesized_cb.set( static_cast< T * >( data) );
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized pull_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
}},
#endif
except{} {
}
template< typename T >
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
boost::context::captured_context & ctx_) noexcept :
other{ cb },
ctx{ std::move( ctx_) },
except{} {
}
template< typename T >
void
push_coroutine< T >::control_block::resume( T const& data) {
// pass an pointer to other context
void * ignored;
std::tie( ctx, ignored) = ctx( const_cast< T * >( & data) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
void
push_coroutine< T >::control_block::resume( T && data) {
// pass an pointer to other context
void * ignored;
std::tie( ctx, ignored) = ctx( std::addressof( data) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
bool
push_coroutine< T >::control_block::valid() const noexcept {
return ctx ? true : false;
}
// push_coroutine< T & >
template< typename T >
template< typename StackAllocator, typename Fn >
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
other{ nullptr },
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
ctx{ std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void * data) mutable {
// create synthesized pull_coroutine< T >
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
pull_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb;
// set transferred value
synthesized_cb.t = static_cast< T * >( data);
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized pull_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
},
std::forward< Fn >( fn),
std::placeholders::_1,
std::placeholders::_2))},
#else
ctx{ std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void * data) mutable {
// create synthesized pull_coroutine< T >
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
pull_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb;
// set transferred value
synthesized_cb.t = static_cast< T * >( data);
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized pull_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
}},
#endif
except{} {
}
template< typename T >
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
boost::context::captured_context & ctx_) noexcept :
other{ cb },
ctx{ std::move( ctx_) },
except{} {
}
template< typename T >
void
push_coroutine< T & >::control_block::resume( T & t) {
// pass an pointer to other context
void * ignored;
std::tie( ctx, ignored) = ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
bool
push_coroutine< T & >::control_block::valid() const noexcept {
return ctx ? true : false;
}
// push_coroutine< void >
template< typename StackAllocator, typename Fn >
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
other{ nullptr },
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
ctx{ std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
// create synthesized pull_coroutine< T >
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
pull_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized pull_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
},
std::forward< Fn >( fn),
std::placeholders::_1,
std::placeholders::_2))},
#else
ctx{ std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
// create synthesized pull_coroutine< T >
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx};
pull_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
try {
auto fn = std::move( fn_);
// call coroutine-fn with synthesized pull_coroutine as argument
fn( synthesized);
} catch ( boost::context::detail::forced_unwind const&) {
throw;
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// jump back to ctx
return std::move( other->ctx);
}},
#endif
except{} {
}
inline
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
boost::context::captured_context & ctx_) noexcept :
other{ cb },
ctx{ std::move( ctx_) },
except{} {
}
inline
void
push_coroutine< void >::control_block::resume() {
void * ignored;
std::tie( ctx, ignored) = ctx();
if ( except) {
std::rethrow_exception( except);
}
}
inline
bool
push_coroutine< void >::control_block::valid() const noexcept {
return ctx ? true : false;
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP

View File

@ -116,9 +116,8 @@ template< typename T >
push_coroutine< T >::control_block::~control_block() noexcept {
if ( state_t::none == ( state & state_t::complete) &&
state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag
state |= state_t::early_exit;
ctx();
// unwind coroutine stack
ctx( context::exec_ontop_arg, unwind_coroutine);
}
}
@ -131,10 +130,6 @@ push_coroutine< T >::control_block::resume( T const& t) {
if ( except) {
std::rethrow_exception( except);
}
// test early-exit-flag
if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind();
}
}
template< typename T >
@ -146,10 +141,6 @@ push_coroutine< T >::control_block::resume( T && t) {
if ( except) {
std::rethrow_exception( except);
}
// test early-exit-flag
if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind();
}
}
template< typename T >
@ -245,9 +236,8 @@ template< typename T >
push_coroutine< T & >::control_block::~control_block() noexcept {
if ( state_t::none == ( state & state_t::complete) &&
state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag
state |= state_t::early_exit;
ctx();
// unwind coroutine stack
ctx( context::exec_ontop_arg, unwind_coroutine);
}
}
@ -260,10 +250,6 @@ push_coroutine< T & >::control_block::resume( T & t) {
if ( except) {
std::rethrow_exception( except);
}
// test early-exit-flag
if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind();
}
}
template< typename T >
@ -354,9 +340,8 @@ inline
push_coroutine< void >::control_block::~control_block() noexcept {
if ( state_t::none == ( state & state_t::complete) &&
state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag
state |= state_t::early_exit;
ctx();
// unwind coroutine stack
ctx( context::exec_ontop_arg, unwind_coroutine);
}
}
@ -368,10 +353,6 @@ push_coroutine< void >::control_block::resume() {
if ( except) {
std::rethrow_exception( except);
}
// test early-exit-flag
if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind();
}
}
inline

View File

@ -25,8 +25,7 @@ namespace detail {
enum class state_t : unsigned int {
none = 0,
complete = 1 << 1,
unwind = 1 << 2,
early_exit = 1 << 3
unwind = 1 << 2
};