diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 67bd232..75fd688 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -40,6 +40,6 @@ exe parser : parser.cpp ; -exe segmented - : segmented.cpp - ; +#exe segmented +# : segmented.cpp +# ; diff --git a/example/segmented.cpp b/example/segmented.cpp index b73ec72..a6ba3f8 100644 --- a/example/segmented.cpp +++ b/example/segmented.cpp @@ -36,15 +36,9 @@ void bar( int i) int main() { int count = 384; -#if defined(BOOST_USE_SEGMENTED_STACKS) std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; std::cout << "initial stack size = " << boost::context::segmented_stack::traits_type::default_size() / 1024 << "kB" << std::endl; std::cout << "application should not fail" << std::endl; -#else - std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; - std::cout << "initial stack size = " << boost::context::fixedsize_stack::traits_type::default_size() / 1024 << "kB" << std::endl; - std::cout << "application might fail" << std::endl; -#endif boost::coroutines2::coroutine< void >::push_type sink( [&]( boost::coroutines2::coroutine< void >::pull_type & source) { diff --git a/include/boost/coroutine2/detail/coroutine.hpp b/include/boost/coroutine2/detail/coroutine.hpp index 7c1483d..1170590 100644 --- a/include/boost/coroutine2/detail/coroutine.hpp +++ b/include/boost/coroutine2/detail/coroutine.hpp @@ -34,8 +34,8 @@ class push_coroutine; # include # include # else -# include -# include +# include +# include # endif # include @@ -45,8 +45,8 @@ class push_coroutine; # include # include # else -# include -# include +# include +# include # endif #endif diff --git a/include/boost/coroutine2/detail/forced_unwind.hpp b/include/boost/coroutine2/detail/forced_unwind.hpp index 0f67f79..d486ed4 100644 --- a/include/boost/coroutine2/detail/forced_unwind.hpp +++ b/include/boost/coroutine2/detail/forced_unwind.hpp @@ -12,8 +12,6 @@ #include #include -#include - #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif diff --git a/include/boost/coroutine2/detail/pull_control_block_ecv2.hpp b/include/boost/coroutine2/detail/pull_control_block_cc.hpp similarity index 72% rename from include/boost/coroutine2/detail/pull_control_block_ecv2.hpp rename to include/boost/coroutine2/detail/pull_control_block_cc.hpp index 58d2488..44a14e2 100644 --- a/include/boost/coroutine2/detail/pull_control_block_ecv2.hpp +++ b/include/boost/coroutine2/detail/pull_control_block_cc.hpp @@ -1,5 +1,5 @@ -// Copyright Oliver Kowalke 2014. +// Copyright Oliver Kowalke 2016. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -11,7 +11,7 @@ #include #include -#include +#include #include @@ -25,7 +25,7 @@ namespace detail { template< typename T > struct pull_coroutine< T >::control_block { - boost::context::execution_context< T * > ctx; + boost::context::continuation c; typename push_coroutine< T >::control_block * other; state_t state; std::exception_ptr except; @@ -37,7 +37,7 @@ struct pull_coroutine< T >::control_block { template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); - control_block( typename push_coroutine< T >::control_block *, boost::context::execution_context< T * > &) noexcept; + control_block( typename push_coroutine< T >::control_block *, boost::context::continuation &) noexcept; ~control_block(); @@ -48,7 +48,9 @@ struct pull_coroutine< T >::control_block { void resume(); - void set( T *); + void set( T const&); + void set( T &&); + void reset(); T & get() noexcept; @@ -57,18 +59,27 @@ struct pull_coroutine< T >::control_block { template< typename T > struct pull_coroutine< T & >::control_block { - boost::context::execution_context< T * > ctx; - typename push_coroutine< T & >::control_block * other; - state_t state; - std::exception_ptr except; - T * t; + struct holder { + T & t; + + holder( T & t_) : + t{ t_ } { + } + }; + + boost::context::continuation c; + typename push_coroutine< T & >::control_block * other; + state_t state; + std::exception_ptr except; + bool bvalid; + typename std::aligned_storage< sizeof( holder), alignof( holder) >::type storage; static void destroy( control_block * cb) noexcept; template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); - control_block( typename push_coroutine< T & >::control_block *, boost::context::execution_context< T * > &) noexcept; + control_block( typename push_coroutine< T & >::control_block *, boost::context::continuation &) noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; @@ -77,13 +88,16 @@ struct pull_coroutine< T & >::control_block { void resume(); + void set( T &); + void reset(); + T & get() noexcept; bool valid() const noexcept; }; struct pull_coroutine< void >::control_block { - boost::context::execution_context< void > ctx; + boost::context::continuation c; push_coroutine< void >::control_block * other; state_t state; std::exception_ptr except; @@ -93,7 +107,7 @@ struct pull_coroutine< void >::control_block { template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); - control_block( push_coroutine< void >::control_block *, boost::context::execution_context< void > &) noexcept; + control_block( push_coroutine< void >::control_block *, boost::context::continuation &) noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; diff --git a/include/boost/coroutine2/detail/pull_control_block_cc.ipp b/include/boost/coroutine2/detail/pull_control_block_cc.ipp new file mode 100644 index 0000000..e77d0af --- /dev/null +++ b/include/boost/coroutine2/detail/pull_control_block_cc.ipp @@ -0,0 +1,460 @@ + +// Copyright Oliver Kowalke 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP +#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { +namespace detail { + +// pull_coroutine< T > + +template< typename T > +void +pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept { + boost::context::continuation c = std::move( cb->c); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + cb->state |= state_t::destroy; + boost::context::callcc( std::move( c) ); +} + +template< typename T > +template< typename StackAllocator, typename Fn > +pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, + Fn && fn) : + c{}, + other{ nullptr }, + state{ state_t::unwind }, + except{}, + bvalid{ false }, + storage{} { +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + std::move( + std::bind( + [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable { + // create synthesized push_coroutine< T > + typename push_coroutine< T >::control_block synthesized_cb{ this, c }; + push_coroutine< T > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }, + std::forward< Fn >( fn), + std::placeholders::_1) ) ); +#else + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable { + // create synthesized push_coroutine< T > + typename push_coroutine< T >::control_block synthesized_cb{ this, c }; + push_coroutine< T > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }); +#endif + if ( boost::context::has_data( c) ) { + set( boost::context::data< T >( c) ); + } +} + +template< typename T > +pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb, + boost::context::continuation & c_) noexcept : + c{ std::move( c_) }, + other{ cb }, + state{ state_t::none }, + except{}, + bvalid{ false }, + storage{} { +} + +template< typename T > +pull_coroutine< T >::control_block::~control_block() { + // destroy data if set + if ( bvalid) { + reinterpret_cast< T * >( std::addressof( storage) )->~T(); + } +} + +template< typename T > +void +pull_coroutine< T >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + +template< typename T > +void +pull_coroutine< T >::control_block::resume() { + c = boost::context::callcc( std::move( c) ); + if ( boost::context::has_data( c) ) { + set( boost::context::data< T >( c) ); + } else { + reset(); + } + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +void +pull_coroutine< T >::control_block::set( T const& t) { + // destroy data if set + if ( bvalid) { + reinterpret_cast< T * >( std::addressof( storage) )->~T(); + } + ::new ( static_cast< void * >( std::addressof( storage) ) ) T( t); + bvalid = true; +} + +template< typename T > +void +pull_coroutine< T >::control_block::set( T && t) { + // destroy data if set + if ( bvalid) { + reinterpret_cast< T * >( std::addressof( storage) )->~T(); + } + ::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( t) ); + bvalid = true; +} + +template< typename T > +void +pull_coroutine< T >::control_block::reset() { + // destroy data if set + if ( bvalid) { + reinterpret_cast< T * >( std::addressof( storage) )->~T(); + } + bvalid = false; +} + +template< typename T > +T & +pull_coroutine< T >::control_block::get() noexcept { + return * reinterpret_cast< T * >( std::addressof( storage) ); +} + +template< typename T > +bool +pull_coroutine< T >::control_block::valid() const noexcept { + return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid; +} + + +// pull_coroutine< T & > + +template< typename T > +void +pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { + boost::context::continuation c = std::move( cb->c); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + cb->state |= state_t::destroy; + boost::context::callcc( std::move( c) ); +} + +template< typename T > +template< typename StackAllocator, typename Fn > +pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, + Fn && fn) : + c{}, + other{ nullptr }, + state{ state_t::unwind }, + except{}, + bvalid{ false }, + storage{} { +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + std::move( + std::bind( + [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable { + // create synthesized push_coroutine< T & > + typename push_coroutine< T & >::control_block synthesized_cb{ this, c }; + push_coroutine< T & > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }, + std::forward< Fn >( fn), + std::placeholders::_1) ) ); +#else + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable { + // create synthesized push_coroutine< T & > + typename push_coroutine< T & >::control_block synthesized_cb{ this, c }; + push_coroutine< T & > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }); +#endif + if ( boost::context::has_data( c) ) { + set( boost::context::data< T & >( c) ); + } +} + +template< typename T > +pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb, + boost::context::continuation & c_) noexcept : + c{ std::move( c_) }, + other{ cb }, + state{ state_t::none }, + except{}, + bvalid{ false }, + storage{} { +} + +template< typename T > +void +pull_coroutine< T & >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + +template< typename T > +void +pull_coroutine< T & >::control_block::resume() { + c = boost::context::callcc( std::move( c) ); + if ( boost::context::has_data( c) ) { + set( boost::context::data< T & >( c) ); + } else { + reset(); + } + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +void +pull_coroutine< T & >::control_block::set( T & t) { + ::new ( static_cast< void * >( std::addressof( storage) ) ) holder{ t }; + bvalid = true; +} + +template< typename T > +void +pull_coroutine< T & >::control_block::reset() { + if ( bvalid) { + reinterpret_cast< holder * >( std::addressof( storage) )->~holder(); + } + bvalid = false; +} + +template< typename T > +T & +pull_coroutine< T & >::control_block::get() noexcept { + return reinterpret_cast< holder * >( std::addressof( storage) )->t; +} + +template< typename T > +bool +pull_coroutine< T & >::control_block::valid() const noexcept { + return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid; +} + + +// pull_coroutine< void > + +inline +void +pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept { + boost::context::continuation c = std::move( cb->c); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + cb->state |= state_t::destroy; + boost::context::callcc( std::move( c) ); +} + +template< typename StackAllocator, typename Fn > +pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, + Fn && fn) : + c{}, + other{ nullptr }, + state{ state_t::unwind }, + except{} { +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + std::move( + std::bind( + [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable { + // create synthesized push_coroutine< void > + typename push_coroutine< void >::control_block synthesized_cb{ this, c }; + push_coroutine< void > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }, + std::forward< Fn >( fn), + std::placeholders::_1) ) ); +#else + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + [this,fn_=std::forward< Fn >( fn)]( boost::context::continuation && c) mutable { + // create synthesized push_coroutine< void > + typename push_coroutine< void >::control_block synthesized_cb{ this, c }; + push_coroutine< void > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized push_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back to ctx + return boost::context::callcc( std::move( other->c) ); + }); +#endif +} + +inline +pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb, + boost::context::continuation & c_) noexcept : + c{ std::move( c_) }, + other{ cb }, + state{ state_t::none }, + except{} { +} + +inline +void +pull_coroutine< void >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + +inline +void +pull_coroutine< void >::control_block::resume() { + c = boost::context::callcc( std::move( c) ); + if ( except) { + std::rethrow_exception( except); + } +} + +inline +bool +pull_coroutine< void >::control_block::valid() const noexcept { + return nullptr != other && state_t::none == ( state & state_t::complete); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP diff --git a/include/boost/coroutine2/detail/pull_control_block_ecv2.ipp b/include/boost/coroutine2/detail/pull_control_block_ecv2.ipp deleted file mode 100644 index a1c7c93..0000000 --- a/include/boost/coroutine2/detail/pull_control_block_ecv2.ipp +++ /dev/null @@ -1,422 +0,0 @@ - -// Copyright Oliver Kowalke 2014. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP -#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines2 { -namespace detail { - -// pull_coroutine< T > - -template< typename T > -void -pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept { - boost::context::execution_context< T * > ctx = std::move( cb->ctx); - // destroy control structure - cb->~control_block(); - // destroy coroutine's stack - cb->state |= state_t::destroy; - ctx( nullptr); -} - -template< typename T > -template< typename StackAllocator, typename Fn > -pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn) : -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - ctx{ std::allocator_arg, palloc, salloc, - std::move( - std::bind( - [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T * > && ctx, T *) mutable { - // create synthesized push_coroutine< T > - typename push_coroutine< T >::control_block synthesized_cb{ this, ctx }; - push_coroutine< T > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - auto result = other->ctx( nullptr); - other->ctx = std::move( std::get< 0 >( result) ); - return std::move( other->ctx); - }, - std::forward< Fn >( fn), - std::placeholders::_1, - std::placeholders::_2))}, -#else - ctx{ std::allocator_arg, palloc, salloc, - [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > && ctx, T *) mutable { - // create synthesized push_coroutine< T > - typename push_coroutine< T >::control_block synthesized_cb{ this, ctx }; - push_coroutine< T > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - auto result = other->ctx( nullptr); - other->ctx = std::move( std::get< 0 >( result) ); - return std::move( other->ctx); - }}, -#endif - other{ nullptr }, - state{ state_t::unwind }, - except{}, - bvalid{ false }, - storage{} { - // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns - resume(); -} - -template< typename T > -pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb, - boost::context::execution_context< T * > & ctx_) noexcept : - ctx{ std::move( ctx_) }, - other{ cb }, - state{ state_t::none }, - except{}, - bvalid{ false }, - storage{} { -} - -template< typename T > -pull_coroutine< T >::control_block::~control_block() { - // destroy data if set - if ( bvalid) { - reinterpret_cast< T * >( std::addressof( storage) )->~T(); - } -} - -template< typename T > -void -pull_coroutine< T >::control_block::deallocate() noexcept { - if ( state_t::none != ( state & state_t::unwind) ) { - destroy( this); - } -} - -template< typename T > -void -pull_coroutine< T >::control_block::resume() { - auto result = ctx( nullptr); - ctx = std::move( std::get< 0 >( result) ); - set( std::get< 1 >( result) ); - if ( except) { - std::rethrow_exception( except); - } -} - -template< typename T > -void -pull_coroutine< T >::control_block::set( T * t) { - // destroy data if set - if ( bvalid) { - reinterpret_cast< T * >( std::addressof( storage) )->~T(); - } - if ( nullptr != t) { - ::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( * t) ); - bvalid = true; - } else { - bvalid = false; - } -} - -template< typename T > -T & -pull_coroutine< T >::control_block::get() noexcept { - return * reinterpret_cast< T * >( std::addressof( storage) ); -} - -template< typename T > -bool -pull_coroutine< T >::control_block::valid() const noexcept { - return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid; -} - - -// pull_coroutine< T & > - -template< typename T > -void -pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { - boost::context::execution_context< T * > ctx = std::move( cb->ctx); - // destroy control structure - cb->~control_block(); - // destroy coroutine's stack - cb->state |= state_t::destroy; - ctx( nullptr); -} - -template< typename T > -template< typename StackAllocator, typename Fn > -pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn) : -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - ctx{ std::allocator_arg, palloc, salloc, - std::move( - std::bind( - [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T *> && ctx, T *) mutable { - // create synthesized push_coroutine< T & > - typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx }; - push_coroutine< T & > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - auto result = other->ctx( nullptr); - other->ctx = std::move( std::get< 0 >( result) ); - return std::move( other->ctx); - }, - std::forward< Fn >( fn), - std::placeholders::_1, - std::placeholders::_2))}, -#else - ctx{ std::allocator_arg, palloc, salloc, - [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > && ctx, T *) mutable { - // create synthesized push_coroutine< T & > - typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx }; - push_coroutine< T & > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - auto result = other->ctx( nullptr); - other->ctx = std::move( std::get< 0 >( result) ); - return std::move( other->ctx); - }}, -#endif - other{ nullptr }, - state{ state_t::unwind }, - except{}, - t{ nullptr } { - // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns - resume(); -} - -template< typename T > -pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb, - boost::context::execution_context< T * > & ctx_) noexcept : - ctx{ std::move( ctx_) }, - other{ cb }, - state{ state_t::none }, - except{}, - t{ nullptr } { -} - -template< typename T > -void -pull_coroutine< T & >::control_block::deallocate() noexcept { - if ( state_t::none != ( state & state_t::unwind) ) { - destroy( this); - } -} - -template< typename T > -void -pull_coroutine< T & >::control_block::resume() { - auto result = ctx( nullptr); - ctx = std::move( std::get< 0 >( result) ); - t = std::get< 1 >( result); - if ( except) { - std::rethrow_exception( except); - } -} - -template< typename T > -T & -pull_coroutine< T & >::control_block::get() noexcept { - return * t; -} - -template< typename T > -bool -pull_coroutine< T & >::control_block::valid() const noexcept { - return nullptr != other && state_t::none == ( state & state_t::complete) && nullptr != t; -} - - -// pull_coroutine< void > - -inline -void -pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept { - boost::context::execution_context< void > ctx = std::move( cb->ctx); - // destroy control structure - cb->~control_block(); - // destroy coroutine's stack - cb->state |= state_t::destroy; - ctx(); -} - -template< typename StackAllocator, typename Fn > -pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn) : -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - ctx{ std::allocator_arg, palloc, salloc, - std::move( - std::bind( - [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< void > && ctx) mutable { - // create synthesized push_coroutine< void > - typename push_coroutine< void >::control_block synthesized_cb{ this, ctx }; - push_coroutine< void > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - other->ctx = other->ctx(); - return std::move( other->ctx); - }, - std::forward< Fn >( fn), - std::placeholders::_1))}, -#else - ctx{ std::allocator_arg, palloc, salloc, - [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< void > && ctx) mutable { - // create synthesized push_coroutine< void > - typename push_coroutine< void >::control_block synthesized_cb{ this, ctx }; - push_coroutine< void > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized push_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - other->ctx = other->ctx(); - return std::move( other->ctx); - }}, -#endif - other{ nullptr }, - state{ state_t::unwind }, - except{} { - // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns - resume(); -} - -inline -pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb, - boost::context::execution_context< void > & ctx_) noexcept : - ctx{ std::move( ctx_) }, - other{ cb }, - state{ state_t::none }, - except{} { -} - -inline -void -pull_coroutine< void >::control_block::deallocate() noexcept { - if ( state_t::none != ( state & state_t::unwind) ) { - destroy( this); - } -} - -inline -void -pull_coroutine< void >::control_block::resume() { - ctx = ctx(); - if ( except) { - std::rethrow_exception( except); - } -} - -inline -bool -pull_coroutine< void >::control_block::valid() const noexcept { - return nullptr != other && state_t::none == ( state & state_t::complete); -} - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP diff --git a/include/boost/coroutine2/detail/push_control_block_ecv2.hpp b/include/boost/coroutine2/detail/push_control_block_cc.hpp similarity index 87% rename from include/boost/coroutine2/detail/push_control_block_ecv2.hpp rename to include/boost/coroutine2/detail/push_control_block_cc.hpp index feb5e4a..d01c98f 100644 --- a/include/boost/coroutine2/detail/push_control_block_ecv2.hpp +++ b/include/boost/coroutine2/detail/push_control_block_cc.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include @@ -24,7 +24,7 @@ namespace detail { template< typename T > struct push_coroutine< T >::control_block { - boost::context::execution_context< T * > ctx; + boost::context::continuation c; typename pull_coroutine< T >::control_block * other; state_t state; std::exception_ptr except; @@ -34,7 +34,7 @@ struct push_coroutine< T >::control_block { template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); - control_block( typename pull_coroutine< T >::control_block *, boost::context::execution_context< T * > &) noexcept; + control_block( typename pull_coroutine< T >::control_block *, boost::context::continuation &) noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; @@ -50,7 +50,7 @@ struct push_coroutine< T >::control_block { template< typename T > struct push_coroutine< T & >::control_block { - boost::context::execution_context< T * > ctx; + boost::context::continuation c; typename pull_coroutine< T & >::control_block * other; state_t state; std::exception_ptr except; @@ -60,7 +60,7 @@ struct push_coroutine< T & >::control_block { template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); - control_block( typename pull_coroutine< T & >::control_block *, boost::context::execution_context< T * > &) noexcept; + control_block( typename pull_coroutine< T & >::control_block *, boost::context::continuation &) noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; @@ -73,7 +73,7 @@ struct push_coroutine< T & >::control_block { }; struct push_coroutine< void >::control_block { - boost::context::execution_context< void > ctx; + boost::context::continuation c; pull_coroutine< void >::control_block * other; state_t state; std::exception_ptr except; @@ -83,7 +83,7 @@ struct push_coroutine< void >::control_block { template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); - control_block( pull_coroutine< void >::control_block *, boost::context::execution_context< void > &) noexcept; + control_block( pull_coroutine< void >::control_block *, boost::context::continuation &) noexcept; control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; diff --git a/include/boost/coroutine2/detail/push_control_block_cc.ipp b/include/boost/coroutine2/detail/push_control_block_cc.ipp new file mode 100644 index 0000000..522de2c --- /dev/null +++ b/include/boost/coroutine2/detail/push_control_block_cc.ipp @@ -0,0 +1,408 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP +#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines2 { +namespace detail { + +// push_coroutine< T > + +template< typename T > +void +push_coroutine< T >::control_block::destroy( control_block * cb) noexcept { + boost::context::continuation c = std::move( cb->c); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + cb->state |= state_t::destroy; + boost::context::callcc( std::move( c) ); +} + +template< typename T > +template< typename StackAllocator, typename Fn > +push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, + Fn && fn) : + c{}, + other{ nullptr }, + state{ state_t::unwind }, + except{} { +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + std::move( + std::bind( + [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable { + // create synthesized pull_coroutine< T > + typename pull_coroutine< T >::control_block synthesized_cb{ this, c }; + pull_coroutine< T > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + other->c = boost::context::callcc( std::move( other->c) ); + // set transferred value + if ( boost::context::has_data( other->c) ) { + synthesized_cb.set( boost::context::data< T >( other->c) ); + } else { + synthesized_cb.reset(); + } + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }, + std::forward< Fn >( fn), + std::placeholders::_1) ) ); +#else + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable { + // create synthesized pull_coroutine< T > + typename pull_coroutine< T >::control_block synthesized_cb{ this, c }; + pull_coroutine< T > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + other->c = boost::context::callcc( std::move( other->c) ); + // set transferred value + if ( boost::context::has_data( other->c) ) { + synthesized_cb.set( boost::context::data< T >( other->c) ); + } else { + synthesized_cb.reset(); + } + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }); +#endif +} + +template< typename T > +push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb, + boost::context::continuation & c_) noexcept : + c{ std::move( c_) }, + other{ cb }, + state{ state_t::none }, + except{} { +} + +template< typename T > +void +push_coroutine< T >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + +template< typename T > +void +push_coroutine< T >::control_block::resume( T const& data) { + // pass an pointer to other context + c = boost::context::callcc( std::move( c), data); + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +void +push_coroutine< T >::control_block::resume( T && data) { + // pass an pointer to other context + c = boost::context::callcc( std::move( c), std::move( data) ); + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +bool +push_coroutine< T >::control_block::valid() const noexcept { + return state_t::none == ( state & state_t::complete ); +} + + +// push_coroutine< T & > + +template< typename T > +void +push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { + boost::context::continuation c = std::move( cb->c); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + cb->state |= state_t::destroy; + boost::context::callcc( std::move( c) ); +} + +template< typename T > +template< typename StackAllocator, typename Fn > +push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, + Fn && fn) : + c{}, + other{ nullptr }, + state{ state_t::unwind }, + except{} { +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + std::move( + std::bind( + [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable { + // create synthesized pull_coroutine< T & > + typename pull_coroutine< T & >::control_block synthesized_cb{ this, c }; + pull_coroutine< T & > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + other->c = boost::context::callcc( std::move( other->c) ); + // set transferred value + if ( boost::context::has_data( other->c) ) { + synthesized_cb.set( boost::context::data< T & >( other->c) ); + } else { + synthesized_cb.reset(); + } + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }, + std::forward< Fn >( fn), + std::placeholders::_1) ) ); +#else + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable { + // create synthesized pull_coroutine< T & > + typename pull_coroutine< T & >::control_block synthesized_cb{ this, c }; + pull_coroutine< T & > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + other->c = boost::context::callcc( std::move( other->c) ); + // set transferred value + if ( boost::context::has_data( other->c) ) { + synthesized_cb.set( boost::context::data< T & >( other->c) ); + } else { + synthesized_cb.reset(); + } + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }); +#endif +} + +template< typename T > +push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb, + boost::context::continuation & c_) noexcept : + c{ std::move( c_) }, + other{ cb }, + state{ state_t::none }, + except{} { +} + +template< typename T > +void +push_coroutine< T & >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + +template< typename T > +void +push_coroutine< T & >::control_block::resume( T & t) { + // pass an pointer to other context + c = boost::context::callcc( std::move( c), std::ref( t) ); + if ( except) { + std::rethrow_exception( except); + } +} + +template< typename T > +bool +push_coroutine< T & >::control_block::valid() const noexcept { + return state_t::none == ( state & state_t::complete ); +} + + +// push_coroutine< void > + +inline +void +push_coroutine< void >::control_block::destroy( control_block * cb) noexcept { + boost::context::continuation c = std::move( cb->c); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + cb->state |= state_t::destroy; + boost::context::callcc( std::move( c) ); +} + +template< typename StackAllocator, typename Fn > +push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : + c{}, + other{ nullptr }, + state{ state_t::unwind }, + except{} { +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + std::move( + std::bind( + [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable { + // create synthesized pull_coroutine< void > + typename pull_coroutine< void >::control_block synthesized_cb{ this, c }; + pull_coroutine< void > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + other->c = boost::context::callcc( std::move( other->c) ); + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }, + std::forward< Fn >( fn), + std::placeholders::_1) ) ); +#else + c = boost::context::callcc( + std::allocator_arg, palloc, salloc, + [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable { + // create synthesized pull_coroutine< void > + typename pull_coroutine< void >::control_block synthesized_cb{ this, c}; + pull_coroutine< void > synthesized{ & synthesized_cb }; + other = & synthesized_cb; + other->c = boost::context::callcc( std::move( other->c) ); + if ( state_t::none == ( state & state_t::destroy) ) { + try { + auto fn = std::move( fn_); + // call coroutine-fn with synthesized pull_coroutine as argument + fn( synthesized); + } catch ( boost::context::detail::forced_unwind const&) { + throw; + } catch (...) { + // store other exceptions in exception-pointer + except = std::current_exception(); + } + } + // set termination flags + state |= state_t::complete; + // jump back + return boost::context::callcc( std::move( other->c) ); + }); +#endif +} + +inline +push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb, + boost::context::continuation & c_) noexcept : + c{ std::move( c_) }, + other{ cb }, + state{ state_t::none }, + except{} { +} + +inline +void +push_coroutine< void >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + +inline +void +push_coroutine< void >::control_block::resume() { + c = boost::context::callcc( std::move( c) ); + if ( except) { + std::rethrow_exception( except); + } +} + +inline +bool +push_coroutine< void >::control_block::valid() const noexcept { + return state_t::none == ( state & state_t::complete ); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP diff --git a/include/boost/coroutine2/detail/push_control_block_ecv2.ipp b/include/boost/coroutine2/detail/push_control_block_ecv2.ipp deleted file mode 100644 index 7ed6c57..0000000 --- a/include/boost/coroutine2/detail/push_control_block_ecv2.ipp +++ /dev/null @@ -1,392 +0,0 @@ - -// Copyright Oliver Kowalke 2014. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP -#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP - -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines2 { -namespace detail { - -// push_coroutine< T > - -template< typename T > -void -push_coroutine< T >::control_block::destroy( control_block * cb) noexcept { - boost::context::execution_context< T * > ctx = std::move( cb->ctx); - // destroy control structure - cb->~control_block(); - // destroy coroutine's stack - cb->state |= state_t::destroy; - ctx( nullptr); -} - -template< typename T > -template< typename StackAllocator, typename Fn > -push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn) : -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - ctx{ std::allocator_arg, palloc, salloc, - std::move( - std::bind( - [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T * > && ctx, T * data) mutable { - // create synthesized pull_coroutine< T > - typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx }; - pull_coroutine< T > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - // set transferred value - synthesized_cb.set( data); - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - auto result = other->ctx( nullptr); - other->ctx = std::move( std::get< 0 >( result) ); - return std::move( other->ctx); - }, - std::forward< Fn >( fn), - std::placeholders::_1, - std::placeholders::_2))}, -#else - ctx{ std::allocator_arg, palloc, salloc, - [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > && ctx, T * data) mutable { - // create synthesized pull_coroutine< T > - typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx }; - pull_coroutine< T > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - // set transferred value - synthesized_cb.set( data); - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - auto result = other->ctx( nullptr); - other->ctx = std::move( std::get< 0 >( result) ); - return std::move( other->ctx); - }}, -#endif - other{ nullptr }, - state{ state_t::unwind }, - except{} { -} - -template< typename T > -push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb, - boost::context::execution_context< T * > & ctx_) noexcept : - ctx{ std::move( ctx_) }, - other{ cb }, - state{ state_t::none }, - except{} { -} - -template< typename T > -void -push_coroutine< T >::control_block::deallocate() noexcept { - if ( state_t::none != ( state & state_t::unwind) ) { - destroy( this); - } -} - -template< typename T > -void -push_coroutine< T >::control_block::resume( T const& data) { - // pass an pointer to other context - auto result = ctx( const_cast< T * >( & data) ); - ctx = std::move( std::get< 0 >( result) ); - if ( except) { - std::rethrow_exception( except); - } -} - -template< typename T > -void -push_coroutine< T >::control_block::resume( T && data) { - // pass an pointer to other context - auto result = ctx( std::addressof( data) ); - ctx = std::move( std::get< 0 >( result) ); - if ( except) { - std::rethrow_exception( except); - } -} - -template< typename T > -bool -push_coroutine< T >::control_block::valid() const noexcept { - return state_t::none == ( state & state_t::complete ); -} - - -// push_coroutine< T & > - -template< typename T > -void -push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { - boost::context::execution_context< T * > ctx = std::move( cb->ctx); - // destroy control structure - cb->~control_block(); - // destroy coroutine's stack - cb->state |= state_t::destroy; - ctx( nullptr); -} - -template< typename T > -template< typename StackAllocator, typename Fn > -push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, - Fn && fn) : -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - ctx{ std::allocator_arg, palloc, salloc, - std::move( - std::bind( - [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T * > && ctx, T * data) mutable { - // create synthesized pull_coroutine< T & > - typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx }; - pull_coroutine< T & > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - // set transferred value - synthesized_cb.t = data; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - auto result = other->ctx( nullptr); - other->ctx = std::move( std::get< 0 >( result) ); - return std::move( other->ctx); - }, - std::forward< Fn >( fn), - std::placeholders::_1, - std::placeholders::_2))}, -#else - ctx{ std::allocator_arg, palloc, salloc, - [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > && ctx, T * data) mutable { - // create synthesized pull_coroutine< T & > - typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx }; - pull_coroutine< T & > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - // set transferred value - synthesized_cb.t = data; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - auto result = other->ctx( nullptr); - other->ctx = std::move( std::get< 0 >( result) ); - return std::move( other->ctx); - }}, -#endif - other{ nullptr }, - state{ state_t::unwind }, - except{} { -} - -template< typename T > -push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb, - boost::context::execution_context< T * > & ctx_) noexcept : - ctx{ std::move( ctx_) }, - other{ cb }, - state{ state_t::none }, - except{} { -} - -template< typename T > -void -push_coroutine< T & >::control_block::deallocate() noexcept { - if ( state_t::none != ( state & state_t::unwind) ) { - destroy( this); - } -} - -template< typename T > -void -push_coroutine< T & >::control_block::resume( T & t) { - // pass an pointer to other context - auto result = ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) ); - ctx = std::move( std::get< 0 >( result) ); - if ( except) { - std::rethrow_exception( except); - } -} - -template< typename T > -bool -push_coroutine< T & >::control_block::valid() const noexcept { - return state_t::none == ( state & state_t::complete ); -} - - -// push_coroutine< void > - -inline -void -push_coroutine< void >::control_block::destroy( control_block * cb) noexcept { - boost::context::execution_context< void > ctx = std::move( cb->ctx); - // destroy control structure - cb->~control_block(); - // destroy coroutine's stack - cb->state |= state_t::destroy; - ctx(); -} - -template< typename StackAllocator, typename Fn > -push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - ctx{ std::allocator_arg, palloc, salloc, - std::move( - std::bind( - [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< void > && ctx) mutable { - // create synthesized pull_coroutine< void > - typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx }; - pull_coroutine< void > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - other->ctx = other->ctx(); - return std::move( other->ctx); - }, - std::forward< Fn >( fn), - std::placeholders::_1))}, -#else - ctx{ std::allocator_arg, palloc, salloc, - [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< void > && ctx) mutable { - // create synthesized pull_coroutine< void > - typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx}; - pull_coroutine< void > synthesized{ & synthesized_cb }; - other = & synthesized_cb; - if ( state_t::none == ( state & state_t::destroy) ) { - try { - auto fn = std::move( fn_); - // call coroutine-fn with synthesized pull_coroutine as argument - fn( synthesized); - } catch ( boost::context::detail::forced_unwind const&) { - throw; - } catch (...) { - // store other exceptions in exception-pointer - except = std::current_exception(); - } - } - // set termination flags - state |= state_t::complete; - // jump back to ctx - other->ctx = other->ctx(); - return std::move( other->ctx); - }}, -#endif - other{ nullptr }, - state{ state_t::unwind }, - except{} { -} - -inline -push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb, - boost::context::execution_context< void > & ctx_) noexcept : - ctx{ std::move( ctx_) }, - other{ cb }, - state{ state_t::none }, - except{} { -} - -inline -void -push_coroutine< void >::control_block::deallocate() noexcept { - if ( state_t::none != ( state & state_t::unwind) ) { - destroy( this); - } -} - -inline -void -push_coroutine< void >::control_block::resume() { - ctx = ctx(); - if ( except) { - std::rethrow_exception( except); - } -} - -inline -bool -push_coroutine< void >::control_block::valid() const noexcept { - return state_t::none == ( state & state_t::complete ); -} - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP diff --git a/include/boost/coroutine2/detail/push_coroutine.hpp b/include/boost/coroutine2/detail/push_coroutine.hpp index 4dc8609..533d4f9 100644 --- a/include/boost/coroutine2/detail/push_coroutine.hpp +++ b/include/boost/coroutine2/detail/push_coroutine.hpp @@ -79,7 +79,7 @@ public: } iterator & operator=( T t) { - BOOST_ASSERT( c_); + BOOST_ASSERT( nullptr != c_); if ( ! ( * c_)( t) ) { c_ = nullptr; } @@ -157,7 +157,7 @@ public: } iterator & operator=( T & t) { - BOOST_ASSERT( c_); + BOOST_ASSERT( nullptr != c_); if ( ! ( * c_)( t) ) { c_ = nullptr; } diff --git a/test/test_coroutine.cpp b/test/test_coroutine.cpp index e274b01..f4117af 100644 --- a/test/test_coroutine.cpp +++ b/test/test_coroutine.cpp @@ -24,7 +24,7 @@ int value1 = 0; std::string value2 = ""; bool value3 = false; double value4 = .0; -int * value5 = 0; +int * value5 = nullptr; int& value6 = value1; int& value7 = value1; int value8 = 0; @@ -171,7 +171,7 @@ void f91( coro::coroutine< int const* >::pull_type & c) void f10( coro::coroutine< int & >::pull_type & c) { - int const& i = c.get(); + int & i = c.get(); value5 = const_cast< int * >( & i); } @@ -370,7 +370,7 @@ void test_fp() void test_ptr() { - value5 = 0; + value5 = nullptr; int a = 3; coro::coroutine< int * >::push_type coro( f9); @@ -382,7 +382,7 @@ void test_ptr() void test_const_ptr() { - value5 = 0; + value5 = nullptr; int a = 3; coro::coroutine< int const* >::push_type coro( f91); @@ -394,19 +394,20 @@ void test_const_ptr() void test_ref() { - value5 = 0; + value5 = nullptr; - int a = 3; + int a_ = 3; + int & a = a_; coro::coroutine< int & >::push_type coro( f10); BOOST_CHECK( coro); - coro( a); + coro( std::ref( a) ); BOOST_CHECK( ! coro); BOOST_CHECK_EQUAL( & a, value5); } void test_const_ref() { - value5 = 0; + value5 = nullptr; int a = 3; coro::coroutine< int const& >::push_type coro( f101);