diff --git a/doc/asymmetric.qbk b/doc/asymmetric.qbk index 2253104..32c4588 100644 --- a/doc/asymmetric.qbk +++ b/doc/asymmetric.qbk @@ -366,16 +366,16 @@ resumed with __push_coro_op__, __pull_coro_op__).] #include - template< typename R, typename StackAllocator = standard_stack_allocator > + template< typename R > class asymmetric_coroutine<>::pull_type { public: pull_type(); template< typename Fn > - pull_type( Fn && fn, attributes const& attr = attributes() ); + pull_type( Fn && fn, attributes const& attr = attributes(), stack_allocator stack_alloc = stack_allocator() ); - template< typename Fn > + template< typename Fn, typename StackAllocator > pull_type( Fn && fn, attributes const& attr, StackAllocator stack_alloc); pull_type( pull_type && other); @@ -409,7 +409,7 @@ resumed with __push_coro_op__, __pull_coro_op__).] ] [heading `template< typename Fn > - pull_type( Fn && fn, attributes const& attr)`] + pull_type( Fn && fn, attributes const& attr, stack_allocator const& stack_alloc)`] [variablelist [[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize() when ! is_stack_unbounded().]] @@ -419,7 +419,7 @@ registers.]] [[Throws:] [Exceptions thrown inside __coro_fn__.]] ] -[heading `template< typename Fn > +[heading `template< typename Fn, typename StackAllocator > pull_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`] [variablelist [[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize() @@ -524,16 +524,16 @@ would return `false`.]] #include - template< typename Arg, typename StackAllocator = standard_stack_allocator > + template< typename Arg > class asymmetric_coroutine<>::push_type { public: push_type(); template< typename Fn > - push_type( Fn && fn, attributes const& attr = attributes()); + push_type( Fn && fn, attributes const& attr = attributes(), stack_allocator const& stack_alloc = stack_allocator() ); - template< typename Fn > + template< typename Fn, typename StackAllocator > push_type( Fn && fn, attributes const& attr, StackAllocator stack_alloc); push_type( push_type && other); @@ -565,7 +565,7 @@ would return `false`.]] ] [heading `template< typename Fn > - push_type( Fn && fn, attributes const& attr)`] + push_type( Fn && fn, attributes const& attr, stack_allocator const& stack_alloc)`] [variablelist [[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize() when ! is_stack_unbounded().]] @@ -573,7 +573,7 @@ when ! is_stack_unbounded().]] determines stack clean-up and preserving floating-point registers.]] ] -[heading `template< typename Fn > +[heading `template< typename Fn, typename StackAllocator > push_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`] [variablelist [[Preconditions:] [`size` >= minimum_stacksize(), `size` <= maximum_stacksize() diff --git a/doc/performance.qbk b/doc/performance.qbk index f99899d..1ee6829 100644 --- a/doc/performance.qbk +++ b/doc/performance.qbk @@ -24,16 +24,16 @@ running thread was pinned to a single CPU. [ [i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)] [49 ns / 50 cycles] - [53 \u00b5s / 53646 cycles] - [25 \u00b5s / 24447 cycles] - [14 \u00b5s / 15141 cycles] + [16 \u00b5s / 41802 cycles] + [6 \u00b5s / 10350 cycles] + [6 \u00b5s / 18817 cycles] ] [ [x86_64 (Intel Core2 Q6700, Linux 64bit)] [12 ns / 39 cycles] - [18 \u00b5s / 40723 cycles] - [9 \u00b5s / 19462 cycles] - [6 \u00b5s / 18073 cycles] + [16 \u00b5s / 41802 cycles] + [6 \u00b5s / 10350 cycles] + [6 \u00b5s / 18817 cycles] ] ] @@ -55,9 +55,9 @@ running thread was pinned to a single CPU. [ [x86_64 (Intel Core2 Q6700, Linux 64bit)] [10 ns / 33 cycles] - [13 \u00b5s / 22828 cycles] - [98 ns / 241 cycles] - [204 ns / 507 cycles] + [10 \u00b5s / 22828 cycles] + [42 ns / 710 cycles] + [135 ns / 362 cycles] ] ] diff --git a/example/cpp03/asymmetric/simple.cpp b/example/cpp03/asymmetric/simple.cpp index 52147c2..aacd2fb 100644 --- a/example/cpp03/asymmetric/simple.cpp +++ b/example/cpp03/asymmetric/simple.cpp @@ -1,26 +1,59 @@ - -// 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 #include #include #include #include -void coro(boost::coroutines::coroutine::pull_type& c) +struct X { - std::printf("in coro!\n"); + int i; + + X( int i_) : + i( i_) + {} +}; + +typedef boost::coroutines::asymmetric_coroutine< X& >::pull_type pull_coro_t; +typedef boost::coroutines::asymmetric_coroutine< X& >::push_type push_coro_t; + +void fn1( push_coro_t & sink) +{ + for ( int i = 0; i < 10; ++i) + { + X x( i); + sink( x); + } } -int main() +void fn2( pull_coro_t & source) +{ + while ( source) { + X & x = source.get(); + std::cout << "i = " << x.i << std::endl; + source(); + } +} + +int main( int argc, char * argv[]) { { - boost::coroutines::coroutine::push_type p(coro); - std::printf("after construction\n"); + pull_coro_t source( fn1); + while ( source) { + X & x = source.get(); + std::cout << "i = " << x.i << std::endl; + source(); + } } + { + push_coro_t sink( fn2); + for ( int i = 0; i < 10; ++i) + { + X x( i); + sink( x); + } + } + std::cout << "Done" << std::endl; + return EXIT_SUCCESS; } + diff --git a/include/boost/coroutine/asymmetric_coroutine.hpp b/include/boost/coroutine/asymmetric_coroutine.hpp index 52e8592..99b4b4c 100644 --- a/include/boost/coroutine/asymmetric_coroutine.hpp +++ b/include/boost/coroutine/asymmetric_coroutine.hpp @@ -16,23 +16,20 @@ #include #include #include -#include -#include -#include -#include #include #include #include #include #include -#include -#include -#include #include #include #include +#include +#include #include +#include +#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -41,95 +38,90 @@ namespace boost { namespace coroutines { -template< typename R, typename StackAllocator > +template< typename R > class pull_coroutine; -template< typename Arg, typename StackAllocator > +template< typename Arg > class push_coroutine { private: - template< - typename X, typename Y, typename Z - > - friend void detail::trampoline_pull( intptr_t); + 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::parameters< Arg > param_type; + 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_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) - push_coroutine( impl_type * impl) : - impl_( impl), - stack_alloc_(), - stack_ctx_() + explicit push_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) { BOOST_ASSERT( impl_); } public: push_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES # ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( pull_coroutine< Arg, StackAllocator > &); + typedef void ( * coroutine_fn)( pull_coroutine< Arg > &); - explicit push_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ); + explicit push_coroutine( coroutine_fn, + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - explicit push_coroutine( coroutine_fn fn, - attributes const& attr, - StackAllocator const& stack_alloc); + template< typename StackAllocator > + explicit push_coroutine( coroutine_fn, + attributes const&, + StackAllocator); # endif template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ); + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc); + template< typename Fn, StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); #else template< typename Fn > explicit push_coroutine( Fn fn, - attributes const& attr = attributes() ); + attributes const& = attributes(), + stack_allocator = stack_allocator() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn fn, + attributes const&, + StackAllocator); template< typename Fn > - explicit push_coroutine( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc); + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ); - - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc); + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); #endif ~push_coroutine() { - if ( 0 != stack_ctx_.sp) + if ( 0 != impl_) { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); + impl_->destroy(); impl_ = 0; } } push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) { swap( other); } push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT @@ -145,11 +137,7 @@ public: { return 0 == impl_ || impl_->is_complete(); } void swap( push_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - } + { std::swap( impl_, other.impl_); } push_coroutine & operator()( Arg arg) { @@ -162,14 +150,14 @@ public: class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > { private: - push_coroutine< Arg, StackAllocator > * c_; + push_coroutine< Arg > * c_; public: iterator() : c_( 0) {} - explicit iterator( push_coroutine< Arg, StackAllocator > * c) : + explicit iterator( push_coroutine< Arg > * c) : c_( c) {} @@ -196,93 +184,87 @@ public: struct const_iterator; }; -template< typename Arg, typename StackAllocator > -class push_coroutine< Arg &, StackAllocator > +template< typename Arg > +class push_coroutine< Arg & > { private: - template< - typename X, typename Y, typename Z - > - friend void detail::trampoline_pull( intptr_t); + 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::parameters< Arg & > param_type; + 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_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) - push_coroutine( impl_type * impl) : - impl_( impl), - stack_alloc_(), - stack_ctx_() + explicit push_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) { BOOST_ASSERT( impl_); } public: push_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES # ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( pull_coroutine< Arg &, StackAllocator > &); + typedef void ( * coroutine_fn)( pull_coroutine< Arg & > &); - explicit push_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ); + explicit push_coroutine( coroutine_fn, + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - explicit push_coroutine( coroutine_fn fn, - attributes const& attr, - StackAllocator const& stack_alloc); + template< typename StackAllocator > + explicit push_coroutine( coroutine_fn, + attributes const&, + StackAllocator); # endif template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ); + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc); + 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& attr = attributes() ); + explicit push_coroutine( Fn, + attributes const& = attributes(), + stack_allocator = stack_allocator() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn, + attributes const&, + StackAllocator); template< typename Fn > - explicit push_coroutine( Fn fn, - attributes const& attr, - StackAllocator const& stack_alloc); + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ); - - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc); + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); #endif ~push_coroutine() { - if ( 0 != stack_ctx_.sp) + if ( 0 != impl_) { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); + impl_->destroy(); impl_ = 0; } } push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) { swap( other); } push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT @@ -298,11 +280,7 @@ public: { return 0 == impl_ || impl_->is_complete(); } void swap( push_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - } + { std::swap( impl_, other.impl_); } push_coroutine & operator()( Arg & arg) { @@ -315,14 +293,14 @@ public: class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > { private: - push_coroutine< Arg &, StackAllocator > * c_; + push_coroutine< Arg & > * c_; public: iterator() : c_( 0) {} - explicit iterator( push_coroutine< Arg &, StackAllocator > * c) : + explicit iterator( push_coroutine< Arg & > * c) : c_( c) {} @@ -349,92 +327,86 @@ public: struct const_iterator; }; -template< typename StackAllocator > -class push_coroutine< void, StackAllocator > +template<> +class push_coroutine< void > { private: - template< - typename X, typename Y, typename Z - > - friend void detail::trampoline_pull_void( intptr_t); + 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::parameters< void > param_type; + 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_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) - push_coroutine( impl_type * impl) : - impl_( impl), - stack_alloc_(), - stack_ctx_() + explicit push_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) { BOOST_ASSERT( impl_); } public: push_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES # ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( pull_coroutine< void, StackAllocator > &); + typedef void ( * coroutine_fn)( pull_coroutine< void > &); - explicit push_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ); + explicit push_coroutine( coroutine_fn, + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - explicit push_coroutine( coroutine_fn fn, attributes const& attr, - StackAllocator const& stack_alloc); + template< typename StackAllocator > + explicit push_coroutine( coroutine_fn, attributes const&, + StackAllocator); # endif template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ); + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc); + 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& attr = attributes() ); + explicit push_coroutine( Fn, + attributes const& = attributes(), + stack_allocator = stack_allocator() ); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn, + attributes const&, + StackAllocator); template< typename Fn > - explicit push_coroutine( Fn fn, - attributes const& attr, - StackAllocator const& stack_alloc); + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const& = attributes(), + stack_allocator = stack_allocator() ); - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ); - - template< typename Fn > - explicit push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc); + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn), + attributes const&, + StackAllocator); #endif ~push_coroutine() { - if ( 0 != stack_ctx_.sp) + if ( 0 != impl_) { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); + impl_->destroy(); impl_ = 0; } } push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) { swap( other); } push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT @@ -450,11 +422,7 @@ public: { return 0 == impl_ || impl_->is_complete(); } void swap( push_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - } + { std::swap( impl_, other.impl_); } push_coroutine & operator()() { @@ -470,225 +438,255 @@ public: -template< typename R, typename StackAllocator > +template< typename R > class pull_coroutine { private: - template< - typename X, typename Y, typename Z - > - friend void detail::trampoline_push( intptr_t); + 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::parameters< R > param_type; + 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_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine) - pull_coroutine( impl_type * impl) : - impl_( impl), - stack_alloc_(), - stack_ctx_() + explicit pull_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) { BOOST_ASSERT( impl_); } public: pull_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES # ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( push_coroutine< R, StackAllocator > &); + typedef void ( * coroutine_fn)( push_coroutine< R > &); explicit pull_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< coroutine_fn, impl_type, push_coroutine< R, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + 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& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< coroutine_fn, impl_type, push_coroutine< R, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); impl_->pull(); } - template< typename Fn > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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 > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( Fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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 > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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(); } @@ -696,19 +694,15 @@ public: ~pull_coroutine() { - if ( 0 != stack_ctx_.sp) + if ( 0 != impl_) { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); + impl_->destroy(); impl_ = 0; } } pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) { swap( other); } pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT @@ -724,11 +718,7 @@ public: { return 0 == impl_ || impl_->is_complete(); } void swap( pull_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - } + { std::swap( impl_, other.impl_); } pull_coroutine & operator()() { @@ -748,8 +738,8 @@ public: class iterator : public std::iterator< std::input_iterator_tag, typename remove_reference< R >::type > { private: - pull_coroutine< R, StackAllocator > * c_; - R * val_; + pull_coroutine< R > * c_; + R * val_; void fetch_() { @@ -781,7 +771,7 @@ public: c_( 0), val_( 0) {} - explicit iterator( pull_coroutine< R, StackAllocator > * c) : + explicit iterator( pull_coroutine< R > * c) : c_( c), val_( 0) { fetch_(); } @@ -838,225 +828,255 @@ public: struct const_iterator; }; -template< typename R, typename StackAllocator > -class pull_coroutine< R &, StackAllocator > +template< typename R > +class pull_coroutine< R & > { private: - template< - typename X, typename Y, typename Z - > - friend void detail::trampoline_push( intptr_t); + 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::parameters< R & > param_type; + 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_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine) - pull_coroutine( impl_type * impl) : - impl_( impl), - stack_alloc_(), - stack_ctx_() + explicit pull_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) { BOOST_ASSERT( impl_); } public: pull_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES # ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( push_coroutine< R &, StackAllocator > &); + typedef void ( * coroutine_fn)( push_coroutine< R & > &); explicit pull_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< coroutine_fn, impl_type, push_coroutine< R &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + 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& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< coroutine_fn, impl_type, push_coroutine< R &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); impl_->pull(); } - template< typename Fn > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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 > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( Fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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 > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull< Fn, impl_type, push_coroutine< R &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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(); } @@ -1064,19 +1084,15 @@ public: ~pull_coroutine() { - if ( 0 != stack_ctx_.sp) + if ( 0 != impl_) { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); + impl_->destroy(); impl_ = 0; } } pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) { swap( other); } pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT @@ -1092,11 +1108,7 @@ public: { return 0 == impl_ || impl_->is_complete(); } void swap( pull_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - } + { std::swap( impl_, other.impl_); } pull_coroutine & operator()() { @@ -1112,8 +1124,8 @@ public: class iterator : public std::iterator< std::input_iterator_tag, R > { private: - pull_coroutine< R &, StackAllocator > * c_; - R * val_; + pull_coroutine< R & > * c_; + R * val_; void fetch_() { @@ -1145,7 +1157,7 @@ public: c_( 0), val_( 0) {} - explicit iterator( pull_coroutine< R &, StackAllocator > * c) : + explicit iterator( pull_coroutine< R & > * c) : c_( c), val_( 0) { fetch_(); } @@ -1202,237 +1214,255 @@ public: struct const_iterator; }; -template< typename StackAllocator > -class pull_coroutine< void, StackAllocator > +template<> +class pull_coroutine< void > { private: - template< - typename X, typename Y, typename Z - > - friend void detail::trampoline_push_void( intptr_t); + 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::parameters< void > param_type; + 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_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine) - pull_coroutine( impl_type * impl) : - impl_( impl), - stack_alloc_(), - stack_ctx_() + explicit pull_coroutine( detail::synthesized_t::flag_t, impl_type & impl) : + impl_( & impl) { BOOST_ASSERT( impl_); } public: pull_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES # ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( push_coroutine< void, StackAllocator > &); + typedef void ( * coroutine_fn)( push_coroutine< void > &); explicit pull_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull_void< - coroutine_fn, impl_type, push_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), - & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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_coroutie< 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( + 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& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull_void< - coroutine_fn, impl_type, push_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), - & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull_void< - Fn, impl_type, push_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), - & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); impl_->pull(); } - template< typename Fn > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull_void< - Fn, impl_type, push_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), - & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull_void< - Fn, impl_type, push_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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 > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( Fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull_void< - Fn, impl_type, push_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_() + attributes const& attrs = attributes(), + stack_allocator stack_alloc = stack_allocator() ) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull_void< - Fn, impl_type, push_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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 > + template< typename Fn, typename StackAllocator > explicit pull_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_pull_void< - Fn, impl_type, push_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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(); } @@ -1440,19 +1470,15 @@ public: ~pull_coroutine() { - if ( 0 != stack_ctx_.sp) + if ( 0 != impl_) { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); + impl_->destroy(); impl_ = 0; } } pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_() + impl_( 0) { swap( other); } pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT @@ -1468,11 +1494,7 @@ public: { return 0 == impl_ || impl_->is_complete(); } void swap( pull_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - } + { std::swap( impl_, other.impl_); } pull_coroutine & operator()() { @@ -1488,673 +1510,752 @@ public: #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES # ifdef BOOST_MSVC -template< typename Arg, typename StackAllocator > -push_coroutine< Arg, StackAllocator >::push_coroutine( coroutine_fn fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +template< typename Arg > +push_coroutine< Arg >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - coroutine_fn, impl_type, pull_coroutine< Arg, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } -template< typename Arg, typename StackAllocator > -push_coroutine< Arg, StackAllocator >::push_coroutine( coroutine_fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +template< typename Arg > +template< typename StackAllocator > +push_coroutine< Arg >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - coroutine_fn, impl_type, pull_coroutine< Arg, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } -template< typename Arg, typename StackAllocator > -push_coroutine< Arg &, StackAllocator >::push_coroutine( coroutine_fn fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +template< typename Arg > +push_coroutine< Arg & >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - coroutine_fn, impl_type, pull_coroutine< Arg &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } -template< typename Arg, typename StackAllocator > -push_coroutine< Arg &, StackAllocator >::push_coroutine( coroutine_fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +template< typename Arg > +template< typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - coroutine_fn, impl_type, pull_coroutine< Arg &, StackAllocator > - coroutine_fn, impl_type, pull_coroutine< Arg &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); + BOOST_ASSERT( impl_); +} + +template<> +push_coroutine< void >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + stack_allocator 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, 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( + forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } template< typename StackAllocator > -push_coroutine< void, StackAllocator >::push_coroutine( coroutine_fn fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< void >::push_coroutine( coroutine_fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push_void< - coroutine_fn, impl_type, pull_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); -} - -template< typename StackAllocator > -push_coroutine< void, StackAllocator >::push_coroutine( coroutine_fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() -{ - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push_void< - coroutine_fn, impl_type, pull_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + forward< coroutine_fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } # endif -template< typename Arg, typename StackAllocator > +template< typename Arg > template< typename Fn > -push_coroutine< Arg, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } -template< typename Arg, typename StackAllocator > -template< typename Fn > -push_coroutine< Arg, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +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) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } -template< typename Arg, typename StackAllocator > +template< typename Arg > template< typename Fn > -push_coroutine< Arg &, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } -template< typename Arg, typename StackAllocator > -template< typename Fn > -push_coroutine< Arg &, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +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) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } -template< typename StackAllocator > template< typename Fn > -push_coroutine< void, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push_void< - Fn, impl_type, pull_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } -template< typename StackAllocator > -template< typename Fn > -push_coroutine< void, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push_void< - Fn, impl_type, pull_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( forward< Fn >( fn), & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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( + forward< Fn >( fn), attrs, stack_ctx, internal_stack_ctx, stack_alloc); BOOST_ASSERT( impl_); } #else -template< typename Arg, typename StackAllocator > +template< typename Arg > template< typename Fn > -push_coroutine< Arg, StackAllocator >::push_coroutine( Fn fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< Arg >::push_coroutine( Fn fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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, typename StackAllocator > -template< typename Fn > -push_coroutine< Arg, StackAllocator >::push_coroutine( Fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg >::push_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, typename StackAllocator > +template< typename Arg > template< typename Fn > -push_coroutine< Arg &, StackAllocator >::push_coroutine( Fn fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< Arg & >::push_coroutine( Fn fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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, typename StackAllocator > -template< typename Fn > -push_coroutine< Arg &, StackAllocator >::push_coroutine( Fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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 StackAllocator > template< typename Fn > -push_coroutine< void, StackAllocator >::push_coroutine( Fn fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< void >::push_coroutine( Fn fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push_void< - Fn, impl_type, pull_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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 StackAllocator > -template< typename Fn > -push_coroutine< void, StackAllocator >::push_coroutine( Fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( Fn fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push_void< - Fn, impl_type, pull_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, typename StackAllocator > +template< typename Arg > template< typename Fn > -push_coroutine< Arg, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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, typename StackAllocator > -template< typename Fn > -push_coroutine< Arg, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +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) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, typename StackAllocator > +template< typename Arg > template< typename Fn > -push_coroutine< Arg &, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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, typename StackAllocator > -template< typename Fn > -push_coroutine< Arg &, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +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) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push< - Fn, impl_type, pull_coroutine< Arg &, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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 StackAllocator > template< typename Fn > -push_coroutine< void, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr) : - impl_( 0), - stack_alloc_(), - stack_ctx_() +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + stack_allocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push_void< - Fn, impl_type, pull_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, 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 StackAllocator > -template< typename Fn > -push_coroutine< void, StackAllocator >::push_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_() +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, + attributes const& attrs, + StackAllocator stack_alloc) : + impl_( 0) { - stack_alloc_.allocate( stack_ctx_, attr.size); - detail::coroutine_context callee( - detail::trampoline_push_void< - Fn, impl_type, pull_coroutine< void, StackAllocator > - >, - stack_ctx_); - detail::coroutine_context caller; - detail::setup< Fn > to( fn, & caller, & callee, attr); - impl_ = reinterpret_cast< impl_type * >( - caller.jump( - callee, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); + // 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, typename StackAllocator > -void swap( pull_coroutine< R, StackAllocator > & l, pull_coroutine< R, StackAllocator > & r) BOOST_NOEXCEPT +template< typename R > +void swap( pull_coroutine< R > & l, pull_coroutine< R > & r) BOOST_NOEXCEPT { l.swap( r); } -template< typename Arg, typename StackAllocator > -void swap( push_coroutine< Arg, StackAllocator > & l, push_coroutine< Arg, StackAllocator > & r) BOOST_NOEXCEPT +template< typename Arg > +void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r) BOOST_NOEXCEPT { l.swap( r); } -template< typename R, typename StackAllocator > +template< typename R > inline -typename pull_coroutine< R, StackAllocator >::iterator -range_begin( pull_coroutine< R, StackAllocator > & c) -{ return typename pull_coroutine< R, StackAllocator >::iterator( & c); } +typename pull_coroutine< R >::iterator +range_begin( pull_coroutine< R > & c) +{ return typename pull_coroutine< R >::iterator( & c); } -template< typename R, typename StackAllocator > +template< typename R > inline -typename pull_coroutine< R, StackAllocator >::iterator -range_end( pull_coroutine< R, StackAllocator > &) -{ return typename pull_coroutine< R, StackAllocator >::iterator(); } +typename pull_coroutine< R >::iterator +range_end( pull_coroutine< R > &) +{ return typename pull_coroutine< R >::iterator(); } -template< typename Arg, typename StackAllocator > +template< typename Arg > inline -typename push_coroutine< Arg, StackAllocator >::iterator -range_begin( push_coroutine< Arg, StackAllocator > & c) -{ return typename push_coroutine< Arg, StackAllocator >::iterator( & c); } +typename push_coroutine< Arg >::iterator +range_begin( push_coroutine< Arg > & c) +{ return typename push_coroutine< Arg >::iterator( & c); } -template< typename Arg, typename StackAllocator > +template< typename Arg > inline -typename push_coroutine< Arg, StackAllocator >::iterator -range_end( push_coroutine< Arg, StackAllocator > &) -{ return typename push_coroutine< Arg, StackAllocator >::iterator(); } +typename push_coroutine< Arg >::iterator +range_end( push_coroutine< Arg > &) +{ return typename push_coroutine< Arg >::iterator(); } -template< typename T, typename StackAllocator = stack_allocator > +template< typename T > struct asymmetric_coroutine { - typedef push_coroutine< T, StackAllocator > push_type; - typedef pull_coroutine< T, StackAllocator > pull_type; + typedef push_coroutine< T > push_type; + typedef pull_coroutine< T > pull_type; }; // deprecated -template< typename T, typename StackAllocator = stack_allocator > +template< typename T > struct coroutine { - typedef push_coroutine< T, StackAllocator > push_type; - typedef pull_coroutine< T, StackAllocator > pull_type; + typedef push_coroutine< T > push_type; + typedef pull_coroutine< T > pull_type; }; } -template< typename Arg, typename StackAllocator > -struct range_mutable_iterator< coroutines::push_coroutine< Arg, StackAllocator > > -{ typedef typename coroutines::push_coroutine< Arg, StackAllocator >::iterator type; }; +template< typename Arg > +struct range_mutable_iterator< coroutines::push_coroutine< Arg > > +{ typedef typename coroutines::push_coroutine< Arg >::iterator type; }; -template< typename R, typename StackAllocator > -struct range_mutable_iterator< coroutines::pull_coroutine< R, StackAllocator > > -{ typedef typename coroutines::pull_coroutine< R, StackAllocator >::iterator type; }; +template< typename R > +struct range_mutable_iterator< coroutines::pull_coroutine< R > > +{ typedef typename coroutines::pull_coroutine< R >::iterator type; }; } namespace std { -template< typename R, typename StackAllocator > +template< typename R > inline -typename boost::coroutines::pull_coroutine< R, StackAllocator >::iterator -begin( boost::coroutines::pull_coroutine< R, StackAllocator > & c) +typename boost::coroutines::pull_coroutine< R >::iterator +begin( boost::coroutines::pull_coroutine< R > & c) { return boost::begin( c); } -template< typename R, typename StackAllocator > +template< typename R > inline -typename boost::coroutines::pull_coroutine< R, StackAllocator >::iterator -end( boost::coroutines::pull_coroutine< R, StackAllocator > & c) +typename boost::coroutines::pull_coroutine< R >::iterator +end( boost::coroutines::pull_coroutine< R > & c) { return boost::end( c); } -template< typename R, typename StackAllocator > +template< typename R > inline -typename boost::coroutines::push_coroutine< R, StackAllocator >::iterator -begin( boost::coroutines::push_coroutine< R, StackAllocator > & c) +typename boost::coroutines::push_coroutine< R >::iterator +begin( boost::coroutines::push_coroutine< R > & c) { return boost::begin( c); } -template< typename R, typename StackAllocator > +template< typename R > inline -typename boost::coroutines::push_coroutine< R, StackAllocator >::iterator -end( boost::coroutines::push_coroutine< R, StackAllocator > & c) +typename boost::coroutines::push_coroutine< R >::iterator +end( boost::coroutines::push_coroutine< R > & c) { return boost::end( c); } } diff --git a/include/boost/coroutine/detail/flags.hpp b/include/boost/coroutine/detail/flags.hpp index 8d16f2b..8d19757 100644 --- a/include/boost/coroutine/detail/flags.hpp +++ b/include/boost/coroutine/detail/flags.hpp @@ -33,6 +33,12 @@ struct unwind_t { force_unwind = 1 }; }; +struct synthesized_t +{ + enum flag_t + { syntesized = 1 }; +}; + }}} #ifdef BOOST_HAS_ABI_HEADERS diff --git a/include/boost/coroutine/detail/parameters.hpp b/include/boost/coroutine/detail/parameters.hpp index e0377b8..8bad391 100644 --- a/include/boost/coroutine/detail/parameters.hpp +++ b/include/boost/coroutine/detail/parameters.hpp @@ -31,6 +31,10 @@ struct 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_) { @@ -54,6 +58,10 @@ struct parameters< Data & > 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_) { diff --git a/include/boost/coroutine/detail/pull_coroutine_impl.hpp b/include/boost/coroutine/detail/pull_coroutine_impl.hpp index 35700a6..97a18bf 100644 --- a/include/boost/coroutine/detail/pull_coroutine_impl.hpp +++ b/include/boost/coroutine/detail/pull_coroutine_impl.hpp @@ -34,14 +34,7 @@ namespace detail { template< typename R > class pull_coroutine_impl : private noncopyable { -private: - template< - typename X, typename Y, typename Z - > - friend void trampoline_pull( intptr_t); - - typedef parameters< R > param_type; - +protected: int flags_; exception_ptr except_; coroutine_context * caller_; @@ -49,6 +42,8 @@ private: R * result_; public: + typedef parameters< R > param_type; + pull_coroutine_impl( coroutine_context * caller, coroutine_context * callee, bool unwind, bool preserve_fpu) : @@ -76,6 +71,8 @@ public: if ( preserve_fpu) flags_ |= flag_preserve_fpu; } + virtual ~pull_coroutine_impl() {} + bool force_unwind() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_force_unwind); } @@ -85,12 +82,18 @@ public: 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_complete() && force_unwind() ) + if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; param_type to( unwind_t::force_unwind); @@ -106,15 +109,18 @@ public: void pull() { + BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); - param_type to; + 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_); @@ -138,19 +144,14 @@ public: invalid_result() ); return result_; } + + virtual void destroy() = 0; }; template< typename R > class pull_coroutine_impl< R & > : private noncopyable { -private: - template< - typename X, typename Y, typename Z - > - friend void trampoline_pull( intptr_t); - - typedef parameters< R & > param_type; - +protected: int flags_; exception_ptr except_; coroutine_context * caller_; @@ -158,6 +159,8 @@ private: R * result_; public: + typedef parameters< R & > param_type; + pull_coroutine_impl( coroutine_context * caller, coroutine_context * callee, bool unwind, bool preserve_fpu) : @@ -185,6 +188,8 @@ public: if ( preserve_fpu) flags_ |= flag_preserve_fpu; } + virtual ~pull_coroutine_impl() {} + bool force_unwind() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_force_unwind); } @@ -194,12 +199,18 @@ public: 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_complete() && force_unwind() ) + if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; param_type to( unwind_t::force_unwind); @@ -215,15 +226,18 @@ public: void pull() { + BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); - param_type to; + 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_); @@ -247,25 +261,22 @@ public: invalid_result() ); return result_; } + + virtual void destroy() = 0; }; template<> class pull_coroutine_impl< void > : private noncopyable { -private: - template< - typename X, typename Y, typename Z - > - friend void trampoline_pull_void( intptr_t); - - typedef parameters< void > param_type; - +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) : @@ -278,6 +289,8 @@ public: if ( preserve_fpu) flags_ |= flag_preserve_fpu; } + virtual ~pull_coroutine_impl() {} + bool force_unwind() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_force_unwind); } @@ -287,12 +300,18 @@ public: 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_complete() && force_unwind() ) + if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; param_type to( unwind_t::force_unwind); @@ -308,18 +327,23 @@ public: void pull() { + BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); - param_type to; + 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; }; }}} diff --git a/include/boost/coroutine/detail/pull_coroutine_object.hpp b/include/boost/coroutine/detail/pull_coroutine_object.hpp new file mode 100644 index 0000000..71cfdeb --- /dev/null +++ b/include/boost/coroutine/detail/pull_coroutine_object.hpp @@ -0,0 +1,315 @@ + +// 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 +#include +#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 { +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_( 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_( 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_( 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); } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H diff --git a/include/boost/coroutine/detail/pull_coroutine_synthesized.hpp b/include/boost/coroutine/detail/pull_coroutine_synthesized.hpp new file mode 100644 index 0000000..1736c86 --- /dev/null +++ b/include/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 + +#include +#include +#include + +#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) + {} + + void destroy() {} +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_SYNTHESIZED_H diff --git a/include/boost/coroutine/detail/push_coroutine_impl.hpp b/include/boost/coroutine/detail/push_coroutine_impl.hpp index a550d11..da052fc 100644 --- a/include/boost/coroutine/detail/push_coroutine_impl.hpp +++ b/include/boost/coroutine/detail/push_coroutine_impl.hpp @@ -34,20 +34,15 @@ namespace detail { template< typename Arg > class push_coroutine_impl : private noncopyable { -private: - template< - typename X, typename Y, typename Z - > - friend void trampoline_push( intptr_t); - - typedef parameters< Arg > param_type; - +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) : @@ -69,12 +64,18 @@ public: 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_complete() && force_unwind() ) + if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; param_type to( unwind_t::force_unwind); @@ -90,52 +91,55 @@ public: void push( Arg const& arg) { + BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); - param_type to( const_cast< Arg * >( & arg) ); + 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() ); - param_type to( const_cast< Arg * >( & arg) ); + 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 { -private: - template< - typename X, typename Y, typename Z - > - friend void trampoline_push( intptr_t); - - typedef parameters< Arg & > param_type; - +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) : @@ -157,12 +161,18 @@ public: 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_complete() && force_unwind() ) + if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; param_type to( unwind_t::force_unwind); @@ -178,37 +188,37 @@ public: void push( Arg & arg) { + BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); - param_type to( & arg); + 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 { -private: - template< - typename X, typename Y, typename Z - > - friend void trampoline_push_void( intptr_t); - - typedef parameters< void > param_type; - +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) : @@ -230,12 +240,18 @@ public: 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_complete() && force_unwind() ) + if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; param_type to( unwind_t::force_unwind); @@ -251,18 +267,23 @@ public: void push() { + BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); - param_type to; + 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; }; }}} diff --git a/include/boost/coroutine/detail/push_coroutine_object.hpp b/include/boost/coroutine/detail/push_coroutine_object.hpp new file mode 100644 index 0000000..e40d5e6 --- /dev/null +++ b/include/boost/coroutine/detail/push_coroutine_object.hpp @@ -0,0 +1,327 @@ + +// 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 +#include +#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 { +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_( 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_( 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_( 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); } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H diff --git a/include/boost/coroutine/detail/push_coroutine_synthesized.hpp b/include/boost/coroutine/detail/push_coroutine_synthesized.hpp new file mode 100644 index 0000000..ac79a76 --- /dev/null +++ b/include/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 + +#include +#include +#include + +#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) + {} + + void destroy() {} +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_SYNTHESIZED_H diff --git a/include/boost/coroutine/detail/symmetric_coroutine_impl.hpp b/include/boost/coroutine/detail/symmetric_coroutine_impl.hpp index 07915dd..d1fb934 100644 --- a/include/boost/coroutine/detail/symmetric_coroutine_impl.hpp +++ b/include/boost/coroutine/detail/symmetric_coroutine_impl.hpp @@ -88,8 +88,8 @@ public: R * yield() { - BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); flags_ &= ~flag_running; param_type to; @@ -153,10 +153,10 @@ protected: template< typename Other > R * yield_to_( Other * other, typename Other::param_type * to) { - BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( is_running() ); - BOOST_ASSERT( ! other->is_complete() ); + BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( ! other->is_running() ); + BOOST_ASSERT( ! other->is_complete() ); other->caller_ = caller_; flags_ &= ~flag_running; @@ -233,8 +233,8 @@ public: R * yield() { - BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); flags_ &= ~flag_running; param_type to; @@ -298,10 +298,10 @@ protected: template< typename Other > R * yield_to_( Other * other, typename Other::param_type * to) { - BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( is_running() ); - BOOST_ASSERT( ! other->is_complete() ); + BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( ! other->is_running() ); + BOOST_ASSERT( ! other->is_complete() ); other->caller_ = caller_; flags_ &= ~flag_running; @@ -385,8 +385,8 @@ public: void yield() BOOST_NOEXCEPT { - BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( is_running() ); + BOOST_ASSERT( ! is_complete() ); flags_ &= ~flag_running; param_type to; @@ -436,10 +436,10 @@ protected: template< typename Other > void yield_to_( Other * other, typename Other::param_type * to) { - BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( is_running() ); - BOOST_ASSERT( ! other->is_complete() ); + BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( ! other->is_running() ); + BOOST_ASSERT( ! other->is_complete() ); other->caller_ = caller_; flags_ &= ~flag_running; diff --git a/include/boost/coroutine/detail/trampoline_pull.hpp b/include/boost/coroutine/detail/trampoline_pull.hpp index c28430b..1790245 100644 --- a/include/boost/coroutine/detail/trampoline_pull.hpp +++ b/include/boost/coroutine/detail/trampoline_pull.hpp @@ -7,21 +7,11 @@ #ifndef BOOST_COROUTINES_DETAIL_TRAMPOLINE_PULL_H #define BOOST_COROUTINES_DETAIL_TRAMPOLINE_PULL_H -#include - #include #include #include -#include -#include #include -#include -#include -#include -#include -#include -#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -31,107 +21,22 @@ namespace boost { namespace coroutines { namespace detail { -template< typename Fn, typename Coro, typename Self > +template< typename Coro > void trampoline_pull( intptr_t vp) { typedef typename Coro::param_type param_type; - BOOST_ASSERT( vp); + BOOST_ASSERT( 0 != vp); - setup< Fn > * from( - reinterpret_cast< setup< Fn > * >( vp) ); + param_type * param( + reinterpret_cast< param_type * >( vp) ); + BOOST_ASSERT( 0 != param); -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - Fn fn( forward< Fn >( from->fn) ); -#else - Fn fn( move( from->fn) ); -#endif + Coro * coro( + reinterpret_cast< Coro * >( param->coro) ); + BOOST_ASSERT( 0 != coro); - coroutine_context caller( * from->caller); - coroutine_context callee( * from->callee); - - Coro c( & caller, & callee, - stack_unwind == from->attr.do_unwind, - fpu_preserved == from->attr.preserve_fpu); - from = 0; - - { - param_type * from( - reinterpret_cast< param_type * >( - c.callee_->jump( - * c.caller_, - reinterpret_cast< intptr_t >( & c), - c.preserve_fpu() ) ) ); - c.result_ = from->data; - - // create push_coroutine - typename Self::impl_type b( & callee, & caller, false, c.preserve_fpu() ); - Self yield( & b); - try - { fn( yield); } - catch ( forced_unwind const&) - {} - catch (...) - { c.except_ = current_exception(); } - } - - c.flags_ |= flag_complete; - param_type to; - c.callee_->jump( - * c.caller_, - reinterpret_cast< intptr_t >( & to), - c.preserve_fpu() ); - BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); -} - -template< typename Fn, typename Coro, typename Self > -void trampoline_pull_void( intptr_t vp) -{ - typedef typename Coro::param_type param_type; - - BOOST_ASSERT( vp); - - setup< Fn > * from( - reinterpret_cast< setup< Fn > * >( vp) ); - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - Fn fn( forward< Fn >( from->fn) ); -#else - Fn fn( move( from->fn) ); -#endif - - coroutine_context caller( * from->caller); - coroutine_context callee( * from->callee); - - Coro c( & caller, & callee, - stack_unwind == from->attr.do_unwind, - fpu_preserved == from->attr.preserve_fpu); - from = 0; - - { - c.callee_->jump( - * c.caller_, - reinterpret_cast< intptr_t >( & c), - c.preserve_fpu() ); - - // create push_coroutine - typename Self::impl_type b( & callee, & caller, false, c.preserve_fpu() ); - Self yield( & b); - try - { fn( yield); } - catch ( forced_unwind const&) - {} - catch (...) - { c.except_ = current_exception(); } - } - - c.flags_ |= flag_complete; - param_type to; - c.callee_->jump( - * c.caller_, - reinterpret_cast< intptr_t >( & to), - c.preserve_fpu() ); - BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + coro->run(); } }}} diff --git a/include/boost/coroutine/detail/trampoline_push.hpp b/include/boost/coroutine/detail/trampoline_push.hpp index 8229237..4489044 100644 --- a/include/boost/coroutine/detail/trampoline_push.hpp +++ b/include/boost/coroutine/detail/trampoline_push.hpp @@ -31,114 +31,41 @@ namespace boost { namespace coroutines { namespace detail { -template< typename Fn, typename Coro, typename Self > +template< typename Coro > void trampoline_push( intptr_t vp) { typedef typename Coro::param_type param_type; BOOST_ASSERT( vp); - setup< Fn > * from( - reinterpret_cast< setup< Fn > * >( vp) ); + param_type * param( + reinterpret_cast< param_type * >( vp) ); + BOOST_ASSERT( 0 != param); + BOOST_ASSERT( 0 != param->data); -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - Fn fn( forward< Fn >( from->fn) ); -#else - Fn fn( move( from->fn) ); -#endif + Coro * coro( + reinterpret_cast< Coro * >( param->coro) ); + BOOST_ASSERT( 0 != coro); - coroutine_context caller( * from->caller); - coroutine_context callee( * from->callee); - - Coro c( & caller, & callee, - stack_unwind == from->attr.do_unwind, - fpu_preserved == from->attr.preserve_fpu); - from = 0; - - { - param_type * from( - reinterpret_cast< param_type * >( - c.callee_->jump( - * c.caller_, - reinterpret_cast< intptr_t >( & c), - c.preserve_fpu() ) ) ); - if ( ! from->do_unwind) - { - BOOST_ASSERT( from->data); - - // create push_coroutine - typename Self::impl_type b( & callee, & caller, false, c.preserve_fpu(), from->data); - Self yield( & b); - try - { fn( yield); } - catch ( forced_unwind const&) - {} - catch (...) - { c.except_ = current_exception(); } - } - } - - c.flags_ |= flag_complete; - param_type to; - c.callee_->jump( - * c.caller_, - reinterpret_cast< intptr_t >( & to), - c.preserve_fpu() ); - BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + coro->run( param->data); } -template< typename Fn, typename Coro, typename Self > +template< typename Coro > void trampoline_push_void( intptr_t vp) { typedef typename Coro::param_type param_type; BOOST_ASSERT( vp); - setup< Fn > * from( - reinterpret_cast< setup< Fn > * >( vp) ); + param_type * param( + reinterpret_cast< param_type * >( vp) ); + BOOST_ASSERT( 0 != param); -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - Fn fn( forward< Fn >( from->fn) ); -#else - Fn fn( move( from->fn) ); -#endif + Coro * coro( + reinterpret_cast< Coro * >( param->coro) ); + BOOST_ASSERT( 0 != coro); - coroutine_context caller( * from->caller); - coroutine_context callee( * from->callee); - - Coro c( & caller, & callee, - stack_unwind == from->attr.do_unwind, - fpu_preserved == from->attr.preserve_fpu); - from = 0; - - { - param_type * from( - reinterpret_cast< param_type * >( - c.callee_->jump( - * c.caller_, - reinterpret_cast< intptr_t >( & c), - c.preserve_fpu() ) ) ); - if ( ! from->do_unwind) - { - // create push_coroutine - typename Self::impl_type b( & callee, & caller, false, c.preserve_fpu() ); - Self yield( & b); - try - { fn( yield); } - catch ( forced_unwind const&) - {} - catch (...) - { c.except_ = current_exception(); } - } - } - - c.flags_ |= flag_complete; - param_type to; - c.callee_->jump( - * c.caller_, - reinterpret_cast< intptr_t >( & to), - c.preserve_fpu() ); - BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + coro->run(); } }}} diff --git a/performance/asymmetric/performance_create_prealloc.cpp b/performance/asymmetric/performance_create_prealloc.cpp index db04222..350d439 100644 --- a/performance/asymmetric/performance_create_prealloc.cpp +++ b/performance/asymmetric/performance_create_prealloc.cpp @@ -18,8 +18,8 @@ #include "../cycle.hpp" #include "../preallocated_stack_allocator.hpp" -typedef preallocated_stack_allocator stack_allocator; -typedef boost::coroutines::asymmetric_coroutine< void, stack_allocator > coro_type; +typedef preallocated_stack_allocator stack_allocator; +typedef boost::coroutines::asymmetric_coroutine< void > coro_type; boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; diff --git a/performance/asymmetric/performance_create_protected.cpp b/performance/asymmetric/performance_create_protected.cpp index 1030c3e..90f46a4 100644 --- a/performance/asymmetric/performance_create_protected.cpp +++ b/performance/asymmetric/performance_create_protected.cpp @@ -17,8 +17,8 @@ #include "../clock.hpp" #include "../cycle.hpp" -typedef boost::coroutines::protected_stack_allocator stack_allocator; -typedef boost::coroutines::asymmetric_coroutine< void, stack_allocator > coro_type; +typedef boost::coroutines::protected_stack_allocator stack_allocator; +typedef boost::coroutines::asymmetric_coroutine< void > coro_type; boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; diff --git a/performance/asymmetric/performance_create_standard.cpp b/performance/asymmetric/performance_create_standard.cpp index 6847fc1..6736a1e 100644 --- a/performance/asymmetric/performance_create_standard.cpp +++ b/performance/asymmetric/performance_create_standard.cpp @@ -17,8 +17,8 @@ #include "../clock.hpp" #include "../cycle.hpp" -typedef boost::coroutines::standard_stack_allocator stack_allocator; -typedef boost::coroutines::asymmetric_coroutine< void, stack_allocator > coro_type; +typedef boost::coroutines::standard_stack_allocator stack_allocator; +typedef boost::coroutines::asymmetric_coroutine< void > coro_type; boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9e81af6..18931ad 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -27,6 +27,6 @@ project boost/coroutine/test ; test-suite "coroutine" : -# [ run test_asymmetric_coroutine.cpp ] + [ run test_asymmetric_coroutine.cpp ] [ run test_symmetric_coroutine.cpp ] ; diff --git a/test/test_asymmetric_coroutine.cpp b/test/test_asymmetric_coroutine.cpp index 683a10f..a0282de 100644 --- a/test/test_asymmetric_coroutine.cpp +++ b/test/test_asymmetric_coroutine.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include namespace coro = boost::coroutines;