diff options
Diffstat (limited to 'boost/coroutine2/detail')
-rw-r--r-- | boost/coroutine2/detail/config.hpp | 51 | ||||
-rw-r--r-- | boost/coroutine2/detail/coroutine.hpp | 44 | ||||
-rw-r--r-- | boost/coroutine2/detail/forced_unwind.hpp | 33 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_control_block.hpp | 100 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_control_block.ipp | 258 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_coroutine.hpp | 312 | ||||
-rw-r--r-- | boost/coroutine2/detail/pull_coroutine.ipp | 271 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_control_block.hpp | 104 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_control_block.ipp | 281 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_coroutine.hpp | 242 | ||||
-rw-r--r-- | boost/coroutine2/detail/push_coroutine.ipp | 253 | ||||
-rw-r--r-- | boost/coroutine2/detail/state.hpp | 37 |
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 |