summaryrefslogtreecommitdiff
path: root/boost/coroutine2/detail
diff options
context:
space:
mode:
Diffstat (limited to 'boost/coroutine2/detail')
-rw-r--r--boost/coroutine2/detail/config.hpp51
-rw-r--r--boost/coroutine2/detail/coroutine.hpp44
-rw-r--r--boost/coroutine2/detail/forced_unwind.hpp33
-rw-r--r--boost/coroutine2/detail/pull_control_block.hpp100
-rw-r--r--boost/coroutine2/detail/pull_control_block.ipp258
-rw-r--r--boost/coroutine2/detail/pull_coroutine.hpp312
-rw-r--r--boost/coroutine2/detail/pull_coroutine.ipp271
-rw-r--r--boost/coroutine2/detail/push_control_block.hpp104
-rw-r--r--boost/coroutine2/detail/push_control_block.ipp281
-rw-r--r--boost/coroutine2/detail/push_coroutine.hpp242
-rw-r--r--boost/coroutine2/detail/push_coroutine.ipp253
-rw-r--r--boost/coroutine2/detail/state.hpp37
12 files changed, 1986 insertions, 0 deletions
diff --git a/boost/coroutine2/detail/config.hpp b/boost/coroutine2/detail/config.hpp
new file mode 100644
index 0000000000..c439ecc0ea
--- /dev/null
+++ b/boost/coroutine2/detail/config.hpp
@@ -0,0 +1,51 @@
+
+// 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_CONFIG_H
+#define BOOST_COROUTINES2_DETAIL_CONFIG_H
+
+#include <boost/config.hpp>
+#include <boost/context/detail/config.hpp>
+#include <boost/detail/workaround.hpp>
+
+#ifdef BOOST_COROUTINES2_DECL
+# undef BOOST_COROUTINES2_DECL
+#endif
+
+#if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES2_DYN_LINK) ) && ! defined(BOOST_COROUTINES2_STATIC_LINK)
+# if defined(BOOST_COROUTINES2_SOURCE)
+# define BOOST_COROUTINES2_DECL BOOST_SYMBOL_EXPORT
+# define BOOST_COROUTINES2_BUILD_DLL
+# else
+# define BOOST_COROUTINES2_DECL BOOST_SYMBOL_IMPORT
+# endif
+#endif
+
+#if ! defined(BOOST_COROUTINES2_DECL)
+# define BOOST_COROUTINES2_DECL
+#endif
+
+#if ! defined(BOOST_COROUTINES2_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_COROUTINES2_NO_LIB)
+# define BOOST_LIB_NAME boost_coroutine
+# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES2_DYN_LINK)
+# define BOOST_DYN_LINK
+# endif
+# include <boost/config/auto_link.hpp>
+#endif
+
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+# if ! ( (defined(__GNUC__) && __GNUC__ > 3 && __GNUC_MINOR__ > 6) || \
+ (defined(__clang__) && __clang_major__ > 2 && __clang_minor__ > 3) )
+# error "compiler does not support segmented_stack stacks"
+# endif
+# define BOOST_COROUTINES2_SEGMENTS 10
+#endif
+
+#if defined(BOOST_CONTEXT_NO_EXECUTION_CONTEXT)
+# error "execution_context from boost.context not supported"
+#endif
+
+#endif // BOOST_COROUTINES2_DETAIL_CONFIG_H
diff --git a/boost/coroutine2/detail/coroutine.hpp b/boost/coroutine2/detail/coroutine.hpp
new file mode 100644
index 0000000000..55641e443c
--- /dev/null
+++ b/boost/coroutine2/detail/coroutine.hpp
@@ -0,0 +1,44 @@
+
+// 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_COROUTINE_HPP
+#define BOOST_COROUTINES2_DETAIL_COROUTINE_HPP
+
+#include <boost/config.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines2 {
+namespace detail {
+
+template< typename T >
+class pull_coroutine;
+
+template< typename T >
+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>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES2_DETAIL_COROUTINE_HPP
diff --git a/boost/coroutine2/detail/forced_unwind.hpp b/boost/coroutine2/detail/forced_unwind.hpp
new file mode 100644
index 0000000000..e04eb72d69
--- /dev/null
+++ b/boost/coroutine2/detail/forced_unwind.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_DETAIL_FORCED_UNWIND_HPP
+#define BOOST_COROUTINES2_DETAIL_FORCED_UNWIND_HPP
+
+#include <exception>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+
+#include <boost/context/execution_context.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines2 {
+namespace detail {
+
+struct forced_unwind {};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES2_DETAIL_FORCED_UNWIND_HPP
diff --git a/boost/coroutine2/detail/pull_control_block.hpp b/boost/coroutine2/detail/pull_control_block.hpp
new file mode 100644
index 0000000000..1abb34a0db
--- /dev/null
+++ b/boost/coroutine2/detail/pull_control_block.hpp
@@ -0,0 +1,100 @@
+
+// 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 <boost/config.hpp>
+#include <boost/context/execution_context.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 {
+ typename push_coroutine< T >::control_block * other;
+ boost::context::execution_context caller;
+ boost::context::execution_context callee;
+ bool preserve_fpu;
+ int state;
+ std::exception_ptr except;
+
+ template< typename StackAllocator, typename Fn >
+ control_block( context::preallocated, StackAllocator, Fn &&, bool);
+
+ explicit control_block( typename push_coroutine< T >::control_block *);
+
+ ~control_block();
+
+ control_block( control_block &) = delete;
+ control_block & operator=( control_block &) = delete;
+
+ void resume();
+
+ bool valid() const noexcept;
+};
+
+template< typename T >
+struct pull_coroutine< T & >::control_block {
+ typename push_coroutine< T & >::control_block * other;
+ boost::context::execution_context caller;
+ boost::context::execution_context callee;
+ bool preserve_fpu;
+ int state;
+ std::exception_ptr except;
+
+ template< typename StackAllocator, typename Fn >
+ control_block( context::preallocated, StackAllocator, Fn &&, bool);
+
+ explicit control_block( typename push_coroutine< T & >::control_block *);
+
+ ~control_block();
+
+ control_block( control_block &) = delete;
+ control_block & operator=( control_block &) = delete;
+
+ void resume();
+
+ bool valid() const noexcept;
+};
+
+struct pull_coroutine< void >::control_block {
+ push_coroutine< void >::control_block * other;
+ boost::context::execution_context caller;
+ boost::context::execution_context callee;
+ bool preserve_fpu;
+ int state;
+ std::exception_ptr except;
+
+ template< typename StackAllocator, typename Fn >
+ control_block( context::preallocated, StackAllocator, Fn &&, bool);
+
+ explicit control_block( push_coroutine< void >::control_block *);
+
+ ~control_block();
+
+ control_block( control_block &) = delete;
+ control_block & operator=( control_block &) = delete;
+
+ 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.ipp b/boost/coroutine2/detail/pull_control_block.ipp
new file mode 100644
index 0000000000..fd806ecb21
--- /dev/null
+++ b/boost/coroutine2/detail/pull_control_block.ipp
@@ -0,0 +1,258 @@
+
+// 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 <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),
+ caller( boost::context::execution_context::current() ),
+ callee( palloc, salloc,
+ [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) {
+ // create synthesized push_coroutine< T >
+ typename push_coroutine< T >::control_block synthesized_cb( this);
+ 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 caller
+ caller( preserve_fpu);
+ BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+ }),
+ preserve_fpu( preserve_fpu_),
+ state( static_cast< int >( state_t::unwind) ),
+ except() {
+ callee( preserve_fpu);
+}
+
+template< typename T >
+pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb) :
+ other( cb),
+ caller( other->callee),
+ callee( other->caller),
+ preserve_fpu( other->preserve_fpu),
+ state( 0),
+ except() {
+}
+
+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);
+ callee( preserve_fpu);
+ }
+}
+
+template< typename T >
+void
+pull_coroutine< T >::control_block::resume() {
+ callee( 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
+pull_coroutine< T >::control_block::valid() const noexcept {
+ return nullptr != other && nullptr != other->t && 0 == ( state & static_cast< int >( state_t::complete) );
+}
+
+
+// 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),
+ caller( boost::context::execution_context::current() ),
+ callee( palloc, salloc,
+ [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) {
+ // create synthesized push_coroutine< T >
+ typename push_coroutine< T & >::control_block synthesized_cb( this);
+ 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 caller
+ caller( preserve_fpu);
+ BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+ }),
+ preserve_fpu( preserve_fpu_),
+ state( static_cast< int >( state_t::unwind) ),
+ except() {
+ callee( preserve_fpu);
+}
+
+template< typename T >
+pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb) :
+ other( cb),
+ caller( other->callee),
+ callee( other->caller),
+ preserve_fpu( other->preserve_fpu),
+ state( 0),
+ except() {
+}
+
+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);
+ callee( preserve_fpu);
+ }
+}
+
+template< typename T >
+void
+pull_coroutine< T & >::control_block::resume() {
+ callee( 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
+pull_coroutine< T & >::control_block::valid() const noexcept {
+ return nullptr != other && nullptr != other->t && 0 == ( state & static_cast< int >( state_t::complete) );
+}
+
+
+// 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),
+ caller( boost::context::execution_context::current() ),
+ callee( palloc, salloc,
+ [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) {
+ // create synthesized push_coroutine< T >
+ typename push_coroutine< void >::control_block synthesized_cb( this);
+ 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 caller
+ caller( preserve_fpu);
+ BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+ }),
+ preserve_fpu( preserve_fpu_),
+ state( static_cast< int >( state_t::unwind) ),
+ except() {
+ callee( preserve_fpu);
+}
+
+inline
+pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb) :
+ other( cb),
+ caller( other->callee),
+ callee( other->caller),
+ 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);
+ callee( preserve_fpu);
+ }
+}
+
+inline
+void
+pull_coroutine< void >::control_block::resume() {
+ callee( 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_coroutine.hpp b/boost/coroutine2/detail/pull_coroutine.hpp
new file mode 100644
index 0000000000..ff76bd3aac
--- /dev/null
+++ b/boost/coroutine2/detail/pull_coroutine.hpp
@@ -0,0 +1,312 @@
+
+// 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_COROUTINE_HPP
+#define BOOST_COROUTINES2_DETAIL_PULL_COROUTINE_HPP
+
+#include <iterator>
+#include <type_traits>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/context/execution_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 T >
+class pull_coroutine {
+private:
+ template< typename X >
+ friend class push_coroutine;
+
+ struct control_block;
+
+ control_block * cb_;
+
+ explicit pull_coroutine( control_block *);
+
+ bool has_result_() const;
+
+public:
+ template< typename Fn >
+ explicit pull_coroutine( Fn &&, bool = false);
+
+ template< typename StackAllocator, typename Fn >
+ explicit pull_coroutine( StackAllocator, Fn &&, bool = false);
+
+ ~pull_coroutine();
+
+ pull_coroutine( pull_coroutine const&) = delete;
+ pull_coroutine & operator=( pull_coroutine const&) = delete;
+
+ pull_coroutine( pull_coroutine &&);
+
+ pull_coroutine & operator=( pull_coroutine && other) {
+ if ( this != & other) {
+ cb_ = other.cb_;
+ other.cb_ = nullptr;
+ }
+ return * this;
+ }
+
+ pull_coroutine & operator()();
+
+ explicit operator bool() const noexcept;
+
+ bool operator!() const noexcept;
+
+ T get() const noexcept;
+
+ class iterator : public std::iterator< std::input_iterator_tag, typename std::remove_reference< T >::type > {
+ private:
+ pull_coroutine< T > * c_;
+
+ void fetch_() {
+ BOOST_ASSERT( nullptr != c_);
+ if ( ! ( * c_) ) {
+ c_ = nullptr;
+ return;
+ }
+ }
+
+ void increment_() {
+ BOOST_ASSERT( nullptr != c_);
+ BOOST_ASSERT( * c_);
+ ( * c_)();
+ fetch_();
+ }
+
+ public:
+ typedef typename iterator::pointer pointer_t;
+ typedef typename iterator::reference reference_t;
+
+ iterator() :
+ c_( nullptr) {
+ }
+
+ explicit iterator( pull_coroutine< T > * c) :
+ c_( c) {
+ fetch_();
+ }
+
+ iterator( iterator const& other) :
+ c_( other.c_) {
+ }
+
+ iterator & operator=( iterator const& other) {
+ if ( this == & other) return * this;
+ c_ = other.c_;
+ return * this;
+ }
+
+ bool operator==( iterator const& other) const {
+ return other.c_ == c_;
+ }
+
+ bool operator!=( iterator const& other) const {
+ return other.c_ != c_;
+ }
+
+ iterator & operator++() {
+ increment_();
+ return * this;
+ }
+
+ iterator operator++( int) = delete;
+
+ reference_t operator*() const {
+ return * c_->cb_->other->t;
+ }
+
+ pointer_t operator->() const {
+ return c_->cb_->other->t;
+ }
+ };
+
+ friend class iterator;
+};
+
+template< typename T >
+class pull_coroutine< T & > {
+private:
+ template< typename X >
+ friend class push_coroutine;
+
+ struct control_block;
+
+ control_block * cb_;
+
+ explicit pull_coroutine( control_block *);
+
+ bool has_result_() const;
+
+public:
+ template< typename Fn >
+ explicit pull_coroutine( Fn &&, bool = false);
+
+ template< typename StackAllocator, typename Fn >
+ explicit pull_coroutine( StackAllocator, Fn &&, bool = false);
+
+ ~pull_coroutine();
+
+ pull_coroutine( pull_coroutine const&) = delete;
+ pull_coroutine & operator=( pull_coroutine const&) = delete;
+
+ pull_coroutine( pull_coroutine &&);
+
+ pull_coroutine & operator=( pull_coroutine && other) {
+ if ( this != & other) {
+ cb_ = other.cb_;
+ other.cb_ = nullptr;
+ }
+ return * this;
+ }
+
+ pull_coroutine & operator()();
+
+ explicit operator bool() const noexcept;
+
+ bool operator!() const noexcept;
+
+ T & get() const noexcept;
+
+ class iterator : public std::iterator< std::input_iterator_tag, typename std::remove_reference< T >::type > {
+ private:
+ pull_coroutine< T & > * c_;
+
+ void fetch_() {
+ BOOST_ASSERT( nullptr != c_);
+ if ( ! ( * c_) ) {
+ c_ = nullptr;
+ return;
+ }
+ }
+
+ void increment_() {
+ BOOST_ASSERT( nullptr != c_);
+ BOOST_ASSERT( * c_);
+ ( * c_)();
+ fetch_();
+ }
+
+ public:
+ typedef typename iterator::pointer pointer_t;
+ typedef typename iterator::reference reference_t;
+
+ iterator() :
+ c_( nullptr) {
+ }
+
+ explicit iterator( pull_coroutine< T & > * c) :
+ c_( c) {
+ fetch_();
+ }
+
+ iterator( iterator const& other) :
+ c_( other.c_) {
+ }
+
+ iterator & operator=( iterator const& other) {
+ if ( this == & other) return * this;
+ c_ = other.c_;
+ return * this;
+ }
+
+ bool operator==( iterator const& other) const {
+ return other.c_ == c_;
+ }
+
+ bool operator!=( iterator const& other) const {
+ return other.c_ != c_;
+ }
+
+ iterator & operator++() {
+ increment_();
+ return * this;
+ }
+
+ iterator operator++( int) = delete;
+
+ reference_t operator*() const {
+ return * c_->cb_->other->t;
+ }
+
+ pointer_t operator->() const {
+ return c_->cb_->other->t;
+ }
+ };
+
+ friend class iterator;
+};
+
+template<>
+class pull_coroutine< void > {
+private:
+ template< typename X >
+ friend class push_coroutine;
+
+ struct control_block;
+
+ control_block * cb_;
+
+ explicit pull_coroutine( control_block *);
+
+public:
+ template< typename Fn >
+ explicit pull_coroutine( Fn &&, bool = false);
+
+ template< typename StackAllocator, typename Fn >
+ explicit pull_coroutine( StackAllocator, Fn &&, bool = false);
+
+ ~pull_coroutine();
+
+ pull_coroutine( pull_coroutine const&) = delete;
+ pull_coroutine & operator=( pull_coroutine const&) = delete;
+
+ pull_coroutine( pull_coroutine &&);
+
+ pull_coroutine & operator=( pull_coroutine && other) {
+ if ( this != & other) {
+ cb_ = other.cb_;
+ other.cb_ = nullptr;
+ }
+ return * this;
+ }
+
+ pull_coroutine & operator()();
+
+ explicit operator bool() const noexcept;
+
+ bool operator!() const noexcept;
+};
+
+template< typename T >
+typename pull_coroutine< T >::iterator
+begin( pull_coroutine< T > & c) {
+ return typename pull_coroutine< T >::iterator( & c);
+}
+
+template< typename T >
+typename pull_coroutine< T >::iterator
+end( pull_coroutine< T > &) {
+ return typename pull_coroutine< T >::iterator();
+}
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES2_DETAIL_PULL_COROUTINE_HPP
diff --git a/boost/coroutine2/detail/pull_coroutine.ipp b/boost/coroutine2/detail/pull_coroutine.ipp
new file mode 100644
index 0000000000..f59bb3cb5f
--- /dev/null
+++ b/boost/coroutine2/detail/pull_coroutine.ipp
@@ -0,0 +1,271 @@
+
+// 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_COROUTINE_IPP
+#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/fixedsize_stack.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines2 {
+namespace detail {
+
+// pull_coroutine< T >
+
+template< typename T >
+pull_coroutine< T >::pull_coroutine( control_block * cb) :
+ cb_( cb) {
+}
+
+template< typename T >
+bool
+pull_coroutine< T >::has_result_() const {
+ return nullptr != cb_->other->t;
+}
+
+template< typename T >
+template< typename Fn >
+pull_coroutine< T >::pull_coroutine( Fn && fn, bool preserve_fpu) :
+ pull_coroutine( fixedsize_stack(), std::forward< Fn >( fn), preserve_fpu) {
+}
+
+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);
+}
+
+template< typename T >
+pull_coroutine< T >::~pull_coroutine() {
+ if ( nullptr != cb_) {
+ cb_->~control_block();
+ }
+}
+
+template< typename T >
+pull_coroutine< T >::pull_coroutine( pull_coroutine && other) :
+ cb_( other.cb_) {
+ other.cb_ = nullptr;
+}
+
+template< typename T >
+pull_coroutine< T > &
+pull_coroutine< T >::operator()() {
+ cb_->resume();
+ return * this;
+}
+
+template< typename T >
+pull_coroutine< T >::operator bool() const noexcept {
+ return nullptr != cb_ && cb_->valid();
+}
+
+template< typename T >
+bool
+pull_coroutine< T >::operator!() const noexcept {
+ return nullptr == cb_ || ! cb_->valid();
+}
+
+template< typename T >
+T
+pull_coroutine< T >::get() const noexcept {
+ return std::move( * cb_->other->t);
+}
+
+
+// pull_coroutine< T & >
+
+template< typename T >
+pull_coroutine< T & >::pull_coroutine( control_block * cb) :
+ cb_( cb) {
+}
+
+template< typename T >
+bool
+pull_coroutine< T & >::has_result_() const {
+ return nullptr != cb_->other->t;
+}
+
+template< typename T >
+template< typename Fn >
+pull_coroutine< T & >::pull_coroutine( Fn && fn, bool preserve_fpu) :
+ pull_coroutine( fixedsize_stack(), std::forward< Fn >( fn), preserve_fpu) {
+}
+
+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);
+}
+
+template< typename T >
+pull_coroutine< T & >::~pull_coroutine() {
+ if ( nullptr != cb_) {
+ cb_->~control_block();
+ }
+}
+
+template< typename T >
+pull_coroutine< T & >::pull_coroutine( pull_coroutine && other) :
+ cb_( other.cb_) {
+ other.cb_ = nullptr;
+}
+
+template< typename T >
+pull_coroutine< T & > &
+pull_coroutine< T & >::operator()() {
+ cb_->resume();
+ return * this;
+}
+
+template< typename T >
+pull_coroutine< T & >::operator bool() const noexcept {
+ return nullptr != cb_ && cb_->valid();
+}
+
+template< typename T >
+bool
+pull_coroutine< T & >::operator!() const noexcept {
+ return nullptr == cb_ || ! cb_->valid();
+}
+
+template< typename T >
+T &
+pull_coroutine< T & >::get() const noexcept {
+ return * cb_->other->t;
+}
+
+
+// pull_coroutine< void >
+
+inline
+pull_coroutine< void >::pull_coroutine( control_block * cb) :
+ cb_( cb) {
+}
+
+template< typename Fn >
+pull_coroutine< void >::pull_coroutine( Fn && fn, bool preserve_fpu) :
+ pull_coroutine( fixedsize_stack(), std::forward< Fn >( fn), preserve_fpu) {
+}
+
+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);
+}
+
+inline
+pull_coroutine< void >::~pull_coroutine() {
+ if ( nullptr != cb_) {
+ cb_->~control_block();
+ }
+}
+
+inline
+pull_coroutine< void >::pull_coroutine( pull_coroutine && other) :
+ cb_( other.cb_) {
+ other.cb_ = nullptr;
+}
+
+inline
+pull_coroutine< void > &
+pull_coroutine< void >::operator()() {
+ cb_->resume();
+ return * this;
+}
+
+inline
+pull_coroutine< void >::operator bool() const noexcept {
+ return nullptr != cb_ && cb_->valid();
+}
+
+inline
+bool
+pull_coroutine< void >::operator!() const noexcept {
+ return nullptr == cb_ || ! cb_->valid();
+}
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES2_DETAIL_PULL_COROUTINE_IPP
diff --git a/boost/coroutine2/detail/push_control_block.hpp b/boost/coroutine2/detail/push_control_block.hpp
new file mode 100644
index 0000000000..e6c86ffd81
--- /dev/null
+++ b/boost/coroutine2/detail/push_control_block.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>
+
+#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 {
+ typename pull_coroutine< T >::control_block * other;
+ boost::context::execution_context caller;
+ boost::context::execution_context callee;
+ bool preserve_fpu;
+ int state;
+ std::exception_ptr except;
+ T * t;
+
+ template< typename StackAllocator, typename Fn >
+ control_block( context::preallocated, StackAllocator, Fn &&, bool);
+
+ explicit control_block( typename pull_coroutine< T >::control_block *);
+
+ ~control_block();
+
+ control_block( control_block &) = delete;
+ control_block & operator=( control_block &) = delete;
+
+ void resume( T const&);
+
+ void resume( T &&);
+
+ bool valid() const noexcept;
+};
+
+template< typename T >
+struct push_coroutine< T & >::control_block {
+ typename pull_coroutine< T & >::control_block * other;
+ boost::context::execution_context caller;
+ boost::context::execution_context callee;
+ bool preserve_fpu;
+ int state;
+ std::exception_ptr except;
+ T * t;
+
+ template< typename StackAllocator, typename Fn >
+ control_block( context::preallocated, StackAllocator, Fn &&, bool);
+
+ explicit control_block( typename pull_coroutine< T & >::control_block *);
+
+ ~control_block();
+
+ control_block( control_block &) = delete;
+ control_block & operator=( control_block &) = delete;
+
+ void resume( T &);
+
+ bool valid() const noexcept;
+};
+
+struct push_coroutine< void >::control_block {
+ pull_coroutine< void >::control_block * other;
+ boost::context::execution_context caller;
+ boost::context::execution_context callee;
+ bool preserve_fpu;
+ int state;
+ std::exception_ptr except;
+
+ template< typename StackAllocator, typename Fn >
+ control_block( context::preallocated, StackAllocator, Fn &&, bool);
+
+ explicit control_block( pull_coroutine< void >::control_block *);
+
+ ~control_block();
+
+ control_block( control_block &) = delete;
+ control_block & operator=( control_block &) = delete;
+
+ 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.ipp b/boost/coroutine2/detail/push_control_block.ipp
new file mode 100644
index 0000000000..ebef5092b5
--- /dev/null
+++ b/boost/coroutine2/detail/push_control_block.ipp
@@ -0,0 +1,281 @@
+
+// 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 <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),
+ caller( boost::context::execution_context::current() ),
+ callee( palloc, salloc,
+ [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) {
+ // create synthesized pull_coroutine< T >
+ typename pull_coroutine< T >::control_block synthesized_cb( this);
+ pull_coroutine< T > synthesized( & synthesized_cb);
+ other = & synthesized_cb;
+ 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);
+ caller( preserve_fpu);
+ BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+ }),
+ preserve_fpu( preserve_fpu_),
+ state( static_cast< int >( state_t::unwind) ),
+ except(),
+ t( nullptr) {
+}
+
+template< typename T >
+push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb) :
+ other( cb),
+ caller( other->callee),
+ callee( other->caller),
+ preserve_fpu( other->preserve_fpu),
+ state( 0),
+ except(),
+ t( nullptr) {
+}
+
+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);
+ callee( preserve_fpu);
+ }
+}
+
+template< typename T >
+void
+push_coroutine< T >::control_block::resume( T const& t_) {
+ // store data on this stack
+ // pass an pointer (address of tmp) to other context
+ T tmp( t_);
+ t = & tmp;
+ callee( preserve_fpu);
+ t = nullptr;
+ 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_) {
+ // store data on this stack
+ // pass an pointer (address of tmp) to other context
+ T tmp( std::move( t_) );
+ t = & tmp;
+ callee( preserve_fpu);
+ t = nullptr;
+ 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),
+ caller( boost::context::execution_context::current() ),
+ callee( palloc, salloc,
+ [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) {
+ // create synthesized pull_coroutine< T >
+ typename pull_coroutine< T & >::control_block synthesized_cb( this);
+ pull_coroutine< T & > synthesized( & synthesized_cb);
+ other = & synthesized_cb;
+ 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);
+ caller( preserve_fpu);
+ BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+ }),
+ preserve_fpu( preserve_fpu_),
+ state( static_cast< int >( state_t::unwind) ),
+ except(),
+ t( nullptr) {
+}
+
+template< typename T >
+push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb) :
+ other( cb),
+ caller( other->callee),
+ callee( other->caller),
+ preserve_fpu( other->preserve_fpu),
+ state( 0),
+ except(),
+ t( nullptr) {
+}
+
+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);
+ callee( preserve_fpu);
+ }
+}
+
+template< typename T >
+void
+push_coroutine< T & >::control_block::resume( T & t_) {
+ t = & t_;
+ callee( preserve_fpu);
+ t = nullptr;
+ 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),
+ caller( boost::context::execution_context::current() ),
+ callee( palloc, salloc,
+ [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) {
+ // create synthesized pull_coroutine< T >
+ typename pull_coroutine< void >::control_block synthesized_cb( this);
+ pull_coroutine< void > synthesized( & synthesized_cb);
+ other = & synthesized_cb;
+ 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);
+ caller( preserve_fpu);
+ BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+ }),
+ preserve_fpu( preserve_fpu_),
+ state( static_cast< int >( state_t::unwind) ),
+ except() {
+}
+
+inline
+push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb) :
+ other( cb),
+ caller( other->callee),
+ callee( other->caller),
+ 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);
+ callee( preserve_fpu);
+ }
+}
+
+inline
+void
+push_coroutine< void >::control_block::resume() {
+ callee( 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_coroutine.hpp b/boost/coroutine2/detail/push_coroutine.hpp
new file mode 100644
index 0000000000..1a2d01f67e
--- /dev/null
+++ b/boost/coroutine2/detail/push_coroutine.hpp
@@ -0,0 +1,242 @@
+
+// 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_COROUTINE_HPP
+#define BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_HPP
+
+#include <iterator>
+#include <type_traits>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/context/execution_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 T >
+class push_coroutine {
+private:
+ template< typename X >
+ friend class pull_coroutine;
+
+ struct control_block;
+
+ control_block * cb_;
+
+ explicit push_coroutine( control_block *);
+
+public:
+ template< typename Fn >
+ explicit push_coroutine( Fn &&, bool = false);
+
+ template< typename StackAllocator, typename Fn >
+ explicit push_coroutine( StackAllocator, Fn &&, bool = false);
+
+ ~push_coroutine();
+
+ push_coroutine( push_coroutine const&) = delete;
+ push_coroutine & operator=( push_coroutine const&) = delete;
+
+ push_coroutine( push_coroutine &&);
+
+ push_coroutine & operator=( push_coroutine && other) {
+ if ( this != & other) {
+ cb_ = other.cb_;
+ other.cb_ = nullptr;
+ }
+ return * this;
+ }
+
+ push_coroutine & operator()( T const&);
+
+ push_coroutine & operator()( T &&);
+
+ explicit operator bool() const noexcept;
+
+ bool operator!() const noexcept;
+
+ class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > {
+ private:
+ push_coroutine< T > * c_;
+
+ public:
+ iterator() :
+ c_( nullptr) {
+ }
+
+ explicit iterator( push_coroutine< T > * c) :
+ c_( c) {
+ }
+
+ iterator & operator=( T t) {
+ BOOST_ASSERT( c_);
+ if ( ! ( * c_)( t) ) c_ = 0;
+ return * this;
+ }
+
+ bool operator==( iterator const& other) const {
+ return other.c_ == c_;
+ }
+
+ bool operator!=( iterator const& other) const {
+ return other.c_ != c_;
+ }
+
+ iterator & operator*() {
+ return * this;
+ }
+
+ iterator & operator++() {
+ return * this;
+ }
+ };
+};
+
+template< typename T >
+class push_coroutine< T & > {
+private:
+ template< typename X >
+ friend class pull_coroutine;
+
+ struct control_block;
+
+ control_block * cb_;
+
+ explicit push_coroutine( control_block *);
+
+public:
+ template< typename Fn >
+ explicit push_coroutine( Fn &&, bool = false);
+
+ template< typename StackAllocator, typename Fn >
+ explicit push_coroutine( StackAllocator, Fn &&, bool = false);
+
+ ~push_coroutine();
+
+ push_coroutine( push_coroutine const&) = delete;
+ push_coroutine & operator=( push_coroutine const&) = delete;
+
+ push_coroutine( push_coroutine &&);
+
+ push_coroutine & operator=( push_coroutine && other) {
+ if ( this != & other) {
+ cb_ = other.cb_;
+ other.cb_ = nullptr;
+ }
+ return * this;
+ }
+
+ push_coroutine & operator()( T &);
+
+ explicit operator bool() const noexcept;
+
+ bool operator!() const noexcept;
+
+ class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > {
+ private:
+ push_coroutine< T & > * c_;
+
+ public:
+ iterator() :
+ c_( nullptr) {
+ }
+
+ explicit iterator( push_coroutine< T & > * c) :
+ c_( c) {
+ }
+
+ iterator & operator=( T & t) {
+ BOOST_ASSERT( c_);
+ if ( ! ( * c_)( t) ) c_ = 0;
+ return * this;
+ }
+
+ bool operator==( iterator const& other) const {
+ return other.c_ == c_;
+ }
+
+ bool operator!=( iterator const& other) const {
+ return other.c_ != c_;
+ }
+
+ iterator & operator*() {
+ return * this;
+ }
+
+ iterator & operator++() {
+ return * this;
+ }
+ };
+};
+
+template<>
+class push_coroutine< void > {
+private:
+ template< typename X >
+ friend class pull_coroutine;
+
+ struct control_block;
+
+ control_block * cb_;
+
+ explicit push_coroutine( control_block *);
+
+public:
+ template< typename Fn >
+ explicit push_coroutine( Fn &&, bool = false);
+
+ template< typename StackAllocator, typename Fn >
+ explicit push_coroutine( StackAllocator, Fn &&, bool = false);
+
+ ~push_coroutine();
+
+ push_coroutine( push_coroutine const&) = delete;
+ push_coroutine & operator=( push_coroutine const&) = delete;
+
+ push_coroutine( push_coroutine &&);
+
+ push_coroutine & operator=( push_coroutine && other) {
+ if ( this != & other) {
+ cb_ = other.cb_;
+ other.cb_ = nullptr;
+ }
+ return * this;
+ }
+
+ push_coroutine & operator()();
+
+ explicit operator bool() const noexcept;
+
+ bool operator!() const noexcept;
+};
+
+template< typename T >
+typename push_coroutine< T >::iterator
+begin( push_coroutine< T > & c) {
+ return typename push_coroutine< T >::iterator( & c);
+}
+
+template< typename T >
+typename push_coroutine< T >::iterator
+end( push_coroutine< T > &) {
+ return typename push_coroutine< T >::iterator();
+}
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_HPP
diff --git a/boost/coroutine2/detail/push_coroutine.ipp b/boost/coroutine2/detail/push_coroutine.ipp
new file mode 100644
index 0000000000..4617e73aac
--- /dev/null
+++ b/boost/coroutine2/detail/push_coroutine.ipp
@@ -0,0 +1,253 @@
+
+// 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_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/fixedsize_stack.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines2 {
+namespace detail {
+
+// push_coroutine< T >
+
+template< typename T >
+push_coroutine< T >::push_coroutine( control_block * cb) :
+ cb_( cb) {
+}
+
+template< typename T >
+template< typename Fn >
+push_coroutine< T >::push_coroutine( Fn && fn, bool preserve_fpu) :
+ push_coroutine( fixedsize_stack(), std::forward< Fn >( fn), preserve_fpu) {
+}
+
+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);
+}
+
+template< typename T >
+push_coroutine< T >::~push_coroutine() {
+ if ( nullptr != cb_) {
+ cb_->~control_block();
+ }
+}
+
+template< typename T >
+push_coroutine< T >::push_coroutine( push_coroutine && other) :
+ cb_( other.cb_) {
+ other.cb_ = nullptr;
+}
+
+template< typename T >
+push_coroutine< T > &
+push_coroutine< T >::operator()( T const& t) {
+ cb_->resume( t);
+ return * this;
+}
+
+template< typename T >
+push_coroutine< T > &
+push_coroutine< T >::operator()( T && t) {
+ cb_->resume( std::forward< T >( t) );
+ return * this;
+}
+
+template< typename T >
+push_coroutine< T >::operator bool() const noexcept {
+ return nullptr != cb_ && cb_->valid();
+}
+
+template< typename T >
+bool
+push_coroutine< T >::operator!() const noexcept {
+ return nullptr == cb_ || ! cb_->valid();
+}
+
+
+// push_coroutine< T & >
+
+template< typename T >
+push_coroutine< T & >::push_coroutine( control_block * cb) :
+ cb_( cb) {
+}
+
+template< typename T >
+template< typename Fn >
+push_coroutine< T & >::push_coroutine( Fn && fn, bool preserve_fpu) :
+ push_coroutine( fixedsize_stack(), std::forward< Fn >( fn), preserve_fpu) {
+}
+
+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);
+}
+
+template< typename T >
+push_coroutine< T & >::~push_coroutine() {
+ if ( nullptr != cb_) {
+ cb_->~control_block();
+ }
+}
+
+template< typename T >
+push_coroutine< T & >::push_coroutine( push_coroutine && other) :
+ cb_( other.cb_) {
+ other.cb_ = nullptr;
+}
+
+template< typename T >
+push_coroutine< T & > &
+push_coroutine< T & >::operator()( T & t) {
+ cb_->resume( t);
+ return * this;
+}
+
+template< typename T >
+push_coroutine< T & >::operator bool() const noexcept {
+ return nullptr != cb_ && cb_->valid();
+}
+
+template< typename T >
+bool
+push_coroutine< T & >::operator!() const noexcept {
+ return nullptr == cb_ || ! cb_->valid();
+}
+
+
+// push_coroutine< void >
+
+inline
+push_coroutine< void >::push_coroutine( control_block * cb) :
+ cb_( cb) {
+}
+
+template< typename Fn >
+push_coroutine< void >::push_coroutine( Fn && fn, bool preserve_fpu) :
+ push_coroutine( fixedsize_stack(), std::forward< Fn >( fn), preserve_fpu) {
+}
+
+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);
+}
+
+inline
+push_coroutine< void >::~push_coroutine() {
+ if ( nullptr != cb_) {
+ cb_->~control_block();
+ }
+}
+
+inline
+push_coroutine< void >::push_coroutine( push_coroutine && other) :
+ cb_( other.cb_) {
+ other.cb_ = nullptr;
+}
+
+inline
+push_coroutine< void > &
+push_coroutine< void >::operator()() {
+ cb_->resume();
+ return * this;
+}
+
+inline
+push_coroutine< void >::operator bool() const noexcept {
+ return nullptr != cb_ && cb_->valid();
+}
+
+inline
+bool
+push_coroutine< void >::operator!() const noexcept {
+ return nullptr == cb_ || ! cb_->valid();
+}
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_IPP
diff --git a/boost/coroutine2/detail/state.hpp b/boost/coroutine2/detail/state.hpp
new file mode 100644
index 0000000000..714548ff63
--- /dev/null
+++ b/boost/coroutine2/detail/state.hpp
@@ -0,0 +1,37 @@
+
+// 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_ASYMMETRIC_COROUTINE_HPP
+#define BOOST_COROUTINES2_DETAIL_ASYMMETRIC_COROUTINE_HPP
+
+#include <exception>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+
+#include <boost/coroutine2/detail/config.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines2 {
+namespace detail {
+
+enum class state_t : unsigned int {
+ complete = 1 << 1,
+ unwind = 1 << 2,
+ early_exit = 1 << 3
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES2_DETAIL_ASYMMETRIC_COROUTINE_HPP