// 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 #include #include #include #include #include #include #include #include #include #include #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) : flags_( 0), except_(), caller_( caller), callee_( callee), result_( 0) { if ( unwind) flags_ |= flag_force_unwind; } pull_coroutine_impl( coroutine_context * caller, coroutine_context * callee, bool unwind, R * result) : flags_( 0), except_(), caller_( caller), callee_( callee), result_( result) { if ( unwind) flags_ |= flag_force_unwind; } 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 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_, & to); 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( static_cast< param_type * >( caller_->jump( * callee_, & to) ) ); 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) : flags_( 0), except_(), caller_( caller), callee_( callee), result_( 0) { if ( unwind) flags_ |= flag_force_unwind; } pull_coroutine_impl( coroutine_context * caller, coroutine_context * callee, bool unwind, R * result) : flags_( 0), except_(), caller_( caller), callee_( callee), result_( result) { if ( unwind) flags_ |= flag_force_unwind; } 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 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_, & to); 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( static_cast< param_type * >( caller_->jump( * callee_, & to) ) ); 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) : flags_( 0), except_(), caller_( caller), callee_( callee) { if ( unwind) flags_ |= flag_force_unwind; } 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 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_, & to); 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( static_cast< param_type * >( caller_->jump( * callee_, & to) ) ); 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