diff options
Diffstat (limited to 'boost/coroutine')
34 files changed, 6925 insertions, 0 deletions
diff --git a/boost/coroutine/all.hpp b/boost/coroutine/all.hpp new file mode 100644 index 0000000000..42f63a0a73 --- /dev/null +++ b/boost/coroutine/all.hpp @@ -0,0 +1,21 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_ALL_H +#define BOOST_COROUTINES_ALL_H + +#include <boost/coroutine/attributes.hpp> +#include <boost/coroutine/coroutine.hpp> +#include <boost/coroutine/exceptions.hpp> +#include <boost/coroutine/flags.hpp> +#include <boost/coroutine/protected_stack_allocator.hpp> +#include <boost/coroutine/segmented_stack_allocator.hpp> +#include <boost/coroutine/stack_allocator.hpp> +#include <boost/coroutine/stack_context.hpp> +#include <boost/coroutine/stack_traits.hpp> +#include <boost/coroutine/standard_stack_allocator.hpp> + +#endif // BOOST_COROUTINES_ALL_H diff --git a/boost/coroutine/asymmetric_coroutine.hpp b/boost/coroutine/asymmetric_coroutine.hpp new file mode 100644 index 0000000000..ff4684f61f --- /dev/null +++ b/boost/coroutine/asymmetric_coroutine.hpp @@ -0,0 +1,2243 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_ASYMMETRIC_COROUTINE_H +#define BOOST_COROUTINES_ASYMMETRIC_COROUTINE_H + +#include <cstddef> +#include <iterator> +#include <memory> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/move/move.hpp> +#include <boost/range.hpp> +#include <boost/throw_exception.hpp> +#include <boost/utility/explicit_operator_bool.hpp> + +#include <boost/coroutine/attributes.hpp> +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/parameters.hpp> +#include <boost/coroutine/exceptions.hpp> +#include <boost/coroutine/stack_allocator.hpp> +#include <boost/coroutine/detail/pull_coroutine_impl.hpp> +#include <boost/coroutine/detail/pull_coroutine_object.hpp> +#include <boost/coroutine/detail/pull_coroutine_synthesized.hpp> +#include <boost/coroutine/detail/push_coroutine_impl.hpp> +#include <boost/coroutine/detail/push_coroutine_object.hpp> +#include <boost/coroutine/detail/push_coroutine_synthesized.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +template< typename R > +class pull_coroutine; + +template< typename Arg > +class push_coroutine +{ +private: + template< typename V, typename X, typename Y, typename Z > + friend class detail::pull_coroutine_object; + + typedef detail::push_coroutine_impl< Arg > impl_type; + typedef detail::push_coroutine_synthesized< Arg > synth_type; + typedef detail::parameters< Arg > param_type; + + struct dummy {}; + + impl_type * impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) + + explicit push_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) + { BOOST_ASSERT( impl_); } + +public: + push_coroutine() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( pull_coroutine< Arg > &); + + explicit push_coroutine( coroutine_fn, + attributes const& = attributes() ); + + template< typename StackAllocator > + explicit push_coroutine( coroutine_fn, + attributes const&, + StackAllocator); +# endif + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); +#else + template< typename Fn > + explicit push_coroutine( Fn fn, + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn fn, + attributes const&, + StackAllocator); + + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); +#endif + + ~push_coroutine() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT + { + push_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + void swap( push_coroutine & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + push_coroutine & operator()( Arg arg) + { + BOOST_ASSERT( * this); + + impl_->push( arg); + return * this; + } + + class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > + { + private: + push_coroutine< Arg > * c_; + + public: + iterator() : + c_( 0) + {} + + explicit iterator( push_coroutine< Arg > * c) : + c_( c) + {} + + iterator & operator=( Arg a) + { + BOOST_ASSERT( c_); + if ( ! ( * c_)( a) ) 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; } + }; + + struct const_iterator; +}; + +template< typename Arg > +class push_coroutine< Arg & > +{ +private: + template< typename V, typename X, typename Y, typename Z > + friend class detail::pull_coroutine_object; + + typedef detail::push_coroutine_impl< Arg & > impl_type; + typedef detail::push_coroutine_synthesized< Arg & > synth_type; + typedef detail::parameters< Arg & > param_type; + + struct dummy {}; + + impl_type * impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) + + explicit push_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) + { BOOST_ASSERT( impl_); } + +public: + push_coroutine() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( pull_coroutine< Arg & > &); + + explicit push_coroutine( coroutine_fn, + attributes const& = attributes() ); + + template< typename StackAllocator > + explicit push_coroutine( coroutine_fn, + attributes const&, + StackAllocator); +# endif + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); +#else + template< typename Fn > + explicit push_coroutine( Fn, + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn, + attributes const&, + StackAllocator); + + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); +#endif + + ~push_coroutine() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT + { + push_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + void swap( push_coroutine & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + push_coroutine & operator()( Arg & arg) + { + BOOST_ASSERT( * this); + + impl_->push( arg); + return * this; + } + + class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > + { + private: + push_coroutine< Arg & > * c_; + + public: + iterator() : + c_( 0) + {} + + explicit iterator( push_coroutine< Arg & > * c) : + c_( c) + {} + + iterator & operator=( Arg & a) + { + BOOST_ASSERT( c_); + if ( ! ( * c_)( a) ) 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; } + }; + + struct const_iterator; +}; + +template<> +class push_coroutine< void > +{ +private: + template< typename V, typename X, typename Y, typename Z > + friend class detail::pull_coroutine_object; + + typedef detail::push_coroutine_impl< void > impl_type; + typedef detail::push_coroutine_synthesized< void > synth_type; + typedef detail::parameters< void > param_type; + + struct dummy {}; + + impl_type * impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) + + explicit push_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) + { BOOST_ASSERT( impl_); } + +public: + push_coroutine() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( pull_coroutine< void > &); + + explicit push_coroutine( coroutine_fn, + attributes const& = attributes() ); + + template< typename StackAllocator > + explicit push_coroutine( coroutine_fn, + attributes const&, + StackAllocator); +# endif + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); +#else + template< typename Fn > + explicit push_coroutine( Fn, + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn, + attributes const&, + StackAllocator); + + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); +#endif + + ~push_coroutine() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + inline push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + inline push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT + { + push_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + inline bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + inline void swap( push_coroutine & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + inline push_coroutine & operator()() + { + BOOST_ASSERT( * this); + + impl_->push(); + return * this; + } + + struct iterator; + struct const_iterator; +}; + + + +template< typename R > +class pull_coroutine +{ +private: + template< typename V, typename X, typename Y, typename Z > + friend class detail::push_coroutine_object; + + typedef detail::pull_coroutine_impl< R > impl_type; + typedef detail::pull_coroutine_synthesized< R > synth_type; + typedef detail::parameters< R > param_type; + + struct dummy {}; + + impl_type * impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine) + + explicit pull_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) + { BOOST_ASSERT( impl_); } + +public: + pull_coroutine() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( push_coroutine< R > &); + + explicit pull_coroutine( coroutine_fn fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R >, R, coroutine_fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename StackAllocator > + explicit pull_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R >, R, coroutine_fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +# endif + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R >, R, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R >, R, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +#else + template< typename Fn > + explicit pull_coroutine( Fn fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R >, R, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R >, R, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R >, R, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R >, R, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +#endif + + ~pull_coroutine() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT + { + pull_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + void swap( pull_coroutine & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + pull_coroutine & operator()() + { + BOOST_ASSERT( * this); + + impl_->pull(); + return * this; + } + + R get() const + { + BOOST_ASSERT( 0 != impl_); + + return impl_->get(); + } + + class iterator : public std::iterator< std::input_iterator_tag, typename remove_reference< R >::type > + { + private: + pull_coroutine< R > * c_; + R * val_; + + void fetch_() + { + BOOST_ASSERT( c_); + + if ( ! ( * c_) ) + { + c_ = 0; + val_ = 0; + return; + } + val_ = c_->impl_->get_pointer(); + } + + void increment_() + { + BOOST_ASSERT( c_); + BOOST_ASSERT( * c_); + + ( * c_)(); + fetch_(); + } + + public: + typedef typename iterator::pointer pointer_t; + typedef typename iterator::reference reference_t; + + iterator() : + c_( 0), val_( 0) + {} + + explicit iterator( pull_coroutine< R > * c) : + c_( c), val_( 0) + { fetch_(); } + + iterator( iterator const& other) : + c_( other.c_), val_( other.val_) + {} + + iterator & operator=( iterator const& other) + { + if ( this == & other) return * this; + c_ = other.c_; + val_ = other.val_; + return * this; + } + + bool operator==( iterator const& other) const + { return other.c_ == c_ && other.val_ == val_; } + + bool operator!=( iterator const& other) const + { return other.c_ != c_ || other.val_ != val_; } + + iterator & operator++() + { + increment_(); + return * this; + } + + iterator operator++( int) + { + iterator tmp( * this); + ++*this; + return tmp; + } + + reference_t operator*() const + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return * val_; + } + + pointer_t operator->() const + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return val_; + } + }; + + friend class iterator; + + struct const_iterator; +}; + +template< typename R > +class pull_coroutine< R & > +{ +private: + template< typename V, typename X, typename Y, typename Z > + friend class detail::push_coroutine_object; + + typedef detail::pull_coroutine_impl< R & > impl_type; + typedef detail::pull_coroutine_synthesized< R & > synth_type; + typedef detail::parameters< R & > param_type; + + struct dummy {}; + + impl_type * impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine) + + explicit pull_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) + { BOOST_ASSERT( impl_); } + +public: + pull_coroutine() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( push_coroutine< R & > &); + + explicit pull_coroutine( coroutine_fn fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R & >, R &, coroutine_fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename StackAllocator > + explicit pull_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R & >, R &, coroutine_fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +# endif + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R & >, R &, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R & >, R &, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +#else + template< typename Fn > + explicit pull_coroutine( Fn fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R & >, R &, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R & >, R &, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R & >, R &, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< R & >, R &, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +#endif + + ~pull_coroutine() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT + { + pull_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + void swap( pull_coroutine & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + pull_coroutine & operator()() + { + BOOST_ASSERT( * this); + + impl_->pull(); + return * this; + } + + R & get() const + { return impl_->get(); } + + class iterator : public std::iterator< std::input_iterator_tag, R > + { + private: + pull_coroutine< R & > * c_; + R * val_; + + void fetch_() + { + BOOST_ASSERT( c_); + + if ( ! ( * c_) ) + { + c_ = 0; + val_ = 0; + return; + } + val_ = c_->impl_->get_pointer(); + } + + void increment_() + { + BOOST_ASSERT( c_); + BOOST_ASSERT( * c_); + + ( * c_)(); + fetch_(); + } + + public: + typedef typename iterator::pointer pointer_t; + typedef typename iterator::reference reference_t; + + iterator() : + c_( 0), val_( 0) + {} + + explicit iterator( pull_coroutine< R & > * c) : + c_( c), val_( 0) + { fetch_(); } + + iterator( iterator const& other) : + c_( other.c_), val_( other.val_) + {} + + iterator & operator=( iterator const& other) + { + if ( this == & other) return * this; + c_ = other.c_; + val_ = other.val_; + return * this; + } + + bool operator==( iterator const& other) const + { return other.c_ == c_ && other.val_ == val_; } + + bool operator!=( iterator const& other) const + { return other.c_ != c_ || other.val_ != val_; } + + iterator & operator++() + { + increment_(); + return * this; + } + + iterator operator++( int) + { + iterator tmp( * this); + ++*this; + return tmp; + } + + reference_t operator*() const + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return * val_; + } + + pointer_t operator->() const + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return val_; + } + }; + + friend class iterator; + + struct const_iterator; +}; + +template<> +class pull_coroutine< void > +{ +private: + template< typename V, typename X, typename Y, typename Z > + friend class detail::push_coroutine_object; + + typedef detail::pull_coroutine_impl< void > impl_type; + typedef detail::pull_coroutine_synthesized< void > synth_type; + typedef detail::parameters< void > param_type; + + struct dummy {}; + + impl_type * impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine) + + explicit pull_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) + { BOOST_ASSERT( impl_); } + +public: + pull_coroutine() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( push_coroutine< void > &); + + explicit pull_coroutine( coroutine_fn fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< void >, void, coroutine_fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename StackAllocator > + explicit pull_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< void >, void, coroutine_fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +# endif + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< void >, void, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< void >, void, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +#else + template< typename Fn > + explicit pull_coroutine( Fn fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< void >, void, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< void >, void, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< void >, void, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::pull_coroutine_object< + push_coroutine< void >, void, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + impl_->pull(); + } +#endif + + ~pull_coroutine() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + inline pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + inline pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT + { + pull_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + inline bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + inline void swap( pull_coroutine & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + inline pull_coroutine & operator()() + { + BOOST_ASSERT( * this); + + impl_->pull(); + return * this; + } + + struct iterator; + struct const_iterator; +}; + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC +template< typename Arg > +push_coroutine< Arg >::push_coroutine( coroutine_fn fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg >, Arg, coroutine_fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename StackAllocator > +push_coroutine< Arg >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg >, Arg, coroutine_fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +push_coroutine< Arg & >::push_coroutine( coroutine_fn fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg & >, Arg &, coroutine_fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg & >, Arg &, coroutine_fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +inline push_coroutine< void >::push_coroutine( coroutine_fn fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< void >, void, coroutine_fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename StackAllocator > +push_coroutine< void >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< void >, void, coroutine_fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} +# endif +template< typename Arg > +template< typename Fn > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg >, Arg, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg >, Arg, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg & >, Arg &, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg & >, Arg &, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Fn > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< void >, void, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< void >, void, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} +#else +template< typename Arg > +template< typename Fn > +push_coroutine< Arg >::push_coroutine( Fn fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg >, Arg, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg >::push_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg >, Arg, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg & >::push_coroutine( Fn fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg & >, Arg &, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg & >, Arg &, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Fn > +push_coroutine< void >::push_coroutine( Fn fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< void >, void, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< void >, void, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg >, Arg, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg >, Arg, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg & >, Arg &, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< Arg & >, Arg &, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Fn > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + stack_allocator stack_alloc; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< void >, void, Fn, stack_allocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) +{ + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef detail::push_coroutine_object< + pull_coroutine< void >, void, Fn, StackAllocator + > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} +#endif + +template< typename R > +void swap( pull_coroutine< R > & l, pull_coroutine< R > & r) BOOST_NOEXCEPT +{ l.swap( r); } + +template< typename Arg > +void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r) BOOST_NOEXCEPT +{ l.swap( r); } + +template< typename R > +typename pull_coroutine< R >::iterator +range_begin( pull_coroutine< R > & c) +{ return typename pull_coroutine< R >::iterator( & c); } + +template< typename R > +typename pull_coroutine< R >::iterator +range_end( pull_coroutine< R > &) +{ return typename pull_coroutine< R >::iterator(); } + +template< typename Arg > +typename push_coroutine< Arg >::iterator +range_begin( push_coroutine< Arg > & c) +{ return typename push_coroutine< Arg >::iterator( & c); } + +template< typename Arg > +typename push_coroutine< Arg >::iterator +range_end( push_coroutine< Arg > &) +{ return typename push_coroutine< Arg >::iterator(); } + +template< typename T > +struct asymmetric_coroutine +{ + typedef push_coroutine< T > push_type; + typedef pull_coroutine< T > pull_type; +}; + +// deprecated +template< typename T > +struct coroutine +{ + typedef push_coroutine< T > push_type; + typedef pull_coroutine< T > pull_type; +}; + +template< typename R > +typename pull_coroutine< R >::iterator +begin( pull_coroutine< R > & c) +{ return boost::begin( c); } + +template< typename R > +typename pull_coroutine< R >::iterator +end( pull_coroutine< R > & c) +{ return boost::end( c); } + +template< typename R > +typename push_coroutine< R >::iterator +begin( push_coroutine< R > & c) +{ return boost::begin( c); } + +template< typename R > +typename push_coroutine< R >::iterator +end( push_coroutine< R > & c) +{ return boost::end( c); } + +} + +template< typename Arg > +struct range_mutable_iterator< coroutines::push_coroutine< Arg > > +{ typedef typename coroutines::push_coroutine< Arg >::iterator type; }; + +template< typename R > +struct range_mutable_iterator< coroutines::pull_coroutine< R > > +{ typedef typename coroutines::pull_coroutine< R >::iterator type; }; + +} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_ASYMMETRIC_COROUTINE_H diff --git a/boost/coroutine/attributes.hpp b/boost/coroutine/attributes.hpp new file mode 100644 index 0000000000..065a4c66e3 --- /dev/null +++ b/boost/coroutine/attributes.hpp @@ -0,0 +1,94 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_ATTRIBUTES_H +#define BOOST_COROUTINES_ATTRIBUTES_H + +#include <cstddef> + +#include <boost/config.hpp> + +#include <boost/coroutine/flags.hpp> +#include <boost/coroutine/stack_allocator.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct attributes +{ + std::size_t size; + flag_unwind_t do_unwind; + flag_fpu_t preserve_fpu; + + attributes() BOOST_NOEXCEPT : + size( stack_allocator::traits_type::default_size() ), + do_unwind( stack_unwind), + preserve_fpu( fpu_preserved) + {} + + explicit attributes( std::size_t size_) BOOST_NOEXCEPT : + size( size_), + do_unwind( stack_unwind), + preserve_fpu( fpu_preserved) + {} + + explicit attributes( flag_unwind_t do_unwind_) BOOST_NOEXCEPT : + size( stack_allocator::traits_type::default_size() ), + do_unwind( do_unwind_), + preserve_fpu( fpu_preserved) + {} + + explicit attributes( flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : + size( stack_allocator::traits_type::default_size() ), + do_unwind( stack_unwind), + preserve_fpu( preserve_fpu_) + {} + + explicit attributes( + std::size_t size_, + flag_unwind_t do_unwind_) BOOST_NOEXCEPT : + size( size_), + do_unwind( do_unwind_), + preserve_fpu( fpu_preserved) + {} + + explicit attributes( + std::size_t size_, + flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : + size( size_), + do_unwind( stack_unwind), + preserve_fpu( preserve_fpu_) + {} + + explicit attributes( + flag_unwind_t do_unwind_, + flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : + size( stack_allocator::traits_type::default_size() ), + do_unwind( do_unwind_), + preserve_fpu( preserve_fpu_) + {} + + explicit attributes( + std::size_t size_, + flag_unwind_t do_unwind_, + flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : + size( size_), + do_unwind( do_unwind_), + preserve_fpu( preserve_fpu_) + {} +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_ATTRIBUTES_H diff --git a/boost/coroutine/coroutine.hpp b/boost/coroutine/coroutine.hpp new file mode 100644 index 0000000000..076ffd26ea --- /dev/null +++ b/boost/coroutine/coroutine.hpp @@ -0,0 +1,13 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_COROUTINE_H +#define BOOST_COROUTINES_COROUTINE_H + +#include <boost/coroutine/asymmetric_coroutine.hpp> +#include <boost/coroutine/symmetric_coroutine.hpp> + +#endif // BOOST_COROUTINES_COROUTINE_H diff --git a/boost/coroutine/detail/config.hpp b/boost/coroutine/detail/config.hpp new file mode 100644 index 0000000000..9a3f4bf334 --- /dev/null +++ b/boost/coroutine/detail/config.hpp @@ -0,0 +1,49 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_CONFIG_H +#define BOOST_COROUTINES_DETAIL_CONFIG_H + +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> + +#ifdef BOOST_COROUTINES_DECL +# undef BOOST_COROUTINES_DECL +#endif + +#if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_DYN_LINK) ) && ! defined(BOOST_COROUTINES_STATIC_LINK) +# if defined(BOOST_COROUTINES_SOURCE) +# define BOOST_COROUTINES_DECL BOOST_SYMBOL_EXPORT +# define BOOST_COROUTINES_BUILD_DLL +# else +# define BOOST_COROUTINES_DECL BOOST_SYMBOL_IMPORT +# endif +#endif + +#if ! defined(BOOST_COROUTINES_DECL) +# define BOOST_COROUTINES_DECL +#endif + +#if ! defined(BOOST_COROUTINES_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_COROUTINES_NO_LIB) +# define BOOST_LIB_NAME boost_coroutine +# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_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 stacks" +# endif +# define BOOST_COROUTINES_SEGMENTS 10 +#endif + +#define BOOST_COROUTINES_UNIDIRECT +#define BOOST_COROUTINES_SYMMETRIC + +#endif // BOOST_COROUTINES_DETAIL_CONFIG_H diff --git a/boost/coroutine/detail/coroutine_context.hpp b/boost/coroutine/detail/coroutine_context.hpp new file mode 100644 index 0000000000..6c4ebb68b1 --- /dev/null +++ b/boost/coroutine/detail/coroutine_context.hpp @@ -0,0 +1,62 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_COROUTINE_CONTEXT_H +#define BOOST_COROUTINES_DETAIL_COROUTINE_CONTEXT_H + +#include <cstddef> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/context/fcontext.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +// class hold stack-context and coroutines execution-context +class BOOST_COROUTINES_DECL coroutine_context + +{ +private: + stack_context stack_ctx_; + context::fcontext_t ctx_; + +public: + typedef void( * ctx_fn)( intptr_t); + + // default ctor represents the current execution-context + coroutine_context(); + + // ctor creates a new execution-context running coroutine-fn `fn` + // `ctx_` will be allocated on top of the stack managed by parameter + // `stack_ctx` + coroutine_context( ctx_fn fn, stack_context const& stack_ctx); + + coroutine_context( coroutine_context const&); + + coroutine_context& operator=( coroutine_context const&); + + intptr_t jump( coroutine_context &, intptr_t = 0, bool = true); + + stack_context & stack_ctx() + { return stack_ctx_; } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_COROUTINE_CONTEXT_H diff --git a/boost/coroutine/detail/flags.hpp b/boost/coroutine/detail/flags.hpp new file mode 100644 index 0000000000..8d19757ee8 --- /dev/null +++ b/boost/coroutine/detail/flags.hpp @@ -0,0 +1,48 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_FLAGS_H +#define BOOST_COROUTINES_DETAIL_FLAGS_H + +#include <boost/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +enum flag_t +{ + flag_started = 1 << 1, + flag_running = 1 << 2, + flag_complete = 1 << 3, + flag_unwind_stack = 1 << 4, + flag_force_unwind = 1 << 5, + flag_preserve_fpu = 1 << 6 +}; + +struct unwind_t +{ + enum flag_t + { force_unwind = 1 }; +}; + +struct synthesized_t +{ + enum flag_t + { syntesized = 1 }; +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_FLAGS_H diff --git a/boost/coroutine/detail/parameters.hpp b/boost/coroutine/detail/parameters.hpp new file mode 100644 index 0000000000..8bad3910a9 --- /dev/null +++ b/boost/coroutine/detail/parameters.hpp @@ -0,0 +1,102 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_PARAMETERS_H +#define BOOST_COROUTINES_DETAIL_PARAMETERS_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> + +#include <boost/coroutine/detail/flags.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename Data > +struct parameters +{ + Data * data; + bool do_unwind; + void * coro; + + parameters() : + data( 0), do_unwind( false), coro( 0) + {} + + explicit parameters( void * coro_) : + data( 0), do_unwind( false), coro( coro_) + { BOOST_ASSERT( 0 != coro); } + + explicit parameters( Data * data_, void * coro_) : + data( data_), do_unwind( false), coro( coro_) + { + BOOST_ASSERT( 0 != data); + BOOST_ASSERT( 0 != coro); + } + + explicit parameters( unwind_t::flag_t) : + data( 0), do_unwind( true) + {} +}; + +template< typename Data > +struct parameters< Data & > +{ + Data * data; + bool do_unwind; + void * coro; + + parameters() : + data( 0), do_unwind( false), coro( 0) + {} + + explicit parameters( void * coro_) : + data( 0), do_unwind( false), coro( coro_) + { BOOST_ASSERT( 0 != coro); } + + explicit parameters( Data * data_, void * coro_) : + data( data_), do_unwind( false), coro( coro_) + { + BOOST_ASSERT( 0 != data); + BOOST_ASSERT( 0 != coro); + } + + explicit parameters( unwind_t::flag_t) : + data( 0), do_unwind( true), coro( 0) + {} +}; + +template<> +struct parameters< void > +{ + bool do_unwind; + void * coro; + + parameters() : + do_unwind( false), coro(0) + {} + + parameters( void * coro_) : + do_unwind( false), coro( coro_) + { BOOST_ASSERT( 0 != coro); } + + explicit parameters( unwind_t::flag_t) : + do_unwind( true), coro( 0) + {} +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PARAMETERS_H diff --git a/boost/coroutine/detail/pull_coroutine_impl.hpp b/boost/coroutine/detail/pull_coroutine_impl.hpp new file mode 100644 index 0000000000..10ca597544 --- /dev/null +++ b/boost/coroutine/detail/pull_coroutine_impl.hpp @@ -0,0 +1,355 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H +#define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/throw_exception.hpp> +#include <boost/utility.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/parameters.hpp> +#include <boost/coroutine/detail/trampoline_pull.hpp> +#include <boost/coroutine/exceptions.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +namespace detail { + +template< typename R > +class pull_coroutine_impl : private noncopyable +{ +protected: + int flags_; + exception_ptr except_; + coroutine_context * caller_; + coroutine_context * callee_; + R * result_; + +public: + typedef parameters< R > param_type; + + pull_coroutine_impl( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + flags_( 0), + except_(), + caller_( caller), + callee_( callee), + result_( 0) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + pull_coroutine_impl( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu, + R * result) : + flags_( 0), + except_(), + caller_( caller), + callee_( callee), + result_( result) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~pull_coroutine_impl() {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + param_type to( unwind_t::force_unwind); + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + void pull() + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + param_type to( this); + param_type * from( + reinterpret_cast< param_type * >( + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ &= ~flag_running; + result_ = from->data; + if ( from->do_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + bool has_result() const + { return 0 != result_; } + + R get() const + { + if ( ! has_result() ) + boost::throw_exception( + invalid_result() ); + return * result_; + } + + R * get_pointer() const + { + if ( ! has_result() ) + boost::throw_exception( + invalid_result() ); + return result_; + } + + virtual void destroy() = 0; +}; + +template< typename R > +class pull_coroutine_impl< R & > : private noncopyable +{ +protected: + int flags_; + exception_ptr except_; + coroutine_context * caller_; + coroutine_context * callee_; + R * result_; + +public: + typedef parameters< R & > param_type; + + pull_coroutine_impl( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + flags_( 0), + except_(), + caller_( caller), + callee_( callee), + result_( 0) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + pull_coroutine_impl( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu, + R * result) : + flags_( 0), + except_(), + caller_( caller), + callee_( callee), + result_( result) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~pull_coroutine_impl() {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + param_type to( unwind_t::force_unwind); + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + void pull() + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + param_type to( this); + param_type * from( + reinterpret_cast< param_type * >( + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ &= ~flag_running; + result_ = from->data; + if ( from->do_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + bool has_result() const + { return 0 != result_; } + + R & get() const + { + if ( ! has_result() ) + boost::throw_exception( + invalid_result() ); + return * result_; + } + + R * get_pointer() const + { + if ( ! has_result() ) + boost::throw_exception( + invalid_result() ); + return result_; + } + + virtual void destroy() = 0; +}; + +template<> +class pull_coroutine_impl< void > : private noncopyable +{ +protected: + int flags_; + exception_ptr except_; + coroutine_context * caller_; + coroutine_context * callee_; + +public: + typedef parameters< void > param_type; + + pull_coroutine_impl( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + flags_( 0), + except_(), + caller_( caller), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~pull_coroutine_impl() {} + + inline bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + inline bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + inline bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + inline bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + inline bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + inline bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + inline void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + param_type to( unwind_t::force_unwind); + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + inline void pull() + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + param_type to( this); + param_type * from( + reinterpret_cast< param_type * >( + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ &= ~flag_running; + if ( from->do_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + virtual void destroy() = 0; +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H diff --git a/boost/coroutine/detail/pull_coroutine_object.hpp b/boost/coroutine/detail/pull_coroutine_object.hpp new file mode 100644 index 0000000000..cfe34bd3c9 --- /dev/null +++ b/boost/coroutine/detail/pull_coroutine_object.hpp @@ -0,0 +1,324 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H +#define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/move/move.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/pull_coroutine_impl.hpp> +#include <boost/coroutine/detail/trampoline_pull.hpp> +#include <boost/coroutine/exceptions.hpp> +#include <boost/coroutine/flags.hpp> +#include <boost/coroutine/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4355) +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +struct pull_coroutine_context +{ + coroutine_context caller; + coroutine_context callee; + + template< typename Coro > + pull_coroutine_context( stack_context const& stack_ctx, Coro *) : + caller(), + callee( trampoline_pull< Coro >, stack_ctx) + {} +}; + +template< typename PushCoro, typename R, typename Fn, typename StackAllocator > +class pull_coroutine_object : private pull_coroutine_context, + public pull_coroutine_impl< R > +{ +private: + typedef pull_coroutine_context ctx_t; + typedef pull_coroutine_impl< R > base_t; + typedef pull_coroutine_object< PushCoro, R, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + pull_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run() + { + BOOST_ASSERT( ! base_t::unwind_requested() ); + + base_t::flags_ |= flag_started; + base_t::flags_ |= flag_running; + + // create push_coroutine + typename PushCoro::synth_type b( & this->callee, & this->caller, false, base_t::preserve_fpu() ); + PushCoro push_coro( synthesized_t::syntesized, b); + try + { fn_( push_coro); } + catch ( forced_unwind const&) + {} + catch (...) + { base_t::except_ = current_exception(); } + + base_t::flags_ |= flag_complete; + base_t::flags_ &= ~flag_running; + typename base_t::param_type to; + this->callee.jump( + this->caller, + reinterpret_cast< intptr_t >( & to), + base_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +template< typename PushCoro, typename R, typename Fn, typename StackAllocator > +class pull_coroutine_object< PushCoro, R &, Fn, StackAllocator > : private pull_coroutine_context, + public pull_coroutine_impl< R & > +{ +private: + typedef pull_coroutine_context ctx_t; + typedef pull_coroutine_impl< R & > base_t; + typedef pull_coroutine_object< PushCoro, R &, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + pull_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run() + { + BOOST_ASSERT( ! base_t::unwind_requested() ); + + base_t::flags_ |= flag_started; + base_t::flags_ |= flag_running; + + // create push_coroutine + typename PushCoro::synth_type b( & this->callee, & this->caller, false, base_t::preserve_fpu() ); + PushCoro push_coro( synthesized_t::syntesized, b); + try + { fn_( push_coro); } + catch ( forced_unwind const&) + {} + catch (...) + { base_t::except_ = current_exception(); } + + base_t::flags_ |= flag_complete; + base_t::flags_ &= ~flag_running; + typename base_t::param_type to; + this->callee.jump( + this->caller, + reinterpret_cast< intptr_t >( & to), + base_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +template< typename PushCoro, typename Fn, typename StackAllocator > +class pull_coroutine_object< PushCoro, void, Fn, StackAllocator > : private pull_coroutine_context, + public pull_coroutine_impl< void > +{ +private: + typedef pull_coroutine_context ctx_t; + typedef pull_coroutine_impl< void > base_t; + typedef pull_coroutine_object< PushCoro, void, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + pull_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run() + { + BOOST_ASSERT( ! base_t::unwind_requested() ); + + base_t::flags_ |= flag_started; + base_t::flags_ |= flag_running; + + // create push_coroutine + typename PushCoro::synth_type b( & this->callee, & this->caller, false, base_t::preserve_fpu() ); + PushCoro push_coro( synthesized_t::syntesized, b); + try + { fn_( push_coro); } + catch ( forced_unwind const&) + {} + catch (...) + { base_t::except_ = current_exception(); } + + base_t::flags_ |= flag_complete; + base_t::flags_ &= ~flag_running; + typename base_t::param_type to; + this->callee.jump( + this->caller, + reinterpret_cast< intptr_t >( & to), + base_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +}}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H diff --git a/boost/coroutine/detail/pull_coroutine_synthesized.hpp b/boost/coroutine/detail/pull_coroutine_synthesized.hpp new file mode 100644 index 0000000000..952d50c113 --- /dev/null +++ b/boost/coroutine/detail/pull_coroutine_synthesized.hpp @@ -0,0 +1,80 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_PULL_COROUTINE_SYNTHESIZED_H +#define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_SYNTHESIZED_H + +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/pull_coroutine_impl.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename R > +class pull_coroutine_synthesized : public pull_coroutine_impl< R > +{ +private: + typedef pull_coroutine_impl< R > impl_t; + +public: + pull_coroutine_synthesized( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu, + R * result) : + impl_t( caller, callee, unwind, preserve_fpu, result) + {} + + void destroy() {} +}; + +template< typename R > +class pull_coroutine_synthesized< R & > : public pull_coroutine_impl< R & > +{ +private: + typedef pull_coroutine_impl< R & > impl_t; + +public: + pull_coroutine_synthesized( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu, + R * result) : + impl_t( caller, callee, unwind, preserve_fpu, result) + {} + + void destroy() {} +}; + +template<> +class pull_coroutine_synthesized< void > : public pull_coroutine_impl< void > +{ +private: + typedef pull_coroutine_impl< void > impl_t; + +public: + pull_coroutine_synthesized( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + impl_t( caller, callee, unwind, preserve_fpu) + {} + + inline void destroy() {} +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_SYNTHESIZED_H diff --git a/boost/coroutine/detail/push_coroutine_impl.hpp b/boost/coroutine/detail/push_coroutine_impl.hpp new file mode 100644 index 0000000000..8ee2bd6f0e --- /dev/null +++ b/boost/coroutine/detail/push_coroutine_impl.hpp @@ -0,0 +1,295 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H +#define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/throw_exception.hpp> +#include <boost/utility.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/parameters.hpp> +#include <boost/coroutine/detail/trampoline_push.hpp> +#include <boost/coroutine/exceptions.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +namespace detail { + +template< typename Arg > +class push_coroutine_impl : private noncopyable +{ +protected: + int flags_; + exception_ptr except_; + coroutine_context * caller_; + coroutine_context * callee_; + +public: + typedef parameters< Arg > param_type; + + push_coroutine_impl( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + flags_( 0), + except_(), + caller_( caller), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + param_type to( unwind_t::force_unwind); + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + void push( Arg const& arg) + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + param_type to( const_cast< Arg * >( & arg), this); + param_type * from( + reinterpret_cast< param_type * >( + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ &= ~flag_running; + if ( from->do_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + void push( BOOST_RV_REF( Arg) arg) + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + param_type to( const_cast< Arg * >( & arg), this); + param_type * from( + reinterpret_cast< param_type * >( + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ &= ~flag_running; + if ( from->do_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + virtual void destroy() = 0; +}; + +template< typename Arg > +class push_coroutine_impl< Arg & > : private noncopyable +{ +protected: + int flags_; + exception_ptr except_; + coroutine_context * caller_; + coroutine_context * callee_; + +public: + typedef parameters< Arg & > param_type; + + push_coroutine_impl( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + flags_( 0), + except_(), + caller_( caller), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + param_type to( unwind_t::force_unwind); + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + void push( Arg & arg) + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + param_type to( & arg, this); + param_type * from( + reinterpret_cast< param_type * >( + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ &= ~flag_running; + if ( from->do_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + virtual void destroy() = 0; +}; + +template<> +class push_coroutine_impl< void > : private noncopyable +{ +protected: + int flags_; + exception_ptr except_; + coroutine_context * caller_; + coroutine_context * callee_; + +public: + typedef parameters< void > param_type; + + push_coroutine_impl( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + flags_( 0), + except_(), + caller_( caller), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + inline bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + inline bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + inline bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + inline bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + inline bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + inline bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + inline void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + param_type to( unwind_t::force_unwind); + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + inline void push() + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + param_type to( this); + param_type * from( + reinterpret_cast< param_type * >( + caller_->jump( + * callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ &= ~flag_running; + if ( from->do_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + virtual void destroy() = 0; +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H diff --git a/boost/coroutine/detail/push_coroutine_object.hpp b/boost/coroutine/detail/push_coroutine_object.hpp new file mode 100644 index 0000000000..1a39c07230 --- /dev/null +++ b/boost/coroutine/detail/push_coroutine_object.hpp @@ -0,0 +1,336 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H +#define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/move/move.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/push_coroutine_impl.hpp> +#include <boost/coroutine/detail/trampoline_push.hpp> +#include <boost/coroutine/exceptions.hpp> +#include <boost/coroutine/flags.hpp> +#include <boost/coroutine/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4355) +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +struct push_coroutine_context +{ + coroutine_context caller; + coroutine_context callee; + + template< typename Coro > + push_coroutine_context( stack_context const& stack_ctx, Coro *) : + caller(), + callee( trampoline_push< Coro >, stack_ctx) + {} +}; + +struct push_coroutine_context_void +{ + coroutine_context caller; + coroutine_context callee; + + template< typename Coro > + push_coroutine_context_void( stack_context const& stack_ctx, Coro *) : + caller(), + callee( trampoline_push_void< Coro >, stack_ctx) + {} +}; + +template< typename PullCoro, typename R, typename Fn, typename StackAllocator > +class push_coroutine_object : private push_coroutine_context, + public push_coroutine_impl< R > +{ +private: + typedef push_coroutine_context ctx_t; + typedef push_coroutine_impl< R > base_t; + typedef push_coroutine_object< PullCoro, R, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + push_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run( R * result) + { + BOOST_ASSERT( ! base_t::unwind_requested() ); + + base_t::flags_ |= flag_started; + base_t::flags_ |= flag_running; + + // create push_coroutine + typename PullCoro::synth_type b( & this->callee, & this->caller, false, base_t::preserve_fpu(), result); + PullCoro pull_coro( synthesized_t::syntesized, b); + try + { fn_( pull_coro); } + catch ( forced_unwind const&) + {} + catch (...) + { base_t::except_ = current_exception(); } + + base_t::flags_ |= flag_complete; + base_t::flags_ &= ~flag_running; + typename base_t::param_type to; + this->callee.jump( + this->caller, + reinterpret_cast< intptr_t >( & to), + base_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +template< typename PullCoro, typename R, typename Fn, typename StackAllocator > +class push_coroutine_object< PullCoro, R &, Fn, StackAllocator > : private push_coroutine_context, + public push_coroutine_impl< R & > +{ +private: + typedef push_coroutine_context ctx_t; + typedef push_coroutine_impl< R & > base_t; + typedef push_coroutine_object< PullCoro, R &, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + push_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run( R * result) + { + BOOST_ASSERT( ! base_t::unwind_requested() ); + + base_t::flags_ |= flag_started; + base_t::flags_ |= flag_running; + + // create push_coroutine + typename PullCoro::synth_type b( & this->callee, & this->caller, false, base_t::preserve_fpu(), result); + PullCoro push_coro( synthesized_t::syntesized, b); + try + { fn_( push_coro); } + catch ( forced_unwind const&) + {} + catch (...) + { base_t::except_ = current_exception(); } + + base_t::flags_ |= flag_complete; + base_t::flags_ &= ~flag_running; + typename base_t::param_type to; + this->callee.jump( + this->caller, + reinterpret_cast< intptr_t >( & to), + base_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +template< typename PullCoro, typename Fn, typename StackAllocator > +class push_coroutine_object< PullCoro, void, Fn, StackAllocator > : private push_coroutine_context_void, + public push_coroutine_impl< void > +{ +private: + typedef push_coroutine_context_void ctx_t; + typedef push_coroutine_impl< void > base_t; + typedef push_coroutine_object< PullCoro, void, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + push_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + ctx_t( internal_stack_ctx, this), + base_t( & this->caller, + & this->callee, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run() + { + BOOST_ASSERT( ! base_t::unwind_requested() ); + + base_t::flags_ |= flag_started; + base_t::flags_ |= flag_running; + + // create push_coroutine + typename PullCoro::synth_type b( & this->callee, & this->caller, false, base_t::preserve_fpu() ); + PullCoro push_coro( synthesized_t::syntesized, b); + try + { fn_( push_coro); } + catch ( forced_unwind const&) + {} + catch (...) + { base_t::except_ = current_exception(); } + + base_t::flags_ |= flag_complete; + base_t::flags_ &= ~flag_running; + typename base_t::param_type to; + this->callee.jump( + this->caller, + reinterpret_cast< intptr_t >( & to), + base_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +}}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H diff --git a/boost/coroutine/detail/push_coroutine_synthesized.hpp b/boost/coroutine/detail/push_coroutine_synthesized.hpp new file mode 100644 index 0000000000..306a841fc0 --- /dev/null +++ b/boost/coroutine/detail/push_coroutine_synthesized.hpp @@ -0,0 +1,78 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_PUSH_COROUTINE_SYNTHESIZED_H +#define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_SYNTHESIZED_H + +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/push_coroutine_impl.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename R > +class push_coroutine_synthesized : public push_coroutine_impl< R > +{ +private: + typedef push_coroutine_impl< R > impl_t; + +public: + push_coroutine_synthesized( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + impl_t( caller, callee, unwind, preserve_fpu) + {} + + void destroy() {} +}; + +template< typename R > +class push_coroutine_synthesized< R & > : public push_coroutine_impl< R & > +{ +private: + typedef push_coroutine_impl< R & > impl_t; + +public: + push_coroutine_synthesized( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + impl_t( caller, callee, unwind, preserve_fpu) + {} + + void destroy() {} +}; + +template<> +class push_coroutine_synthesized< void > : public push_coroutine_impl< void > +{ +private: + typedef push_coroutine_impl< void > impl_t; + +public: + push_coroutine_synthesized( coroutine_context * caller, + coroutine_context * callee, + bool unwind, bool preserve_fpu) : + impl_t( caller, callee, unwind, preserve_fpu) + {} + + inline void destroy() {} +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_SYNTHESIZED_H diff --git a/boost/coroutine/detail/setup.hpp b/boost/coroutine/detail/setup.hpp new file mode 100644 index 0000000000..35f601a779 --- /dev/null +++ b/boost/coroutine/detail/setup.hpp @@ -0,0 +1,75 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_SETUP_H +#define BOOST_COROUTINES_DETAIL_SETUP_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/move/move.hpp> +#include <boost/type_traits/decay.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/coroutine/attributes.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/flags.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename Fn > +struct setup +{ + struct dummy {}; + + Fn fn; + coroutine_context * caller; + coroutine_context * callee; + attributes attr; + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + setup( Fn fn_, + coroutine_context * caller_, + coroutine_context * callee_, + attributes const& attr_) : + fn( boost::forward< Fn >( fn_) ), + caller( caller_), + callee( callee_), + attr( attr_) + {} +#endif + setup( BOOST_RV_REF( Fn) fn_, + coroutine_context * caller_, + coroutine_context * callee_, + attributes const& attr_, + typename disable_if< + is_same< typename decay< Fn >::type, setup >, + dummy* + >::type = 0) : +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn( fn_), +#else + fn( boost::forward< Fn >( fn_) ), +#endif + caller( caller_), + callee( callee_), + attr( attr_) + {} +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_SETUP_H diff --git a/boost/coroutine/detail/symmetric_coroutine_call.hpp b/boost/coroutine/detail/symmetric_coroutine_call.hpp new file mode 100644 index 0000000000..a499275636 --- /dev/null +++ b/boost/coroutine/detail/symmetric_coroutine_call.hpp @@ -0,0 +1,822 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H +#define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/move/move.hpp> +#include <boost/utility/explicit_operator_bool.hpp> + +#include <boost/coroutine/attributes.hpp> +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/symmetric_coroutine_impl.hpp> +#include <boost/coroutine/detail/symmetric_coroutine_object.hpp> +#include <boost/coroutine/detail/symmetric_coroutine_yield.hpp> +#include <boost/coroutine/stack_allocator.hpp> +#include <boost/coroutine/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename Arg > +class symmetric_coroutine_call +{ +private: + template< typename X > + friend class symmetric_coroutine_yield; + + typedef symmetric_coroutine_impl< Arg > impl_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call) + + struct dummy {}; + + impl_type * impl_; + +public: + typedef Arg value_type; + typedef symmetric_coroutine_yield< Arg > yield_type; + + symmetric_coroutine_call() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( yield_type &); + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg, coroutine_fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename StackAllocator > + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg, coroutine_fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +# endif + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +#else + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +#endif + + ~symmetric_coroutine_call() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT + { + symmetric_coroutine_call tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete() || impl_->is_running(); } + + void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + symmetric_coroutine_call & operator()( Arg arg) BOOST_NOEXCEPT + { + BOOST_ASSERT( * this); + + impl_->resume( arg); + return * this; + } +}; + +template< typename Arg > +class symmetric_coroutine_call< Arg & > +{ +private: + template< typename X > + friend class symmetric_coroutine_yield; + + typedef symmetric_coroutine_impl< Arg & > impl_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call) + + struct dummy {}; + + impl_type * impl_; + +public: + typedef Arg value_type; + typedef symmetric_coroutine_yield< Arg & > yield_type; + + symmetric_coroutine_call() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( yield_type &); + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg &, coroutine_fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename StackAllocator > + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg &, coroutine_fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +# endif + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg &, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg &, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +#else + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg &, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg &, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg &, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< Arg &, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +#endif + + ~symmetric_coroutine_call() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT + { + symmetric_coroutine_call tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete() || impl_->is_running(); } + + void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + symmetric_coroutine_call & operator()( Arg & arg) BOOST_NOEXCEPT + { + BOOST_ASSERT( * this); + + impl_->resume( arg); + return * this; + } +}; + +template<> +class symmetric_coroutine_call< void > +{ +private: + template< typename X > + friend class symmetric_coroutine_yield; + + typedef symmetric_coroutine_impl< void > impl_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call) + + struct dummy {}; + + impl_type * impl_; + +public: + typedef void value_type; + typedef symmetric_coroutine_yield< void > yield_type; + + symmetric_coroutine_call() BOOST_NOEXCEPT : + impl_( 0) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( yield_type &); + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< void, coroutine_fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename StackAllocator > + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< void, coroutine_fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +# endif + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< void, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< void, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( + boost::forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +#else + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< void, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< void, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< void, Fn, stack_allocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } + + template< typename Fn, typename StackAllocator > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) + { + // create a stack-context + stack_context stack_ctx; + // allocate the coroutine-stack + stack_alloc.allocate( stack_ctx, attrs.size); + BOOST_ASSERT( 0 < stack_ctx.sp); + // typedef of internal coroutine-type + typedef symmetric_coroutine_object< void, Fn, StackAllocator > object_t; + // reserve space on top of coroutine-stack for internal coroutine-type + stack_context internal_stack_ctx; + internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.sp); + internal_stack_ctx.size = stack_ctx.size - sizeof( object_t); + BOOST_ASSERT( 0 < internal_stack_ctx.size); + // placement new for internal coroutine + impl_ = new ( internal_stack_ctx.sp) object_t( fn, attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); + } +#endif + + ~symmetric_coroutine_call() + { + if ( 0 != impl_) + { + impl_->destroy(); + impl_ = 0; + } + } + + inline symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + inline symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT + { + symmetric_coroutine_call tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + inline bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete() || impl_->is_running(); } + + inline void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + inline symmetric_coroutine_call & operator()() BOOST_NOEXCEPT + { + BOOST_ASSERT( * this); + + impl_->resume(); + return * this; + } +}; + +template< typename Arg > +void swap( symmetric_coroutine_call< Arg > & l, + symmetric_coroutine_call< Arg > & r) +{ l.swap( r); } + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H diff --git a/boost/coroutine/detail/symmetric_coroutine_impl.hpp b/boost/coroutine/detail/symmetric_coroutine_impl.hpp new file mode 100644 index 0000000000..0234ca7765 --- /dev/null +++ b/boost/coroutine/detail/symmetric_coroutine_impl.hpp @@ -0,0 +1,472 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H +#define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/utility.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/parameters.hpp> +#include <boost/coroutine/detail/trampoline.hpp> +#include <boost/coroutine/exceptions.hpp> +#include <boost/coroutine/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename R > +class symmetric_coroutine_impl : private noncopyable +{ +public: + typedef parameters< R > param_type; + + symmetric_coroutine_impl( stack_context const& stack_ctx, + bool unwind, bool preserve_fpu) BOOST_NOEXCEPT : + flags_( 0), + caller_(), + callee_( trampoline< symmetric_coroutine_impl< R > >, stack_ctx) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~symmetric_coroutine_impl() {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + flags_ |= flag_running; + param_type to( unwind_t::force_unwind); + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_running; + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + void resume( R r) BOOST_NOEXCEPT + { + param_type to( const_cast< R * >( & r), this); + resume_( & to); + } + + R * yield() + { + BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ &= ~flag_running; + param_type to; + param_type * from( + reinterpret_cast< param_type * >( + callee_.jump( + caller_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ |= flag_running; + if ( from->do_unwind) throw forced_unwind(); + BOOST_ASSERT( from->data); + return from->data; + } + + template< typename X > + R * yield_to( symmetric_coroutine_impl< X > * other, X x) + { + typename symmetric_coroutine_impl< X >::param_type to( & x, other); + return yield_to_( other, & to); + } + + template< typename X > + R * yield_to( symmetric_coroutine_impl< X & > * other, X & x) + { + typename symmetric_coroutine_impl< X & >::param_type to( & x, other); + return yield_to_( other, & to); + } + + template< typename X > + R * yield_to( symmetric_coroutine_impl< X > * other) + { + typename symmetric_coroutine_impl< X >::param_type to( other); + return yield_to_( other, & to); + } + + virtual void run( R *) BOOST_NOEXCEPT = 0; + + virtual void destroy() = 0; + +protected: + template< typename X > + friend class symmetric_coroutine_impl; + + int flags_; + coroutine_context caller_; + coroutine_context callee_; + + void resume_( param_type * to) BOOST_NOEXCEPT + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( to), + preserve_fpu() ); + flags_ &= ~flag_running; + } + + template< typename Other > + R * yield_to_( Other * other, typename Other::param_type * to) + { + BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); + BOOST_ASSERT( ! other->is_running() ); + BOOST_ASSERT( ! other->is_complete() ); + + other->caller_ = caller_; + flags_ &= ~flag_running; + param_type * from( + reinterpret_cast< param_type * >( + callee_.jump( + other->callee_, + reinterpret_cast< intptr_t >( to), + preserve_fpu() ) ) ); + flags_ |= flag_running; + if ( from->do_unwind) throw forced_unwind(); + BOOST_ASSERT( from->data); + return from->data; + } +}; + +template< typename R > +class symmetric_coroutine_impl< R & > : private noncopyable +{ +public: + typedef parameters< R & > param_type; + + symmetric_coroutine_impl( stack_context const& stack_ctx, + bool unwind, bool preserve_fpu) BOOST_NOEXCEPT : + flags_( 0), + caller_(), + callee_( trampoline< symmetric_coroutine_impl< R > >, stack_ctx) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~symmetric_coroutine_impl() {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + flags_ |= flag_running; + param_type to( unwind_t::force_unwind); + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_running; + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + void resume( R & arg) BOOST_NOEXCEPT + { + param_type to( & arg, this); + resume_( & to); + } + + R * yield() + { + BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ &= ~flag_running; + param_type to; + param_type * from( + reinterpret_cast< param_type * >( + callee_.jump( + caller_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ |= flag_running; + if ( from->do_unwind) throw forced_unwind(); + BOOST_ASSERT( from->data); + return from->data; + } + + template< typename X > + R * yield_to( symmetric_coroutine_impl< X > * other, X x) + { + typename symmetric_coroutine_impl< X >::param_type to( & x, other); + return yield_to_( other, & to); + } + + template< typename X > + R * yield_to( symmetric_coroutine_impl< X & > * other, X & x) + { + typename symmetric_coroutine_impl< X & >::param_type to( & x, other); + return yield_to_( other, & to); + } + + template< typename X > + R * yield_to( symmetric_coroutine_impl< X > * other) + { + typename symmetric_coroutine_impl< X >::param_type to( other); + return yield_to_( other, & to); + } + + virtual void run( R *) BOOST_NOEXCEPT = 0; + + virtual void destroy() = 0; + +protected: + template< typename X > + friend class symmetric_coroutine_impl; + + int flags_; + coroutine_context caller_; + coroutine_context callee_; + + void resume_( param_type * to) BOOST_NOEXCEPT + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ |= flag_running; + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( to), + preserve_fpu() ); + flags_ &= ~flag_running; + } + + template< typename Other > + R * yield_to_( Other * other, typename Other::param_type * to) + { + BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); + BOOST_ASSERT( ! other->is_running() ); + BOOST_ASSERT( ! other->is_complete() ); + + other->caller_ = caller_; + flags_ &= ~flag_running; + param_type * from( + reinterpret_cast< param_type * >( + callee_.jump( + other->callee_, + reinterpret_cast< intptr_t >( to), + preserve_fpu() ) ) ); + flags_ |= flag_running; + if ( from->do_unwind) throw forced_unwind(); + BOOST_ASSERT( from->data); + return from->data; + } +}; + +template<> +class symmetric_coroutine_impl< void > : private noncopyable +{ +public: + typedef parameters< void > param_type; + + symmetric_coroutine_impl( stack_context const& stack_ctx, + bool unwind, bool preserve_fpu) BOOST_NOEXCEPT : + flags_( 0), + caller_(), + callee_( trampoline_void< symmetric_coroutine_impl< void > >, stack_ctx) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~symmetric_coroutine_impl() {} + + inline bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + inline bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + inline bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + inline bool is_started() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_started); } + + inline bool is_running() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_running); } + + inline bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + inline void unwind_stack() BOOST_NOEXCEPT + { + if ( is_started() && ! is_complete() && force_unwind() ) + { + flags_ |= flag_unwind_stack; + flags_ |= flag_running; + param_type to( unwind_t::force_unwind); + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_running; + flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( is_complete() ); + } + } + + inline void resume() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! is_running() ); + BOOST_ASSERT( ! is_complete() ); + + param_type to( this); + flags_ |= flag_running; + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ); + flags_ &= ~flag_running; + } + + inline void yield() BOOST_NOEXCEPT + { + BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); + + flags_ &= ~flag_running; + param_type to; + param_type * from( + reinterpret_cast< param_type * >( + callee_.jump( + caller_, + reinterpret_cast< intptr_t >( & to), + preserve_fpu() ) ) ); + flags_ |= flag_running; + if ( from->do_unwind) throw forced_unwind(); + } + + template< typename X > + void yield_to( symmetric_coroutine_impl< X > * other, X x) + { + typename symmetric_coroutine_impl< X >::param_type to( & x, other); + yield_to_( other, & to); + } + + template< typename X > + void yield_to( symmetric_coroutine_impl< X & > * other, X & x) + { + typename symmetric_coroutine_impl< X & >::param_type to( & x, other); + yield_to_( other, & to); + } + + template< typename X > + void yield_to( symmetric_coroutine_impl< X > * other) + { + typename symmetric_coroutine_impl< X >::param_type to( other); + yield_to_( other, & to); + } + + virtual void run() BOOST_NOEXCEPT = 0; + + virtual void destroy() = 0; + +protected: + template< typename X > + friend class symmetric_coroutine_impl; + + int flags_; + coroutine_context caller_; + coroutine_context callee_; + + template< typename Other > + void yield_to_( Other * other, typename Other::param_type * to) + { + BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); + BOOST_ASSERT( ! other->is_running() ); + BOOST_ASSERT( ! other->is_complete() ); + + other->caller_ = caller_; + flags_ &= ~flag_running; + param_type * from( + reinterpret_cast< param_type * >( + callee_.jump( + other->callee_, + reinterpret_cast< intptr_t >( to), + preserve_fpu() ) ) ); + flags_ |= flag_running; + if ( from->do_unwind) throw forced_unwind(); + } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H diff --git a/boost/coroutine/detail/symmetric_coroutine_object.hpp b/boost/coroutine/detail/symmetric_coroutine_object.hpp new file mode 100644 index 0000000000..a1c0c052a5 --- /dev/null +++ b/boost/coroutine/detail/symmetric_coroutine_object.hpp @@ -0,0 +1,281 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H +#define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/move/move.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/symmetric_coroutine_impl.hpp> +#include <boost/coroutine/detail/symmetric_coroutine_yield.hpp> +#include <boost/coroutine/exceptions.hpp> +#include <boost/coroutine/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +namespace detail { + +template< typename R, typename Fn, typename StackAllocator > +class symmetric_coroutine_object : public symmetric_coroutine_impl< R > +{ +private: + typedef symmetric_coroutine_impl< R > impl_t; + typedef symmetric_coroutine_object< R, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + symmetric_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + impl_t( internal_stack_ctx, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + impl_t( internal_stack_ctx, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run( R * r) BOOST_NOEXCEPT + { + BOOST_ASSERT( ! impl_t::unwind_requested() ); + + impl_t::flags_ |= flag_started; + impl_t::flags_ |= flag_running; + try + { + symmetric_coroutine_yield< R > yc( this, r); + fn_( yc); + } + catch ( forced_unwind const&) + {} + catch (...) + { std::terminate(); } + + impl_t::flags_ |= flag_complete; + impl_t::flags_ &= ~flag_running; + typename impl_t::param_type to; + impl_t::callee_.jump( + impl_t::caller_, + reinterpret_cast< intptr_t >( & to), + impl_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +template< typename R, typename Fn, typename StackAllocator > +class symmetric_coroutine_object< R &, Fn, StackAllocator > : public symmetric_coroutine_impl< R & > +{ +private: + typedef symmetric_coroutine_impl< R & > impl_t; + typedef symmetric_coroutine_object< R &, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + symmetric_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + impl_t( internal_stack_ctx, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + impl_t( internal_stack_ctx, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run( R * r) BOOST_NOEXCEPT + { + BOOST_ASSERT( ! impl_t::unwind_requested() ); + + impl_t::flags_ |= flag_started; + impl_t::flags_ |= flag_running; + try + { + symmetric_coroutine_yield< R & > yc( this, r); + fn_( yc); + } + catch ( forced_unwind const&) + {} + catch (...) + { std::terminate(); } + + impl_t::flags_ |= flag_complete; + impl_t::flags_ &= ~flag_running; + typename impl_t::param_type to; + impl_t::callee_.jump( + impl_t::caller_, + reinterpret_cast< intptr_t >( & to), + impl_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +template< typename Fn, typename StackAllocator > +class symmetric_coroutine_object< void, Fn, StackAllocator > : public symmetric_coroutine_impl< void > +{ +private: + typedef symmetric_coroutine_impl< void > impl_t; + typedef symmetric_coroutine_object< void, Fn, StackAllocator > obj_t; + + Fn fn_; + stack_context stack_ctx_; + StackAllocator stack_alloc_; + + static void deallocate_( obj_t * obj) + { + stack_context stack_ctx( obj->stack_ctx_); + StackAllocator stack_alloc( obj->stack_alloc_); + obj->unwind_stack(); + obj->~obj_t(); + stack_alloc.deallocate( stack_ctx); + } + +public: +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + symmetric_coroutine_object( Fn fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + impl_t( internal_stack_ctx, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), + fn_( fn), + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} +#endif + + symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, + stack_context const& stack_ctx, + stack_context const& internal_stack_ctx, + StackAllocator const& stack_alloc) BOOST_NOEXCEPT : + impl_t( internal_stack_ctx, + stack_unwind == attrs.do_unwind, + fpu_preserved == attrs.preserve_fpu), +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + fn_( fn), +#else + fn_( boost::forward< Fn >( fn) ), +#endif + stack_ctx_( stack_ctx), + stack_alloc_( stack_alloc) + {} + + void run() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! impl_t::unwind_requested() ); + + impl_t::flags_ |= flag_started; + impl_t::flags_ |= flag_running; + try + { + symmetric_coroutine_yield< void > yc( this); + fn_( yc); + } + catch ( forced_unwind const&) + {} + catch (...) + { std::terminate(); } + + impl_t::flags_ |= flag_complete; + impl_t::flags_ &= ~flag_running; + typename impl_t::param_type to; + impl_t::callee_.jump( + impl_t::caller_, + reinterpret_cast< intptr_t >( & to), + impl_t::preserve_fpu() ); + BOOST_ASSERT_MSG( false, "coroutine is complete"); + } + + void destroy() + { deallocate_( this); } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H diff --git a/boost/coroutine/detail/symmetric_coroutine_yield.hpp b/boost/coroutine/detail/symmetric_coroutine_yield.hpp new file mode 100644 index 0000000000..296676b6f9 --- /dev/null +++ b/boost/coroutine/detail/symmetric_coroutine_yield.hpp @@ -0,0 +1,307 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_YIELD_H +#define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_YIELD_H + +#include <algorithm> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/move/move.hpp> +#include <boost/throw_exception.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/utility/explicit_operator_bool.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/exceptions.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename R > +class symmetric_coroutine_yield +{ +private: + template< typename X, typename Y, typename Z > + friend class symmetric_coroutine_object; + + typedef symmetric_coroutine_impl< R > impl_type; + + struct dummy {}; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_yield) + + impl_type * impl_; + R * result_; + + symmetric_coroutine_yield( impl_type * impl, R * result) BOOST_NOEXCEPT : + impl_( impl), + result_( result) + { + BOOST_ASSERT( 0 != impl_); + BOOST_ASSERT( 0 != result_); + } + +public: + symmetric_coroutine_yield() BOOST_NOEXCEPT : + impl_( 0), + result_( 0) + {} + + symmetric_coroutine_yield( BOOST_RV_REF( symmetric_coroutine_yield) other) BOOST_NOEXCEPT : + impl_( 0), + result_( 0) + { swap( other); } + + symmetric_coroutine_yield & operator=( BOOST_RV_REF( symmetric_coroutine_yield) other) BOOST_NOEXCEPT + { + symmetric_coroutine_yield tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_; } + + void swap( symmetric_coroutine_yield & other) BOOST_NOEXCEPT + { + std::swap( impl_, other.impl_); + std::swap( result_, other.result_); + } + + symmetric_coroutine_yield & operator()() + { + result_ = impl_->yield(); + return * this; + } + + template< typename Coro > + symmetric_coroutine_yield & operator()( Coro & other, typename Coro::value_type x, + typename disable_if< + is_same< typename Coro::value_type, void >, + dummy* + >::type = 0) + { + BOOST_ASSERT( other); + + result_ = impl_->yield_to( other.impl_, x); + return * this; + } + + template< typename Coro > + symmetric_coroutine_yield & operator()( Coro & other, + typename enable_if< + is_same< typename Coro::value_type, void >, + dummy* + >::type = 0) + { + BOOST_ASSERT( other); + + result_ = impl_->yield_to( other.impl_); + return * this; + } + + R get() const + { + if ( 0 == result_) + boost::throw_exception( + invalid_result() ); + + return * result_; + } +}; + +template< typename R > +class symmetric_coroutine_yield< R & > +{ +private: + template< typename X, typename Y, typename Z > + friend class symmetric_coroutine_object; + + typedef symmetric_coroutine_impl< R & > impl_type; + + struct dummy {}; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_yield) + + impl_type * impl_; + R * result_; + + symmetric_coroutine_yield( impl_type * impl, R * result) BOOST_NOEXCEPT : + impl_( impl), + result_( result) + { + BOOST_ASSERT( 0 != impl_); + BOOST_ASSERT( 0 != result_); + } + +public: + symmetric_coroutine_yield() BOOST_NOEXCEPT : + impl_( 0), + result_( 0) + {} + + symmetric_coroutine_yield( BOOST_RV_REF( symmetric_coroutine_yield) other) BOOST_NOEXCEPT : + impl_( 0), + result_( 0) + { swap( other); } + + symmetric_coroutine_yield & operator=( BOOST_RV_REF( symmetric_coroutine_yield) other) BOOST_NOEXCEPT + { + symmetric_coroutine_yield tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_; } + + void swap( symmetric_coroutine_yield & other) BOOST_NOEXCEPT + { + std::swap( impl_, other.impl_); + std::swap( result_, other.result_); + } + + symmetric_coroutine_yield & operator()() + { + result_ = impl_->yield(); + return * this; + } + + template< typename Coro > + symmetric_coroutine_yield & operator()( Coro & other, typename Coro::value_type & x, + typename disable_if< + is_same< typename Coro::value_type, void >, + dummy* + >::type = 0) + { + BOOST_ASSERT( other); + + result_ = impl_->yield_to( other.impl_, x); + return * this; + } + + template< typename Coro > + symmetric_coroutine_yield & operator()( Coro & other, + typename enable_if< + is_same< typename Coro::value_type, void >, + dummy* + >::type = 0) + { + BOOST_ASSERT( other); + + result_ = impl_->yield_to( other.impl_); + return * this; + } + + R & get() const + { + if ( 0 == result_) + boost::throw_exception( + invalid_result() ); + + return * result_; + } +}; + +template<> +class symmetric_coroutine_yield< void > +{ +private: + template< typename X, typename Y, typename Z > + friend class symmetric_coroutine_object; + + typedef symmetric_coroutine_impl< void > impl_type; + + struct dummy {}; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_yield) + + impl_type * impl_; + + symmetric_coroutine_yield( impl_type * impl) BOOST_NOEXCEPT : + impl_( impl) + { BOOST_ASSERT( 0 != impl_); } + +public: + symmetric_coroutine_yield() BOOST_NOEXCEPT : + impl_( 0) + {} + + symmetric_coroutine_yield( BOOST_RV_REF( symmetric_coroutine_yield) other) BOOST_NOEXCEPT : + impl_( 0) + { swap( other); } + + symmetric_coroutine_yield & operator=( BOOST_RV_REF( symmetric_coroutine_yield) other) BOOST_NOEXCEPT + { + symmetric_coroutine_yield tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + inline bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_; } + + inline void swap( symmetric_coroutine_yield & other) BOOST_NOEXCEPT + { std::swap( impl_, other.impl_); } + + inline symmetric_coroutine_yield & operator()() + { + impl_->yield(); + return * this; + } + + template< typename Coro > + symmetric_coroutine_yield & operator()( Coro & other, typename Coro::value_type & x, + typename disable_if< + is_same< typename Coro::value_type, void >, + dummy* + >::type = 0) + { + BOOST_ASSERT( other); + + impl_->yield_to( other.impl_, x); + return * this; + } + + template< typename Coro > + symmetric_coroutine_yield & operator()( Coro & other, + typename enable_if< + is_same< typename Coro::value_type, void >, + dummy* + >::type = 0) + { + BOOST_ASSERT( other); + + impl_->yield_to( other.impl_); + return * this; + } +}; + +template< typename R > +void swap( symmetric_coroutine_yield< R > & l, symmetric_coroutine_yield< R > & r) +{ l.swap( r); } + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_YIELD_H diff --git a/boost/coroutine/detail/trampoline.hpp b/boost/coroutine/detail/trampoline.hpp new file mode 100644 index 0000000000..1cb3226d15 --- /dev/null +++ b/boost/coroutine/detail/trampoline.hpp @@ -0,0 +1,67 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_TRAMPOLINE_H +#define BOOST_COROUTINES_DETAIL_TRAMPOLINE_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> + +#include <boost/coroutine/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename Coro > +void trampoline( intptr_t vp) +{ + typedef typename Coro::param_type param_type; + + BOOST_ASSERT( 0 != vp); + + param_type * param( + reinterpret_cast< param_type * >( vp) ); + BOOST_ASSERT( 0 != param); + BOOST_ASSERT( 0 != param->data); + + Coro * coro( + reinterpret_cast< Coro * >( param->coro) ); + BOOST_ASSERT( 0 != coro); + + coro->run( param->data); +} + +template< typename Coro > +void trampoline_void( intptr_t vp) +{ + typedef typename Coro::param_type param_type; + + BOOST_ASSERT( 0 != vp); + + param_type * param( + reinterpret_cast< param_type * >( vp) ); + BOOST_ASSERT( 0 != param); + + Coro * coro( + reinterpret_cast< Coro * >( param->coro) ); + BOOST_ASSERT( 0 != coro); + + coro->run(); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_H diff --git a/boost/coroutine/detail/trampoline_pull.hpp b/boost/coroutine/detail/trampoline_pull.hpp new file mode 100644 index 0000000000..179024529d --- /dev/null +++ b/boost/coroutine/detail/trampoline_pull.hpp @@ -0,0 +1,48 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_TRAMPOLINE_PULL_H +#define BOOST_COROUTINES_DETAIL_TRAMPOLINE_PULL_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> + +#include <boost/coroutine/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename Coro > +void trampoline_pull( intptr_t vp) +{ + typedef typename Coro::param_type param_type; + + BOOST_ASSERT( 0 != vp); + + param_type * param( + reinterpret_cast< param_type * >( vp) ); + BOOST_ASSERT( 0 != param); + + Coro * coro( + reinterpret_cast< Coro * >( param->coro) ); + BOOST_ASSERT( 0 != coro); + + coro->run(); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_PULL_H diff --git a/boost/coroutine/detail/trampoline_push.hpp b/boost/coroutine/detail/trampoline_push.hpp new file mode 100644 index 0000000000..448904456e --- /dev/null +++ b/boost/coroutine/detail/trampoline_push.hpp @@ -0,0 +1,77 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_DETAIL_TRAMPOLINE_PUSH_H +#define BOOST_COROUTINES_DETAIL_TRAMPOLINE_PUSH_H + +#include <cstddef> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/move/move.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/parameters.hpp> +#include <boost/coroutine/detail/setup.hpp> +#include <boost/coroutine/detail/setup.hpp> +#include <boost/coroutine/exceptions.hpp> +#include <boost/coroutine/flags.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename Coro > +void trampoline_push( intptr_t vp) +{ + typedef typename Coro::param_type param_type; + + BOOST_ASSERT( vp); + + param_type * param( + reinterpret_cast< param_type * >( vp) ); + BOOST_ASSERT( 0 != param); + BOOST_ASSERT( 0 != param->data); + + Coro * coro( + reinterpret_cast< Coro * >( param->coro) ); + BOOST_ASSERT( 0 != coro); + + coro->run( param->data); +} + +template< typename Coro > +void trampoline_push_void( intptr_t vp) +{ + typedef typename Coro::param_type param_type; + + BOOST_ASSERT( vp); + + param_type * param( + reinterpret_cast< param_type * >( vp) ); + BOOST_ASSERT( 0 != param); + + Coro * coro( + reinterpret_cast< Coro * >( param->coro) ); + BOOST_ASSERT( 0 != coro); + + coro->run(); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_PUSH_H diff --git a/boost/coroutine/exceptions.hpp b/boost/coroutine/exceptions.hpp new file mode 100644 index 0000000000..f263429719 --- /dev/null +++ b/boost/coroutine/exceptions.hpp @@ -0,0 +1,105 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_EXCEPTIONS_H +#define BOOST_COROUTINES_EXCEPTIONS_H + +#include <stdexcept> +#include <string> + +#include <boost/config.hpp> +#include <boost/detail/scoped_enum_emulation.hpp> +#include <boost/system/error_code.hpp> +#include <boost/system/system_error.hpp> +#include <boost/type_traits/integral_constant.hpp> + +#include <boost/coroutine/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +struct forced_unwind {}; + +} + +BOOST_SCOPED_ENUM_DECLARE_BEGIN(coroutine_errc) +{ + no_data = 1 +} +BOOST_SCOPED_ENUM_DECLARE_END(coroutine_errc) + +BOOST_COROUTINES_DECL system::error_category const& coroutine_category() BOOST_NOEXCEPT; + +} + +namespace system { + +template<> +struct is_error_code_enum< coroutines::coroutine_errc > : public true_type +{}; + +#ifdef BOOST_NO_CXX11_SCOPED_ENUMS +template<> +struct is_error_code_enum< coroutines::coroutine_errc::enum_type > : public true_type +{}; +#endif + +inline +error_code make_error_code( coroutines::coroutine_errc e) //BOOST_NOEXCEPT +{ + return error_code( underlying_cast< int >( e), coroutines::coroutine_category() ); +} + +inline +error_condition make_error_condition( coroutines::coroutine_errc e) //BOOST_NOEXCEPT +{ + return error_condition( underlying_cast< int >( e), coroutines::coroutine_category() ); +} + +} + +namespace coroutines { + +class coroutine_error : public std::logic_error +{ +private: + system::error_code ec_; + +public: + coroutine_error( system::error_code ec) : + logic_error( ec.message() ), + ec_( ec) + {} + + system::error_code const& code() const BOOST_NOEXCEPT + { return ec_; } + + const char* what() const throw() + { return code().message().c_str(); } +}; + +class invalid_result : public coroutine_error +{ +public: + invalid_result() : + coroutine_error( + system::make_error_code( + coroutine_errc::no_data) ) + {} +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_EXCEPTIONS_H diff --git a/boost/coroutine/flags.hpp b/boost/coroutine/flags.hpp new file mode 100644 index 0000000000..a8194c60ee --- /dev/null +++ b/boost/coroutine/flags.hpp @@ -0,0 +1,27 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_FLAGS_H +#define BOOST_COROUTINES_FLAGS_H + +namespace boost { +namespace coroutines { + +enum flag_unwind_t +{ + stack_unwind = 0, + no_stack_unwind +}; + +enum flag_fpu_t +{ + fpu_preserved = 0, + fpu_not_preserved +}; + +}} + +#endif // BOOST_COROUTINES_FLAGS_H diff --git a/boost/coroutine/posix/protected_stack_allocator.hpp b/boost/coroutine/posix/protected_stack_allocator.hpp new file mode 100644 index 0000000000..659de337a1 --- /dev/null +++ b/boost/coroutine/posix/protected_stack_allocator.hpp @@ -0,0 +1,105 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_PROTECTED_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H + +extern "C" { +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> +} + +#if defined(BOOST_USE_VALGRIND) +#include <valgrind/valgrind.h> +#endif + +#include <cmath> +#include <cstddef> +#include <new> + +#include <boost/assert.hpp> +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/stack_context.hpp> +#include <boost/coroutine/stack_traits.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +template< typename traitsT > +struct basic_protected_stack_allocator +{ + typedef traitsT traits_type; + + void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) + { + BOOST_ASSERT( traits_type::minimum_size() <= size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); + + // page at bottom will be used as guard-page + const std::size_t pages( + static_cast< std::size_t >( + std::floor( + static_cast< float >( size) / traits_type::page_size() ) ) ); + BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); + const std::size_t size_( pages * traits_type::page_size() ); + BOOST_ASSERT( 0 < size && 0 < size_); + BOOST_ASSERT( size_ <= size); + + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) +#if defined(MAP_ANON) + void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +#else + void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif + if ( MAP_FAILED == limit) throw std::bad_alloc(); + + // conforming to POSIX.1-2001 +#if defined(BOOST_DISABLE_ASSERTS) + ::mprotect( limit, traits_type::page_size(), PROT_NONE); +#else + const int result( ::mprotect( limit, traits_type::page_size(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); +#endif + + ctx.size = size_; + ctx.sp = static_cast< char * >( limit) + ctx.size; +#if defined(BOOST_USE_VALGRIND) + ctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( ctx.sp, limit); +#endif + } + + void deallocate( stack_context & ctx) + { + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); + +#if defined(BOOST_USE_VALGRIND) + VALGRIND_STACK_DEREGISTER( ctx.valgrind_stack_id); +#endif + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) + ::munmap( limit, ctx.size); + } +}; + +typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H diff --git a/boost/coroutine/posix/segmented_stack_allocator.hpp b/boost/coroutine/posix/segmented_stack_allocator.hpp new file mode 100644 index 0000000000..335e5789b4 --- /dev/null +++ b/boost/coroutine/posix/segmented_stack_allocator.hpp @@ -0,0 +1,69 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H + +#include <cstddef> +#include <new> + +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/stack_context.hpp> +#include <boost/coroutine/stack_traits.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +// forward declaration for splitstack-functions defined in libgcc +extern "C" { +void *__splitstack_makecontext( std::size_t, + void * [BOOST_COROUTINES_SEGMENTS], + std::size_t *); + +void __splitstack_releasecontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_resetcontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_block_signals_context( void * [BOOST_COROUTINES_SEGMENTS], + int * new_value, int * old_value); +} + +namespace boost { +namespace coroutines { + +template< typename traitsT > +struct basic_segmented_stack_allocator +{ + typedef traitsT traits_type; + + void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) + { + void * limit = __splitstack_makecontext( size, ctx.segments_ctx, & ctx.size); + if ( ! limit) throw std::bad_alloc(); + + // ctx.size is already filled by __splitstack_makecontext + ctx.sp = static_cast< char * >( limit) + ctx.size; + + int off = 0; + __splitstack_block_signals_context( ctx.segments_ctx, & off, 0); + } + + void deallocate( stack_context & ctx) + { __splitstack_releasecontext( ctx.segments_ctx); } +}; + +typedef basic_segmented_stack_allocator< stack_traits > segmented_stack_allocator; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H diff --git a/boost/coroutine/protected_stack_allocator.hpp b/boost/coroutine/protected_stack_allocator.hpp new file mode 100644 index 0000000000..268786fec4 --- /dev/null +++ b/boost/coroutine/protected_stack_allocator.hpp @@ -0,0 +1,13 @@ + +// Copyright Oliver Kowalke 2009. +// 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) + +#include <boost/config.hpp> + +#if defined(BOOST_WINDOWS) +# include <boost/coroutine/windows/protected_stack_allocator.hpp> +#else +# include <boost/coroutine/posix/protected_stack_allocator.hpp> +#endif diff --git a/boost/coroutine/segmented_stack_allocator.hpp b/boost/coroutine/segmented_stack_allocator.hpp new file mode 100644 index 0000000000..f9525a1a5e --- /dev/null +++ b/boost/coroutine/segmented_stack_allocator.hpp @@ -0,0 +1,15 @@ + +// Copyright Oliver Kowalke 2009. +// 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) + +#include <boost/config.hpp> + +#if defined(BOOST_USE_SEGMENTED_STACKS) +# if defined(BOOST_WINDOWS) +# error "segmented stacks are not supported by Windows" +# else +# include <boost/coroutine/posix/segmented_stack_allocator.hpp> +# endif +#endif diff --git a/boost/coroutine/stack_allocator.hpp b/boost/coroutine/stack_allocator.hpp new file mode 100644 index 0000000000..662533efe7 --- /dev/null +++ b/boost/coroutine/stack_allocator.hpp @@ -0,0 +1,37 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_STACK_ALLOCATOR_H + +#include <cstddef> + +#include <boost/config.hpp> + +#include <boost/context/detail/config.hpp> +#include <boost/coroutine/segmented_stack_allocator.hpp> +#include <boost/coroutine/standard_stack_allocator.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +#if defined(BOOST_USE_SEGMENTED_STACKS) +typedef segmented_stack_allocator stack_allocator; +#else +typedef standard_stack_allocator stack_allocator; +#endif + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_STACK_ALLOCATOR_H diff --git a/boost/coroutine/stack_context.hpp b/boost/coroutine/stack_context.hpp new file mode 100644 index 0000000000..1ca11eb4a8 --- /dev/null +++ b/boost/coroutine/stack_context.hpp @@ -0,0 +1,66 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_STACK_CONTEXT_H +#define BOOST_COROUTINES_STACK_CONTEXT_H + +#include <cstddef> + +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +#if defined(BOOST_USE_SEGMENTED_STACKS) +struct stack_context +{ + typedef void * segments_context[BOOST_COROUTINES_SEGMENTS]; + + std::size_t size; + void * sp; + segments_context segments_ctx; +#if defined(BOOST_USE_VALGRIND) + unsigned valgrind_stack_id; +#endif + + stack_context() : + size( 0), sp( 0), segments_ctx() +#if defined(BOOST_USE_VALGRIND) + , valgrind_stack_id( 0) +#endif + {} +}; +#else +struct stack_context +{ + std::size_t size; + void * sp; +#if defined(BOOST_USE_VALGRIND) + unsigned valgrind_stack_id; +#endif + + stack_context() : + size( 0), sp( 0) +#if defined(BOOST_USE_VALGRIND) + , valgrind_stack_id( 0) +#endif + {} +}; +#endif + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_STACK_CONTEXT_H diff --git a/boost/coroutine/stack_traits.hpp b/boost/coroutine/stack_traits.hpp new file mode 100644 index 0000000000..0e8f25182d --- /dev/null +++ b/boost/coroutine/stack_traits.hpp @@ -0,0 +1,42 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_STACK_TRAITS_H +#define BOOST_COROUTINES_STACK_TRAITS_H + +#include <cstddef> + +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct BOOST_COROUTINES_DECL stack_traits +{ + static bool is_unbounded() BOOST_NOEXCEPT; + + static std::size_t page_size() BOOST_NOEXCEPT; + + static std::size_t default_size() BOOST_NOEXCEPT; + + static std::size_t minimum_size() BOOST_NOEXCEPT; + + static std::size_t maximum_size() BOOST_NOEXCEPT; +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_STACK_TRAITS_H diff --git a/boost/coroutine/standard_stack_allocator.hpp b/boost/coroutine/standard_stack_allocator.hpp new file mode 100644 index 0000000000..b946fffc4a --- /dev/null +++ b/boost/coroutine/standard_stack_allocator.hpp @@ -0,0 +1,75 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_STANDARD_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_STANDARD_STACK_ALLOCATOR_H + +#if defined(BOOST_USE_VALGRIND) +#include <valgrind/valgrind.h> +#endif + +#include <cstddef> +#include <cstdlib> +#include <new> + +#include <boost/assert.hpp> +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/stack_context.hpp> +#include <boost/coroutine/stack_traits.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +template< typename traitsT > +struct basic_standard_stack_allocator +{ + typedef traitsT traits_type; + + void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) + { + BOOST_ASSERT( traits_type::minimum_size() <= size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); + + void * limit = std::malloc( size); + if ( ! limit) throw std::bad_alloc(); + + ctx.size = size; + ctx.sp = static_cast< char * >( limit) + ctx.size; +#if defined(BOOST_USE_VALGRIND) + ctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( ctx.sp, limit); +#endif + } + + void deallocate( stack_context & ctx) + { + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); + +#if defined(BOOST_USE_VALGRIND) + VALGRIND_STACK_DEREGISTER( ctx.valgrind_stack_id); +#endif + + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + std::free( limit); + } +}; + +typedef basic_standard_stack_allocator< stack_traits > standard_stack_allocator; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_STANDARD_STACK_ALLOCATOR_H diff --git a/boost/coroutine/symmetric_coroutine.hpp b/boost/coroutine/symmetric_coroutine.hpp new file mode 100644 index 0000000000..543cae0a37 --- /dev/null +++ b/boost/coroutine/symmetric_coroutine.hpp @@ -0,0 +1,35 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_SYMMETRIC_COROUTINE_H +#define BOOST_COROUTINES_SYMMETRIC_COROUTINE_H + +#include <boost/config.hpp> + +#include <boost/coroutine/detail/symmetric_coroutine_call.hpp> +#include <boost/coroutine/detail/symmetric_coroutine_yield.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +template< typename T > +struct symmetric_coroutine +{ + typedef detail::symmetric_coroutine_call< T > call_type; + typedef detail::symmetric_coroutine_yield< T > yield_type; +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_SYMMETRIC_COROUTINE_H diff --git a/boost/coroutine/windows/protected_stack_allocator.hpp b/boost/coroutine/windows/protected_stack_allocator.hpp new file mode 100644 index 0000000000..293901223b --- /dev/null +++ b/boost/coroutine/windows/protected_stack_allocator.hpp @@ -0,0 +1,87 @@ + +// Copyright Oliver Kowalke 2009. +// 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_COROUTINES_PROTECTED_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H + +extern "C" { +#include <windows.h> +} + +#include <cmath> +#include <cstddef> +#include <new> + +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/stack_traits.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +template< typename traitsT > +struct basic_protected_stack_allocator +{ + typedef traitsT traits_type; + + void allocate( stack_context & ctx, std::size_t size) + { + BOOST_ASSERT( traits_type::minimum_size() <= size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); + + // page at bottom will be used as guard-page + const std::size_t pages( + static_cast< std::size_t >( + std::floor( + static_cast< float >( size) / traits_type::page_size() ) ) ); + BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); + const std::size_t size_ = pages * traits_type::page_size(); + BOOST_ASSERT( 0 < size && 0 < size_); + + void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE); + if ( ! limit) throw std::bad_alloc(); + + DWORD old_options; +#if defined(BOOST_DISABLE_ASSERTS) + ::VirtualProtect( + limit, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); +#else + const BOOL result = ::VirtualProtect( + limit, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); + BOOST_ASSERT( FALSE != result); +#endif + + ctx.size = size_; + ctx.sp = static_cast< char * >( limit) + ctx.size; + } + + void deallocate( stack_context & ctx) + { + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); + + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + ::VirtualFree( limit, 0, MEM_RELEASE); + } +}; + +typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H |