diff options
Diffstat (limited to 'boost/coroutine2')
-rw-r--r-- | boost/coroutine2/detail/config.hpp | 3 | ||||
-rw-r--r-- | boost/coroutine2/detail/coroutine.hpp | 8 | ||||
-rw-r--r-- | boost/coroutine2/detail/forced_unwind.hpp | 2 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_control_block_cc.hpp (renamed from boost/coroutine2/detail/pull_control_block_ecv2.hpp) | 40 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_control_block_cc.ipp | 452 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_control_block_ecv1.ipp | 22 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_control_block_ecv2.ipp | 422 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_coroutine.hpp | 4 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_control_block_cc.hpp (renamed from boost/coroutine2/detail/push_control_block_ecv2.hpp) | 14 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_control_block_cc.ipp | 400 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_control_block_ecv1.ipp | 22 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_control_block_ecv2.ipp | 392 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_coroutine.hpp | 8 | ||||
-rw-r--r-- | boost/coroutine2/detail/wrap.hpp | 112 |
14 files changed, 1023 insertions, 878 deletions
diff --git a/boost/coroutine2/detail/config.hpp b/boost/coroutine2/detail/config.hpp index cfb95846a5..307ee4e78a 100644 --- a/boost/coroutine2/detail/config.hpp +++ b/boost/coroutine2/detail/config.hpp @@ -18,7 +18,6 @@ #if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES2_DYN_LINK) ) && ! defined(BOOST_COROUTINES2_STATIC_LINK) # if defined(BOOST_COROUTINES2_SOURCE) # define BOOST_COROUTINES2_DECL BOOST_SYMBOL_EXPORT -# define BOOST_COROUTINES2_BUILD_DLL # else # define BOOST_COROUTINES2_DECL BOOST_SYMBOL_IMPORT # endif @@ -29,7 +28,7 @@ #endif #if ! defined(BOOST_COROUTINES2_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_COROUTINES2_NO_LIB) -# define BOOST_LIB_NAME boost_coroutine +# define BOOST_LIB_NAME boost_coroutine2 # if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES2_DYN_LINK) # define BOOST_DYN_LINK # endif diff --git a/boost/coroutine2/detail/coroutine.hpp b/boost/coroutine2/detail/coroutine.hpp index 7c1483d3be..1170590183 100644 --- a/boost/coroutine2/detail/coroutine.hpp +++ b/boost/coroutine2/detail/coroutine.hpp @@ -34,8 +34,8 @@ class push_coroutine; # include <boost/coroutine2/detail/pull_control_block_ecv1.hpp> # include <boost/coroutine2/detail/push_control_block_ecv1.hpp> # else -# include <boost/coroutine2/detail/pull_control_block_ecv2.hpp> -# include <boost/coroutine2/detail/push_control_block_ecv2.hpp> +# include <boost/coroutine2/detail/pull_control_block_cc.hpp> +# include <boost/coroutine2/detail/push_control_block_cc.hpp> # endif # 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/push_control_block_ecv1.ipp> # else -# include <boost/coroutine2/detail/pull_control_block_ecv2.ipp> -# include <boost/coroutine2/detail/push_control_block_ecv2.ipp> +# include <boost/coroutine2/detail/pull_control_block_cc.ipp> +# include <boost/coroutine2/detail/push_control_block_cc.ipp> # endif #endif diff --git a/boost/coroutine2/detail/forced_unwind.hpp b/boost/coroutine2/detail/forced_unwind.hpp index 0f67f79a5f..d486ed43dd 100644 --- a/boost/coroutine2/detail/forced_unwind.hpp +++ b/boost/coroutine2/detail/forced_unwind.hpp @@ -12,8 +12,6 @@ #include <boost/assert.hpp> #include <boost/config.hpp> -#include <boost/context/execution_context.hpp> - #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif diff --git a/boost/coroutine2/detail/pull_control_block_ecv2.hpp b/boost/coroutine2/detail/pull_control_block_cc.hpp index 58d248833a..44a14e2102 100644 --- a/boost/coroutine2/detail/pull_control_block_ecv2.hpp +++ b/boost/coroutine2/detail/pull_control_block_cc.hpp @@ -1,5 +1,5 @@ -// Copyright Oliver Kowalke 2014. +// 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) @@ -11,7 +11,7 @@ #include <type_traits> #include <boost/config.hpp> -#include <boost/context/execution_context.hpp> +#include <boost/context/continuation.hpp> #include <boost/coroutine2/detail/state.hpp> @@ -25,7 +25,7 @@ namespace detail { template< typename T > struct pull_coroutine< T >::control_block { - boost::context::execution_context< T * > ctx; + boost::context::continuation c; typename push_coroutine< T >::control_block * other; state_t state; std::exception_ptr except; @@ -37,7 +37,7 @@ struct pull_coroutine< T >::control_block { template< typename StackAllocator, typename 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(); @@ -48,7 +48,9 @@ struct pull_coroutine< T >::control_block { void resume(); - void set( T *); + void set( T const&); + void set( T &&); + void reset(); T & get() noexcept; @@ -57,18 +59,27 @@ struct pull_coroutine< T >::control_block { template< typename T > struct pull_coroutine< T & >::control_block { - boost::context::execution_context< T * > ctx; - typename push_coroutine< T & >::control_block * other; - state_t state; - std::exception_ptr except; - T * t; + struct holder { + T & t; + + holder( 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; template< typename StackAllocator, typename 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 & operator=( control_block &) = delete; @@ -77,13 +88,16 @@ struct pull_coroutine< T & >::control_block { void resume(); + void set( T &); + void reset(); + T & get() noexcept; bool valid() const noexcept; }; struct pull_coroutine< void >::control_block { - boost::context::execution_context< void > ctx; + boost::context::continuation c; push_coroutine< void >::control_block * other; state_t state; std::exception_ptr except; @@ -93,7 +107,7 @@ struct pull_coroutine< void >::control_block { template< typename StackAllocator, typename 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 & operator=( control_block &) = delete; diff --git a/boost/coroutine2/detail/pull_control_block_cc.ipp b/boost/coroutine2/detail/pull_control_block_cc.ipp new file mode 100644 index 0000000000..0406202016 --- /dev/null +++ b/boost/coroutine2/detail/pull_control_block_cc.ipp @@ -0,0 +1,452 @@ + +// 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> +#include <boost/coroutine2/detail/wrap.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; + c.resume(); +} + +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, + wrap( [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 other->c.resume(); + }, + std::forward< Fn >( fn) ) ); +#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 other->c.resume(); + }); +#endif + if ( c.data_available() ) { + set( c.get_data< T >() ); + } +} + +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 = c.resume(); + if ( c.data_available() ) { + set( c.get_data< T >() ); + } 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; + c.resume(); +} + +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, + wrap( [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 other->c.resume(); + }, + std::forward< Fn >( fn) ) ); +#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 other->c.resume(); + }); +#endif + if ( c.data_available() ) { + set( c.get_data< T & >() ); + } +} + +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 = c.resume(); + if ( c.data_available() ) { + set( c.get_data< T & >() ); + } 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; + c.resume(); +} + +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, + wrap( [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 other->c.resume(); + }, + std::forward< Fn >( fn) ) ); +#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 other->c.resume(); + }); +#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 = c.resume(); + 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 diff --git a/boost/coroutine2/detail/pull_control_block_ecv1.ipp b/boost/coroutine2/detail/pull_control_block_ecv1.ipp index eb2ae2778f..77866041fe 100644 --- a/boost/coroutine2/detail/pull_control_block_ecv1.ipp +++ b/boost/coroutine2/detail/pull_control_block_ecv1.ipp @@ -20,6 +20,7 @@ #include <boost/coroutine2/detail/decay_copy.hpp> #include <boost/coroutine2/detail/forced_unwind.hpp> #include <boost/coroutine2/detail/state.hpp> +#include <boost/coroutine2/detail/wrap.hpp> #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -46,9 +47,7 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc, 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 & ctx, void *) mutable noexcept { + wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept { // create synthesized push_coroutine< T > typename push_coroutine< T >::control_block synthesized_cb{ this, ctx }; push_coroutine< T > synthesized{ & synthesized_cb }; @@ -72,8 +71,7 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc, BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); }, std::forward< Fn >( fn), - boost::context::execution_context::current(), - std::placeholders::_1))}, + boost::context::execution_context::current() ) }, #else ctx{ std::allocator_arg, palloc, salloc, [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { @@ -197,9 +195,7 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo 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 & ctx, void *) mutable noexcept { + wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept { // create synthesized push_coroutine< T > typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx }; push_coroutine< T & > synthesized{ & synthesized_cb }; @@ -223,8 +219,7 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); }, std::forward< Fn >( fn), - boost::context::execution_context::current(), - std::placeholders::_1))}, + boost::context::execution_context::current() ) }, #else ctx{ std::allocator_arg, palloc, salloc, [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { @@ -326,9 +321,7 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall 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 & ctx, void *) mutable noexcept { + wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept { // create synthesized push_coroutine< T > typename push_coroutine< void >::control_block synthesized_cb{ this, ctx }; push_coroutine< void > synthesized{ & synthesized_cb }; @@ -352,8 +345,7 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); }, std::forward< Fn >( fn), - boost::context::execution_context::current(), - std::placeholders::_1))}, + boost::context::execution_context::current() ) }, #else ctx{ std::allocator_arg, palloc, salloc, [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { diff --git a/boost/coroutine2/detail/pull_control_block_ecv2.ipp b/boost/coroutine2/detail/pull_control_block_ecv2.ipp deleted file mode 100644 index a1c7c93cd0..0000000000 --- a/boost/coroutine2/detail/pull_control_block_ecv2.ipp +++ /dev/null @@ -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 diff --git a/boost/coroutine2/detail/pull_coroutine.hpp b/boost/coroutine2/detail/pull_coroutine.hpp index b97bdc3e9c..f4c40733bb 100644 --- a/boost/coroutine2/detail/pull_coroutine.hpp +++ b/boost/coroutine2/detail/pull_coroutine.hpp @@ -92,7 +92,7 @@ public: typedef typename iterator::pointer pointer_t; typedef typename iterator::reference reference_t; - constexpr iterator() noexcept = default; + iterator() noexcept = default; explicit iterator( pull_coroutine< T > * c) noexcept : c_{ c } { @@ -204,7 +204,7 @@ public: typedef typename iterator::pointer pointer_t; typedef typename iterator::reference reference_t; - constexpr iterator() noexcept = default; + iterator() noexcept = default; explicit iterator( pull_coroutine< T & > * c) noexcept : c_{ c } { diff --git a/boost/coroutine2/detail/push_control_block_ecv2.hpp b/boost/coroutine2/detail/push_control_block_cc.hpp index feb5e4a61c..d01c98f089 100644 --- a/boost/coroutine2/detail/push_control_block_ecv2.hpp +++ b/boost/coroutine2/detail/push_control_block_cc.hpp @@ -10,7 +10,7 @@ #include <exception> #include <boost/config.hpp> -#include <boost/context/execution_context.hpp> +#include <boost/context/continuation.hpp> #include <boost/coroutine2/detail/state.hpp> @@ -24,7 +24,7 @@ namespace detail { template< typename T > struct push_coroutine< T >::control_block { - boost::context::execution_context< T * > ctx; + boost::context::continuation c; typename pull_coroutine< T >::control_block * other; state_t state; std::exception_ptr except; @@ -34,7 +34,7 @@ struct push_coroutine< T >::control_block { template< typename StackAllocator, typename 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 & operator=( control_block &) = delete; @@ -50,7 +50,7 @@ struct push_coroutine< T >::control_block { template< typename T > struct push_coroutine< T & >::control_block { - boost::context::execution_context< T * > ctx; + boost::context::continuation c; typename pull_coroutine< T & >::control_block * other; state_t state; std::exception_ptr except; @@ -60,7 +60,7 @@ struct push_coroutine< T & >::control_block { template< typename StackAllocator, typename 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 & operator=( control_block &) = delete; @@ -73,7 +73,7 @@ struct push_coroutine< T & >::control_block { }; struct push_coroutine< void >::control_block { - boost::context::execution_context< void > ctx; + boost::context::continuation c; pull_coroutine< void >::control_block * other; state_t state; std::exception_ptr except; @@ -83,7 +83,7 @@ struct push_coroutine< void >::control_block { template< typename StackAllocator, typename 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 & operator=( control_block &) = delete; diff --git a/boost/coroutine2/detail/push_control_block_cc.ipp b/boost/coroutine2/detail/push_control_block_cc.ipp new file mode 100644 index 0000000000..9972c7039f --- /dev/null +++ b/boost/coroutine2/detail/push_control_block_cc.ipp @@ -0,0 +1,400 @@ + +// 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> +#include <boost/coroutine2/detail/wrap.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; + c.resume(); +} + +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, + wrap( [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 = other->c.resume(); + // set transferred value + if ( other->c.data_available() ) { + synthesized_cb.set( other->c.template get_data< T >() ); + } 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 other->c.resume(); + }, + std::forward< Fn >( fn) ) ); +#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 = other->c.resume(); + // set transferred value + if ( other->c.data_available() ) { + synthesized_cb.set( other->c.template get_data< T >() ); + } 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 other->c.resume(); + }); +#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 = c.resume( 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 = c.resume( 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; + c.resume(); +} + +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, + wrap( [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 = other->c.resume(); + // set transferred value + if ( other->c.data_available() ) { + synthesized_cb.set( other->c.template get_data< T & >() ); + } 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 other->c.resume(); + }, + std::forward< Fn >( fn) ) ); +#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 = other->c.resume(); + // set transferred value + if ( other->c.data_available() ) { + synthesized_cb.set( other->c.template get_data< T & >() ); + } 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 other->c.resume(); + }); +#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 = c.resume( 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; + c.resume(); +} + +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, + wrap( [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 = other->c.resume(); + 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 other->c.resume(); + }, + std::forward< Fn >( fn) ) ); +#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 = other->c.resume(); + 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 other->c.resume(); + }); +#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 = c.resume(); + 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 diff --git a/boost/coroutine2/detail/push_control_block_ecv1.ipp b/boost/coroutine2/detail/push_control_block_ecv1.ipp index cc9622dfbe..8b4ae3fb04 100644 --- a/boost/coroutine2/detail/push_control_block_ecv1.ipp +++ b/boost/coroutine2/detail/push_control_block_ecv1.ipp @@ -21,6 +21,7 @@ #include <boost/coroutine2/detail/decay_copy.hpp> #include <boost/coroutine2/detail/forced_unwind.hpp> #include <boost/coroutine2/detail/state.hpp> +#include <boost/coroutine2/detail/wrap.hpp> #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -47,9 +48,7 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc, 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 & ctx, void * vp) mutable noexcept { + wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void * vp) mutable noexcept { // create synthesized pull_coroutine< T > typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx }; pull_coroutine< T > synthesized{ & synthesized_cb }; @@ -77,8 +76,7 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc, BOOST_ASSERT_MSG( false, "push_coroutine is complete"); }, std::forward< Fn >( fn), - boost::context::execution_context::current(), - std::placeholders::_1))}, + boost::context::execution_context::current() ) }, #else ctx{ std::allocator_arg, palloc, salloc, [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { @@ -189,9 +187,7 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo 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 & ctx, void * vp) mutable noexcept { + wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void * vp) mutable noexcept { // create synthesized pull_coroutine< T > typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx }; pull_coroutine< T & > synthesized{ & synthesized_cb }; @@ -219,8 +215,7 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo BOOST_ASSERT_MSG( false, "push_coroutine is complete"); }, std::forward< Fn >( fn), - boost::context::execution_context::current(), - std::placeholders::_1))}, + boost::context::execution_context::current() ) }, #else ctx{ std::allocator_arg, palloc, salloc, [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { @@ -318,9 +313,7 @@ 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 & ctx, + wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void * vp) mutable noexcept { // create synthesized pull_coroutine< T > typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx }; @@ -347,8 +340,7 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall BOOST_ASSERT_MSG( false, "push_coroutine is complete"); }, std::forward< Fn >( fn), - boost::context::execution_context::current(), - std::placeholders::_1))}, + boost::context::execution_context::current() ) }, #else ctx{ std::allocator_arg, palloc, salloc, [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { diff --git a/boost/coroutine2/detail/push_control_block_ecv2.ipp b/boost/coroutine2/detail/push_control_block_ecv2.ipp deleted file mode 100644 index 7ed6c572e1..0000000000 --- a/boost/coroutine2/detail/push_control_block_ecv2.ipp +++ /dev/null @@ -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 diff --git a/boost/coroutine2/detail/push_coroutine.hpp b/boost/coroutine2/detail/push_coroutine.hpp index 1b62663ab7..533d4f930f 100644 --- a/boost/coroutine2/detail/push_coroutine.hpp +++ b/boost/coroutine2/detail/push_coroutine.hpp @@ -72,14 +72,14 @@ public: push_coroutine< T > * c_{ nullptr }; public: - constexpr iterator() noexcept = default; + iterator() noexcept = default; explicit iterator( push_coroutine< T > * c) noexcept : c_{ c } { } iterator & operator=( T t) { - BOOST_ASSERT( c_); + BOOST_ASSERT( nullptr != c_); if ( ! ( * c_)( t) ) { c_ = nullptr; } @@ -150,14 +150,14 @@ public: push_coroutine< T & > * c_{ nullptr }; public: - constexpr iterator() noexcept = default; + iterator() noexcept = default; explicit iterator( push_coroutine< T & > * c) noexcept : c_{ c } { } iterator & operator=( T & t) { - BOOST_ASSERT( c_); + BOOST_ASSERT( nullptr != c_); if ( ! ( * c_)( t) ) { c_ = nullptr; } diff --git a/boost/coroutine2/detail/wrap.hpp b/boost/coroutine2/detail/wrap.hpp new file mode 100644 index 0000000000..25abce3b61 --- /dev/null +++ b/boost/coroutine2/detail/wrap.hpp @@ -0,0 +1,112 @@ + +// 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_COROUTINE2_DETAIL_WRAP_H +#define BOOST_COROUTINE2_DETAIL_WRAP_H + +#include <type_traits> + +#include <boost/config.hpp> +#include <boost/context/detail/invoke.hpp> +#if (BOOST_EXECUTION_CONTEXT==1) +# include <boost/context/execution_context.hpp> +#else +# include <boost/context/continuation.hpp> +#endif + +#include <boost/fiber/detail/config.hpp> +#include <boost/fiber/detail/data.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { +namespace detail { + +#if (BOOST_EXECUTION_CONTEXT==1) +template< typename Fn1, typename Fn2 > +class wrapper { +private: + typename std::decay< Fn1 >::type fn1_; + typename std::decay< Fn2 >::type fn2_; + boost::context::execution_context ctx_; + +public: + wrapper( Fn1 && fn1, Fn2 && fn2, + boost::context::execution_context const& ctx) : + fn1_( std::move( fn1) ), + fn2_( std::move( fn2) ), + ctx_{ ctx } { + } + + wrapper( wrapper const&) = delete; + wrapper & operator=( wrapper const&) = delete; + + wrapper( wrapper && other) = default; + wrapper & operator=( wrapper && other) = default; + + void operator()( void * vp) { + boost::context::detail::invoke( + std::move( fn1_), + fn2_, ctx_, vp); + } +}; + +template< typename Fn1, typename Fn2 > +wrapper< Fn1, Fn2 > +wrap( Fn1 && fn1, Fn2 && fn2, + boost::context::execution_context const& ctx) { + return wrapper< Fn1, Fn2 >( + std::forward< Fn1 >( fn1), + std::forward< Fn2 >( fn2), + ctx); +} +#else +template< typename Fn1, typename Fn2 > +class wrapper { +private: + typename std::decay< Fn1 >::type fn1_; + typename std::decay< Fn2 >::type fn2_; + +public: + wrapper( Fn1 && fn1, Fn2 && fn2) : + fn1_( std::move( fn1) ), + fn2_( std::move( fn2) ) { + } + + wrapper( wrapper const&) = delete; + wrapper & operator=( wrapper const&) = delete; + + wrapper( wrapper && other) = default; + wrapper & operator=( wrapper && other) = default; + + boost::context::continuation + operator()( boost::context::continuation && c) { + return boost::context::detail::invoke( + std::move( fn1_), + fn2_, + std::forward< boost::context::continuation >( c) ); + } +}; + +template< typename Fn1, typename Fn2 > +wrapper< Fn1, Fn2 > +wrap( Fn1 && fn1, Fn2 && fn2) { + return wrapper< Fn1, Fn2 >( + std::forward< Fn1 >( fn1), + std::forward< Fn2 >( fn2) ); +} +#endif + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINE2_DETAIL_WRAP_H |