diff options
Diffstat (limited to 'boost/coroutine2')
26 files changed, 2379 insertions, 964 deletions
diff --git a/boost/coroutine2/all.hpp b/boost/coroutine2/all.hpp index f54b4569eb..dcd30aa029 100644 --- a/boost/coroutine2/all.hpp +++ b/boost/coroutine2/all.hpp @@ -9,6 +9,7 @@ #include <boost/coroutine2/coroutine.hpp> #include <boost/coroutine2/fixedsize_stack.hpp> +#include <boost/coroutine2/pooled_fixedsize_stack.hpp> #include <boost/coroutine2/protected_fixedsize_stack.hpp> #include <boost/coroutine2/segmented_stack.hpp> diff --git a/boost/coroutine2/coroutine.hpp b/boost/coroutine2/coroutine.hpp index 0269299518..39aa767cc3 100644 --- a/boost/coroutine2/coroutine.hpp +++ b/boost/coroutine2/coroutine.hpp @@ -23,8 +23,8 @@ namespace coroutines2 { template< typename T > struct coroutine { - typedef detail::pull_coroutine< T > pull_type; - typedef detail::push_coroutine< T > push_type; + using pull_type = detail::pull_coroutine< T >; + using push_type = detail::push_coroutine< T >; }; template< typename T > diff --git a/boost/coroutine2/detail/coroutine.hpp b/boost/coroutine2/detail/coroutine.hpp index 55641e443c..7c1483d3be 100644 --- a/boost/coroutine2/detail/coroutine.hpp +++ b/boost/coroutine2/detail/coroutine.hpp @@ -8,6 +8,7 @@ #define BOOST_COROUTINES2_DETAIL_COROUTINE_HPP #include <boost/config.hpp> +#include <boost/context/detail/config.hpp> #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -28,14 +29,26 @@ class push_coroutine; #include <boost/coroutine2/detail/pull_coroutine.hpp> #include <boost/coroutine2/detail/push_coroutine.hpp> -#include <boost/coroutine2/detail/pull_control_block.hpp> -#include <boost/coroutine2/detail/push_control_block.hpp> - -#include <boost/coroutine2/detail/pull_coroutine.ipp> -#include <boost/coroutine2/detail/push_coroutine.ipp> - -#include <boost/coroutine2/detail/pull_control_block.ipp> -#include <boost/coroutine2/detail/push_control_block.ipp> +#if defined(BOOST_EXECUTION_CONTEXT) +# if (BOOST_EXECUTION_CONTEXT==1) +# 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> +# endif + +# include <boost/coroutine2/detail/pull_coroutine.ipp> +# include <boost/coroutine2/detail/push_coroutine.ipp> + +# if (BOOST_EXECUTION_CONTEXT==1) +# 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> +# endif +#endif #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_SUFFIX diff --git a/boost/coroutine2/detail/create_control_block.ipp b/boost/coroutine2/detail/create_control_block.ipp new file mode 100644 index 0000000000..9eaea2ebf3 --- /dev/null +++ b/boost/coroutine2/detail/create_control_block.ipp @@ -0,0 +1,60 @@ + +// 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_CREATE_CONTROLBLOCK_IPP +#define BOOST_COROUTINES2_DETAIL_CREATE_CONTROLBLOCK_IPP + +#include <cstddef> +#include <memory> +#include <utility> + +#include <boost/assert.hpp> +#include <boost/config.hpp> + +#include <boost/context/preallocated.hpp> +#include <boost/context/stack_context.hpp> + +#include <boost/coroutine2/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { +namespace detail { + +template< typename ControlBlock, typename StackAllocator, typename Fn > +ControlBlock * create_control_block( StackAllocator salloc, Fn && fn) { + auto sctx = salloc.allocate(); + // reserve space for control structure +#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) + void * sp = static_cast< char * >( sctx.sp) - sizeof( ControlBlock); + const std::size_t size = sctx.size - sizeof( ControlBlock); +#else + constexpr std::size_t func_alignment = 64; // alignof( ControlBlock); + constexpr std::size_t func_size = sizeof( ControlBlock); + // reserve space on stack + void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; + // align sp pointer + std::size_t space = func_size + func_alignment; + sp = std::align( func_alignment, func_size, sp, space); + BOOST_ASSERT( nullptr != sp); + // calculate remaining size + const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); +#endif + // placment new for control structure on coroutine stack + return new ( sp) ControlBlock{ context::preallocated( sp, size, sctx), + salloc, std::forward< Fn >( fn) }; +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES2_DETAIL_CREATE_CONTROLBLOCK_IPP diff --git a/boost/coroutine2/detail/decay_copy.hpp b/boost/coroutine2/detail/decay_copy.hpp new file mode 100644 index 0000000000..3a5008dd81 --- /dev/null +++ b/boost/coroutine2/detail/decay_copy.hpp @@ -0,0 +1,36 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_COROUTINES2_DETAIL_DECAY_COPY_H +#define BOOST_COROUTINES2_DETAIL_DECAY_COPY_H + +#include <type_traits> + +#include <boost/config.hpp> + +#include <boost/context/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { +namespace detail { + +template< typename T > +typename std::decay< T >::type +decay_copy( T && t) { + return std::forward< T >( t); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES2_DETAIL_DECAY_COPY_H diff --git a/boost/coroutine2/detail/disable_overload.hpp b/boost/coroutine2/detail/disable_overload.hpp new file mode 100644 index 0000000000..633d46883c --- /dev/null +++ b/boost/coroutine2/detail/disable_overload.hpp @@ -0,0 +1,34 @@ + +// 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_DISABLE_OVERLOAD_H +#define BOOST_COROUTINES2_DETAIL_DISABLE_OVERLOAD_H + +#include <type_traits> + +#include <boost/config.hpp> +#include <boost/context/detail/disable_overload.hpp> + +#include <boost/coroutine2/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { +namespace detail { + +template< typename X, typename Y > +using disable_overload = boost::context::detail::disable_overload< X, Y >; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES2_DETAIL_DISABLE_OVERLOAD_H diff --git a/boost/coroutine2/detail/forced_unwind.hpp b/boost/coroutine2/detail/forced_unwind.hpp index e04eb72d69..0f67f79a5f 100644 --- a/boost/coroutine2/detail/forced_unwind.hpp +++ b/boost/coroutine2/detail/forced_unwind.hpp @@ -24,6 +24,12 @@ namespace detail { struct forced_unwind {}; +inline +void * unwind_coroutine( void * data) { + throw forced_unwind{}; + return data; +} + }}} #ifdef BOOST_HAS_ABI_HEADERS diff --git a/boost/coroutine2/detail/pull_control_block.ipp b/boost/coroutine2/detail/pull_control_block.ipp deleted file mode 100644 index 536e5e6a94..0000000000 --- a/boost/coroutine2/detail/pull_control_block.ipp +++ /dev/null @@ -1,299 +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 <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> -#include <boost/coroutine2/detail/state.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines2 { -namespace detail { - -// pull_coroutine< T > - -template< typename T > -template< typename StackAllocator, typename Fn > -pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn_, bool preserve_fpu_) : - other( nullptr), - ctx( std::allocator_arg, palloc, salloc, - [=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { - // create synthesized push_coroutine< T > - typename push_coroutine< T >::control_block synthesized_cb( this, ctx); - push_coroutine< T > synthesized( & synthesized_cb); - other = & synthesized_cb; - try { - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( forced_unwind const&) { - // do nothing for unwinding exception - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - // set termination flags - state |= static_cast< int >( state_t::complete); - // jump back to ctx - other->ctx( nullptr, preserve_fpu); - BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); - }), - preserve_fpu( preserve_fpu_), - state( static_cast< int >( state_t::unwind) ), - except(), - bvalid( false), - storage() { - // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns - set( reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ) ); -} - -template< typename T > -pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb, - boost::context::execution_context const& ctx_) : - other( cb), - ctx( ctx_), - preserve_fpu( other->preserve_fpu), - state( 0), - except(), - bvalid( false), - storage() { -} - -template< typename T > -pull_coroutine< T >::control_block::~control_block() { - if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && - 0 != ( state & static_cast< int >( state_t::unwind) ) ) { - // set early-exit flag - state |= static_cast< int >( state_t::early_exit); - ctx( nullptr, preserve_fpu); - } - // destroy data if it set - if ( bvalid) { - reinterpret_cast< T const* >( storage)->~T(); - } -} - -template< typename T > -void -pull_coroutine< T >::control_block::resume() { - other->ctx = boost::context::execution_context::current(); - set( reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ) ); - if ( except) { - std::rethrow_exception( except); - } - // test early-exit-flag - if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { - throw forced_unwind(); - } -} - -template< typename T > -void -pull_coroutine< T >::control_block::set( T * t) { - // destroy data if it set - if ( bvalid) { - reinterpret_cast< T const* >( storage)->~T(); - } - if ( nullptr != t) { - new ( storage) T( std::move( * t) ); // FIXME: differrentiation between move/copy - bvalid = true; - } else { - bvalid = false; - } -} - -template< typename T > -T & -pull_coroutine< T >::control_block::get() { - return * reinterpret_cast< T * >( storage); -} - -template< typename T > -bool -pull_coroutine< T >::control_block::valid() const noexcept { - return nullptr != other && 0 == ( state & static_cast< int >( state_t::complete) ) && bvalid; -} - - -// pull_coroutine< T & > - -template< typename T > -template< typename StackAllocator, typename Fn > -pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn_, bool preserve_fpu_) : - other( nullptr), - ctx( std::allocator_arg, palloc, salloc, - [=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { - // create synthesized push_coroutine< T > - typename push_coroutine< T & >::control_block synthesized_cb( this, ctx); - push_coroutine< T & > synthesized( & synthesized_cb); - other = & synthesized_cb; - try { - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( forced_unwind const&) { - // do nothing for unwinding exception - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - // set termination flags - state |= static_cast< int >( state_t::complete); - // jump back to ctx - other->ctx( nullptr, preserve_fpu); - BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); - }), - preserve_fpu( preserve_fpu_), - state( static_cast< int >( state_t::unwind) ), - except(), - t( nullptr) { - // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns - t = reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ); -} - -template< typename T > -pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb, - boost::context::execution_context const& ctx_) : - other( cb), - ctx( ctx_), - preserve_fpu( other->preserve_fpu), - state( 0), - except(), - t( nullptr) { -} - -template< typename T > -pull_coroutine< T & >::control_block::~control_block() { - if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && - 0 != ( state & static_cast< int >( state_t::unwind) ) ) { - // set early-exit flag - state |= static_cast< int >( state_t::early_exit); - ctx( nullptr, preserve_fpu); - } -} - -template< typename T > -void -pull_coroutine< T & >::control_block::resume() { - other->ctx = boost::context::execution_context::current(); - t = reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ); - if ( except) { - std::rethrow_exception( except); - } - // test early-exit-flag - if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { - throw forced_unwind(); - } -} - -template< typename T > -T & -pull_coroutine< T & >::control_block::get() { - return * reinterpret_cast< T * >( t); -} - -template< typename T > -bool -pull_coroutine< T & >::control_block::valid() const noexcept { - return nullptr != other && 0 == ( state & static_cast< int >( state_t::complete) ) && nullptr != t; -} - - -// pull_coroutine< void > - -template< typename StackAllocator, typename Fn > -pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn_, bool preserve_fpu_) : - other( nullptr), - ctx( std::allocator_arg, palloc, salloc, - [=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { - // create synthesized push_coroutine< T > - typename push_coroutine< void >::control_block synthesized_cb( this, ctx); - push_coroutine< void > synthesized( & synthesized_cb); - other = & synthesized_cb; - try { - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( forced_unwind const&) { - // do nothing for unwinding exception - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - // set termination flags - state |= static_cast< int >( state_t::complete); - // jump back to ctx - other->ctx( nullptr, preserve_fpu); - BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); - }), - preserve_fpu( preserve_fpu_), - state( static_cast< int >( state_t::unwind) ), - except() { - // enter coroutine-fn in order to have first value available after ctor returns - ctx( nullptr, preserve_fpu); -} - -inline -pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb, - boost::context::execution_context const& ctx_) : - other( cb), - ctx( ctx_), - preserve_fpu( other->preserve_fpu), - state( 0), - except() { -} - -inline -pull_coroutine< void >::control_block::~control_block() { - if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && - 0 != ( state & static_cast< int >( state_t::unwind) ) ) { - // set early-exit flag - state |= static_cast< int >( state_t::early_exit); - ctx( nullptr, preserve_fpu); - } -} - -inline -void -pull_coroutine< void >::control_block::resume() { - other->ctx = boost::context::execution_context::current(); - ctx( nullptr, preserve_fpu); - if ( except) { - std::rethrow_exception( except); - } - // test early-exit-flag - if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { - throw forced_unwind(); - } -} - -inline -bool -pull_coroutine< void >::control_block::valid() const noexcept { - return nullptr != other && 0 == ( state & static_cast< int >( 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.hpp b/boost/coroutine2/detail/pull_control_block_ecv1.hpp index 7009454c88..16d65a3e62 100644 --- a/boost/coroutine2/detail/pull_control_block.hpp +++ b/boost/coroutine2/detail/pull_control_block_ecv1.hpp @@ -8,11 +8,14 @@ #define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP #include <exception> +#include <functional> #include <type_traits> #include <boost/config.hpp> #include <boost/context/execution_context.hpp> +#include <boost/coroutine2/detail/state.hpp> + #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif @@ -23,76 +26,85 @@ namespace detail { template< typename T > struct pull_coroutine< T >::control_block { - typename push_coroutine< T >::control_block * other; boost::context::execution_context ctx; - bool preserve_fpu; - int state; + typename push_coroutine< T >::control_block * other; + state_t state; std::exception_ptr except; bool bvalid; - typename std::aligned_storage< sizeof( T), alignof( T) >::type storage[1]; + typename std::aligned_storage< sizeof( T), alignof( T) >::type storage; + + static void destroy( control_block * cb) noexcept; template< typename StackAllocator, typename Fn > - control_block( context::preallocated, StackAllocator, Fn &&, bool); + control_block( context::preallocated, StackAllocator, Fn &&); - explicit control_block( typename push_coroutine< T >::control_block *, boost::context::execution_context const&); + control_block( typename push_coroutine< T >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block(); + ~control_block() noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); void set( T *); - T & get(); + T & get() noexcept; bool valid() const noexcept; }; template< typename T > struct pull_coroutine< T & >::control_block { - typename push_coroutine< T & >::control_block * other; boost::context::execution_context ctx; - bool preserve_fpu; - int state; + typename push_coroutine< T & >::control_block * other; + state_t state; std::exception_ptr except; T * t; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > - control_block( context::preallocated, StackAllocator, Fn &&, bool); + control_block( context::preallocated, StackAllocator, Fn &&); - explicit control_block( typename push_coroutine< T & >::control_block *, boost::context::execution_context const&); + control_block( typename push_coroutine< T & >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block(); + ~control_block() noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); - T & get(); + T & get() noexcept; bool valid() const noexcept; }; struct pull_coroutine< void >::control_block { - push_coroutine< void >::control_block * other; boost::context::execution_context ctx; - bool preserve_fpu; - int state; + push_coroutine< void >::control_block * other; + state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > - control_block( context::preallocated, StackAllocator, Fn &&, bool); + control_block( context::preallocated, StackAllocator, Fn &&); - explicit control_block( push_coroutine< void >::control_block *, boost::context::execution_context const&); + control_block( push_coroutine< void >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block(); + ~control_block() noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); bool valid() const noexcept; diff --git a/boost/coroutine2/detail/pull_control_block_ecv1.ipp b/boost/coroutine2/detail/pull_control_block_ecv1.ipp new file mode 100644 index 0000000000..f271e795df --- /dev/null +++ b/boost/coroutine2/detail/pull_control_block_ecv1.ipp @@ -0,0 +1,421 @@ + +// 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 <exception> +#include <functional> +#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/decay_copy.hpp> +#include <boost/coroutine2/detail/forced_unwind.hpp> +#include <boost/coroutine2/detail/state.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 ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + +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 & 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 }; + other = & synthesized_cb; + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + }, + std::forward< Fn >( fn), + boost::context::execution_context::current(), + std::placeholders::_1))}, +#else + ctx{ std::allocator_arg, palloc, salloc, + [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { + // create synthesized push_coroutine< T > + typename push_coroutine< T >::control_block synthesized_cb{ this, ctx }; + push_coroutine< T > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + }}, +#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 + set( static_cast< T * >( ctx() ) ); +} + +template< typename T > +pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb, + boost::context::execution_context const& ctx_) noexcept : + ctx{ ctx_ }, + other{ cb }, + state{ state_t::none }, + except{}, + bvalid{ false }, + storage{} { +} + +template< typename T > +pull_coroutine< T >::control_block::~control_block() { + if ( state_t::none == ( state & state_t::complete) && + state_t::none != ( state & state_t::unwind) ) { + // unwind coroutine stack + ctx( context::exec_ontop_arg, unwind_coroutine); + } + // destroy data if it 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() { + other->ctx = boost::context::execution_context::current(); + set( static_cast< T * >( ctx() ) ); + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +void +pull_coroutine< T >::control_block::set( T * t) { + // destroy data if it 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 ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + +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 & 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 }; + other = & synthesized_cb; + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + }, + std::forward< Fn >( fn), + boost::context::execution_context::current(), + std::placeholders::_1))}, +#else + ctx{ std::allocator_arg, palloc, salloc, + [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { + // create synthesized push_coroutine< T > + typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx }; + push_coroutine< T & > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + }}, +#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 + t = static_cast< T * >( ctx() ); +} + +template< typename T > +pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb, + boost::context::execution_context const& ctx_) noexcept : + ctx{ ctx_ }, + other{ cb }, + state{ state_t::none }, + except{}, + t( nullptr) { +} + +template< typename T > +pull_coroutine< T & >::control_block::~control_block() { + if ( state_t::none == ( state & state_t::complete) && + state_t::none != ( state & state_t::unwind) ) { + // unwind coroutine stack + ctx( context::exec_ontop_arg, unwind_coroutine); + } +} + +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() { + other->ctx = boost::context::execution_context::current(); + t = static_cast< T * >( ctx() ); + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +T & +pull_coroutine< T & >::control_block::get() noexcept { + return * static_cast< T * >( t); +} + +template< typename T > +bool +pull_coroutine< T & >::control_block::valid() const noexcept { + return nullptr != other && 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 ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + +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 & 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 }; + other = & synthesized_cb; + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + }, + std::forward< Fn >( fn), + boost::context::execution_context::current(), + std::placeholders::_1))}, +#else + ctx{ std::allocator_arg, palloc, salloc, + [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { + // create synthesized push_coroutine< T > + typename push_coroutine< void >::control_block synthesized_cb{ this, ctx }; + push_coroutine< void > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + }}, +#endif + other{ nullptr }, + state{ state_t::unwind }, + except{} { + // enter coroutine-fn in order to have first value available after ctor returns + ctx(); +} + +inline +pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb, + boost::context::execution_context const& ctx_) noexcept : + ctx{ ctx_ }, + other{ cb }, + state{ state_t::none }, + except{} { +} + +inline +pull_coroutine< void >::control_block::~control_block() { + if ( state_t::none == ( state & state_t::complete) && + state_t::none != ( state & state_t::unwind) ) { + // unwind coroutine stack + ctx( context::exec_ontop_arg, unwind_coroutine); + } +} + +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() { + other->ctx = boost::context::execution_context::current(); + 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_control_block_ecv2.hpp b/boost/coroutine2/detail/pull_control_block_ecv2.hpp new file mode 100644 index 0000000000..58d248833a --- /dev/null +++ b/boost/coroutine2/detail/pull_control_block_ecv2.hpp @@ -0,0 +1,114 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP +#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP + +#include <exception> +#include <type_traits> + +#include <boost/config.hpp> +#include <boost/context/execution_context.hpp> + +#include <boost/coroutine2/detail/state.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { +namespace detail { + +template< typename T > +struct pull_coroutine< T >::control_block { + boost::context::execution_context< T * > ctx; + typename push_coroutine< T >::control_block * other; + state_t state; + std::exception_ptr except; + bool bvalid; + typename std::aligned_storage< sizeof( T), alignof( T) >::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(); + + control_block( control_block &) = delete; + control_block & operator=( control_block &) = delete; + + void deallocate() noexcept; + + void resume(); + + void set( T *); + + T & get() noexcept; + + bool valid() const noexcept; +}; + +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; + + 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( control_block &) = delete; + control_block & operator=( control_block &) = delete; + + void deallocate() noexcept; + + void resume(); + + T & get() noexcept; + + bool valid() const noexcept; +}; + +struct pull_coroutine< void >::control_block { + boost::context::execution_context< void > ctx; + push_coroutine< void >::control_block * other; + state_t state; + std::exception_ptr except; + + static void destroy( control_block * cb) noexcept; + + 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( control_block &) = delete; + control_block & operator=( control_block &) = delete; + + void deallocate() noexcept; + + void resume(); + + bool valid() const noexcept; +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP diff --git a/boost/coroutine2/detail/pull_control_block_ecv2.ipp b/boost/coroutine2/detail/pull_control_block_ecv2.ipp new file mode 100644 index 0000000000..785bc59ff1 --- /dev/null +++ b/boost/coroutine2/detail/pull_control_block_ecv2.ipp @@ -0,0 +1,411 @@ + +// 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 + 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; + 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; + 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 + auto result = ctx( nullptr); + ctx = std::move( std::get< 0 >( result) ); + set( std::get< 1 >( result) ); +} + +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 + 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; + 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; + 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 + auto result = ctx( nullptr); + ctx = std::move( std::get< 0 >( result) ); + t = std::get< 1 >( result); +} + +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 + 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; + 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; + 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 + ctx = ctx(); +} + +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 c78750442e..7123eac8b8 100644 --- a/boost/coroutine2/detail/pull_coroutine.hpp +++ b/boost/coroutine2/detail/pull_coroutine.hpp @@ -12,9 +12,9 @@ #include <boost/assert.hpp> #include <boost/config.hpp> -#include <boost/context/execution_context.hpp> #include <boost/coroutine2/detail/config.hpp> +#include <boost/coroutine2/detail/disable_overload.hpp> #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -34,29 +34,30 @@ private: control_block * cb_; - explicit pull_coroutine( control_block *); + explicit pull_coroutine( control_block *) noexcept; - bool has_result_() const; + bool has_result_() const noexcept; public: - template< typename Fn > - explicit pull_coroutine( Fn &&, bool = false); + template< typename Fn, + typename = detail::disable_overload< pull_coroutine, Fn > + > + explicit pull_coroutine( Fn &&); template< typename StackAllocator, typename Fn > - explicit pull_coroutine( StackAllocator, Fn &&, bool = false); + pull_coroutine( StackAllocator, Fn &&); - ~pull_coroutine(); + ~pull_coroutine() noexcept; pull_coroutine( pull_coroutine const&) = delete; pull_coroutine & operator=( pull_coroutine const&) = delete; - pull_coroutine( pull_coroutine &&); + pull_coroutine( pull_coroutine &&) noexcept; - pull_coroutine & operator=( pull_coroutine && other) { - if ( this != & other) { - cb_ = other.cb_; - other.cb_ = nullptr; - } + pull_coroutine & operator=( pull_coroutine && other) noexcept { + if ( this == & other) return * this; + cb_ = other.cb_; + other.cb_ = nullptr; return * this; } @@ -66,13 +67,13 @@ public: bool operator!() const noexcept; - T get(); + T get() noexcept; class iterator : public std::iterator< std::input_iterator_tag, typename std::remove_reference< T >::type > { private: - pull_coroutine< T > * c_; + pull_coroutine< T > * c_{ nullptr }; - void fetch_() { + void fetch_() noexcept { BOOST_ASSERT( nullptr != c_); if ( ! ( * c_) ) { c_ = nullptr; @@ -91,30 +92,28 @@ public: typedef typename iterator::pointer pointer_t; typedef typename iterator::reference reference_t; - iterator() : - c_( nullptr) { - } + constexpr iterator() noexcept = default; - explicit iterator( pull_coroutine< T > * c) : - c_( c) { + explicit iterator( pull_coroutine< T > * c) noexcept : + c_{ c } { fetch_(); } - iterator( iterator const& other) : - c_( other.c_) { + iterator( iterator const& other) noexcept : + c_{ other.c_ } { } - iterator & operator=( iterator const& other) { + iterator & operator=( iterator const& other) noexcept { if ( this == & other) return * this; c_ = other.c_; return * this; } - bool operator==( iterator const& other) const { + bool operator==( iterator const& other) const noexcept { return other.c_ == c_; } - bool operator!=( iterator const& other) const { + bool operator!=( iterator const& other) const noexcept { return other.c_ != c_; } @@ -125,11 +124,11 @@ public: iterator operator++( int) = delete; - reference_t operator*() const { + reference_t operator*() const noexcept { return c_->cb_->get(); } - pointer_t operator->() const { + pointer_t operator->() const noexcept { return std::addressof( c_->cb_->get() ); } }; @@ -147,29 +146,30 @@ private: control_block * cb_; - explicit pull_coroutine( control_block *); + explicit pull_coroutine( control_block *) noexcept; - bool has_result_() const; + bool has_result_() const noexcept; public: - template< typename Fn > - explicit pull_coroutine( Fn &&, bool = false); + template< typename Fn, + typename = detail::disable_overload< pull_coroutine, Fn > + > + explicit pull_coroutine( Fn &&); template< typename StackAllocator, typename Fn > - explicit pull_coroutine( StackAllocator, Fn &&, bool = false); + pull_coroutine( StackAllocator, Fn &&); - ~pull_coroutine(); + ~pull_coroutine() noexcept; pull_coroutine( pull_coroutine const&) = delete; pull_coroutine & operator=( pull_coroutine const&) = delete; - pull_coroutine( pull_coroutine &&); + pull_coroutine( pull_coroutine &&) noexcept; - pull_coroutine & operator=( pull_coroutine && other) { - if ( this != & other) { - cb_ = other.cb_; - other.cb_ = nullptr; - } + pull_coroutine & operator=( pull_coroutine && other) noexcept { + if ( this == & other) return * this; + cb_ = other.cb_; + other.cb_ = nullptr; return * this; } @@ -179,13 +179,13 @@ public: bool operator!() const noexcept; - T & get(); + T & get() noexcept; class iterator : public std::iterator< std::input_iterator_tag, typename std::remove_reference< T >::type > { private: - pull_coroutine< T & > * c_; + pull_coroutine< T & > * c_{ nullptr }; - void fetch_() { + void fetch_() noexcept { BOOST_ASSERT( nullptr != c_); if ( ! ( * c_) ) { c_ = nullptr; @@ -204,30 +204,28 @@ public: typedef typename iterator::pointer pointer_t; typedef typename iterator::reference reference_t; - iterator() : - c_( nullptr) { - } + constexpr iterator() noexcept = default; - explicit iterator( pull_coroutine< T & > * c) : - c_( c) { + explicit iterator( pull_coroutine< T & > * c) noexcept : + c_{ c } { fetch_(); } - iterator( iterator const& other) : - c_( other.c_) { + iterator( iterator const& other) noexcept : + c_{ other.c_ } { } - iterator & operator=( iterator const& other) { + iterator & operator=( iterator const& other) noexcept { if ( this == & other) return * this; c_ = other.c_; return * this; } - bool operator==( iterator const& other) const { + bool operator==( iterator const& other) const noexcept { return other.c_ == c_; } - bool operator!=( iterator const& other) const { + bool operator!=( iterator const& other) const noexcept { return other.c_ != c_; } @@ -238,11 +236,11 @@ public: iterator operator++( int) = delete; - reference_t operator*() const { + reference_t operator*() const noexcept { return c_->cb_->get(); } - pointer_t operator->() const { + pointer_t operator->() const noexcept { return std::addressof( c_->cb_->get() ); } }; @@ -260,27 +258,28 @@ private: control_block * cb_; - explicit pull_coroutine( control_block *); + explicit pull_coroutine( control_block *) noexcept; public: - template< typename Fn > - explicit pull_coroutine( Fn &&, bool = false); + template< typename Fn, + typename = detail::disable_overload< pull_coroutine, Fn > + > + explicit pull_coroutine( Fn &&); template< typename StackAllocator, typename Fn > - explicit pull_coroutine( StackAllocator, Fn &&, bool = false); + pull_coroutine( StackAllocator, Fn &&); - ~pull_coroutine(); + ~pull_coroutine() noexcept; pull_coroutine( pull_coroutine const&) = delete; pull_coroutine & operator=( pull_coroutine const&) = delete; - pull_coroutine( pull_coroutine &&); + pull_coroutine( pull_coroutine &&) noexcept; - pull_coroutine & operator=( pull_coroutine && other) { - if ( this != & other) { - cb_ = other.cb_; - other.cb_ = nullptr; - } + pull_coroutine & operator=( pull_coroutine && other) noexcept { + if ( this == & other) return * this; + cb_ = other.cb_; + other.cb_ = nullptr; return * this; } diff --git a/boost/coroutine2/detail/pull_coroutine.ipp b/boost/coroutine2/detail/pull_coroutine.ipp index 2e37ef2a98..58fe84575e 100644 --- a/boost/coroutine2/detail/pull_coroutine.ipp +++ b/boost/coroutine2/detail/pull_coroutine.ipp @@ -8,16 +8,14 @@ #define BOOST_COROUTINES2_DETAIL_PULL_COROUTINE_IPP #include <algorithm> -#include <memory> #include <utility> #include <boost/assert.hpp> #include <boost/config.hpp> -#include <boost/context/execution_context.hpp> -#include <boost/context/stack_context.hpp> - #include <boost/coroutine2/detail/config.hpp> +#include <boost/coroutine2/detail/create_control_block.ipp> +#include <boost/coroutine2/detail/disable_overload.hpp> #include <boost/coroutine2/fixedsize_stack.hpp> #include <boost/coroutine2/segmented_stack.hpp> @@ -32,58 +30,44 @@ namespace detail { // pull_coroutine< T > template< typename T > -pull_coroutine< T >::pull_coroutine( control_block * cb) : - cb_( cb) { +pull_coroutine< T >::pull_coroutine( control_block * cb) noexcept : + cb_{ cb } { } template< typename T > bool -pull_coroutine< T >::has_result_() const { +pull_coroutine< T >::has_result_() const noexcept { return nullptr != cb_->other->t; } template< typename T > -template< typename Fn > -pull_coroutine< T >::pull_coroutine( Fn && fn, bool preserve_fpu) : - pull_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { +template< typename Fn, + typename +> +pull_coroutine< T >::pull_coroutine( Fn && fn) : + pull_coroutine{ default_stack(), std::forward< Fn >( fn) } { } template< typename T > template< typename StackAllocator, typename Fn > -pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : - cb_( nullptr) { - context::stack_context sctx( salloc.allocate() ); - // reserve space for control structure -#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) - void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); - std::size_t size = sctx.size - sizeof( control_block); -#else - constexpr std::size_t func_alignment = 64; // alignof( control_block); - constexpr std::size_t func_size = sizeof( control_block); - // reserve space on stack - void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; - // align sp pointer - std::size_t space = func_size + func_alignment; - sp = std::align( func_alignment, func_size, sp, space); - BOOST_ASSERT( nullptr != sp); - // calculate remaining size - std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); -#endif - // placment new for control structure on coroutine stack - cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx), - salloc, std::forward< Fn >( fn), preserve_fpu); +pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) : + cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { + if ( ! cb_->valid() ) { + cb_->deallocate(); + cb_ = nullptr; + } } template< typename T > -pull_coroutine< T >::~pull_coroutine() { +pull_coroutine< T >::~pull_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } template< typename T > -pull_coroutine< T >::pull_coroutine( pull_coroutine && other) : - cb_( other.cb_) { +pull_coroutine< T >::pull_coroutine( pull_coroutine && other) noexcept : + cb_{ other.cb_ } { other.cb_ = nullptr; } @@ -107,7 +91,7 @@ pull_coroutine< T >::operator!() const noexcept { template< typename T > T -pull_coroutine< T >::get() { +pull_coroutine< T >::get() noexcept { return std::move( cb_->get() ); } @@ -115,58 +99,44 @@ pull_coroutine< T >::get() { // pull_coroutine< T & > template< typename T > -pull_coroutine< T & >::pull_coroutine( control_block * cb) : - cb_( cb) { +pull_coroutine< T & >::pull_coroutine( control_block * cb) noexcept : + cb_{ cb } { } template< typename T > bool -pull_coroutine< T & >::has_result_() const { +pull_coroutine< T & >::has_result_() const noexcept { return nullptr != cb_->other->t; } template< typename T > -template< typename Fn > -pull_coroutine< T & >::pull_coroutine( Fn && fn, bool preserve_fpu) : - pull_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { +template< typename Fn, + typename +> +pull_coroutine< T & >::pull_coroutine( Fn && fn) : + pull_coroutine{ default_stack(), std::forward< Fn >( fn) } { } template< typename T > template< typename StackAllocator, typename Fn > -pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : - cb_( nullptr) { - context::stack_context sctx( salloc.allocate() ); - // reserve space for control structure -#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) - void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); - std::size_t size = sctx.size - sizeof( control_block); -#else - constexpr std::size_t func_alignment = 64; // alignof( control_block); - constexpr std::size_t func_size = sizeof( control_block); - // reserve space on stack - void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; - // align sp pointer - std::size_t space = func_size + func_alignment; - sp = std::align( func_alignment, func_size, sp, space); - BOOST_ASSERT( nullptr != sp); - // calculate remaining size - std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); -#endif - // placment new for control structure on coroutine stack - cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx), - salloc, std::forward< Fn >( fn), preserve_fpu); +pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) : + cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { + if ( ! cb_->valid() ) { + cb_->deallocate(); + cb_ = nullptr; + } } template< typename T > -pull_coroutine< T & >::~pull_coroutine() { +pull_coroutine< T & >::~pull_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } template< typename T > -pull_coroutine< T & >::pull_coroutine( pull_coroutine && other) : - cb_( other.cb_) { +pull_coroutine< T & >::pull_coroutine( pull_coroutine && other) noexcept : + cb_{ other.cb_ } { other.cb_ = nullptr; } @@ -190,7 +160,7 @@ pull_coroutine< T & >::operator!() const noexcept { template< typename T > T & -pull_coroutine< T & >::get() { +pull_coroutine< T & >::get() noexcept { return cb_->get(); } @@ -198,50 +168,36 @@ pull_coroutine< T & >::get() { // pull_coroutine< void > inline -pull_coroutine< void >::pull_coroutine( control_block * cb) : - cb_( cb) { +pull_coroutine< void >::pull_coroutine( control_block * cb) noexcept : + cb_{ cb } { } -template< typename Fn > -pull_coroutine< void >::pull_coroutine( Fn && fn, bool preserve_fpu) : - pull_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { +template< typename Fn, + typename +> +pull_coroutine< void >::pull_coroutine( Fn && fn) : + pull_coroutine{ default_stack(), std::forward< Fn >( fn) } { } template< typename StackAllocator, typename Fn > -pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : - cb_( nullptr) { - context::stack_context sctx( salloc.allocate() ); - // reserve space for control structure -#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) - void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); - std::size_t size = sctx.size - sizeof( control_block); -#else - constexpr std::size_t func_alignment = 64; // alignof( control_block); - constexpr std::size_t func_size = sizeof( control_block); - // reserve space on stack - void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; - // align sp pointer - std::size_t space = func_size + func_alignment; - sp = std::align( func_alignment, func_size, sp, space); - BOOST_ASSERT( nullptr != sp); - // calculate remaining size - std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); -#endif - // placment new for control structure on coroutine stack - cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx), - salloc, std::forward< Fn >( fn), preserve_fpu); +pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) : + cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { + if ( ! cb_->valid() ) { + cb_->deallocate(); + cb_ = nullptr; + } } inline -pull_coroutine< void >::~pull_coroutine() { +pull_coroutine< void >::~pull_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } inline -pull_coroutine< void >::pull_coroutine( pull_coroutine && other) : - cb_( other.cb_) { +pull_coroutine< void >::pull_coroutine( pull_coroutine && other) noexcept : + cb_{ other.cb_ } { other.cb_ = nullptr; } diff --git a/boost/coroutine2/detail/push_control_block.ipp b/boost/coroutine2/detail/push_control_block.ipp deleted file mode 100644 index ce6776f600..0000000000 --- a/boost/coroutine2/detail/push_control_block.ipp +++ /dev/null @@ -1,289 +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> -#include <boost/coroutine2/detail/state.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines2 { -namespace detail { - -// push_coroutine< T > - -template< typename T > -template< typename StackAllocator, typename Fn > -push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn_, bool preserve_fpu_) : - other( nullptr), - ctx( std::allocator_arg, palloc, salloc, - [=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { - // create synthesized pull_coroutine< T > - typename pull_coroutine< T >::control_block synthesized_cb( this, ctx); - pull_coroutine< T > synthesized( & synthesized_cb); - other = & synthesized_cb; - // jump back to ctor - T * t = reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ); - // set transferred value - synthesized_cb.set( t); - try { - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( forced_unwind const&) { - // do nothing for unwinding exception - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - // set termination flags - state |= static_cast< int >( state_t::complete); - // jump back to ctx - other->ctx( nullptr, preserve_fpu); - BOOST_ASSERT_MSG( false, "push_coroutine is complete"); - }), - preserve_fpu( preserve_fpu_), - state( static_cast< int >( state_t::unwind) ), - except() { - // enter coroutine-fn in order to get other set - ctx( nullptr, preserve_fpu); -} - -template< typename T > -push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb, - boost::context::execution_context const& ctx_) : - other( cb), - ctx( ctx_), - preserve_fpu( other->preserve_fpu), - state( 0), - except() { -} - -template< typename T > -push_coroutine< T >::control_block::~control_block() { - if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && - 0 != ( state & static_cast< int >( state_t::unwind) ) ) { - // set early-exit flag - state |= static_cast< int >( state_t::early_exit); - ctx( nullptr, preserve_fpu); - } -} - -template< typename T > -void -push_coroutine< T >::control_block::resume( T const& t) { - other->ctx = boost::context::execution_context::current(); - // pass an pointer to other context - ctx( const_cast< T * >( & t), preserve_fpu); - if ( except) { - std::rethrow_exception( except); - } - // test early-exit-flag - if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { - throw forced_unwind(); - } -} - -template< typename T > -void -push_coroutine< T >::control_block::resume( T && t) { - other->ctx = boost::context::execution_context::current(); - // pass an pointer to other context - ctx( std::addressof( t), preserve_fpu); - if ( except) { - std::rethrow_exception( except); - } - // test early-exit-flag - if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { - throw forced_unwind(); - } -} - -template< typename T > -bool -push_coroutine< T >::control_block::valid() const noexcept { - return 0 == ( state & static_cast< int >( state_t::complete) ); -} - - -// push_coroutine< T & > - -template< typename T > -template< typename StackAllocator, typename Fn > -push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn_, bool preserve_fpu_) : - other( nullptr), - ctx( std::allocator_arg, palloc, salloc, - [=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { - // create synthesized pull_coroutine< T > - typename pull_coroutine< T & >::control_block synthesized_cb( this, ctx); - pull_coroutine< T & > synthesized( & synthesized_cb); - other = & synthesized_cb; - // jump back to ctor - T * t = reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ); - // set transferred value - synthesized_cb.t = t; - try { - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( forced_unwind const&) { - // do nothing for unwinding exception - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - // set termination flags - state |= static_cast< int >( state_t::complete); - // jump back to ctx - other->ctx( nullptr, preserve_fpu); - BOOST_ASSERT_MSG( false, "push_coroutine is complete"); - }), - preserve_fpu( preserve_fpu_), - state( static_cast< int >( state_t::unwind) ), - except() { - // enter coroutine-fn in order to get other set - ctx( nullptr, preserve_fpu); -} - -template< typename T > -push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb, - boost::context::execution_context const& ctx_) : - other( cb), - ctx( ctx_), - preserve_fpu( other->preserve_fpu), - state( 0), - except() { -} - -template< typename T > -push_coroutine< T & >::control_block::~control_block() { - if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && - 0 != ( state & static_cast< int >( state_t::unwind) ) ) { - // set early-exit flag - state |= static_cast< int >( state_t::early_exit); - ctx( nullptr, preserve_fpu); - } -} - -template< typename T > -void -push_coroutine< T & >::control_block::resume( T & t) { - other->ctx = boost::context::execution_context::current(); - // pass an pointer to other context - ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ), preserve_fpu); - if ( except) { - std::rethrow_exception( except); - } - // test early-exit-flag - if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { - throw forced_unwind(); - } -} - -template< typename T > -bool -push_coroutine< T & >::control_block::valid() const noexcept { - return 0 == ( state & static_cast< int >( state_t::complete) ); -} - - -// push_coroutine< void > - -template< typename StackAllocator, typename Fn > -push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn_, bool preserve_fpu_) : - other( nullptr), - ctx( std::allocator_arg, palloc, salloc, - [=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { - // create synthesized pull_coroutine< T > - typename pull_coroutine< void >::control_block synthesized_cb( this, ctx); - pull_coroutine< void > synthesized( & synthesized_cb); - other = & synthesized_cb; - // jump back to ctor - ctx( nullptr, preserve_fpu); - try { - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( forced_unwind const&) { - // do nothing for unwinding exception - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - // set termination flags - state |= static_cast< int >( state_t::complete); - // jump back to ctx - other->ctx( nullptr, preserve_fpu); - BOOST_ASSERT_MSG( false, "push_coroutine is complete"); - }), - preserve_fpu( preserve_fpu_), - state( static_cast< int >( state_t::unwind) ), - except() { - // enter coroutine-fn in order to get other set - ctx( nullptr, preserve_fpu); -} - -inline -push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb, - boost::context::execution_context const& ctx_) : - other( cb), - ctx( ctx_), - preserve_fpu( other->preserve_fpu), - state( 0), - except() { -} - -inline -push_coroutine< void >::control_block::~control_block() { - if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && - 0 != ( state & static_cast< int >( state_t::unwind) ) ) { - // set early-exit flag - state |= static_cast< int >( state_t::early_exit); - ctx( nullptr, preserve_fpu); - } -} - -inline -void -push_coroutine< void >::control_block::resume() { - other->ctx = boost::context::execution_context::current(); - ctx( nullptr, preserve_fpu); - if ( except) { - std::rethrow_exception( except); - } - // test early-exit-flag - if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { - throw forced_unwind(); - } -} - -inline -bool -push_coroutine< void >::control_block::valid() const noexcept { - return 0 == ( state & static_cast< int >( 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.hpp b/boost/coroutine2/detail/push_control_block_ecv1.hpp index 03aa9125eb..29d49716a7 100644 --- a/boost/coroutine2/detail/push_control_block.hpp +++ b/boost/coroutine2/detail/push_control_block_ecv1.hpp @@ -7,11 +7,14 @@ #ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP #define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP +#include <functional> #include <exception> #include <boost/config.hpp> #include <boost/context/execution_context.hpp> +#include <boost/coroutine2/detail/state.hpp> + #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif @@ -22,22 +25,25 @@ namespace detail { template< typename T > struct push_coroutine< T >::control_block { - typename pull_coroutine< T >::control_block * other; boost::context::execution_context ctx; - bool preserve_fpu; - int state; + typename pull_coroutine< T >::control_block * other; + state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > - control_block( context::preallocated, StackAllocator, Fn &&, bool); + control_block( context::preallocated, StackAllocator, Fn &&); - explicit control_block( typename pull_coroutine< T >::control_block *, boost::context::execution_context const&); + control_block( typename pull_coroutine< T >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block(); + ~control_block() noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume( T const&); void resume( T &&); @@ -47,44 +53,50 @@ struct push_coroutine< T >::control_block { template< typename T > struct push_coroutine< T & >::control_block { - typename pull_coroutine< T & >::control_block * other; boost::context::execution_context ctx; - bool preserve_fpu; - int state; + typename pull_coroutine< T & >::control_block * other; + state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > - control_block( context::preallocated, StackAllocator, Fn &&, bool); + control_block( context::preallocated, StackAllocator, Fn &&); - explicit control_block( typename pull_coroutine< T & >::control_block *, boost::context::execution_context const&); + control_block( typename pull_coroutine< T & >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block(); + ~control_block() noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume( T &); bool valid() const noexcept; }; struct push_coroutine< void >::control_block { - pull_coroutine< void >::control_block * other; boost::context::execution_context ctx; - bool preserve_fpu; - int state; + pull_coroutine< void >::control_block * other; + state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > - control_block( context::preallocated, StackAllocator, Fn &&, bool); + control_block( context::preallocated, StackAllocator, Fn &&); - explicit control_block( pull_coroutine< void >::control_block *, boost::context::execution_context const&); + control_block( pull_coroutine< void >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block(); + ~control_block() noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); bool valid() const noexcept; diff --git a/boost/coroutine2/detail/push_control_block_ecv1.ipp b/boost/coroutine2/detail/push_control_block_ecv1.ipp new file mode 100644 index 0000000000..f9119fd771 --- /dev/null +++ b/boost/coroutine2/detail/push_control_block_ecv1.ipp @@ -0,0 +1,418 @@ + +// 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 <functional> +#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/decay_copy.hpp> +#include <boost/coroutine2/detail/forced_unwind.hpp> +#include <boost/coroutine2/detail/state.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 ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + +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 & 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 }; + other = & synthesized_cb; + try { + // jump back to ctor + T * t = static_cast< T * >( ctx() ); + // set transferred value + synthesized_cb.set( t); + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + }, + std::forward< Fn >( fn), + boost::context::execution_context::current(), + std::placeholders::_1))}, +#else + ctx{ std::allocator_arg, palloc, salloc, + [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { + // create synthesized pull_coroutine< T > + typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx }; + pull_coroutine< T > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + try { + // jump back to ctor + T * t = static_cast< T * >( ctx() ); + // set transferred value + synthesized_cb.set( t); + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + }}, +#endif + other{ nullptr }, + state{ state_t::unwind }, + except{} { + // enter coroutine-fn in order to get other set + ctx(); +} + +template< typename T > +push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb, + boost::context::execution_context const& ctx_) noexcept : + ctx{ ctx_ }, + other{ cb }, + state{ state_t::none }, + except{} { +} + +template< typename T > +push_coroutine< T >::control_block::~control_block() { + if ( state_t::none == ( state & state_t::complete) && + state_t::none != ( state & state_t::unwind) ) { + // unwind coroutine stack + ctx( context::exec_ontop_arg, unwind_coroutine); + } +} + +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& t) { + other->ctx = boost::context::execution_context::current(); + // pass an pointer to other context + ctx( const_cast< T * >( & t) ); + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +void +push_coroutine< T >::control_block::resume( T && t) { + other->ctx = boost::context::execution_context::current(); + // pass an pointer to other context + ctx( std::addressof( 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< T & > + +template< typename T > +void +push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { + boost::context::execution_context ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + +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 & 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 }; + other = & synthesized_cb; + try { + // jump back to ctor + T * t = static_cast< T * >( ctx() ); + // set transferred value + synthesized_cb.t = t; + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + }, + std::forward< Fn >( fn), + boost::context::execution_context::current(), + std::placeholders::_1))}, +#else + ctx{ std::allocator_arg, palloc, salloc, + [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { + // create synthesized pull_coroutine< T > + typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx }; + pull_coroutine< T & > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + try { + // jump back to ctor + T * t = static_cast< T * >( ctx() ); + // set transferred value + synthesized_cb.t = t; + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + }}, +#endif + other{ nullptr }, + state{ state_t::unwind }, + except{} { + // enter coroutine-fn in order to get other set + ctx(); +} + +template< typename T > +push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb, + boost::context::execution_context const& ctx_) noexcept : + ctx{ ctx_ }, + other{ cb }, + state{ state_t::none }, + except{} { +} + +template< typename T > +push_coroutine< T & >::control_block::~control_block() { + if ( state_t::none == ( state & state_t::complete) && + state_t::none != ( state & state_t::unwind) ) { + // unwind coroutine stack + ctx( context::exec_ontop_arg, unwind_coroutine); + } +} + +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) { + other->ctx = boost::context::execution_context::current(); + // pass an pointer to other context + ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) ); + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +bool +push_coroutine< T & >::control_block::valid() const noexcept { + return 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 ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + +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, + void * vp) mutable noexcept { + // create synthesized pull_coroutine< T > + typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx }; + pull_coroutine< void > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + try { + // jump back to ctor + ctx(); + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + }, + std::forward< Fn >( fn), + boost::context::execution_context::current(), + std::placeholders::_1))}, +#else + ctx{ std::allocator_arg, palloc, salloc, + [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept { + // create synthesized pull_coroutine< T > + typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx }; + pull_coroutine< void > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + try { + // jump back to ctor + ctx(); + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( forced_unwind const&) { + // do nothing for unwinding exception + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + other->ctx(); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + }}, +#endif + other{ nullptr }, + state{ state_t::unwind }, + except{} { + // enter coroutine-fn in order to get other set + ctx(); +} + +inline +push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb, + boost::context::execution_context const& ctx_) noexcept : + ctx{ ctx_ }, + other{ cb }, + state{ state_t::none }, + except{} { +} + +inline +push_coroutine< void >::control_block::~control_block() { + if ( state_t::none == ( state & state_t::complete) && + state_t::none != ( state & state_t::unwind) ) { + // unwind coroutine stack + ctx( context::exec_ontop_arg, unwind_coroutine); + } +} + +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() { + other->ctx = boost::context::execution_context::current(); + 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_control_block_ecv2.hpp b/boost/coroutine2/detail/push_control_block_ecv2.hpp new file mode 100644 index 0000000000..feb5e4a61c --- /dev/null +++ b/boost/coroutine2/detail/push_control_block_ecv2.hpp @@ -0,0 +1,104 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP +#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP + +#include <exception> + +#include <boost/config.hpp> +#include <boost/context/execution_context.hpp> + +#include <boost/coroutine2/detail/state.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { +namespace detail { + +template< typename T > +struct push_coroutine< T >::control_block { + boost::context::execution_context< T * > ctx; + typename pull_coroutine< T >::control_block * other; + state_t state; + std::exception_ptr except; + + static void destroy( control_block * cb) noexcept; + + 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( control_block &) = delete; + control_block & operator=( control_block &) = delete; + + void deallocate() noexcept; + + void resume( T const&); + + void resume( T &&); + + bool valid() const noexcept; +}; + +template< typename T > +struct push_coroutine< T & >::control_block { + boost::context::execution_context< T * > ctx; + typename pull_coroutine< T & >::control_block * other; + state_t state; + std::exception_ptr except; + + static void destroy( control_block * cb) noexcept; + + 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( control_block &) = delete; + control_block & operator=( control_block &) = delete; + + void deallocate() noexcept; + + void resume( T &); + + bool valid() const noexcept; +}; + +struct push_coroutine< void >::control_block { + boost::context::execution_context< void > ctx; + pull_coroutine< void >::control_block * other; + state_t state; + std::exception_ptr except; + + static void destroy( control_block * cb) noexcept; + + 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( control_block &) = delete; + control_block & operator=( control_block &) = delete; + + void deallocate() noexcept; + + void resume(); + + bool valid() const noexcept; +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP diff --git a/boost/coroutine2/detail/push_control_block_ecv2.ipp b/boost/coroutine2/detail/push_control_block_ecv2.ipp new file mode 100644 index 0000000000..bfdee06a18 --- /dev/null +++ b/boost/coroutine2/detail/push_control_block_ecv2.ipp @@ -0,0 +1,377 @@ + +// 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 + 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); + 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); + 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 + 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; + 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; + 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 + 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; + 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; + 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 1a2d01f67e..5d9d092b65 100644 --- a/boost/coroutine2/detail/push_coroutine.hpp +++ b/boost/coroutine2/detail/push_coroutine.hpp @@ -12,9 +12,9 @@ #include <boost/assert.hpp> #include <boost/config.hpp> -#include <boost/context/execution_context.hpp> #include <boost/coroutine2/detail/config.hpp> +#include <boost/coroutine2/detail/disable_overload.hpp> #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -34,27 +34,28 @@ private: control_block * cb_; - explicit push_coroutine( control_block *); + explicit push_coroutine( control_block *) noexcept; public: - template< typename Fn > - explicit push_coroutine( Fn &&, bool = false); + template< typename Fn, + typename = detail::disable_overload< push_coroutine, Fn > + > + explicit push_coroutine( Fn &&); template< typename StackAllocator, typename Fn > - explicit push_coroutine( StackAllocator, Fn &&, bool = false); + push_coroutine( StackAllocator, Fn &&); - ~push_coroutine(); + ~push_coroutine() noexcept; push_coroutine( push_coroutine const&) = delete; push_coroutine & operator=( push_coroutine const&) = delete; - push_coroutine( push_coroutine &&); + push_coroutine( push_coroutine &&) noexcept; - push_coroutine & operator=( push_coroutine && other) { - if ( this != & other) { - cb_ = other.cb_; - other.cb_ = nullptr; - } + push_coroutine & operator=( push_coroutine && other) noexcept { + if ( this == & other) return * this; + cb_ = other.cb_; + other.cb_ = nullptr; return * this; } @@ -68,36 +69,36 @@ public: class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > { private: - push_coroutine< T > * c_; + push_coroutine< T > * c_{ nullptr }; public: - iterator() : - c_( nullptr) { - } + constexpr iterator() noexcept = default; - explicit iterator( push_coroutine< T > * c) : - c_( c) { + explicit iterator( push_coroutine< T > * c) noexcept : + c_{ c } { } iterator & operator=( T t) { BOOST_ASSERT( c_); - if ( ! ( * c_)( t) ) c_ = 0; + if ( ! ( * c_)( t) ) { + c_ = nullptr; + } return * this; } - bool operator==( iterator const& other) const { + bool operator==( iterator const& other) const noexcept { return other.c_ == c_; } - bool operator!=( iterator const& other) const { + bool operator!=( iterator const& other) const noexcept { return other.c_ != c_; } - iterator & operator*() { + iterator & operator*() noexcept { return * this; } - iterator & operator++() { + iterator & operator++() noexcept { return * this; } }; @@ -113,27 +114,28 @@ private: control_block * cb_; - explicit push_coroutine( control_block *); + explicit push_coroutine( control_block *) noexcept; public: - template< typename Fn > - explicit push_coroutine( Fn &&, bool = false); + template< typename Fn, + typename = detail::disable_overload< push_coroutine, Fn > + > + explicit push_coroutine( Fn &&); template< typename StackAllocator, typename Fn > - explicit push_coroutine( StackAllocator, Fn &&, bool = false); + push_coroutine( StackAllocator, Fn &&); - ~push_coroutine(); + ~push_coroutine() noexcept; push_coroutine( push_coroutine const&) = delete; push_coroutine & operator=( push_coroutine const&) = delete; - push_coroutine( push_coroutine &&); + push_coroutine( push_coroutine &&) noexcept; - push_coroutine & operator=( push_coroutine && other) { - if ( this != & other) { - cb_ = other.cb_; - other.cb_ = nullptr; - } + push_coroutine & operator=( push_coroutine && other) noexcept { + if ( this == & other) return * this; + cb_ = other.cb_; + other.cb_ = nullptr; return * this; } @@ -145,36 +147,36 @@ public: class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > { private: - push_coroutine< T & > * c_; + push_coroutine< T & > * c_{ nullptr }; public: - iterator() : - c_( nullptr) { - } + constexpr iterator() noexcept = default; - explicit iterator( push_coroutine< T & > * c) : - c_( c) { + explicit iterator( push_coroutine< T & > * c) noexcept : + c_{ c } { } iterator & operator=( T & t) { BOOST_ASSERT( c_); - if ( ! ( * c_)( t) ) c_ = 0; + if ( ! ( * c_)( t) ) { + c_ = nullptr; + } return * this; } - bool operator==( iterator const& other) const { + bool operator==( iterator const& other) const noexcept { return other.c_ == c_; } - bool operator!=( iterator const& other) const { + bool operator!=( iterator const& other) const noexcept { return other.c_ != c_; } - iterator & operator*() { + iterator & operator*() noexcept { return * this; } - iterator & operator++() { + iterator & operator++() noexcept { return * this; } }; @@ -190,27 +192,28 @@ private: control_block * cb_; - explicit push_coroutine( control_block *); + explicit push_coroutine( control_block *) noexcept; public: - template< typename Fn > - explicit push_coroutine( Fn &&, bool = false); + template< typename Fn, + typename = detail::disable_overload< push_coroutine, Fn > + > + explicit push_coroutine( Fn &&); template< typename StackAllocator, typename Fn > - explicit push_coroutine( StackAllocator, Fn &&, bool = false); + push_coroutine( StackAllocator, Fn &&); - ~push_coroutine(); + ~push_coroutine() noexcept; push_coroutine( push_coroutine const&) = delete; push_coroutine & operator=( push_coroutine const&) = delete; - push_coroutine( push_coroutine &&); + push_coroutine( push_coroutine &&) noexcept; - push_coroutine & operator=( push_coroutine && other) { - if ( this != & other) { - cb_ = other.cb_; - other.cb_ = nullptr; - } + push_coroutine & operator=( push_coroutine && other) noexcept { + if ( this == & other) return * this; + cb_ = other.cb_; + other.cb_ = nullptr; return * this; } diff --git a/boost/coroutine2/detail/push_coroutine.ipp b/boost/coroutine2/detail/push_coroutine.ipp index 5f4817802a..304e07729e 100644 --- a/boost/coroutine2/detail/push_coroutine.ipp +++ b/boost/coroutine2/detail/push_coroutine.ipp @@ -7,16 +7,14 @@ #ifndef BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_IPP #define BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_IPP -#include <memory> #include <utility> #include <boost/assert.hpp> #include <boost/config.hpp> -#include <boost/context/execution_context.hpp> -#include <boost/context/stack_context.hpp> - #include <boost/coroutine2/detail/config.hpp> +#include <boost/coroutine2/detail/create_control_block.ipp> +#include <boost/coroutine2/detail/disable_overload.hpp> #include <boost/coroutine2/fixedsize_stack.hpp> #include <boost/coroutine2/segmented_stack.hpp> @@ -31,52 +29,34 @@ namespace detail { // push_coroutine< T > template< typename T > -push_coroutine< T >::push_coroutine( control_block * cb) : - cb_( cb) { +push_coroutine< T >::push_coroutine( control_block * cb) noexcept : + cb_{ cb } { } template< typename T > -template< typename Fn > -push_coroutine< T >::push_coroutine( Fn && fn, bool preserve_fpu) : - push_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { +template< typename Fn, + typename +> +push_coroutine< T >::push_coroutine( Fn && fn) : + push_coroutine{ default_stack(), std::forward< Fn >( fn) } { } template< typename T > template< typename StackAllocator, typename Fn > -push_coroutine< T >::push_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : - cb_( nullptr) { - context::stack_context sctx( salloc.allocate() ); - // reserve space for control structure -#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) - void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); - std::size_t size = sctx.size - sizeof( control_block); -#else - constexpr std::size_t func_alignment = 64; // alignof( control_block); - constexpr std::size_t func_size = sizeof( control_block); - // reserve space on stack - void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; - // align sp pointer - std::size_t space = func_size + func_alignment; - sp = std::align( func_alignment, func_size, sp, space); - BOOST_ASSERT( nullptr != sp); - // calculate remaining size - std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); -#endif - // placment new for control structure on coroutine stack - cb_= new ( sp) control_block( context::preallocated( sp, size, sctx), - salloc, std::forward< Fn >( fn), preserve_fpu); +push_coroutine< T >::push_coroutine( StackAllocator salloc, Fn && fn) : + cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { } template< typename T > -push_coroutine< T >::~push_coroutine() { +push_coroutine< T >::~push_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } template< typename T > -push_coroutine< T >::push_coroutine( push_coroutine && other) : - cb_( other.cb_) { +push_coroutine< T >::push_coroutine( push_coroutine && other) noexcept : + cb_{ other.cb_ } { other.cb_ = nullptr; } @@ -109,52 +89,34 @@ push_coroutine< T >::operator!() const noexcept { // push_coroutine< T & > template< typename T > -push_coroutine< T & >::push_coroutine( control_block * cb) : - cb_( cb) { +push_coroutine< T & >::push_coroutine( control_block * cb) noexcept : + cb_{ cb } { } template< typename T > -template< typename Fn > -push_coroutine< T & >::push_coroutine( Fn && fn, bool preserve_fpu) : - push_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { +template< typename Fn, + typename +> +push_coroutine< T & >::push_coroutine( Fn && fn) : + push_coroutine{ default_stack(), std::forward< Fn >( fn) } { } template< typename T > template< typename StackAllocator, typename Fn > -push_coroutine< T & >::push_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : - cb_( nullptr) { - context::stack_context sctx( salloc.allocate() ); - // reserve space for control structure -#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) - void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); - std::size_t size = sctx.size - sizeof( control_block); -#else - constexpr std::size_t func_alignment = 64; // alignof( control_block); - constexpr std::size_t func_size = sizeof( control_block); - // reserve space on stack - void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; - // align sp pointer - std::size_t space = func_size + func_alignment; - sp = std::align( func_alignment, func_size, sp, space); - BOOST_ASSERT( nullptr != sp); - // calculate remaining size - std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); -#endif - // placment new for control structure on coroutine stack - cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx), - salloc, std::forward< Fn >( fn), preserve_fpu); +push_coroutine< T & >::push_coroutine( StackAllocator salloc, Fn && fn) : + cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { } template< typename T > -push_coroutine< T & >::~push_coroutine() { +push_coroutine< T & >::~push_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } template< typename T > -push_coroutine< T & >::push_coroutine( push_coroutine && other) : - cb_( other.cb_) { +push_coroutine< T & >::push_coroutine( push_coroutine && other) noexcept : + cb_{ other.cb_ } { other.cb_ = nullptr; } @@ -180,50 +142,32 @@ push_coroutine< T & >::operator!() const noexcept { // push_coroutine< void > inline -push_coroutine< void >::push_coroutine( control_block * cb) : - cb_( cb) { +push_coroutine< void >::push_coroutine( control_block * cb) noexcept : + cb_{ cb } { } -template< typename Fn > -push_coroutine< void >::push_coroutine( Fn && fn, bool preserve_fpu) : - push_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { +template< typename Fn, + typename +> +push_coroutine< void >::push_coroutine( Fn && fn) : + push_coroutine{ default_stack(), std::forward< Fn >( fn) } { } template< typename StackAllocator, typename Fn > -push_coroutine< void >::push_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : - cb_( nullptr) { - context::stack_context sctx( salloc.allocate() ); - // reserve space for control structure -#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) - void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); - std::size_t size = sctx.size - sizeof( control_block); -#else - constexpr std::size_t func_alignment = 64; // alignof( control_block); - constexpr std::size_t func_size = sizeof( control_block); - // reserve space on stack - void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; - // align sp pointer - std::size_t space = func_size + func_alignment; - sp = std::align( func_alignment, func_size, sp, space); - BOOST_ASSERT( nullptr != sp); - // calculate remaining size - std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); -#endif - // placment new for control structure on coroutine stack - cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx), - salloc, std::forward< Fn >( fn), preserve_fpu); +push_coroutine< void >::push_coroutine( StackAllocator salloc, Fn && fn) : + cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { } inline -push_coroutine< void >::~push_coroutine() { +push_coroutine< void >::~push_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } inline -push_coroutine< void >::push_coroutine( push_coroutine && other) : - cb_( other.cb_) { +push_coroutine< void >::push_coroutine( push_coroutine && other) noexcept : + cb_{ other.cb_ } { other.cb_ = nullptr; } diff --git a/boost/coroutine2/detail/state.hpp b/boost/coroutine2/detail/state.hpp index 714548ff63..e338a5aed4 100644 --- a/boost/coroutine2/detail/state.hpp +++ b/boost/coroutine2/detail/state.hpp @@ -23,11 +23,60 @@ namespace coroutines2 { namespace detail { enum class state_t : unsigned int { + none = 0, complete = 1 << 1, - unwind = 1 << 2, - early_exit = 1 << 3 + unwind = 1 << 2 }; + +inline +constexpr state_t +operator&( state_t l, state_t r) { + return static_cast< state_t >( + static_cast< unsigned int >( l) & static_cast< unsigned int >( r) ); +} + +inline +constexpr state_t +operator|( state_t l, state_t r) { + return static_cast< state_t >( + static_cast< unsigned int >( l) | static_cast< unsigned int >( r) ); +} + +inline +constexpr state_t +operator^( state_t l, state_t r) { + return static_cast< state_t >( + static_cast< unsigned int >( l) ^ static_cast< unsigned int >( r) ); +} + +inline +constexpr state_t +operator~( state_t l) { + return static_cast< state_t >( ~static_cast< unsigned int >( l) ); +} + +inline +state_t & +operator&=( state_t & l, state_t r) { + l = l & r; + return l; +} + +inline +state_t & +operator|=( state_t & l, state_t r) { + l = l | r; + return l; +} + +inline +state_t & +operator^=( state_t & l, state_t r) { + l = l ^ r; + return l; +} + }}} #ifdef BOOST_HAS_ABI_HEADERS diff --git a/boost/coroutine2/fixedsize_stack.hpp b/boost/coroutine2/fixedsize_stack.hpp index 8aa66fee61..54fc3dfddc 100644 --- a/boost/coroutine2/fixedsize_stack.hpp +++ b/boost/coroutine2/fixedsize_stack.hpp @@ -22,9 +22,9 @@ namespace boost { namespace coroutines2 { -typedef boost::context::fixedsize_stack fixedsize_stack; +using fixedsize_stack = boost::context::fixedsize_stack; #if !defined(BOOST_USE_SEGMENTED_STACKS) -typedef boost::context::default_stack default_stack; +using default_stack = boost::context::default_stack; #endif }} diff --git a/boost/coroutine2/pooled_fixedsize_stack.hpp b/boost/coroutine2/pooled_fixedsize_stack.hpp new file mode 100644 index 0000000000..24b59bb0d1 --- /dev/null +++ b/boost/coroutine2/pooled_fixedsize_stack.hpp @@ -0,0 +1,33 @@ + +// 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_POOLED_FIXEDSIZE_H +#define BOOST_COROUTINES2_POOLED_FIXEDSIZE_H + +#include <exception> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/context/pooled_fixedsize_stack.hpp> + +#include <boost/coroutine2/detail/coroutine.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { + +using pooled_fixedsize_stack = boost::context::pooled_fixedsize_stack; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES2_POOLED_FIXEDSIZE_H diff --git a/boost/coroutine2/protected_fixedsize_stack.hpp b/boost/coroutine2/protected_fixedsize_stack.hpp index d2ee279775..938b6776db 100644 --- a/boost/coroutine2/protected_fixedsize_stack.hpp +++ b/boost/coroutine2/protected_fixedsize_stack.hpp @@ -22,7 +22,7 @@ namespace boost { namespace coroutines2 { -typedef boost::context::protected_fixedsize_stack protected_fixedsize_stack; +using protected_fixedsize_stack = boost::context::protected_fixedsize_stack; }} diff --git a/boost/coroutine2/segmented_stack.hpp b/boost/coroutine2/segmented_stack.hpp index 8443bc3561..24f93c86c2 100644 --- a/boost/coroutine2/segmented_stack.hpp +++ b/boost/coroutine2/segmented_stack.hpp @@ -24,8 +24,8 @@ namespace coroutines2 { #if defined(BOOST_USE_SEGMENTED_STACKS) # if ! defined(BOOST_WINDOWS) -typedef boost::context::segmented_stack segmented_stack; -typedef boost::context::default_stack default_stack; +using segmented_stack = boost::context::segmented_stack; +using default_stack = boost::context::default_stack; # endif #endif |