diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 3393bf4..9aa27af 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -69,18 +69,18 @@ exe same_fringe : same_fringe.cpp ; -exe asio/stream_client - : asio/stream_client.cpp - ; +#exe asio/stream_client +# : asio/stream_client.cpp +# ; +# +#exe asio/stream_server +# : asio/stream_server.cpp +# ; -exe asio/stream_server - : asio/stream_server.cpp - ; - -#exe same_fringe +#exe same_fringe11 # : c++11/same_fringe.cpp # ; # -#exe fibonacci +#exe fibonacci11 # : c++11/fibonacci.cpp # ; diff --git a/example/c++11/fibonacci.cpp b/example/c++11/fibonacci.cpp index 8c7a1e9..a8c20f4 100644 --- a/example/c++11/fibonacci.cpp +++ b/example/c++11/fibonacci.cpp @@ -9,6 +9,29 @@ #include <boost/coroutine/all.hpp> +#ifdef BOOST_COROUTINES_V2 +int main() +{ + boost::coroutines::pull_coroutine< int > c( + [&]( boost::coroutines::push_coroutine< int > & c) { + int first = 1, second = 1; + for ( int i = 0; i < 10; ++i) + { + int third = first + second; + first = second; + second = third; + c( third); + } + }); + + for ( auto i : c) + std::cout << i << " "; + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} +#else int main() { boost::coroutines::coroutine< int() > c( @@ -30,3 +53,4 @@ int main() return EXIT_SUCCESS; } +#endif diff --git a/example/c++11/same_fringe.cpp b/example/c++11/same_fringe.cpp index a0c9908..47cd5e4 100644 --- a/example/c++11/same_fringe.cpp +++ b/example/c++11/same_fringe.cpp @@ -10,6 +10,71 @@ #include "tree.h" +node::ptr_t create_tree1() +{ + return branch::create( + leaf::create( "A"), + branch::create( + leaf::create( "B"), + leaf::create( "C") ) ); +} + +node::ptr_t create_tree2() +{ + return branch::create( + branch::create( + leaf::create( "A"), + leaf::create( "B") ), + leaf::create( "C") ); +} + +#ifdef BOOST_COROUTINES_V2 +class coro_visitor : public visitor +{ +private: + boost::coroutines::push_coroutine< leaf& > & c_; + +public: + coro_visitor( boost::coroutines::push_coroutine< leaf& > & c) : + c_( c) + {} + + void visit( branch & b) + { + if ( b.left) b.left->accept( * this); + if ( b.right) b.right->accept( * this); + } + + void visit( leaf & l) + { c_( l); } +}; + +int main() +{ + node::ptr_t t1 = create_tree1(); + boost::coroutines::pull_coroutine< leaf& > c1( + [&]( boost::coroutines::push_coroutine< leaf & > & c) { + coro_visitor v( c); + t1->accept( v); + }); + + node::ptr_t t2 = create_tree2(); + boost::coroutines::pull_coroutine< leaf& > c2( + [&]( boost::coroutines::push_coroutine< leaf & > & c) { + coro_visitor v( c); + t2->accept( v); + }); + + bool result = std::equal( + boost::begin( c1), + boost::end( c1), + boost::begin( c2) ); + + std::cout << std::boolalpha << "same fringe == " << result << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} +#else class coro_visitor : public visitor { private: @@ -30,24 +95,6 @@ public: { c_( l); } }; -node::ptr_t create_tree1() -{ - return branch::create( - leaf::create( "A"), - branch::create( - leaf::create( "B"), - leaf::create( "C") ) ); -} - -node::ptr_t create_tree2() -{ - return branch::create( - branch::create( - leaf::create( "A"), - leaf::create( "B") ), - leaf::create( "C") ); -} - int main() { node::ptr_t t1 = create_tree1(); @@ -73,3 +120,4 @@ int main() return EXIT_SUCCESS; } +#endif diff --git a/example/echo.cpp b/example/echo.cpp index 92b7b5e..1c48679 100644 --- a/example/echo.cpp +++ b/example/echo.cpp @@ -10,6 +10,43 @@ #include <boost/bind.hpp> #include <boost/coroutine/all.hpp> +#ifdef BOOST_COROUTINES_V2 +typedef boost::coroutines::pull_coroutine< void > pull_coro_t; +typedef boost::coroutines::push_coroutine< void > push_coro_t; + +void echo( pull_coro_t & c, int i) +{ + std::cout << i; + c(); +} + +void runit( push_coro_t & ca) +{ + std::cout << "started! "; + for ( int i = 0; i < 10; ++i) + { + push_coro_t c( boost::bind( echo, _1, i) ); + while ( c) + c(); + ca(); + } +} + +int main( int argc, char * argv[]) +{ + { + pull_coro_t c( runit); + while ( c) { + std::cout << "-"; + c(); + } + } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} +#else typedef boost::coroutines::coroutine< void() > coro_t; void echo( coro_t & ca, int i) @@ -44,3 +81,4 @@ int main( int argc, char * argv[]) return EXIT_SUCCESS; } +#endif diff --git a/example/fibonacci.cpp b/example/fibonacci.cpp index 41dff61..aad0c5a 100644 --- a/example/fibonacci.cpp +++ b/example/fibonacci.cpp @@ -10,7 +10,8 @@ #include <boost/range.hpp> #include <boost/coroutine/all.hpp> -void fibonacci( boost::coroutines::coroutine< void( int) > & c) +#ifdef BOOST_COROUTINES_V2 +void fibonacci( boost::coroutines::push_coroutine< int > & c) { int first = 1, second = 1; while ( true) @@ -22,6 +23,35 @@ void fibonacci( boost::coroutines::coroutine< void( int) > & c) } } +int main() +{ + boost::coroutines::pull_coroutine< int > c( fibonacci); + boost::range_iterator< + boost::coroutines::pull_coroutine< int > + >::type it( boost::begin( c) ); + for ( int i = 0; i < 10; ++i) + { + std::cout << * it << " "; + ++it; + } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} +#else +void fibonacci( boost::coroutines::coroutine< void( int) > & c) +{ + int first = 1, second = 1; + while ( true) + { + int third = first + second; + first = second; + second = third; + c( third); + } +} + int main() { boost::coroutines::coroutine< int() > c( fibonacci); @@ -38,35 +68,4 @@ int main() return EXIT_SUCCESS; } - -// C++11 -#if 0 -int main() -{ - boost::coroutines::coroutine< int() > c( - [&]( boost::coroutines::coroutine< void( int) > & c) { - int first = 1, second = 1; - while ( true) - { - int third = first + second; - first = second; - second = third; - c( third); - } - }); - - boost::range_iterator< - boost::coroutines::coroutine< int() > - >::type it( boost::begin( c) ); - - for ( int i = 0; i < 10; ++i) - { - std::cout << * it << " "; - ++it; - } - - std::cout << "\nDone" << std::endl; - - return EXIT_SUCCESS; -} #endif diff --git a/example/parallel.cpp b/example/parallel.cpp index 1c1f683..5523940 100644 --- a/example/parallel.cpp +++ b/example/parallel.cpp @@ -10,6 +10,45 @@ #include <boost/bind.hpp> #include <boost/coroutine/all.hpp> +#ifdef BOOST_COROUTINES_V2 +void first( boost::coroutines::push_coroutine< void > & c) +{ + std::cout << "started first! "; + for ( int i = 0; i < 10; ++i) + { + c(); + std::cout << "a" << i; + } +} + +void second( boost::coroutines::push_coroutine< void > & c) +{ + std::cout << "started second! "; + for ( int i = 0; i < 10; ++i) + { + c(); + std::cout << "b" << i; + } +} + +int main( int argc, char * argv[]) +{ + { + boost::coroutines::pull_coroutine< void > c1( boost::bind( first, _1) ); + boost::coroutines::pull_coroutine< void > c2( boost::bind( second, _1) ); + while ( c1 && c2) { + c1(); + std::cout << " "; + c2(); + std::cout << " "; + } + } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} +#else typedef boost::coroutines::coroutine< void() > coroutine_t; void first( coroutine_t::caller_type & self) @@ -49,3 +88,4 @@ int main( int argc, char * argv[]) return EXIT_SUCCESS; } +#endif diff --git a/example/power.cpp b/example/power.cpp index 9800e64..dc495d5 100644 --- a/example/power.cpp +++ b/example/power.cpp @@ -12,6 +12,41 @@ #include <boost/range.hpp> #include <boost/coroutine/all.hpp> +#ifdef BOOST_COROUTINES_V2 +void power( boost::coroutines::push_coroutine< int > & c, int number, int exponent) +{ + int counter = 0; + int result = 1; + while ( counter++ < exponent) + { + result = result * number; + c( result); + } +} + +int main() +{ + { + std::cout << "using range functions" << std::endl; + boost::coroutines::pull_coroutine< int > c( boost::bind( power, _1, 2, 8) ); + boost::coroutines::pull_coroutine< int >::iterator e( boost::end( c) ); + for ( boost::coroutines::pull_coroutine< int >::iterator i( boost::begin( c) ); + i != e; ++i) + std::cout << * i << " "; + } + + { + std::cout << "\nusing BOOST_FOREACH" << std::endl; + boost::coroutines::pull_coroutine< int > c( boost::bind( power, _1, 2, 8) ); + BOOST_FOREACH( int i, c) + { std::cout << i << " "; } + } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} +#else typedef boost::coroutines::coroutine< int() > coro1_t; typedef boost::coroutines::coroutine< void( int) > coro2_t; typedef boost::range_iterator< coro1_t >::type iterator_t; @@ -48,45 +83,4 @@ int main() return EXIT_SUCCESS; } -#if 0 -int main() -{ - { - std::cout << "using range functions" << std::endl; - boost::coroutines::coroutine< int() > c( - [&]( boost::coroutines::coroutine< void( int) > &c) { - int counter = 0; - int result = 1; - while ( counter++ < 8) - { - result = result * 2; - c( result); - } - }); - iterator_t e( boost::end( c) ); - for ( iterator_t i( boost::begin( c) ); i != e; ++i) - std::cout << * i << " "; - } - - { - std::cout << "\nusing BOOST_FOREACH" << std::endl; - boost::coroutines::coroutine< int() > c( - [&]( boost::coroutines::coroutine< void( int) > &c) { - int counter = 0; - int result = 1; - while ( counter++ < 8) - { - result = result * 2; - c( result); - } - }); - for ( int i : c) { - std::cout << i << " "; - } - } - - std::cout << "\nDone" << std::endl; - - return EXIT_SUCCESS; -} #endif diff --git a/example/same_fringe.cpp b/example/same_fringe.cpp index 99172d4..0150a9c 100644 --- a/example/same_fringe.cpp +++ b/example/same_fringe.cpp @@ -15,15 +15,6 @@ #include "tree.h" -bool match_trees( coro_t & c1, coro_t & c2) -{ - typedef boost::range_iterator< coro_t >::type iterator_t; - iterator_t i1( boost::begin( c1) ); - iterator_t e1( boost::end( c1) ); - iterator_t i2( boost::begin( c2) ); - return std::equal( i1, e1, i2); -} - std::pair< node::ptr_t, node::ptr_t > create_eq_trees() { branch::ptr_t tree1 = branch::create( @@ -58,6 +49,48 @@ std::pair< node::ptr_t, node::ptr_t > create_diff_trees() return std::make_pair( tree1, tree2); } +#ifdef BOOST_COROUTINES_V2 +bool match_trees( boost::coroutines::pull_coroutine< leaf & > & c1, + boost::coroutines::pull_coroutine< leaf & > & c2) +{ + typedef boost::range_iterator< boost::coroutines::pull_coroutine< leaf & > >::type iterator_t; + iterator_t i1( boost::begin( c1) ); + iterator_t e1( boost::end( c1) ); + iterator_t i2( boost::begin( c2) ); + return std::equal( i1, e1, i2); +} + +int main() +{ + { + std::pair< node::ptr_t, node::ptr_t > pt = create_eq_trees(); + boost::coroutines::pull_coroutine< leaf & > te1( boost::bind( enumerate_leafs, _1, pt.first) ); + boost::coroutines::pull_coroutine< leaf & > te2( boost::bind( enumerate_leafs, _1, pt.second) ); + bool result = match_trees( te1, te2); + std::cout << std::boolalpha << "eq. trees matched == " << result << std::endl; + } + { + std::pair< node::ptr_t, node::ptr_t > pt = create_diff_trees(); + boost::coroutines::pull_coroutine< leaf & > te1( boost::bind( enumerate_leafs, _1, pt.first) ); + boost::coroutines::pull_coroutine< leaf & > te2( boost::bind( enumerate_leafs, _1, pt.second) ); + bool result = match_trees( te1, te2); + std::cout << std::boolalpha << "diff. trees matched == " << result << std::endl; + } + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; +} +#else +bool match_trees( coro_t & c1, coro_t & c2) +{ + typedef boost::range_iterator< coro_t >::type iterator_t; + iterator_t i1( boost::begin( c1) ); + iterator_t e1( boost::end( c1) ); + iterator_t i2( boost::begin( c2) ); + return std::equal( i1, e1, i2); +} + int main() { { @@ -79,3 +112,4 @@ int main() return EXIT_SUCCESS; } +#endif diff --git a/example/segmented_stack.cpp b/example/segmented_stack.cpp index 4a3859a..6fc9af8 100644 --- a/example/segmented_stack.cpp +++ b/example/segmented_stack.cpp @@ -10,8 +10,6 @@ #include <boost/coroutine/all.hpp> #include <boost/thread.hpp> -typedef boost::coroutines::coroutine< void() > coro_t; - int count = 20; void access( char *buf) __attribute__ ((noinline)); @@ -19,6 +17,7 @@ void access( char *buf) { buf[0] = '\0'; } + void bar( int i) { char buf[4 * 1024]; @@ -31,6 +30,23 @@ void bar( int i) } } +#ifdef BOOST_COROUTINES_V2 +void foo( boost::coroutines::pull_coroutine< void > & c) +{ + bar( count); + c(); +} + +void thread_fn() +{ + { + boost::coroutines::push_coroutine< void > c( foo); + c(); + } +} +#else +typedef boost::coroutines::coroutine< void() > coro_t; + void foo( coro_t & c) { bar( count); @@ -42,9 +58,9 @@ void thread_fn() { coro_t c( foo); c(); - int i = 7; } } +#endif int main( int argc, char * argv[]) { diff --git a/example/tree.h b/example/tree.h index f0c2187..39bb3c8 100644 --- a/example/tree.h +++ b/example/tree.h @@ -91,6 +91,33 @@ inline bool operator!=( leaf const& l, leaf const& r) { return l.value != r.value; } +#ifdef BOOST_COROUTINES_V2 +class tree_visitor : public visitor +{ +private: + boost::coroutines::push_coroutine< leaf & > & c_; + +public: + tree_visitor( boost::coroutines::push_coroutine< leaf & > & c) : + c_( c) + {} + + void visit( branch & b) + { + if ( b.left) b.left->accept( * this); + if ( b.right) b.right->accept( * this); + } + + void visit( leaf & l) + { c_( l); } +}; + +void enumerate_leafs( boost::coroutines::push_coroutine< leaf & > & c, node::ptr_t root) +{ + tree_visitor v( c); + root->accept( v); +} +#else typedef boost::coroutines::coroutine< leaf&() > coro_t; class tree_visitor : public visitor @@ -118,6 +145,7 @@ void enumerate_leafs( coro_t::caller_type & c, node::ptr_t root) tree_visitor v( c); root->accept( v); } +#endif # if defined(BOOST_MSVC) # pragma warning(pop) diff --git a/example/unwind.cpp b/example/unwind.cpp index 32df2ab..4bcaa1d 100644 --- a/example/unwind.cpp +++ b/example/unwind.cpp @@ -10,6 +10,40 @@ #include <boost/bind.hpp> #include <boost/coroutine/all.hpp> +#ifdef BOOST_COROUTINES_V2 +struct X : private boost::noncopyable +{ + X() { std::cout << "X()" << std::endl; } + ~X() { std::cout << "~X()" << std::endl; } +}; + +void fn( boost::coroutines::push_coroutine< void > & c) +{ + X x; + int i = 0; + while ( true) + { + std::cout << "fn() : " << ++i << std::endl; + c(); + } +} + +int main( int argc, char * argv[]) +{ + { + boost::coroutines::pull_coroutine< void > c( fn); + for ( int k = 0; k < 3; ++k) + { + c(); + } + std::cout << "destroying coroutine and unwinding stack" << std::endl; + } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} +#else typedef boost::coroutines::coroutine< void() > coro_t; struct X : private boost::noncopyable @@ -44,3 +78,4 @@ int main( int argc, char * argv[]) return EXIT_SUCCESS; } +#endif diff --git a/include/boost/coroutine/detail/config.hpp b/include/boost/coroutine/detail/config.hpp index 0452730..6d6860a 100644 --- a/include/boost/coroutine/detail/config.hpp +++ b/include/boost/coroutine/detail/config.hpp @@ -46,8 +46,8 @@ # define BOOST_COROUTINES_SEGMENTS 10 #endif -//#ifndef BOOST_COROUTINES_V1 -//# define BOOST_COROUTINES_V2 -//#endif +#ifndef BOOST_COROUTINES_V1 +# define BOOST_COROUTINES_V2 +#endif #endif // BOOST_COROUTINES_DETAIL_CONFIG_H diff --git a/include/boost/coroutine/detail/exceptions.hpp b/include/boost/coroutine/detail/exceptions.hpp index 39f3854..4b92872 100644 --- a/include/boost/coroutine/detail/exceptions.hpp +++ b/include/boost/coroutine/detail/exceptions.hpp @@ -4,8 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_COROUTINES_DETAIL_EXCEPTIONs_H -#define BOOST_COROUTINES_DETAIL_EXCEPTIONs_H +#ifndef BOOST_COROUTINES_DETAIL_EXCEPTIONS_H +#define BOOST_COROUTINES_DETAIL_EXCEPTIONS_H #include <boost/config.hpp> @@ -25,4 +25,4 @@ struct forced_unwind {}; # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_DETAIL_EXCEPTIONs_H +#endif // BOOST_COROUTINES_DETAIL_EXCEPTIONS_H diff --git a/include/boost/coroutine/detail/stack_tuple.hpp b/include/boost/coroutine/detail/stack_tuple.hpp new file mode 100644 index 0000000..80935cb --- /dev/null +++ b/include/boost/coroutine/detail/stack_tuple.hpp @@ -0,0 +1,47 @@ + +// 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_STACK_TUPLE_H +#define BOOST_COROUTINES_DETAIL_STACK_TUPLE_H + +#include <cstddef> + +#include <boost/config.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename StackAllocator > +struct stack_tuple +{ + coroutines::stack_context stack_ctx; + StackAllocator stack_alloc; + + stack_tuple( StackAllocator const& stack_alloc_, std::size_t size) : + stack_ctx(), + stack_alloc( stack_alloc_) + { stack_alloc.allocate( stack_ctx, size); } + + ~stack_tuple() + { stack_alloc.deallocate( stack_ctx); } +}; + + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_STACK_TUPLE_H diff --git a/include/boost/coroutine/detail/trampoline.hpp b/include/boost/coroutine/detail/trampoline.hpp new file mode 100644 index 0000000..2c8088f --- /dev/null +++ b/include/boost/coroutine/detail/trampoline.hpp @@ -0,0 +1,52 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_COROUTINES_DETAIL_TRAMPOLINE_H +#define BOOST_COROUTINES_DETAIL_TRAMPOLINE_H + +#include <cstddef> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/tuple/tuple.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename Coroutine > +void trampoline1( intptr_t vp) +{ + BOOST_ASSERT( vp); + + reinterpret_cast< Coroutine * >( vp)->run(); +} + +template< typename Coroutine, typename Arg > +void trampoline2( intptr_t vp) +{ + BOOST_ASSERT( vp); + + tuple< Coroutine *, Arg > * tpl( + reinterpret_cast< tuple< Coroutine *, Arg > * >( vp) ); + Coroutine * coro( get< 0 >( * tpl) ); + Arg arg( get< 1 >( * tpl) ); + + coro->run( arg); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_H diff --git a/include/boost/coroutine/v1/detail/coroutine_object.hpp b/include/boost/coroutine/v1/detail/coroutine_object.hpp index 6e8978a..17ef4d4 100644 --- a/include/boost/coroutine/v1/detail/coroutine_object.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_object.hpp @@ -25,8 +25,11 @@ #include <boost/coroutine/detail/flags.hpp> #include <boost/coroutine/detail/holder.hpp> #include <boost/coroutine/detail/param.hpp> +#include <boost/coroutine/detail/stack_tuple.hpp> +#include <boost/coroutine/detail/trampoline.hpp> #include <boost/coroutine/flags.hpp> #include <boost/coroutine/stack_context.hpp> +#include <boost/coroutine/stack_context.hpp> #include <boost/coroutine/v1/detail/arg.hpp> #include <boost/coroutine/v1/detail/coroutine_base.hpp> @@ -43,46 +46,6 @@ namespace boost { namespace coroutines { namespace detail { -template< typename Coroutine > -void trampoline1( intptr_t vp) -{ - BOOST_ASSERT( vp); - - reinterpret_cast< Coroutine * >( vp)->run(); -} - -template< typename Coroutine, typename Arg > -void trampoline2( intptr_t vp) -{ - BOOST_ASSERT( vp); - - tuple< Coroutine *, Arg > * tpl( - reinterpret_cast< tuple< Coroutine *, Arg > * >( vp) ); - Coroutine * coro( get< 0 >( * tpl) ); - Arg arg( get< 1 >( * tpl) ); - - coro->run( arg); -} - -template< typename StackAllocator > -struct stack_tuple -{ - coroutines::stack_context stack_ctx; - StackAllocator stack_alloc; - - stack_tuple( StackAllocator const& stack_alloc_, std::size_t size) : - stack_ctx(), - stack_alloc( stack_alloc_) - { - stack_alloc.allocate( stack_ctx, size); - } - - ~stack_tuple() - { - stack_alloc.deallocate( stack_ctx); - } -}; - template< typename Signature, typename Fn, typename StackAllocator, typename Allocator, diff --git a/include/boost/coroutine/v2/coroutine.hpp b/include/boost/coroutine/v2/coroutine.hpp new file mode 100644 index 0000000..691f927 --- /dev/null +++ b/include/boost/coroutine/v2/coroutine.hpp @@ -0,0 +1,2428 @@ + +// 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_V2_COROUTINE_H +#define BOOST_COROUTINES_V2_COROUTINE_H + +#include <cstddef> +#include <iterator> +#include <memory> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/move/move.hpp> +#include <boost/optional.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/decay.hpp> +#include <boost/type_traits/function_traits.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/utility/enable_if.hpp> + +#include <boost/coroutine/attributes.hpp> +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/param.hpp> +#include <boost/coroutine/stack_allocator.hpp> +#include <boost/coroutine/v2/detail/pull_coroutine_base.hpp> +#include <boost/coroutine/v2/detail/pull_coroutine_caller.hpp> +#include <boost/coroutine/v2/detail/pull_coroutine_object.hpp> +#include <boost/coroutine/v2/detail/push_coroutine_base.hpp> +#include <boost/coroutine/v2/detail/push_coroutine_caller.hpp> +#include <boost/coroutine/v2/detail/push_coroutine_object.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +template< typename Arg > +class push_coroutine +{ +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class detail::pull_coroutine_object; + + typedef detail::push_coroutine_base< Arg > base_t; + typedef typename base_t::ptr_t ptr_t; + + struct dummy + { void nonnull() {} }; + + typedef void ( dummy::*safe_bool)(); + + ptr_t impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) + + template< typename Allocator > + push_coroutine( detail::coroutine_context const& callee, + bool unwind, bool preserve_fpu, + Allocator const& alloc) : + impl_() + { + typedef detail::push_coroutine_caller< + Arg, Allocator + > caller_t; + typename caller_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) caller_t( + callee, unwind, preserve_fpu, a) ); + } + +public: + push_coroutine() BOOST_NOEXCEPT : + impl_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); +#else + template< typename Fn > + explicit push_coroutine( Fn fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); +#endif + + push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : + impl_() + { swap( other); } + + push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT + { + push_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + bool empty() const BOOST_NOEXCEPT + { return ! impl_; } + + operator safe_bool() const BOOST_NOEXCEPT + { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; } + + bool operator!() const BOOST_NOEXCEPT + { return empty() || impl_->is_complete(); } + + void swap( push_coroutine & other) BOOST_NOEXCEPT + { impl_.swap( other.impl_); } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + push_coroutine & operator()( Arg const& arg) + { + BOOST_ASSERT( * this); + + impl_->push( arg); + return * this; + } + + push_coroutine & operator()( Arg && arg) { + BOOST_ASSERT( * this); + + impl_->push( arg); + return * this; + } +#else + push_coroutine & operator()( Arg arg) + { + BOOST_ASSERT( * this); + + impl_->push( forward< Arg >( arg) ); + return * this; + } + + push_coroutine & operator()( BOOST_RV_REF( Arg) arg) + { + BOOST_ASSERT( * this); + + impl_->push( forward< Arg >( arg) ); + return * this; + } +#endif + + class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > + { + private: + push_coroutine< Arg > * c_; + + public: + iterator() : + c_( 0) + {} + + explicit iterator( push_coroutine< Arg > * c) : + c_( c) + {} + + iterator & operator=( Arg a) + { + BOOST_ASSERT( c_); + if ( ! ( * c_)( a) ) c_ = 0; + return * this; + } + + bool operator==( iterator const& other) + { return other.c_ == c_; } + + bool operator!=( iterator const& other) + { return other.c_ != c_; } + + iterator & operator*() + { return * this; } + + iterator & operator++() + { return * this; } + }; + + struct const_iterator; +}; + +template< typename Arg > +class push_coroutine< Arg & > +{ +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class detail::pull_coroutine_object; + + typedef detail::push_coroutine_base< Arg & > base_t; + typedef typename base_t::ptr_t ptr_t; + + struct dummy + { void nonnull() {} }; + + typedef void ( dummy::*safe_bool)(); + + ptr_t impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) + + template< typename Allocator > + push_coroutine( detail::coroutine_context const& callee, + bool unwind, bool preserve_fpu, + Allocator const& alloc) : + impl_() + { + typedef detail::push_coroutine_caller< + Arg &, Allocator + > caller_t; + typename caller_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) caller_t( + callee, unwind, preserve_fpu, a) ); + } + +public: + push_coroutine() BOOST_NOEXCEPT : + impl_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); +#else + template< typename Fn > + explicit push_coroutine( Fn fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); +#endif + + push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : + impl_() + { swap( other); } + + push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT + { + push_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + bool empty() const BOOST_NOEXCEPT + { return ! impl_; } + + operator safe_bool() const BOOST_NOEXCEPT + { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; } + + bool operator!() const BOOST_NOEXCEPT + { return empty() || impl_->is_complete(); } + + void swap( push_coroutine & other) BOOST_NOEXCEPT + { impl_.swap( other.impl_); } + + push_coroutine & operator()( Arg & arg) + { + BOOST_ASSERT( * this); + + impl_->push( forward< Arg & >( arg) ); + return * this; + } + + class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > + { + private: + push_coroutine< Arg & > * c_; + + public: + iterator() : + c_( 0) + {} + + explicit iterator( push_coroutine< Arg & > * c) : + c_( c) + {} + + iterator & operator=( Arg & a) + { + BOOST_ASSERT( c_); + if ( ! ( * c_)( a) ) c_ = 0; + return * this; + } + + bool operator==( iterator const& other) + { return other.c_ == c_; } + + bool operator!=( iterator const& other) + { return other.c_ != c_; } + + iterator & operator*() + { return * this; } + + iterator & operator++() + { return * this; } + }; + + struct const_iterator; +}; + +template< typename Arg > +class push_coroutine< Arg const& > +{ +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class detail::pull_coroutine_object; + + typedef detail::push_coroutine_base< Arg const& > base_t; + typedef typename base_t::ptr_t ptr_t; + + struct dummy + { void nonnull() {} }; + + typedef void ( dummy::*safe_bool)(); + + ptr_t impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) + + template< typename Allocator > + push_coroutine( detail::coroutine_context const& callee, + bool unwind, bool preserve_fpu, + Allocator const& alloc) : + impl_() + { + typedef detail::push_coroutine_caller< + Arg const&, Allocator + > caller_t; + typename caller_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) caller_t( + callee, unwind, preserve_fpu, a) ); + } + +public: + push_coroutine() BOOST_NOEXCEPT : + impl_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); +#else + template< typename Fn > + explicit push_coroutine( Fn fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); +#endif + + push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : + impl_() + { swap( other); } + + push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT + { + push_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + bool empty() const BOOST_NOEXCEPT + { return ! impl_; } + + operator safe_bool() const BOOST_NOEXCEPT + { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; } + + bool operator!() const BOOST_NOEXCEPT + { return empty() || impl_->is_complete(); } + + void swap( push_coroutine & other) BOOST_NOEXCEPT + { impl_.swap( other.impl_); } + + push_coroutine & operator()( Arg const& arg) + { + BOOST_ASSERT( * this); + + impl_->push( forward< Arg const& >( arg) ); + return * this; + } + + class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > + { + private: + push_coroutine< Arg const& > * c_; + + public: + iterator() : + c_( 0) + {} + + explicit iterator( push_coroutine< Arg const& > * c) : + c_( c) + {} + + iterator & operator=( Arg const& a) + { + BOOST_ASSERT( c_); + if ( ! ( * c_)( a) ) c_ = 0; + return * this; + } + + bool operator==( iterator const& other) + { return other.c_ == c_; } + + bool operator!=( iterator const& other) + { return other.c_ != c_; } + + iterator & operator*() + { return * this; } + + iterator & operator++() + { return * this; } + }; + + struct const_iterator; +}; + +template<> +class push_coroutine< void > +{ +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class detail::pull_coroutine_object; + + typedef detail::push_coroutine_base< void > base_t; + typedef typename base_t::ptr_t ptr_t; + + struct dummy + { void nonnull() {} }; + + typedef void ( dummy::*safe_bool)(); + + ptr_t impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine) + + template< typename Allocator > + push_coroutine( detail::coroutine_context const& callee, + bool unwind, bool preserve_fpu, + Allocator const& alloc) : + impl_() + { + typedef detail::push_coroutine_caller< + void, Allocator + > caller_t; + typename caller_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) caller_t( + callee, unwind, preserve_fpu, a) ); + } + +public: + push_coroutine() BOOST_NOEXCEPT : + impl_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); +#else + template< typename Fn > + explicit push_coroutine( Fn fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0); + + template< typename Fn > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc = + std::allocator< push_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type = 0); +#endif + + push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT : + impl_() + { swap( other); } + + push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT + { + push_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + bool empty() const BOOST_NOEXCEPT + { return ! impl_; } + + operator safe_bool() const BOOST_NOEXCEPT + { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; } + + bool operator!() const BOOST_NOEXCEPT + { return empty() || impl_->is_complete(); } + + void swap( push_coroutine & other) BOOST_NOEXCEPT + { impl_.swap( other.impl_); } + + push_coroutine & operator()() + { + BOOST_ASSERT( * this); + + impl_->push(); + return * this; + } + + struct iterator; + struct const_iterator; +}; + + + +template< typename R > +class pull_coroutine +{ +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class detail::push_coroutine_object; + + typedef detail::pull_coroutine_base< R > base_t; + typedef typename base_t::ptr_t ptr_t; + + struct dummy + { void nonnull() {} }; + + typedef void ( dummy::*safe_bool)(); + + ptr_t impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine) + + template< typename Allocator > + pull_coroutine( detail::coroutine_context const& callee, + bool unwind, bool preserve_fpu, + Allocator const& alloc, + optional< R > const& result) : + impl_() + { + typedef detail::pull_coroutine_caller< + R, Allocator + > caller_t; + typename caller_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) caller_t( + callee, unwind, preserve_fpu, a, result) ); + } + +public: + pull_coroutine() BOOST_NOEXCEPT : + impl_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, stack_allocator, std::allocator< pull_coroutine >, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, StackAllocator, std::allocator< pull_coroutine >, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, StackAllocator, Allocator, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); + } +#else + template< typename Fn > + explicit pull_coroutine( Fn fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, stack_allocator, std::allocator< pull_coroutine >, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, StackAllocator, std::allocator< pull_coroutine >, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit pull_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, StackAllocator, Allocator, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, stack_allocator, std::allocator< pull_coroutine >, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, StackAllocator, std::allocator< pull_coroutine >, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + R, Fn, StackAllocator, Allocator, + push_coroutine< R > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } +#endif + + pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT : + impl_() + { swap( other); } + + pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT + { + pull_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + bool empty() const BOOST_NOEXCEPT + { return ! impl_; } + + operator safe_bool() const BOOST_NOEXCEPT + { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; } + + bool operator!() const BOOST_NOEXCEPT + { return empty() || impl_->is_complete(); } + + void swap( pull_coroutine & other) BOOST_NOEXCEPT + { impl_.swap( other.impl_); } + + pull_coroutine & operator()() + { + BOOST_ASSERT( * this); + + impl_->pull(); + return * this; + } + + bool has_result() const + { + BOOST_ASSERT( ! empty() ); + + return impl_->has_result(); + } + + R get() const + { + BOOST_ASSERT( has_result() ); + + return impl_->get(); + } + + class iterator : public std::iterator< std::input_iterator_tag, typename remove_reference< R >::type > + { + private: + pull_coroutine< R > * c_; + optional< R > val_; + + void fetch_() + { + BOOST_ASSERT( c_); + + if ( ! c_->has_result() ) + { + c_ = 0; + val_ = none; + return; + } + val_ = c_->get(); + } + + void increment_() + { + BOOST_ASSERT( c_); + BOOST_ASSERT( * c_); + + ( * c_)(); + fetch_(); + } + + public: + typedef typename iterator::pointer pointer_t; + typedef typename iterator::reference reference_t; + + iterator() : + c_( 0), val_() + {} + + explicit iterator( pull_coroutine< R > * c) : + c_( c), val_() + { fetch_(); } + + iterator( iterator const& other) : + c_( other.c_), val_( other.val_) + {} + + iterator & operator=( iterator const& other) + { + if ( this == & other) return * this; + c_ = other.c_; + val_ = other.val_; + return * this; + } + + bool operator==( iterator const& other) + { return other.c_ == c_ && other.val_ == val_; } + + bool operator!=( iterator const& other) + { return other.c_ != c_ || other.val_ != val_; } + + iterator & operator++() + { + increment_(); + return * this; + } + + iterator operator++( int) + { + iterator tmp( * this); + ++*this; + return tmp; + } + + reference_t operator*() const + { return const_cast< optional< R > & >( val_).get(); } + + pointer_t operator->() const + { return const_cast< optional< R > & >( val_).get_ptr(); } + }; + + class const_iterator : public std::iterator< std::input_iterator_tag, const typename remove_reference< R >::type > + { + private: + pull_coroutine< R > * c_; + optional< R > val_; + + void fetch_() + { + BOOST_ASSERT( c_); + + if ( ! c_->has_result() ) + { + c_ = 0; + val_ = none; + return; + } + val_ = c_->get(); + } + + void increment_() + { + BOOST_ASSERT( c_); + BOOST_ASSERT( * c_); + + ( * c_)(); + fetch_(); + } + + public: + typedef typename const_iterator::pointer pointer_t; + typedef typename const_iterator::reference reference_t; + + const_iterator() : + c_( 0), val_() + {} + + explicit const_iterator( pull_coroutine< R > const* c) : + c_( const_cast< pull_coroutine< R > * >( c) ), val_() + { fetch_(); } + + const_iterator( const_iterator const& other) : + c_( other.c_), val_( other.val_) + {} + + const_iterator & operator=( const_iterator const& other) + { + if ( this == & other) return * this; + c_ = other.c_; + val_ = other.val_; + return * this; + } + + bool operator==( const_iterator const& other) + { return other.c_ == c_ && other.val_ == val_; } + + bool operator!=( const_iterator const& other) + { return other.c_ != c_ || other.val_ != val_; } + + const_iterator & operator++() + { + increment_(); + return * this; + } + + const_iterator operator++( int) + { + const_iterator tmp( * this); + ++*this; + return tmp; + } + + reference_t operator*() const + { return val_.get(); } + + pointer_t operator->() const + { return val_.get_ptr(); } + }; +}; + +template<> +class pull_coroutine< void > +{ +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class detail::push_coroutine_object; + + typedef detail::pull_coroutine_base< void > base_t; + typedef typename base_t::ptr_t ptr_t; + + struct dummy + { void nonnull() {} }; + + typedef void ( dummy::*safe_bool)(); + + ptr_t impl_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine) + + template< typename Allocator > + pull_coroutine( detail::coroutine_context const& callee, + bool unwind, bool preserve_fpu, + Allocator const& alloc) : + impl_() + { + typedef detail::pull_coroutine_caller< + void, Allocator + > caller_t; + typename caller_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) caller_t( + callee, unwind, preserve_fpu, a) ); + } + +public: + pull_coroutine() BOOST_NOEXCEPT : + impl_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, stack_allocator, std::allocator< pull_coroutine >, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, StackAllocator, std::allocator< pull_coroutine >, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, StackAllocator, Allocator, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); + } +#else + template< typename Fn > + explicit pull_coroutine( Fn fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, stack_allocator, std::allocator< pull_coroutine >, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, StackAllocator, std::allocator< pull_coroutine >, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit pull_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, StackAllocator, Allocator, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(), + stack_allocator const& stack_alloc = + stack_allocator(), + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, stack_allocator, std::allocator< pull_coroutine >, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< pull_coroutine > const& alloc = + std::allocator< pull_coroutine >(), + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, StackAllocator, std::allocator< pull_coroutine >, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } + + template< typename Fn, typename StackAllocator, typename Allocator > + explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, pull_coroutine >, + dummy * + >::type = 0) : + impl_() + { + typedef detail::pull_coroutine_object< + void, Fn, StackAllocator, Allocator, + push_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); + } +#endif + + pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT : + impl_() + { swap( other); } + + pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT + { + pull_coroutine tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + bool empty() const BOOST_NOEXCEPT + { return ! impl_; } + + operator safe_bool() const BOOST_NOEXCEPT + { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; } + + bool operator!() const BOOST_NOEXCEPT + { return empty() || impl_->is_complete(); } + + void swap( pull_coroutine & other) BOOST_NOEXCEPT + { impl_.swap( other.impl_); } + + pull_coroutine & operator()() + { + BOOST_ASSERT( * this); + + impl_->pull(); + return * this; + } + + struct iterator; + struct const_iterator; +}; + + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template< typename Arg > +template< typename Fn > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, StackAllocator, Allocator, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, StackAllocator, Allocator, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, StackAllocator, Allocator, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Fn > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} + +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, StackAllocator, Allocator, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) ); +} +#else +template< typename Arg > +template< typename Fn > +push_coroutine< Arg >::push_coroutine( Fn fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg >::push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< Arg >::push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, StackAllocator, Allocator, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg, Fn, StackAllocator, Allocator, + pull_coroutine< Arg > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg & >::push_coroutine( Fn fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< Arg & >::push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, StackAllocator, Allocator, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine<Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg &, Fn, StackAllocator, Allocator, + pull_coroutine< Arg & > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg const& >::push_coroutine( Fn fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg const& >::push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< Arg const& >::push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, StackAllocator, Allocator, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn > +push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator > +push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Arg > +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + Arg const&, Fn, StackAllocator, Allocator, + pull_coroutine< Arg const& > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Fn > +push_coroutine< void >::push_coroutine( Fn fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< void >::push_coroutine( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_convertible< Fn &, BOOST_RV_REF( Fn) >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, StackAllocator, Allocator, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Fn > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + stack_allocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, stack_allocator, std::allocator< push_coroutine >, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Fn, typename StackAllocator > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + std::allocator< push_coroutine > const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, StackAllocator, std::allocator< push_coroutine >, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} + +template< typename Fn, typename StackAllocator, typename Allocator > +push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + Allocator const& alloc, + typename disable_if< + is_same< typename decay< Fn >::type, push_coroutine >, + dummy * + >::type) : + impl_() +{ + typedef detail::push_coroutine_object< + void, Fn, StackAllocator, Allocator, + pull_coroutine< void > + > object_t; + typename object_t::allocator_t a( alloc); + impl_ = ptr_t( + // placement new + ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) ); +} +#endif + +template< typename R > +void swap( pull_coroutine< R > & l, pull_coroutine< R > & r) BOOST_NOEXCEPT +{ l.swap( r); } + +template< typename Arg > +void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r) BOOST_NOEXCEPT +{ l.swap( r); } + +template< typename R > +inline +typename pull_coroutine< R >::iterator +range_begin( pull_coroutine< R > & c) +{ return typename pull_coroutine< R >::iterator( & c); } + +template< typename R > +inline +typename pull_coroutine< R >::const_iterator +range_begin( pull_coroutine< R > const& c) +{ return typename pull_coroutine< R >::const_iterator( & c); } + +template< typename R > +inline +typename pull_coroutine< R >::iterator +range_end( pull_coroutine< R > &) +{ return typename pull_coroutine< R >::iterator(); } + +template< typename R > +inline +typename pull_coroutine< R >::const_iterator +range_end( pull_coroutine< R > const&) +{ return typename pull_coroutine< R >::const_iterator(); } + +template< typename R > +inline +typename pull_coroutine< R >::iterator +begin( pull_coroutine< R > & c) +{ return boost::begin( c); } + +template< typename R > +inline +typename pull_coroutine< R >::iterator +end( pull_coroutine< R > & c) +{ return boost::end( c); } + +template< typename R > +inline +typename pull_coroutine< R >::const_iterator +begin( pull_coroutine< R > const& c) +{ return boost::const_begin( c); } + +template< typename R > +inline +typename pull_coroutine< R >::const_iterator +end( pull_coroutine< R > const& c) +{ return boost::const_end( c); } + +template< typename Arg > +inline +typename push_coroutine< Arg >::iterator +range_begin( push_coroutine< Arg > & c) +{ return typename push_coroutine< Arg >::iterator( & c); } + +template< typename Arg > +inline +typename push_coroutine< Arg >::const_iterator +range_begin( push_coroutine< Arg > const& c) +{ return typename push_coroutine< Arg >::const_iterator( & c); } + +template< typename Arg > +inline +typename push_coroutine< Arg >::iterator +range_end( push_coroutine< Arg > &) +{ return typename push_coroutine< Arg >::iterator(); } + +template< typename Arg > +inline +typename push_coroutine< Arg >::const_iterator +range_end( push_coroutine< Arg > const&) +{ return typename push_coroutine< Arg >::const_iterator(); } + +template< typename Arg > +inline +typename push_coroutine< Arg >::iterator +begin( push_coroutine< Arg > & c) +{ return boost::begin( c); } + +template< typename Arg > +inline +typename push_coroutine< Arg >::iterator +end( push_coroutine< Arg > & c) +{ return boost::end( c); } + +template< typename Arg > +inline +typename push_coroutine< Arg >::const_iterator +begin( push_coroutine< Arg > const& c) +{ return boost::const_begin( c); } + +template< typename Arg > +inline +typename push_coroutine< Arg >::const_iterator +end( push_coroutine< Arg > const& c) +{ return boost::const_end( c); } + +} + +template< typename Arg > +struct range_mutable_iterator< coroutines::push_coroutine< Arg > > +{ typedef typename coroutines::push_coroutine< Arg >::iterator type; }; + +template< typename Arg > +struct range_const_iterator< coroutines::push_coroutine< Arg > > +{ typedef typename coroutines::push_coroutine< Arg >::const_iterator type; }; + +template< typename R > +struct range_mutable_iterator< coroutines::pull_coroutine< R > > +{ typedef typename coroutines::pull_coroutine< R >::iterator type; }; + +template< typename R > +struct range_const_iterator< coroutines::pull_coroutine< R > > +{ typedef typename coroutines::pull_coroutine< R >::const_iterator type; }; + +} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_V2_COROUTINE_H diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp new file mode 100644 index 0000000..f3398fc --- /dev/null +++ b/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp @@ -0,0 +1,232 @@ + +// 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_V2_DETAIL_PULL_COROUTINE_BASE_H +#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/context/fcontext.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/optional.hpp> +#include <boost/type_traits/function_traits.hpp> +#include <boost/utility.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/holder.hpp> +#include <boost/coroutine/detail/param.hpp> +#include <boost/coroutine/detail/exceptions.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +namespace detail { + +template< typename R > +class pull_coroutine_base : private noncopyable +{ +public: + typedef intrusive_ptr< pull_coroutine_base > ptr_t; + +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class push_coroutine_object; + + unsigned int use_count_; + +protected: + int flags_; + exception_ptr except_; + coroutine_context caller_; + coroutine_context callee_; + optional< R > result_; + + virtual void deallocate_object() = 0; + +public: + pull_coroutine_base( coroutine_context::ctx_fn fn, + stack_context * stack_ctx, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( fn, stack_ctx), + result_() + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + pull_coroutine_base( coroutine_context const& callee, + bool unwind, bool preserve_fpu, + optional< R > const& result) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( callee), + result_( result) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~pull_coroutine_base() + {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT + { ++p->use_count_; } + + friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT + { if ( --p->use_count_ == 0) p->deallocate_object(); } + + void pull() + { + BOOST_ASSERT( ! is_complete() ); + + holder< R > hldr_to( & caller_); + holder< R > * hldr_from( + reinterpret_cast< holder< R > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + result_ = hldr_from->data; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + bool has_result() const + { return result_; } + + R get() const + { + BOOST_ASSERT( has_result() ); + + return result_.get(); + } +}; + +template<> +class pull_coroutine_base< void > : private noncopyable +{ +public: + typedef intrusive_ptr< pull_coroutine_base > ptr_t; + +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class push_coroutine_object; + + unsigned int use_count_; + +protected: + int flags_; + exception_ptr except_; + coroutine_context caller_; + coroutine_context callee_; + + virtual void deallocate_object() = 0; + +public: + pull_coroutine_base( coroutine_context::ctx_fn fn, + stack_context * stack_ctx, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( fn, stack_ctx) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + pull_coroutine_base( coroutine_context const& callee, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~pull_coroutine_base() + {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT + { ++p->use_count_; } + + friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT + { if ( --p->use_count_ == 0) p->deallocate_object(); } + + void pull() + { + BOOST_ASSERT( ! is_complete() ); + + holder< void > hldr_to( & caller_); + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_caller.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_caller.hpp new file mode 100644 index 0000000..43b3506 --- /dev/null +++ b/include/boost/coroutine/v2/detail/pull_coroutine_caller.hpp @@ -0,0 +1,84 @@ +// 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_V2_DETAIL_PULL_COROUTINE_CALLER_H +#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_CALLER_H + +#include <boost/config.hpp> +#include <boost/context/fcontext.hpp> +#include <boost/optional.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/v2/detail/pull_coroutine_base.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename R, typename Allocator > +class pull_coroutine_caller : public pull_coroutine_base< R > +{ +public: + typedef typename Allocator::template rebind< + pull_coroutine_caller< R, Allocator > + >::other allocator_t; + + pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu, + allocator_t const& alloc, optional< R > const& data) BOOST_NOEXCEPT : + pull_coroutine_base< R >( callee, unwind, preserve_fpu, data), + alloc_( alloc) + {} + + void deallocate_object() + { destroy_( alloc_, this); } + +private: + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, pull_coroutine_caller * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } +}; + +template< typename Allocator > +class pull_coroutine_caller< void, Allocator > : public pull_coroutine_base< void > +{ +public: + typedef typename Allocator::template rebind< + pull_coroutine_caller< void, Allocator > + >::other allocator_t; + + pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu, + allocator_t const& alloc) BOOST_NOEXCEPT : + pull_coroutine_base< void >( callee, unwind, preserve_fpu), + alloc_( alloc) + {} + + void deallocate_object() + { destroy_( alloc_, this); } + +private: + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, pull_coroutine_caller * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_CALLER_H diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp new file mode 100644 index 0000000..1698417 --- /dev/null +++ b/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp @@ -0,0 +1,768 @@ + +// 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_V2_DETAIL_PULL_COROUTINE_OBJECT_H +#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_OBJECT_H + +#include <cstddef> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/move/move.hpp> +#include <boost/ref.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/type_traits/function_traits.hpp> +#include <boost/utility.hpp> + +#include <boost/coroutine/attributes.hpp> +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/exceptions.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/holder.hpp> +#include <boost/coroutine/detail/param.hpp> +#include <boost/coroutine/detail/stack_tuple.hpp> +#include <boost/coroutine/detail/trampoline.hpp> +#include <boost/coroutine/flags.hpp> +#include <boost/coroutine/stack_context.hpp> +#include <boost/coroutine/v2/detail/pull_coroutine_base.hpp> + +#ifdef BOOST_MSVC + #pragma warning (push) + #pragma warning (disable: 4355) // using 'this' in initializer list +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< + typename R, typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class pull_coroutine_object : private stack_tuple< StackAllocator >, + public pull_coroutine_base< R > +{ +public: + typedef typename Allocator::template rebind< + pull_coroutine_object< + R, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef pull_coroutine_base< R > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, pull_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + pull_coroutine_object( pull_coroutine_object &); + pull_coroutine_object & operator=( pull_coroutine_object const&); + + void enter_() + { + holder< R > * hldr_from( + reinterpret_cast< holder< R > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + this->result_ = hldr_from->data; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< R > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + pull_coroutine_object( Fn && fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( forward< Fn >( fn) ), + alloc_( alloc) + { enter_(); } +#else + pull_coroutine_object( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } +#endif + + ~pull_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + // create push_coroutine + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< R > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename R, typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class pull_coroutine_object< R, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public pull_coroutine_base< R > +{ +public: + typedef typename Allocator::template rebind< + pull_coroutine_object< + R, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef pull_coroutine_base< R > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, pull_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + pull_coroutine_object( pull_coroutine_object &); + pull_coroutine_object & operator=( pull_coroutine_object const&); + + void enter_() + { + holder< R > * hldr_from( + reinterpret_cast< holder< R > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< R > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: + pull_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + ~pull_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + // create pull_coroutine + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< R > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename R, typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class pull_coroutine_object< R, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public pull_coroutine_base< R > +{ +public: + typedef typename Allocator::template rebind< + pull_coroutine_object< + R, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef pull_coroutine_base< R > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, pull_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + pull_coroutine_object( pull_coroutine_object &); + pull_coroutine_object & operator=( pull_coroutine_object const&); + + void enter_() + { + holder< R > * hldr_from( + reinterpret_cast< holder< R > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< R > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: + pull_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + ~pull_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + // create pull_coroutine + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< R > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class pull_coroutine_object< void, Fn, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public pull_coroutine_base< void > +{ +public: + typedef typename Allocator::template rebind< + pull_coroutine_object< + void, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef pull_coroutine_base< void > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, pull_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + pull_coroutine_object( pull_coroutine_object &); + pull_coroutine_object & operator=( pull_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + pull_coroutine_object( Fn && fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( forward< Fn >( fn) ), + alloc_( alloc) + { enter_(); } +#else + pull_coroutine_object( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } +#endif + + ~pull_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + // create push_coroutine + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class pull_coroutine_object< void, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public pull_coroutine_base< void > +{ +public: + typedef typename Allocator::template rebind< + pull_coroutine_object< + void, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef pull_coroutine_base< void > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, pull_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + pull_coroutine_object( pull_coroutine_object &); + pull_coroutine_object & operator=( pull_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: + pull_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + ~pull_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + // create pull_coroutine + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class pull_coroutine_object< void, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public pull_coroutine_base< void > +{ +public: + typedef typename Allocator::template rebind< + pull_coroutine_object< + void, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef pull_coroutine_base< void > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, pull_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + pull_coroutine_object( pull_coroutine_object &); + pull_coroutine_object & operator=( pull_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: + pull_coroutine_object( const reference_wrapper< Fn > fn, + attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< pull_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + ~pull_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + // create pull_coroutine + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#ifdef BOOST_MSVC + #pragma warning (pop) +#endif + +#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_OBJECT_H diff --git a/include/boost/coroutine/v2/detail/push_coroutine_base.hpp b/include/boost/coroutine/v2/detail/push_coroutine_base.hpp new file mode 100644 index 0000000..1a4156d --- /dev/null +++ b/include/boost/coroutine/v2/detail/push_coroutine_base.hpp @@ -0,0 +1,441 @@ + +// 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_V2_DETAIL_PUSH_COROUTINE_BASE_H +#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/context/fcontext.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/type_traits/function_traits.hpp> +#include <boost/utility.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/coroutine_context.hpp> +#include <boost/coroutine/detail/exceptions.hpp> +#include <boost/coroutine/detail/flags.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +namespace detail { + +template< typename Arg > +class push_coroutine_base : private noncopyable +{ +public: + typedef intrusive_ptr< push_coroutine_base > ptr_t; + +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class pull_coroutine_object; + + unsigned int use_count_; + +protected: + int flags_; + exception_ptr except_; + coroutine_context caller_; + coroutine_context callee_; + + virtual void deallocate_object() = 0; + +public: + push_coroutine_base( coroutine_context::ctx_fn fn, + stack_context * stack_ctx, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( fn, stack_ctx) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + push_coroutine_base( coroutine_context const& callee, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~push_coroutine_base() + {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT + { ++p->use_count_; } + + friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT + { if ( --p->use_count_ == 0) p->deallocate_object(); } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + void push( Arg const& arg) + { + BOOST_ASSERT( ! is_complete() ); + + holder< Arg > hldr_to( & caller_, arg); + holder< Arg > * hldr_from( + reinterpret_cast< holder< Arg > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + void push( Arg && arg) + { + BOOST_ASSERT( ! is_complete() ); + + holder< Arg > hldr_to( & caller_, arg); + holder< Arg > * hldr_from( + reinterpret_cast< holder< Arg > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } +#else + void push( Arg arg) + { + BOOST_ASSERT( ! is_complete() ); + + holder< Arg > hldr_to( & caller_, arg); + holder< Arg > * hldr_from( + reinterpret_cast< holder< Arg > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } + + void push( BOOST_RV_REF( Arg) arg) + { + BOOST_ASSERT( ! is_complete() ); + + holder< Arg > hldr_to( & caller_, arg); + holder< Arg > * hldr_from( + reinterpret_cast< holder< Arg > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } +#endif +}; + +template< typename Arg > +class push_coroutine_base< Arg & > : private noncopyable +{ +public: + typedef intrusive_ptr< push_coroutine_base > ptr_t; + +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class pull_coroutine_object; + + unsigned int use_count_; + +protected: + int flags_; + exception_ptr except_; + coroutine_context caller_; + coroutine_context callee_; + + virtual void deallocate_object() = 0; + +public: + push_coroutine_base( coroutine_context::ctx_fn fn, + stack_context * stack_ctx, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( fn, stack_ctx) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + push_coroutine_base( coroutine_context const& callee, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~push_coroutine_base() + {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT + { ++p->use_count_; } + + friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT + { if ( --p->use_count_ == 0) p->deallocate_object(); } + + void push( Arg & arg) + { + BOOST_ASSERT( ! is_complete() ); + + holder< Arg & > hldr_to( & caller_, arg); + holder< Arg & > * hldr_from( + reinterpret_cast< holder< Arg & > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } +}; + +template< typename Arg > +class push_coroutine_base< Arg const& > : private noncopyable +{ +public: + typedef intrusive_ptr< push_coroutine_base > ptr_t; + +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class pull_coroutine_object; + + unsigned int use_count_; + +protected: + int flags_; + exception_ptr except_; + coroutine_context caller_; + coroutine_context callee_; + + virtual void deallocate_object() = 0; + +public: + push_coroutine_base( coroutine_context::ctx_fn fn, + stack_context * stack_ctx, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( fn, stack_ctx) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + push_coroutine_base( coroutine_context const& callee, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~push_coroutine_base() + {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT + { ++p->use_count_; } + + friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT + { if ( --p->use_count_ == 0) p->deallocate_object(); } + + void push( Arg const& arg) + { + BOOST_ASSERT( ! is_complete() ); + + holder< Arg const& > hldr_to( & caller_, arg); + holder< Arg const& > * hldr_from( + reinterpret_cast< holder< Arg const& > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } +}; + +template<> +class push_coroutine_base< void > : private noncopyable +{ +public: + typedef intrusive_ptr< push_coroutine_base > ptr_t; + +private: + template< + typename X, typename Y, typename Z, typename V, typename W + > + friend class pull_coroutine_object; + + unsigned int use_count_; + +protected: + int flags_; + exception_ptr except_; + coroutine_context caller_; + coroutine_context callee_; + + virtual void deallocate_object() = 0; + +public: + push_coroutine_base( coroutine_context::ctx_fn fn, + stack_context * stack_ctx, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( fn, stack_ctx) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + push_coroutine_base( coroutine_context const& callee, + bool unwind, bool preserve_fpu) : + use_count_( 0), + flags_( 0), + except_(), + caller_(), + callee_( callee) + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + virtual ~push_coroutine_base() + {} + + bool force_unwind() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_force_unwind); } + + bool unwind_requested() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_unwind_stack); } + + bool preserve_fpu() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_preserve_fpu); } + + bool is_complete() const BOOST_NOEXCEPT + { return 0 != ( flags_ & flag_complete); } + + friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT + { ++p->use_count_; } + + friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT + { if ( --p->use_count_ == 0) p->deallocate_object(); } + + void push() + { + BOOST_ASSERT( ! is_complete() ); + + holder< void > hldr_to( & caller_); + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + hldr_to.ctx->jump( + callee_, + reinterpret_cast< intptr_t >( & hldr_to), + preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + callee_ = * hldr_from->ctx; + if ( hldr_from->force_unwind) throw forced_unwind(); + if ( except_) rethrow_exception( except_); + } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H diff --git a/include/boost/coroutine/v2/detail/push_coroutine_caller.hpp b/include/boost/coroutine/v2/detail/push_coroutine_caller.hpp new file mode 100644 index 0000000..1358250 --- /dev/null +++ b/include/boost/coroutine/v2/detail/push_coroutine_caller.hpp @@ -0,0 +1,56 @@ +// 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_V2_DETAIL_PUSH_COROUTINE_CALLER_H +#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_CALLER_H + +#include <boost/config.hpp> +#include <boost/context/fcontext.hpp> + +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/v2/detail/push_coroutine_base.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< typename Arg, typename Allocator > +class push_coroutine_caller : public push_coroutine_base< Arg > +{ +public: + typedef typename Allocator::template rebind< + push_coroutine_caller< Arg, Allocator > + >::other allocator_t; + + push_coroutine_caller( coroutine_context const& callee, bool unwind, + bool preserve_fpu, allocator_t const& alloc) BOOST_NOEXCEPT : + push_coroutine_base< Arg >( callee, unwind, preserve_fpu), + alloc_( alloc) + {} + + void deallocate_object() + { destroy_( alloc_, this); } + +private: + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, push_coroutine_caller * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_CALLER_H diff --git a/include/boost/coroutine/v2/detail/push_coroutine_object.hpp b/include/boost/coroutine/v2/detail/push_coroutine_object.hpp new file mode 100644 index 0000000..2fc439a --- /dev/null +++ b/include/boost/coroutine/v2/detail/push_coroutine_object.hpp @@ -0,0 +1,823 @@ + +// 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_V2_DETAIL_PUSH_COROUTINE_OBJECT_H +#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_OBJECT_H + +#include <cstddef> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/move/move.hpp> +#include <boost/ref.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/type_traits/function_traits.hpp> +#include <boost/utility.hpp> + +#include <boost/coroutine/attributes.hpp> +#include <boost/coroutine/detail/config.hpp> +#include <boost/coroutine/detail/exceptions.hpp> +#include <boost/coroutine/detail/flags.hpp> +#include <boost/coroutine/detail/holder.hpp> +#include <boost/coroutine/detail/param.hpp> +#include <boost/coroutine/detail/stack_tuple.hpp> +#include <boost/coroutine/detail/trampoline.hpp> +#include <boost/coroutine/flags.hpp> +#include <boost/coroutine/stack_context.hpp> +#include <boost/coroutine/v2/detail/push_coroutine_base.hpp> + +#ifdef BOOST_MSVC + #pragma warning (push) + #pragma warning (disable: 4355) // using 'this' in initializer list +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +template< + typename Arg, typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class push_coroutine_object : private stack_tuple< StackAllocator >, + public push_coroutine_base< Arg > +{ +public: + typedef typename Allocator::template rebind< + push_coroutine_object< + Arg, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef push_coroutine_base< Arg > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, push_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + push_coroutine_object( push_coroutine_object &); + push_coroutine_object & operator=( push_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< Arg > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + push_coroutine_object( Fn && fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( forward< Fn >( fn) ), + alloc_( alloc) + { enter_(); } +#else + push_coroutine_object( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } +#endif + + ~push_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + holder< void > hldr_to( & caller); + holder< Arg > * hldr_from( + reinterpret_cast< holder< Arg > * >( + caller.jump( + this->caller_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + BOOST_ASSERT( hldr_from->data); + + // create pull_coroutine + Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< Arg > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename Arg, typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class push_coroutine_object< Arg, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public push_coroutine_base< Arg > +{ +public: + typedef typename Allocator::template rebind< + push_coroutine_object< + Arg, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef push_coroutine_base< Arg > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, push_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + push_coroutine_object( push_coroutine_object &); + push_coroutine_object & operator=( push_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< Arg > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: + push_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + ~push_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + holder< void > hldr_to( & caller); + holder< Arg > * hldr_from( + reinterpret_cast< holder< Arg > * >( + caller.jump( + this->caller_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + BOOST_ASSERT( hldr_from->data); + + // create pull_coroutine + Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< Arg > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename Arg, typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class push_coroutine_object< Arg, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public push_coroutine_base< Arg > +{ +public: + typedef typename Allocator::template rebind< + push_coroutine_object< + Arg, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef push_coroutine_base< Arg > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, push_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + push_coroutine_object( push_coroutine_object &); + push_coroutine_object & operator=( push_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< Arg > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: + push_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + ~push_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + holder< void > hldr_to( & caller); + holder< Arg > * hldr_from( + reinterpret_cast< holder< Arg > * >( + caller.jump( + this->caller_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + BOOST_ASSERT( hldr_from->data); + + // create pull_coroutine + Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< Arg > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class push_coroutine_object< void, Fn, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public push_coroutine_base< void > +{ +public: + typedef typename Allocator::template rebind< + push_coroutine_object< + void, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef push_coroutine_base< void > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, push_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + push_coroutine_object( push_coroutine_object &); + push_coroutine_object & operator=( push_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + push_coroutine_object( Fn && fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( forward< Fn >( fn) ), + alloc_( alloc) + { enter_(); } +#else + push_coroutine_object( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } +#endif + + ~push_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + holder< void > hldr_to( & caller); + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + caller.jump( + this->caller_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + + // create pull_coroutine + Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class push_coroutine_object< void, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public push_coroutine_base< void > +{ +public: + typedef typename Allocator::template rebind< + push_coroutine_object< + void, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef push_coroutine_base< void > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, push_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + push_coroutine_object( push_coroutine_object &); + push_coroutine_object & operator=( push_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: + push_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + ~push_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + holder< void > hldr_to( & caller); + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + caller.jump( + this->caller_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + + // create pull_coroutine + Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +template< + typename Fn, + typename StackAllocator, typename Allocator, + typename Caller +> +class push_coroutine_object< void, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > : + private stack_tuple< StackAllocator >, + public push_coroutine_base< void > +{ +public: + typedef typename Allocator::template rebind< + push_coroutine_object< + void, Fn, StackAllocator, Allocator, Caller + > + >::other allocator_t; + +private: + typedef stack_tuple< StackAllocator > pbase_type; + typedef push_coroutine_base< void > base_type; + + Fn fn_; + allocator_t alloc_; + + static void destroy_( allocator_t & alloc, push_coroutine_object * p) + { + alloc.destroy( p); + alloc.deallocate( p, 1); + } + + push_coroutine_object( push_coroutine_object &); + push_coroutine_object & operator=( push_coroutine_object const&); + + void enter_() + { + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; + if ( this->except_) rethrow_exception( this->except_); + } + + void unwind_stack_() BOOST_NOEXCEPT + { + BOOST_ASSERT( ! this->is_complete() ); + + this->flags_ |= flag_unwind_stack; + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + this->flags_ &= ~flag_unwind_stack; + + BOOST_ASSERT( this->is_complete() ); + } + +public: + push_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, + StackAllocator const& stack_alloc, + allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), + base_type( + trampoline1< push_coroutine_object >, + & this->stack_ctx, + stack_unwind == attr.do_unwind, + fpu_preserved == attr.preserve_fpu), + fn_( fn), + alloc_( alloc) + { enter_(); } + + ~push_coroutine_object() + { + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); + } + + void run() + { + coroutine_context callee; + coroutine_context caller; + + { + holder< void > hldr_to( & caller); + holder< void > * hldr_from( + reinterpret_cast< holder< void > * >( + caller.jump( + this->caller_, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + + // create pull_coroutine + Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_); + try + { fn_( c); } + catch ( forced_unwind const&) + {} + catch (...) + { this->except_ = current_exception(); } + callee = c.impl_->callee_; + } + + this->flags_ |= flag_complete; + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), + this->preserve_fpu() ); + BOOST_ASSERT_MSG( false, "push_coroutine is complete"); + } + + void deallocate_object() + { destroy_( alloc_, this); } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#ifdef BOOST_MSVC + #pragma warning (pop) +#endif + +#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_OBJECT_H diff --git a/performance/performance.cpp b/performance/performance.cpp index c9ac8ab..67ec895 100644 --- a/performance/performance.cpp +++ b/performance/performance.cpp @@ -27,25 +27,24 @@ namespace coro = boost::coroutines; -typedef coro::coroutine< void() > coro_t; +# define COUNTER BOOST_PP_LIMIT_MAG -#define COUNTER BOOST_PP_LIMIT_MAG - -#define CALL_COROUTINE(z,n,unused) \ +# define CALL_COROUTINE(z,n,unused) \ c(); -void fn( coro_t::caller_type & c) +#ifdef BOOST_COROUTINES_V2 +void fn( boost::coroutines::push_coroutine< void > & c) { while ( true) c(); } -#ifdef BOOST_CONTEXT_CYCLE +# ifdef BOOST_CONTEXT_CYCLE cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu) { -#if defined(BOOST_USE_SEGMENTED_STACKS) - coro_t c( fn, coro::attributes( preserve_fpu) ); -#else +# if defined(BOOST_USE_SEGMENTED_STACKS) + boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu) ); +# else coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; - coro_t c( fn, coro::attributes( preserve_fpu), alloc); -#endif + boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu), alloc); +# endif // cache warum-up BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) @@ -61,17 +60,17 @@ BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) return total; } -#endif +# endif -#if _POSIX_C_SOURCE >= 199309L +# if _POSIX_C_SOURCE >= 199309L zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu) { -#if defined(BOOST_USE_SEGMENTED_STACKS) - coro_t c( fn, coro::attributes( preserve_fpu) ); -#else +# if defined(BOOST_USE_SEGMENTED_STACKS) + boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu) ); +# else coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; - coro_t c( fn, coro::attributes( preserve_fpu), alloc); -#endif + boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu), alloc); +# endif // cache warum-up BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~) @@ -87,6 +86,64 @@ BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~) return total; } +# endif +#else +typedef coro::coroutine< void() > coro_t; + +void fn( coro_t::caller_type & c) +{ while ( true) c(); } + +# ifdef BOOST_CONTEXT_CYCLE +cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu) +{ +# if defined(BOOST_USE_SEGMENTED_STACKS) + coro_t c( fn, coro::attributes( preserve_fpu) ); +# else + coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; + coro_t c( fn, coro::attributes( preserve_fpu), alloc); +# endif + + // cache warum-up +BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) + + cycle_t start( cycles() ); +BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) + cycle_t total( cycles() - start); + + // we have two jumps and two measuremt-overheads + total -= ov; // overhead of measurement + total /= COUNTER; // per call + total /= 2; // 2x jump_to c1->c2 && c2->c1 + + return total; +} +# endif + +# if _POSIX_C_SOURCE >= 199309L +zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu) +{ +# if defined(BOOST_USE_SEGMENTED_STACKS) + coro_t c( fn, coro::attributes( preserve_fpu) ); +# else + coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; + coro_t c( fn, coro::attributes( preserve_fpu), alloc); +# endif + + // cache warum-up +BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~) + + zeit_t start( zeit() ); +BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~) + zeit_t total( zeit() - start); + + // we have two jumps and two measuremt-overheads + total -= ov; // overhead of measurement + total /= BOOST_PP_LIMIT_MAG; // per call + total /= 2; // 2x jump_to c1->c2 && c2->c1 + + return total; +} +# endif #endif int main( int argc, char * argv[]) diff --git a/test/test_coroutine.cpp b/test/test_coroutine.cpp index c2adea2..1361b0c 100644 --- a/test/test_coroutine.cpp +++ b/test/test_coroutine.cpp @@ -30,7 +30,487 @@ namespace coro = boost::coroutines; int value1 = 0; std::string value2 = ""; bool value3 = false; +double value4 = .0; +int * value5 = 0; +int& value6 = value1; +int& value7 = value1; +int value8 = 0; +int value9 = 0; +#ifdef BOOST_COROUTINES_V2 +struct X : private boost::noncopyable +{ + X() { value1 = 7; } + ~X() { value1 = 0; } +}; + +class copyable +{ +public: + bool state; + + copyable() : + state( false) + {} + + copyable( int) : + state( true) + {} + + void operator()( coro::push_coroutine< int > &) + { value3 = state; } +}; + +class moveable +{ +private: + BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable); + +public: + bool state; + + moveable() : + state( false) + {} + + moveable( int) : + state( true) + {} + + moveable( BOOST_RV_REF( moveable) other) : + state( false) + { std::swap( state, other.state); } + + moveable & operator=( BOOST_RV_REF( moveable) other) + { + if ( this == & other) return * this; + moveable tmp( boost::move( other) ); + std::swap( state, tmp.state); + return * this; + } + + void operator()( coro::push_coroutine< int > &) + { value3 = state; } +}; + +struct my_exception {}; + +void f1( coro::push_coroutine< void > & c) +{ c(); } + +void f2( coro::push_coroutine< void > &) +{ ++value1; } + +void f3( coro::push_coroutine< void > & c) +{ + ++value1; + c(); + ++value1; +} + +void f4( coro::push_coroutine< int > & c) +{ + c( 3); + c( 7); +} + +void f5( coro::push_coroutine< std::string > & c) +{ + std::string res("abc"); + c( res); + res = "xyz"; + c( res); +} + +void f6( coro::pull_coroutine< int > & c) +{ value1 = c.get(); } + +void f7( coro::pull_coroutine< std::string > & c) +{ value2 = c.get(); } + +void f8( coro::pull_coroutine< boost::tuple< double, double > > & c) +{ + double x = 0, y = 0; + boost::tie( x, y) = c.get(); + value4 = x + y; + c(); + boost::tie( x, y) = c.get(); + value4 = x + y; +} + +void f9( coro::pull_coroutine< int * > & c) +{ value5 = c.get(); } + +void f91( coro::pull_coroutine< int const* > & c) +{ value5 = const_cast< int * >( c.get() ); } + +void f10( coro::pull_coroutine< int & > & c) +{ + int const& i = c.get(); + value5 = const_cast< int * >( & i); +} + +void f101( coro::pull_coroutine< int const& > & c) +{ + int const& i = c.get(); + value5 = const_cast< int * >( & i); +} + +void f11( coro::pull_coroutine< boost::tuple< int, int > > & c) +{ + boost::tie( value8, value9) = c.get(); +} + +void f12( coro::pull_coroutine< void > & c) +{ + X x_; + c(); + c(); +} + +template< typename E > +void f14( coro::pull_coroutine< void > &, E const& e) +{ throw e; } + +void f16( coro::push_coroutine< int > & c) +{ + c( 1); + c( 2); + c( 3); + c( 4); + c( 5); +} + +void f17( coro::pull_coroutine< int > & c, std::vector< int > & vec) +{ + int x = c.get(); + while ( 5 > x) + { + vec.push_back( x); + x = c().get(); + } +} + +void f19( coro::push_coroutine< const int* > & c, std::vector< const int * > & vec) +{ + BOOST_FOREACH( const int * ptr, vec) + { c( ptr); } +} + +void test_move() +{ + { + coro::pull_coroutine< void > coro1; + coro::pull_coroutine< void > coro2( f1); + BOOST_CHECK( ! coro1); + BOOST_CHECK( coro1.empty() ); + BOOST_CHECK( coro2); + BOOST_CHECK( ! coro2.empty() ); + coro1 = boost::move( coro2); + BOOST_CHECK( coro1); + BOOST_CHECK( ! coro1.empty() ); + BOOST_CHECK( ! coro2); + BOOST_CHECK( coro2.empty() ); + } + + { + value3 = false; + copyable cp( 3); + BOOST_CHECK( cp.state); + BOOST_CHECK( ! value3); + coro::pull_coroutine< int > coro( cp); + BOOST_CHECK( cp.state); + BOOST_CHECK( value3); + } + + { + value3 = false; + moveable mv( 7); + BOOST_CHECK( mv.state); + BOOST_CHECK( ! value3); + coro::pull_coroutine< int > coro( boost::move( mv) ); + BOOST_CHECK( ! mv.state); + BOOST_CHECK( value3); + } +} + +void test_complete() +{ + value1 = 0; + + coro::pull_coroutine< void > coro( f2); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( ( int)1, value1); +} + +void test_jump() +{ + value1 = 0; + + coro::pull_coroutine< void > coro( f3); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( ( int)1, value1); + coro(); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( ( int)2, value1); +} + +void test_result_int() +{ + coro::pull_coroutine< int > coro( f4); + BOOST_CHECK( coro); + int result = coro.get(); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( 3, result); + result = coro().get(); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( 7, result); + coro(); + BOOST_CHECK( ! coro); +} + +void test_result_string() +{ + coro::pull_coroutine< std::string > coro( f5); + BOOST_CHECK( coro); + std::string result = coro.get(); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( std::string("abc"), result); + result = coro().get(); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( std::string("xyz"), result); + coro(); + BOOST_CHECK( ! coro); +} + +void test_arg_int() +{ + value1 = 0; + + coro::push_coroutine< int > coro( f6); + BOOST_CHECK( coro); + coro( 3); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( 3, value1); +} + +void test_arg_string() +{ + value2 = ""; + + coro::push_coroutine< std::string > coro( f7); + BOOST_CHECK( coro); + coro( std::string("abc") ); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( std::string("abc"), value2); +} + +void test_fp() +{ + value4 = 0; + + coro::push_coroutine< boost::tuple< double, double > > coro( f8); + BOOST_CHECK( coro); + coro( boost::make_tuple( 7.35, 3.14) ); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( ( double) 10.49, value4); + + value4 = 0; + coro( boost::make_tuple( 1.15, 3.14) ); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( ( double) 4.29, value4); +} + +void test_ptr() +{ + value5 = 0; + + int a = 3; + coro::push_coroutine< int * > coro( f9); + BOOST_CHECK( coro); + coro( & a); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( & a, value5); +} + +void test_const_ptr() +{ + value5 = 0; + + int a = 3; + coro::push_coroutine< int const* > coro( f91); + BOOST_CHECK( coro); + coro( & a); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( & a, value5); +} + +void test_ref() +{ + value5 = 0; + + int a = 3; + coro::push_coroutine< int & > coro( f10); + BOOST_CHECK( coro); + coro( a); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( & a, value5); +} + +void test_const_ref() +{ + value5 = 0; + + int a = 3; + coro::push_coroutine< int const& > coro( f101); + BOOST_CHECK( coro); + coro( a); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( & a, value5); +} + +void test_tuple() +{ + value8 = 0; + value9 = 0; + + int a = 3, b = 7; + boost::tuple< int, int > tpl( a, b); + BOOST_CHECK_EQUAL( a, tpl.get< 0 >() ); + BOOST_CHECK_EQUAL( b, tpl.get< 1 >() ); + coro::push_coroutine< boost::tuple< int, int > > coro( f11); + BOOST_CHECK( coro); + coro( tpl); + BOOST_CHECK( ! coro); + BOOST_CHECK_EQUAL( a, value8); + BOOST_CHECK_EQUAL( b, value9); +} + +void test_unwind() +{ + value1 = 0; + { + coro::push_coroutine< void > coro( f12); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( ( int) 0, value1); + coro(); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( ( int) 7, value1); + coro(); + BOOST_CHECK_EQUAL( ( int) 7, value1); + } + BOOST_CHECK_EQUAL( ( int) 0, value1); +} + +void test_no_unwind() +{ + value1 = 0; + { + coro::push_coroutine< void > coro( + f12, + coro::attributes( + coro::stack_allocator::default_stacksize(), + coro::no_stack_unwind) ); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( ( int) 0, value1); + coro(); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( ( int) 7, value1); + coro(); + BOOST_CHECK_EQUAL( ( int) 7, value1); + } + BOOST_CHECK_EQUAL( ( int) 7, value1); +} + +void test_exceptions() +{ + bool thrown = false; + std::runtime_error ex("abc"); + try + { + coro::push_coroutine< void > coro( boost::bind( f14< std::runtime_error >, _1, ex) ); + BOOST_CHECK( coro); + coro(); + BOOST_CHECK( ! coro); + BOOST_CHECK( false); + } + catch ( std::runtime_error const&) + { thrown = true; } + catch ( std::exception const&) + {} + catch (...) + {} + BOOST_CHECK( thrown); +} + +void test_output_iterator() +{ + { + std::vector< int > vec; + coro::pull_coroutine< int > coro( f16); + BOOST_FOREACH( int i, coro) + { vec.push_back( i); } + BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() ); + BOOST_CHECK_EQUAL( ( int)1, vec[0] ); + BOOST_CHECK_EQUAL( ( int)2, vec[1] ); + BOOST_CHECK_EQUAL( ( int)3, vec[2] ); + BOOST_CHECK_EQUAL( ( int)4, vec[3] ); + BOOST_CHECK_EQUAL( ( int)5, vec[4] ); + } + { + std::vector< int > vec; + coro::pull_coroutine< int > coro( f16); + coro::pull_coroutine< int >::iterator e = boost::end( coro); + for ( + coro::pull_coroutine< int >::iterator i = boost::begin( coro); + i != e; ++i) + { vec.push_back( * i); } + BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() ); + BOOST_CHECK_EQUAL( ( int)1, vec[0] ); + BOOST_CHECK_EQUAL( ( int)2, vec[1] ); + BOOST_CHECK_EQUAL( ( int)3, vec[2] ); + BOOST_CHECK_EQUAL( ( int)4, vec[3] ); + BOOST_CHECK_EQUAL( ( int)5, vec[4] ); + } + { + int i1 = 1, i2 = 2, i3 = 3; + std::vector< const int* > vec_in; + vec_in.push_back( & i1); + vec_in.push_back( & i2); + vec_in.push_back( & i3); + std::vector< const int* > vec_out; + coro::pull_coroutine< const int* > coro( boost::bind( f19, _1, boost::ref( vec_in) ) ); + coro::pull_coroutine< const int* >::const_iterator e = boost::const_end( coro); + for ( + coro::pull_coroutine< const int* >::const_iterator i = boost::const_begin( coro); + i != e; ++i) + { vec_out.push_back( * i); } + BOOST_CHECK_EQUAL( ( std::size_t)3, vec_out.size() ); + BOOST_CHECK_EQUAL( & i1, vec_out[0] ); + BOOST_CHECK_EQUAL( & i2, vec_out[1] ); + BOOST_CHECK_EQUAL( & i3, vec_out[2] ); + } +} + +void test_input_iterator() +{ + int counter = 0; + std::vector< int > vec; + coro::push_coroutine< int > coro( + boost::bind( f17, _1, boost::ref( vec) ) ); + coro::push_coroutine< int >::iterator e( boost::end( coro) ); + for ( coro::push_coroutine< int >::iterator i( boost::begin( coro) ); + i != e; ++i) + { + i = ++counter; + } + BOOST_CHECK_EQUAL( ( std::size_t)4, vec.size() ); + BOOST_CHECK_EQUAL( ( int)1, vec[0] ); + BOOST_CHECK_EQUAL( ( int)2, vec[1] ); + BOOST_CHECK_EQUAL( ( int)3, vec[2] ); + BOOST_CHECK_EQUAL( ( int)4, vec[3] ); +} +#else typedef coro::coroutine< void() > coro_void_void; typedef coro::coroutine< int() > coro_int_void; typedef coro::coroutine< std::string() > coro_string_void; @@ -40,7 +520,9 @@ typedef coro::coroutine< double(double,double) > coro_double; typedef coro::coroutine< int(int,int) > coro_int; typedef coro::coroutine< int(int) > coro_int_int; typedef coro::coroutine< int*(int*) > coro_ptr; -typedef coro::coroutine< int const&(int const&) > coro_ref; +typedef coro::coroutine< int const*(int const*) > coro_const_ptr; +typedef coro::coroutine< int&(int&) > coro_ref; +typedef coro::coroutine< int const&(int const&) > coro_const_ref; typedef coro::coroutine< boost::tuple<int&,int&>(int&,int&) > coro_tuple; typedef coro::coroutine< const int *() > coro_const_int_ptr_void; @@ -146,9 +628,15 @@ void f8( coro_double::caller_type & self) void f9( coro_ptr::caller_type & self) { self( self.get() ); } +void f91( coro_const_ptr::caller_type & self) +{ self( self.get() ); } + void f10( coro_ref::caller_type & self) { self( self.get() ); } +void f101( coro_const_ref::caller_type & self) +{ self( self.get() ); } + void f11( coro_tuple::caller_type & self) { boost::tuple<int&,int&> tpl( self.get().get< 0 >(), self.get().get< 1 >() ); @@ -338,6 +826,18 @@ void test_ptr() BOOST_CHECK( ! coro); } +void test_const_ptr() +{ + int a = 3; + coro_const_ptr coro( f91, & a); + BOOST_CHECK( coro); + int const* res = coro.get(); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( & a, res); + coro( & a); + BOOST_CHECK( ! coro); +} + void test_ref() { int a = 3; @@ -350,6 +850,18 @@ void test_ref() BOOST_CHECK( ! coro); } +void test_const_ref() +{ + int a = 3; + coro_const_ref coro( f101, a); + BOOST_CHECK( coro); + int const& res = coro.get(); + BOOST_CHECK( coro); + BOOST_CHECK_EQUAL( & a, & res); + coro( a); + BOOST_CHECK( ! coro); +} + void test_tuple() { int a = 3, b = 7; @@ -507,6 +1019,7 @@ void test_post() coro( -1); BOOST_CHECK( ! coro); } +#endif boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { @@ -516,15 +1029,19 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* []) test->add( BOOST_TEST_CASE( & test_move) ); test->add( BOOST_TEST_CASE( & test_complete) ); test->add( BOOST_TEST_CASE( & test_jump) ); - test->add( BOOST_TEST_CASE( & test_pre) ); - test->add( BOOST_TEST_CASE( & test_post) ); test->add( BOOST_TEST_CASE( & test_result_int) ); test->add( BOOST_TEST_CASE( & test_result_string) ); test->add( BOOST_TEST_CASE( & test_arg_int) ); test->add( BOOST_TEST_CASE( & test_arg_string) ); test->add( BOOST_TEST_CASE( & test_fp) ); test->add( BOOST_TEST_CASE( & test_ptr) ); + test->add( BOOST_TEST_CASE( & test_const_ptr) ); +#ifndef BOOST_COROUTINES_V2 + test->add( BOOST_TEST_CASE( & test_pre) ); + test->add( BOOST_TEST_CASE( & test_post) ); +#endif test->add( BOOST_TEST_CASE( & test_ref) ); + test->add( BOOST_TEST_CASE( & test_const_ref) ); test->add( BOOST_TEST_CASE( & test_tuple) ); test->add( BOOST_TEST_CASE( & test_unwind) ); test->add( BOOST_TEST_CASE( & test_no_unwind) );