diff options
Diffstat (limited to 'boost/coroutine/detail/pull_coroutine_object.hpp')
-rw-r--r-- | boost/coroutine/detail/pull_coroutine_object.hpp | 324 |
1 files changed, 324 insertions, 0 deletions
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 |