summaryrefslogtreecommitdiff
path: root/boost/coroutine2
diff options
context:
space:
mode:
Diffstat (limited to 'boost/coroutine2')
-rw-r--r--boost/coroutine2/all.hpp1
-rw-r--r--boost/coroutine2/coroutine.hpp4
-rw-r--r--boost/coroutine2/detail/coroutine.hpp29
-rw-r--r--boost/coroutine2/detail/create_control_block.ipp60
-rw-r--r--boost/coroutine2/detail/decay_copy.hpp36
-rw-r--r--boost/coroutine2/detail/disable_overload.hpp34
-rw-r--r--boost/coroutine2/detail/forced_unwind.hpp6
-rw-r--r--boost/coroutine2/detail/pull_control_block.ipp299
-rw-r--r--boost/coroutine2/detail/pull_control_block_ecv1.hpp (renamed from boost/coroutine2/detail/pull_control_block.hpp)54
-rw-r--r--boost/coroutine2/detail/pull_control_block_ecv1.ipp421
-rw-r--r--boost/coroutine2/detail/pull_control_block_ecv2.hpp114
-rw-r--r--boost/coroutine2/detail/pull_control_block_ecv2.ipp411
-rw-r--r--boost/coroutine2/detail/pull_coroutine.hpp131
-rw-r--r--boost/coroutine2/detail/pull_coroutine.ipp158
-rw-r--r--boost/coroutine2/detail/push_control_block.ipp289
-rw-r--r--boost/coroutine2/detail/push_control_block_ecv1.hpp (renamed from boost/coroutine2/detail/push_control_block.hpp)48
-rw-r--r--boost/coroutine2/detail/push_control_block_ecv1.ipp418
-rw-r--r--boost/coroutine2/detail/push_control_block_ecv2.hpp104
-rw-r--r--boost/coroutine2/detail/push_control_block_ecv2.ipp377
-rw-r--r--boost/coroutine2/detail/push_coroutine.hpp115
-rw-r--r--boost/coroutine2/detail/push_coroutine.ipp138
-rw-r--r--boost/coroutine2/detail/state.hpp53
-rw-r--r--boost/coroutine2/fixedsize_stack.hpp4
-rw-r--r--boost/coroutine2/pooled_fixedsize_stack.hpp33
-rw-r--r--boost/coroutine2/protected_fixedsize_stack.hpp2
-rw-r--r--boost/coroutine2/segmented_stack.hpp4
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