add support for callcc()

This commit is contained in:
Oliver Kowalke 2017-01-01 14:35:39 +01:00
parent b7e1be3713
commit 9a166cd623
12 changed files with 920 additions and 859 deletions

View File

@ -40,6 +40,6 @@ exe parser
: parser.cpp : parser.cpp
; ;
exe segmented #exe segmented
: segmented.cpp # : segmented.cpp
; # ;

View File

@ -36,15 +36,9 @@ void bar( int i)
int main() { int main() {
int count = 384; int count = 384;
#if defined(BOOST_USE_SEGMENTED_STACKS)
std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
std::cout << "initial stack size = " << boost::context::segmented_stack::traits_type::default_size() / 1024 << "kB" << std::endl; std::cout << "initial stack size = " << boost::context::segmented_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
std::cout << "application should not fail" << std::endl; std::cout << "application should not fail" << std::endl;
#else
std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
std::cout << "initial stack size = " << boost::context::fixedsize_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
std::cout << "application might fail" << std::endl;
#endif
boost::coroutines2::coroutine< void >::push_type sink( boost::coroutines2::coroutine< void >::push_type sink(
[&]( boost::coroutines2::coroutine< void >::pull_type & source) { [&]( boost::coroutines2::coroutine< void >::pull_type & source) {

View File

@ -34,8 +34,8 @@ class push_coroutine;
# include <boost/coroutine2/detail/pull_control_block_ecv1.hpp> # include <boost/coroutine2/detail/pull_control_block_ecv1.hpp>
# include <boost/coroutine2/detail/push_control_block_ecv1.hpp> # include <boost/coroutine2/detail/push_control_block_ecv1.hpp>
# else # else
# include <boost/coroutine2/detail/pull_control_block_ecv2.hpp> # include <boost/coroutine2/detail/pull_control_block_cc.hpp>
# include <boost/coroutine2/detail/push_control_block_ecv2.hpp> # include <boost/coroutine2/detail/push_control_block_cc.hpp>
# endif # endif
# include <boost/coroutine2/detail/pull_coroutine.ipp> # include <boost/coroutine2/detail/pull_coroutine.ipp>
@ -45,8 +45,8 @@ class push_coroutine;
# include <boost/coroutine2/detail/pull_control_block_ecv1.ipp> # include <boost/coroutine2/detail/pull_control_block_ecv1.ipp>
# include <boost/coroutine2/detail/push_control_block_ecv1.ipp> # include <boost/coroutine2/detail/push_control_block_ecv1.ipp>
# else # else
# include <boost/coroutine2/detail/pull_control_block_ecv2.ipp> # include <boost/coroutine2/detail/pull_control_block_cc.ipp>
# include <boost/coroutine2/detail/push_control_block_ecv2.ipp> # include <boost/coroutine2/detail/push_control_block_cc.ipp>
# endif # endif
#endif #endif

View File

@ -12,8 +12,6 @@
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS #ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX # include BOOST_ABI_PREFIX
#endif #endif

View File

@ -1,5 +1,5 @@
// Copyright Oliver Kowalke 2014. // Copyright Oliver Kowalke 2016.
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
@ -11,7 +11,7 @@
#include <type_traits> #include <type_traits>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp> #include <boost/context/continuation.hpp>
#include <boost/coroutine2/detail/state.hpp> #include <boost/coroutine2/detail/state.hpp>
@ -25,7 +25,7 @@ namespace detail {
template< typename T > template< typename T >
struct pull_coroutine< T >::control_block { struct pull_coroutine< T >::control_block {
boost::context::execution_context< T * > ctx; boost::context::continuation c;
typename push_coroutine< T >::control_block * other; typename push_coroutine< T >::control_block * other;
state_t state; state_t state;
std::exception_ptr except; std::exception_ptr except;
@ -37,7 +37,7 @@ struct pull_coroutine< T >::control_block {
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&); control_block( context::preallocated, StackAllocator, Fn &&);
control_block( typename push_coroutine< T >::control_block *, boost::context::execution_context< T * > &) noexcept; control_block( typename push_coroutine< T >::control_block *, boost::context::continuation &) noexcept;
~control_block(); ~control_block();
@ -48,7 +48,9 @@ struct pull_coroutine< T >::control_block {
void resume(); void resume();
void set( T *); void set( T const&);
void set( T &&);
void reset();
T & get() noexcept; T & get() noexcept;
@ -57,18 +59,27 @@ struct pull_coroutine< T >::control_block {
template< typename T > template< typename T >
struct pull_coroutine< T & >::control_block { struct pull_coroutine< T & >::control_block {
boost::context::execution_context< T * > ctx; struct holder {
typename push_coroutine< T & >::control_block * other; T & t;
state_t state;
std::exception_ptr except; holder( T & t_) :
T * t; t{ t_ } {
}
};
boost::context::continuation c;
typename push_coroutine< T & >::control_block * other;
state_t state;
std::exception_ptr except;
bool bvalid;
typename std::aligned_storage< sizeof( holder), alignof( holder) >::type storage;
static void destroy( control_block * cb) noexcept; static void destroy( control_block * cb) noexcept;
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&); control_block( context::preallocated, StackAllocator, Fn &&);
control_block( typename push_coroutine< T & >::control_block *, boost::context::execution_context< T * > &) noexcept; control_block( typename push_coroutine< T & >::control_block *, boost::context::continuation &) noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;
@ -77,13 +88,16 @@ struct pull_coroutine< T & >::control_block {
void resume(); void resume();
void set( T &);
void reset();
T & get() noexcept; T & get() noexcept;
bool valid() const noexcept; bool valid() const noexcept;
}; };
struct pull_coroutine< void >::control_block { struct pull_coroutine< void >::control_block {
boost::context::execution_context< void > ctx; boost::context::continuation c;
push_coroutine< void >::control_block * other; push_coroutine< void >::control_block * other;
state_t state; state_t state;
std::exception_ptr except; std::exception_ptr except;
@ -93,7 +107,7 @@ struct pull_coroutine< void >::control_block {
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&); control_block( context::preallocated, StackAllocator, Fn &&);
control_block( push_coroutine< void >::control_block *, boost::context::execution_context< void > &) noexcept; control_block( push_coroutine< void >::control_block *, boost::context::continuation &) noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;

View File

@ -0,0 +1,460 @@
// Copyright Oliver Kowalke 2016.
// 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/continuation.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 >
void
pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
boost::context::continuation c = std::move( cb->c);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
boost::context::callcc( std::move( c) );
}
template< typename T >
template< typename StackAllocator, typename Fn >
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
c{},
other{ nullptr },
state{ state_t::unwind },
except{},
bvalid{ false },
storage{} {
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
// create synthesized push_coroutine< T >
typename push_coroutine< T >::control_block synthesized_cb{ this, c };
push_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
},
std::forward< Fn >( fn),
std::placeholders::_1) ) );
#else
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
// create synthesized push_coroutine< T >
typename push_coroutine< T >::control_block synthesized_cb{ this, c };
push_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
});
#endif
if ( boost::context::has_data( c) ) {
set( boost::context::data< T >( c) );
}
}
template< typename T >
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
boost::context::continuation & c_) noexcept :
c{ std::move( c_) },
other{ cb },
state{ state_t::none },
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::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
template< typename T >
void
pull_coroutine< T >::control_block::resume() {
c = boost::context::callcc( std::move( c) );
if ( boost::context::has_data( c) ) {
set( boost::context::data< T >( c) );
} else {
reset();
}
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
void
pull_coroutine< T >::control_block::set( T const& t) {
// destroy data if set
if ( bvalid) {
reinterpret_cast< T * >( std::addressof( storage) )->~T();
}
::new ( static_cast< void * >( std::addressof( storage) ) ) T( t);
bvalid = true;
}
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();
}
::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( t) );
bvalid = true;
}
template< typename T >
void
pull_coroutine< T >::control_block::reset() {
// destroy data if set
if ( bvalid) {
reinterpret_cast< T * >( std::addressof( storage) )->~T();
}
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 && state_t::none == ( state & state_t::complete) && bvalid;
}
// pull_coroutine< T & >
template< typename T >
void
pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
boost::context::continuation c = std::move( cb->c);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
boost::context::callcc( std::move( c) );
}
template< typename T >
template< typename StackAllocator, typename Fn >
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
c{},
other{ nullptr },
state{ state_t::unwind },
except{},
bvalid{ false },
storage{} {
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
// create synthesized push_coroutine< T & >
typename push_coroutine< T & >::control_block synthesized_cb{ this, c };
push_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
},
std::forward< Fn >( fn),
std::placeholders::_1) ) );
#else
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
// create synthesized push_coroutine< T & >
typename push_coroutine< T & >::control_block synthesized_cb{ this, c };
push_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
});
#endif
if ( boost::context::has_data( c) ) {
set( boost::context::data< T & >( c) );
}
}
template< typename T >
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
boost::context::continuation & c_) noexcept :
c{ std::move( c_) },
other{ cb },
state{ state_t::none },
except{},
bvalid{ false },
storage{} {
}
template< typename T >
void
pull_coroutine< T & >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
template< typename T >
void
pull_coroutine< T & >::control_block::resume() {
c = boost::context::callcc( std::move( c) );
if ( boost::context::has_data( c) ) {
set( boost::context::data< T & >( c) );
} else {
reset();
}
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
void
pull_coroutine< T & >::control_block::set( T & t) {
::new ( static_cast< void * >( std::addressof( storage) ) ) holder{ t };
bvalid = true;
}
template< typename T >
void
pull_coroutine< T & >::control_block::reset() {
if ( bvalid) {
reinterpret_cast< holder * >( std::addressof( storage) )->~holder();
}
bvalid = false;
}
template< typename T >
T &
pull_coroutine< T & >::control_block::get() noexcept {
return reinterpret_cast< holder * >( std::addressof( storage) )->t;
}
template< typename T >
bool
pull_coroutine< T & >::control_block::valid() const noexcept {
return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
}
// pull_coroutine< void >
inline
void
pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
boost::context::continuation c = std::move( cb->c);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
boost::context::callcc( std::move( c) );
}
template< typename StackAllocator, typename Fn >
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
c{},
other{ nullptr },
state{ state_t::unwind },
except{} {
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
// create synthesized push_coroutine< void >
typename push_coroutine< void >::control_block synthesized_cb{ this, c };
push_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
},
std::forward< Fn >( fn),
std::placeholders::_1) ) );
#else
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::continuation && c) mutable {
// create synthesized push_coroutine< void >
typename push_coroutine< void >::control_block synthesized_cb{ this, c };
push_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
return boost::context::callcc( std::move( other->c) );
});
#endif
}
inline
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
boost::context::continuation & c_) noexcept :
c{ std::move( c_) },
other{ cb },
state{ state_t::none },
except{} {
}
inline
void
pull_coroutine< void >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
inline
void
pull_coroutine< void >::control_block::resume() {
c = boost::context::callcc( std::move( c) );
if ( except) {
std::rethrow_exception( except);
}
}
inline
bool
pull_coroutine< void >::control_block::valid() const noexcept {
return nullptr != other && state_t::none == ( state & state_t::complete);
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP

View File

@ -1,422 +0,0 @@
// 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/execution_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 >
void
pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
boost::context::execution_context< T * > ctx = std::move( cb->ctx);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
ctx( nullptr);
}
template< typename T >
template< typename StackAllocator, typename Fn >
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
#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::execution_context< T * > && ctx, T *) 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;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
auto result = other->ctx( nullptr);
other->ctx = std::move( std::get< 0 >( result) );
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::execution_context< T * > && ctx, T *) 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;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
auto result = other->ctx( nullptr);
other->ctx = std::move( std::get< 0 >( result) );
return std::move( other->ctx);
}},
#endif
other{ nullptr },
state{ state_t::unwind },
except{},
bvalid{ false },
storage{} {
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
resume();
}
template< typename T >
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
boost::context::execution_context< T * > & ctx_) noexcept :
ctx{ std::move( ctx_) },
other{ cb },
state{ state_t::none },
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::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
template< typename T >
void
pull_coroutine< T >::control_block::resume() {
auto result = ctx( nullptr);
ctx = std::move( std::get< 0 >( result) );
set( std::get< 1 >( result) );
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 && state_t::none == ( state & state_t::complete) && bvalid;
}
// pull_coroutine< T & >
template< typename T >
void
pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
boost::context::execution_context< T * > ctx = std::move( cb->ctx);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
ctx( nullptr);
}
template< typename T >
template< typename StackAllocator, typename Fn >
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
#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::execution_context< T *> && ctx, T *) 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;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
auto result = other->ctx( nullptr);
other->ctx = std::move( std::get< 0 >( result) );
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::execution_context< T * > && ctx, T *) 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;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
auto result = other->ctx( nullptr);
other->ctx = std::move( std::get< 0 >( result) );
return std::move( other->ctx);
}},
#endif
other{ nullptr },
state{ state_t::unwind },
except{},
t{ nullptr } {
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
resume();
}
template< typename T >
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
boost::context::execution_context< T * > & ctx_) noexcept :
ctx{ std::move( ctx_) },
other{ cb },
state{ state_t::none },
except{},
t{ nullptr } {
}
template< typename T >
void
pull_coroutine< T & >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
template< typename T >
void
pull_coroutine< T & >::control_block::resume() {
auto result = ctx( nullptr);
ctx = std::move( std::get< 0 >( result) );
t = std::get< 1 >( result);
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
T &
pull_coroutine< T & >::control_block::get() noexcept {
return * t;
}
template< typename T >
bool
pull_coroutine< T & >::control_block::valid() const noexcept {
return nullptr != other && state_t::none == ( state & state_t::complete) && nullptr != t;
}
// pull_coroutine< void >
inline
void
pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
boost::context::execution_context< void > ctx = std::move( cb->ctx);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
ctx();
}
template< typename StackAllocator, typename Fn >
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
#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::execution_context< void > && ctx) mutable {
// create synthesized push_coroutine< void >
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
push_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
other->ctx = other->ctx();
return std::move( other->ctx);
},
std::forward< Fn >( fn),
std::placeholders::_1))},
#else
ctx{ std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< void > && ctx) mutable {
// create synthesized push_coroutine< void >
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
push_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
other->ctx = other->ctx();
return std::move( other->ctx);
}},
#endif
other{ nullptr },
state{ state_t::unwind },
except{} {
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
resume();
}
inline
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
boost::context::execution_context< void > & ctx_) noexcept :
ctx{ std::move( ctx_) },
other{ cb },
state{ state_t::none },
except{} {
}
inline
void
pull_coroutine< void >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
inline
void
pull_coroutine< void >::control_block::resume() {
ctx = ctx();
if ( except) {
std::rethrow_exception( except);
}
}
inline
bool
pull_coroutine< void >::control_block::valid() const noexcept {
return nullptr != other && state_t::none == ( state & state_t::complete);
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP

View File

@ -10,7 +10,7 @@
#include <exception> #include <exception>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp> #include <boost/context/continuation.hpp>
#include <boost/coroutine2/detail/state.hpp> #include <boost/coroutine2/detail/state.hpp>
@ -24,7 +24,7 @@ namespace detail {
template< typename T > template< typename T >
struct push_coroutine< T >::control_block { struct push_coroutine< T >::control_block {
boost::context::execution_context< T * > ctx; boost::context::continuation c;
typename pull_coroutine< T >::control_block * other; typename pull_coroutine< T >::control_block * other;
state_t state; state_t state;
std::exception_ptr except; std::exception_ptr except;
@ -34,7 +34,7 @@ struct push_coroutine< T >::control_block {
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&); control_block( context::preallocated, StackAllocator, Fn &&);
control_block( typename pull_coroutine< T >::control_block *, boost::context::execution_context< T * > &) noexcept; control_block( typename pull_coroutine< T >::control_block *, boost::context::continuation &) noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;
@ -50,7 +50,7 @@ struct push_coroutine< T >::control_block {
template< typename T > template< typename T >
struct push_coroutine< T & >::control_block { struct push_coroutine< T & >::control_block {
boost::context::execution_context< T * > ctx; boost::context::continuation c;
typename pull_coroutine< T & >::control_block * other; typename pull_coroutine< T & >::control_block * other;
state_t state; state_t state;
std::exception_ptr except; std::exception_ptr except;
@ -60,7 +60,7 @@ struct push_coroutine< T & >::control_block {
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&); control_block( context::preallocated, StackAllocator, Fn &&);
control_block( typename pull_coroutine< T & >::control_block *, boost::context::execution_context< T * > &) noexcept; control_block( typename pull_coroutine< T & >::control_block *, boost::context::continuation &) noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;
@ -73,7 +73,7 @@ struct push_coroutine< T & >::control_block {
}; };
struct push_coroutine< void >::control_block { struct push_coroutine< void >::control_block {
boost::context::execution_context< void > ctx; boost::context::continuation c;
pull_coroutine< void >::control_block * other; pull_coroutine< void >::control_block * other;
state_t state; state_t state;
std::exception_ptr except; std::exception_ptr except;
@ -83,7 +83,7 @@ struct push_coroutine< void >::control_block {
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&); control_block( context::preallocated, StackAllocator, Fn &&);
control_block( pull_coroutine< void >::control_block *, boost::context::execution_context< void > &) noexcept; control_block( pull_coroutine< void >::control_block *, boost::context::continuation &) noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;

View File

@ -0,0 +1,408 @@
// 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/continuation.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 >
void
push_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
boost::context::continuation c = std::move( cb->c);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
boost::context::callcc( std::move( c) );
}
template< typename T >
template< typename StackAllocator, typename Fn >
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
c{},
other{ nullptr },
state{ state_t::unwind },
except{} {
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
// create synthesized pull_coroutine< T >
typename pull_coroutine< T >::control_block synthesized_cb{ this, c };
pull_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb;
other->c = boost::context::callcc( std::move( other->c) );
// set transferred value
if ( boost::context::has_data( other->c) ) {
synthesized_cb.set( boost::context::data< T >( other->c) );
} else {
synthesized_cb.reset();
}
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
},
std::forward< Fn >( fn),
std::placeholders::_1) ) );
#else
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
// create synthesized pull_coroutine< T >
typename pull_coroutine< T >::control_block synthesized_cb{ this, c };
pull_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb;
other->c = boost::context::callcc( std::move( other->c) );
// set transferred value
if ( boost::context::has_data( other->c) ) {
synthesized_cb.set( boost::context::data< T >( other->c) );
} else {
synthesized_cb.reset();
}
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
});
#endif
}
template< typename T >
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
boost::context::continuation & c_) noexcept :
c{ std::move( c_) },
other{ cb },
state{ state_t::none },
except{} {
}
template< typename T >
void
push_coroutine< T >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
template< typename T >
void
push_coroutine< T >::control_block::resume( T const& data) {
// pass an pointer to other context
c = boost::context::callcc( std::move( c), 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
c = boost::context::callcc( std::move( c), std::move( data) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
bool
push_coroutine< T >::control_block::valid() const noexcept {
return state_t::none == ( state & state_t::complete );
}
// push_coroutine< T & >
template< typename T >
void
push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
boost::context::continuation c = std::move( cb->c);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
boost::context::callcc( std::move( c) );
}
template< typename T >
template< typename StackAllocator, typename Fn >
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
c{},
other{ nullptr },
state{ state_t::unwind },
except{} {
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
// create synthesized pull_coroutine< T & >
typename pull_coroutine< T & >::control_block synthesized_cb{ this, c };
pull_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb;
other->c = boost::context::callcc( std::move( other->c) );
// set transferred value
if ( boost::context::has_data( other->c) ) {
synthesized_cb.set( boost::context::data< T & >( other->c) );
} else {
synthesized_cb.reset();
}
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
},
std::forward< Fn >( fn),
std::placeholders::_1) ) );
#else
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
// create synthesized pull_coroutine< T & >
typename pull_coroutine< T & >::control_block synthesized_cb{ this, c };
pull_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb;
other->c = boost::context::callcc( std::move( other->c) );
// set transferred value
if ( boost::context::has_data( other->c) ) {
synthesized_cb.set( boost::context::data< T & >( other->c) );
} else {
synthesized_cb.reset();
}
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
});
#endif
}
template< typename T >
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
boost::context::continuation & c_) noexcept :
c{ std::move( c_) },
other{ cb },
state{ state_t::none },
except{} {
}
template< typename T >
void
push_coroutine< T & >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
template< typename T >
void
push_coroutine< T & >::control_block::resume( T & t) {
// pass an pointer to other context
c = boost::context::callcc( std::move( c), std::ref( t) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
bool
push_coroutine< T & >::control_block::valid() const noexcept {
return state_t::none == ( state & state_t::complete );
}
// push_coroutine< void >
inline
void
push_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
boost::context::continuation c = std::move( cb->c);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
boost::context::callcc( std::move( c) );
}
template< typename StackAllocator, typename Fn >
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
c{},
other{ nullptr },
state{ state_t::unwind },
except{} {
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
std::move(
std::bind(
[this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
// create synthesized pull_coroutine< void >
typename pull_coroutine< void >::control_block synthesized_cb{ this, c };
pull_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
other->c = boost::context::callcc( std::move( other->c) );
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
},
std::forward< Fn >( fn),
std::placeholders::_1) ) );
#else
c = boost::context::callcc(
std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
// create synthesized pull_coroutine< void >
typename pull_coroutine< void >::control_block synthesized_cb{ this, c};
pull_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
other->c = boost::context::callcc( std::move( other->c) );
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back
return boost::context::callcc( std::move( other->c) );
});
#endif
}
inline
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
boost::context::continuation & c_) noexcept :
c{ std::move( c_) },
other{ cb },
state{ state_t::none },
except{} {
}
inline
void
push_coroutine< void >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
inline
void
push_coroutine< void >::control_block::resume() {
c = boost::context::callcc( std::move( c) );
if ( except) {
std::rethrow_exception( except);
}
}
inline
bool
push_coroutine< void >::control_block::valid() const noexcept {
return state_t::none == ( state & state_t::complete );
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP

View File

@ -1,392 +0,0 @@
// 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/execution_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 >
void
push_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
boost::context::execution_context< T * > ctx = std::move( cb->ctx);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
ctx( nullptr);
}
template< typename T >
template< typename StackAllocator, typename Fn >
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
#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::execution_context< T * > && ctx, T * 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( data);
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
auto result = other->ctx( nullptr);
other->ctx = std::move( std::get< 0 >( result) );
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::execution_context< T * > && ctx, T * 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( data);
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
auto result = other->ctx( nullptr);
other->ctx = std::move( std::get< 0 >( result) );
return std::move( other->ctx);
}},
#endif
other{ nullptr },
state{ state_t::unwind },
except{} {
}
template< typename T >
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
boost::context::execution_context< T * > & ctx_) noexcept :
ctx{ std::move( ctx_) },
other{ cb },
state{ state_t::none },
except{} {
}
template< typename T >
void
push_coroutine< T >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
template< typename T >
void
push_coroutine< T >::control_block::resume( T const& data) {
// pass an pointer to other context
auto result = ctx( const_cast< T * >( & data) );
ctx = std::move( std::get< 0 >( result) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
void
push_coroutine< T >::control_block::resume( T && data) {
// pass an pointer to other context
auto result = ctx( std::addressof( data) );
ctx = std::move( std::get< 0 >( result) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
bool
push_coroutine< T >::control_block::valid() const noexcept {
return state_t::none == ( state & state_t::complete );
}
// push_coroutine< T & >
template< typename T >
void
push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
boost::context::execution_context< T * > ctx = std::move( cb->ctx);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
ctx( nullptr);
}
template< typename T >
template< typename StackAllocator, typename Fn >
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn) :
#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::execution_context< T * > && ctx, T * 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 = data;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
auto result = other->ctx( nullptr);
other->ctx = std::move( std::get< 0 >( result) );
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::execution_context< T * > && ctx, T * 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 = data;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
auto result = other->ctx( nullptr);
other->ctx = std::move( std::get< 0 >( result) );
return std::move( other->ctx);
}},
#endif
other{ nullptr },
state{ state_t::unwind },
except{} {
}
template< typename T >
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
boost::context::execution_context< T * > & ctx_) noexcept :
ctx{ std::move( ctx_) },
other{ cb },
state{ state_t::none },
except{} {
}
template< typename T >
void
push_coroutine< T & >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
template< typename T >
void
push_coroutine< T & >::control_block::resume( T & t) {
// pass an pointer to other context
auto result = ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) );
ctx = std::move( std::get< 0 >( result) );
if ( except) {
std::rethrow_exception( except);
}
}
template< typename T >
bool
push_coroutine< T & >::control_block::valid() const noexcept {
return state_t::none == ( state & state_t::complete );
}
// push_coroutine< void >
inline
void
push_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
boost::context::execution_context< void > ctx = std::move( cb->ctx);
// destroy control structure
cb->~control_block();
// destroy coroutine's stack
cb->state |= state_t::destroy;
ctx();
}
template< typename StackAllocator, typename Fn >
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
#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::execution_context< void > && ctx) mutable {
// create synthesized pull_coroutine< void >
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
pull_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
other->ctx = other->ctx();
return std::move( other->ctx);
},
std::forward< Fn >( fn),
std::placeholders::_1))},
#else
ctx{ std::allocator_arg, palloc, salloc,
[this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< void > && ctx) mutable {
// create synthesized pull_coroutine< void >
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx};
pull_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb;
if ( state_t::none == ( state & state_t::destroy) ) {
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();
}
}
// set termination flags
state |= state_t::complete;
// jump back to ctx
other->ctx = other->ctx();
return std::move( other->ctx);
}},
#endif
other{ nullptr },
state{ state_t::unwind },
except{} {
}
inline
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
boost::context::execution_context< void > & ctx_) noexcept :
ctx{ std::move( ctx_) },
other{ cb },
state{ state_t::none },
except{} {
}
inline
void
push_coroutine< void >::control_block::deallocate() noexcept {
if ( state_t::none != ( state & state_t::unwind) ) {
destroy( this);
}
}
inline
void
push_coroutine< void >::control_block::resume() {
ctx = ctx();
if ( except) {
std::rethrow_exception( except);
}
}
inline
bool
push_coroutine< void >::control_block::valid() const noexcept {
return state_t::none == ( state & state_t::complete );
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP

View File

@ -79,7 +79,7 @@ public:
} }
iterator & operator=( T t) { iterator & operator=( T t) {
BOOST_ASSERT( c_); BOOST_ASSERT( nullptr != c_);
if ( ! ( * c_)( t) ) { if ( ! ( * c_)( t) ) {
c_ = nullptr; c_ = nullptr;
} }
@ -157,7 +157,7 @@ public:
} }
iterator & operator=( T & t) { iterator & operator=( T & t) {
BOOST_ASSERT( c_); BOOST_ASSERT( nullptr != c_);
if ( ! ( * c_)( t) ) { if ( ! ( * c_)( t) ) {
c_ = nullptr; c_ = nullptr;
} }

View File

@ -24,7 +24,7 @@ int value1 = 0;
std::string value2 = ""; std::string value2 = "";
bool value3 = false; bool value3 = false;
double value4 = .0; double value4 = .0;
int * value5 = 0; int * value5 = nullptr;
int& value6 = value1; int& value6 = value1;
int& value7 = value1; int& value7 = value1;
int value8 = 0; int value8 = 0;
@ -171,7 +171,7 @@ void f91( coro::coroutine< int const* >::pull_type & c)
void f10( coro::coroutine< int & >::pull_type & c) void f10( coro::coroutine< int & >::pull_type & c)
{ {
int const& i = c.get(); int & i = c.get();
value5 = const_cast< int * >( & i); value5 = const_cast< int * >( & i);
} }
@ -370,7 +370,7 @@ void test_fp()
void test_ptr() void test_ptr()
{ {
value5 = 0; value5 = nullptr;
int a = 3; int a = 3;
coro::coroutine< int * >::push_type coro( f9); coro::coroutine< int * >::push_type coro( f9);
@ -382,7 +382,7 @@ void test_ptr()
void test_const_ptr() void test_const_ptr()
{ {
value5 = 0; value5 = nullptr;
int a = 3; int a = 3;
coro::coroutine< int const* >::push_type coro( f91); coro::coroutine< int const* >::push_type coro( f91);
@ -394,19 +394,20 @@ void test_const_ptr()
void test_ref() void test_ref()
{ {
value5 = 0; value5 = nullptr;
int a = 3; int a_ = 3;
int & a = a_;
coro::coroutine< int & >::push_type coro( f10); coro::coroutine< int & >::push_type coro( f10);
BOOST_CHECK( coro); BOOST_CHECK( coro);
coro( a); coro( std::ref( a) );
BOOST_CHECK( ! coro); BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5); BOOST_CHECK_EQUAL( & a, value5);
} }
void test_const_ref() void test_const_ref()
{ {
value5 = 0; value5 = nullptr;
int a = 3; int a = 3;
coro::coroutine< int const& >::push_type coro( f101); coro::coroutine< int const& >::push_type coro( f101);