From a7c36808de8d462c8cf7503e5fa73625e7d9bfe1 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Thu, 6 Jun 2013 17:26:45 +0000 Subject: [PATCH] coroutine: new push/pull interface [SVN r84657] --- doc/coro.qbk | 5 + doc/coroutine.qbk | 798 +--------------- doc/old.qbk | 809 ++++++++++++++++ doc/unidirect.qbk | 878 ++++++++++++++++++ example/c++11/fibonacci.cpp | 2 +- example/c++11/same_fringe.cpp | 2 +- example/echo.cpp | 2 +- example/fibonacci.cpp | 2 +- example/parallel.cpp | 2 +- example/power.cpp | 2 +- example/same_fringe.cpp | 2 +- example/segmented_stack.cpp | 2 +- example/tree.h | 2 +- example/unwind.cpp | 2 +- include/boost/coroutine/coroutine.hpp | 2 +- include/boost/coroutine/detail/config.hpp | 4 +- include/boost/coroutine/v1/coroutine.hpp | 6 +- include/boost/coroutine/v1/detail/arg.hpp | 6 +- .../coroutine/v1/detail/coroutine_base.hpp | 6 +- .../v1/detail/coroutine_base_resume.hpp | 6 +- .../coroutine/v1/detail/coroutine_caller.hpp | 6 +- .../coroutine/v1/detail/coroutine_get.hpp | 6 +- .../coroutine/v1/detail/coroutine_object.hpp | 6 +- .../coroutine/v1/detail/coroutine_op.hpp | 6 +- include/boost/coroutine/v2/coroutine.hpp | 6 +- .../coroutine/v2/detail/coroutine_object.hpp | 423 --------- .../v2/detail/pull_coroutine_base.hpp | 6 +- .../v2/detail/pull_coroutine_caller.hpp | 6 +- .../v2/detail/pull_coroutine_object.hpp | 6 +- .../v2/detail/push_coroutine_base.hpp | 6 +- .../v2/detail/push_coroutine_caller.hpp | 6 +- .../v2/detail/push_coroutine_object.hpp | 6 +- include/boost/coroutine/v2/pull_corotuine.hpp | 355 ------- include/boost/coroutine/v2/push_coroutine.hpp | 357 ------- performance/performance.cpp | 2 +- test/test_coroutine.cpp | 4 +- 36 files changed, 1757 insertions(+), 1990 deletions(-) create mode 100644 doc/old.qbk create mode 100644 doc/unidirect.qbk delete mode 100644 include/boost/coroutine/v2/detail/coroutine_object.hpp delete mode 100644 include/boost/coroutine/v2/pull_corotuine.hpp delete mode 100644 include/boost/coroutine/v2/push_coroutine.hpp diff --git a/doc/coro.qbk b/doc/coro.qbk index 01f1bad..31f77c8 100644 --- a/doc/coro.qbk +++ b/doc/coro.qbk @@ -39,6 +39,8 @@ [def __ctx__ ['context]] [def __coro__ ['coroutine]] +[def __push_coro__ ['push_coroutine]] +[def __pull_coro__ ['pull_coroutine]] [def __coro_fn__ ['coroutine-function]] [def __coros__ ['coroutines]] [def __not_a_coro__ ['not-a-coroutine]] @@ -66,6 +68,9 @@ [def __getline__ ['std::getline()]] [def __handle_read__ ['session::handle_read()]] [def __io_service__ ['boost::asio::io_sevice]] +[def __pull_coro_get__ ['boost::coroutines::pull_coroutine<>::get()]] +[def __pull_coro_op__ ['boost::coroutines::push_coroutine<>::operator()]] +[def __push_coro_op__ ['boost::coroutines::push_coroutine<>::operator()]] [def __server__ ['server]] [def __session__ ['session]] [def __stack_context__ ['boost::coroutines::stack_context]] diff --git a/doc/coroutine.qbk b/doc/coroutine.qbk index 1a9d063..e1b7840 100644 --- a/doc/coroutine.qbk +++ b/doc/coroutine.qbk @@ -7,800 +7,10 @@ [section:coroutine Coroutine] -Each instance of __coro__ has its own context of execution (CPU registers and -stack space) or represents __not_a_coro__ (similar to __thread__). -Objects of type __coro__ are moveable but not copyable and can be returned by a -function. +__boost_coroutine__ provides two interfaces - one with uni- and one with bidirectional +data transfer. - boost::coroutines::coroutine< void() > f(); - - void g() - { - boost::coroutines::coroutine< void() > c( f() ); - c(); - } - -[note __boost_move__ is used to emulate rvalue references.] - - -[heading Creating a coroutine] - -A new __coro__ is created from a __coro_fn__ (function or functor) which will be -executed in a new __ctx__ (CPU registers and stack space). - -[note __coro_fn__ is required to return ['void] and accept a reference of type -__coro_caller__.] - -The template argument __signature__ determines the data-types transferred to -__coro_fn__ and from __coro_fn__ by calling __coro_op__ and __coro_get__. - - typedef boost::coroutines::coroutine< int( std::string const&) > coro_t; - - // void f( boost::coroutine< std::string const&( int) > & ca) - void f( coro_t::caller_type & ca) - { - ... - // access argument - std::string str( ca.get() ); - ... - ca( 7); - ... - } - - std::string str; - ... - coro_t c( f); - // pass argument - c( str); - // returned value - int res = c.get(); - - -The __coro_fn__ is started at __coro__ construction (similar to __thread__) -in a newly created __coro__ complete with registers, flags, stack and -instruction pointer. -If __coro_fn__ requires some arguments (types defined by __signature__) -on start-up those parameters must be applied to the __coro__ constructor. -A single arguments can be passed as it is: - - typedef boost::coroutines::coroutine< int( std::string const&) > coro_t; - - // void f( boost::coroutine< std::string const&( int) > & ca) - void f( coro_t::caller_type & ca); - - std::string str("abc"); - coro_t c( f, str); - - -For multiple arguments __args__ must be used (it is a typedef of __tuple__): - - typedef boost::coroutines::coroutine< int( int, std::string const&) > coro_t; - - // void f( boost::coroutine< boost::tuple< int, std::string const& >( int) > & ca) - void f( coro_t::caller_type & ca); - - std::string str("abc"); - coro_t c( f, coro_t::arguments( 7, str) ); - - -[note The maximum number of arguments is limited to 10 (limit defined by -__boost_tuple__).] - -[note Parameters bound with __bind__ to __coro_fn__ will not be part of the -__coro_op__ signature.] - -__attrs__, an additional constructor argument of __coro__, defines the stack -size, stack unwinding and floating-point preserving behaviour used for __ctx__ -construction. - -The __coro__ constructor uses the __stack_allocator_concept__ to allocate an -associated stack, and the destructor uses the same __stack_allocator_concept__ -to deallocate the stack. The default __stack_allocator_concept__ is -__stack_allocator__, but a custom stack-allocator can be passed to the -constructor. - - -[heading Calling a coroutine] - -The execution control is transferred to __coro__ at construction (__coro_fn__ -entered) - when control should be returned to the original calling routine, -invoke __coro_op__ on the first argument of type __coro_caller__ inside -__coro_fn__. __coro_caller__ is a typedef of __coro__ with an inverted -__signature__. Inverted __signature__ means that the return type becomes an -argument and vice versa. Multiple arguments are wrapped into __tuple__. - - void f( boost::coroutines::coroutine< std::string const&( int) & ca); - boost::coroutines::coroutine< int( std::string const&) > c1( f); - - void g( boost::coroutines::coroutine< boost::tuple< X, Y >( int) & ca); - boost::coroutines::coroutine< int( X, X) > c2( g); - - -The current coroutine information (registers, flags, and stack and instruction -pointer) is saved and the original context information is restored. Calling -__coro_op__ resumes execution in the coroutine after saving the new state of the -original routine. - - typedef boost::coroutines::coroutine< void() > coro_t; - - // void fn( boost::coroutines::coroutine< void() > & ca, int j) - void fn( coro_t::caller_type & ca, int j) - { - for( int i = 0; i < j; ++i) - { - std::cout << "fn(): local variable i == " << i << std::endl; - - // save current coroutine - // value of local variable is preserved - // transfer execution control back to main() - ca(); - - // coroutine<>::operator()() was called - // execution control transferred back from main() - } - } - - int main( int argc, char * argv[]) - { - // bind parameter '7' to coroutine-fn - coro_t c( boost::bind( fn, _1, 7) ); - - std::cout << "main() starts coroutine c" << std::endl; - - while ( c) - { - std::cout << "main() calls coroutine c" << std::endl; - // execution control is transferred to c - c(); - } - - std::cout << "Done" << std::endl; - - return EXIT_SUCCESS; - } - - output: - main() starts coroutine c - fn(): local variable i == 0 - main() calls coroutine c - fn(): local variable i == 1 - main() calls coroutine c - fn(): local variable i == 2 - main() calls coroutine c - fn(): local variable i == 3 - main() calls coroutine c - fn(): local variable i == 4 - main() calls coroutine c - fn(): local variable i == 5 - main() calls coroutine c - fn(): local variable i == 6 - main() calls coroutine c - Done - -[warning Calling __coro_op__ from inside the [_same] coroutine results in -undefined behaviour.] - - -[heading Transfer of data] - -__signature__, the template argument of __coro__, defines the types transferred -to and returned from the __coro_fn__, e.g. it determines the signature of -__coro_op__ and the return-type of __coro_get__. - -[note __coro_caller__ is not part of __signature__ and __coro_fn__ is required -to return void and accept __coro_caller__ as argument.] - -__coro_op__ accepts arguments as defined in __signature__ and returns a -reference to __coro__. The arguments passed to __coro_op__, in one coroutine, -is returned (as a __tuple__) by __coro_get__ in the other coroutine. -If __coro__ is constructed and arguments are passed to the constructor, the -__coro_fn__ will be entered and the arguments are accessed thorough __coro_get__ -in __coro_fn__ on entry. - -The value given to __coro_op__ of __coro_caller__, in one coroutine, is returned by -__coro_get__ in the other routine. - - typedef boost::coroutines::coroutine< int( int) > coro_t; - - // void fn( boost::coroutines::coroutine< int( int) > & ca) - void fn( coro_t::caller_type & ca) - { - // access the integer argument given to coroutine ctor - int i = ca.get(); - std::cout << "fn(): local variable i == " << i << std::endl; - - // save current coroutine context and - // transfer execution control back to caller - // pass content of variable 'i' to caller - // after execution control is returned back coroutine<>::operator() - // returns and the transferred integer s accessed via coroutine<>::get() - i = ca( i).get(); - - // i == 10 because c( 10) in main() - std::cout << "fn(): local variable i == " << i << std::endl; - ca( i); - } - - int main( int argc, char * argv[]) - { - std::cout << "main(): call coroutine c" << std::endl; - coro_t c( fn, 7); - - int x = c.get(); - std::cout << "main(): transferred value: " << x << std::endl; - - x = c( 10).get(); - std::cout << "main(): transferred value: " << x << std::endl; - - std::cout << "Done" << std::endl; - - return EXIT_SUCCESS; - } - - output: - main(): call coroutine c - fn(): local variable i == 7 - main(): transferred value: 7 - fn(): local variable i == 10 - main(): transferred value: 10 - Done - - -[heading __coro_fn__ with multiple arguments] - -If __coro_fn__ has more than one argument __coro_op__ has the same size of -arguments and __coro_get__ from __coro_caller__ returns a __tuple__ corresponding -to the arguments of __signature__. __tie__ helps to access the values stored in -the __tuple__ returned by __coro_get__. - - typedef boost::coroutines::coroutine< int(int,int) > coro_t; - - // void fn( boost::coroutines::coroutine< boost::tuple< int, int >( int) > & ca) - void fn( coro_t::caller_type & ca) - { - int a, b; - boost::tie( a, b) = ca.get(); - boost::tie( a, b) = ca( a + b).get(); - ca( a + b); - } - - int main( int argc, char * argv[]) - { - std::cout << "main(): call coroutine c" << std::endl; - coro_t coro( fn, coro_t::arguments( 3, 7) ); - - int res = coro.get(); - std::cout << "main(): 3 + 7 == " << res << std::endl; - - res = coro( 5, 7).get(); - std::cout << "main(): 5 + 7 == " << res << std::endl; - - std::cout << "Done" << std::endl; - - return EXIT_SUCCESS; - } - - output: - main(): call coroutine c - main(): 3 + 7 == 10 - main(): 5 + 7 == 12 - Done - - -[heading Transfer of pointers and references] - -You can transfer references and pointers from and to coroutines but as usual -you must take care (scope, no re-assignment of const references etc.). -In the following code `x` points to `local` which is allocated on stack of -`c`. When `c` goes out of scope the stack becomes deallocated. Using `x` -after `c` is gone will fail! - - struct X - { - void g(); - }; - - typedef boost::coroutines::coroutine< X*() > coro_t; - - // void fn( boost::coroutines::coroutine< void( X*) > & ca) - void fn( coro_t::caller_t & ca) { - X local; - ca( & local); - } - - int main() { - X * x = 0; - { - coro_t c( fn); - x = c.get(); // let x point to X on stack owned by c - // stack gets unwound -> X will be destructed - } - x->g(); // segmentation fault! - return EXIT_SUCCESS; - } - - -[heading Range iterators] - -__boost_coroutine__ provides output- and input-iterators using __boost_range__. -`coroutine< T() >` can be used via output-iterators using __begin__ and __end__. - - typedef boost::coroutines::coroutine< int() > coro_t; - typedef boost::range_iterator< coro_t >::type iterator_t; - - // void power( boost::coroutines::coroutine< void( int) > & ca, int number, int exponent) - void power( coro_t::caller_type & ca, int number, int exponent) - { - int counter = 0; - int result = 1; - while ( counter++ < exponent) - { - result = result * number; - ca( result); - } - } - - int main() - { - coro_t c( boost::bind( power, _1, 2, 8) ); - iterator_t e( boost::end( c) ); - for ( iterator_t i( boost::begin( c) ); i != e; ++i) - std::cout << * i << " "; - - std::cout << "\nDone" << std::endl; - - return EXIT_SUCCESS; - } - - output: - 2 4 8 16 32 64 128 256 - Done - -`BOOST_FOREACH` can be used to iterate over the coroutine range too. - - typedef boost::coroutines::coroutine< int() > coro_t; - typedef boost::range_iterator< coro_t >::type iterator_t; - - // void power( boost::coroutines::coroutine< void( int) > & ca, int number, int exponent) - void power( coro_t::caller_type & ca, int number, int exponent) - { - int counter = 0; - int result = 1; - while ( counter++ < exponent) - { - result = result * number; - ca( result); - } - } - - int main() - { - coro_t c( boost::bind( power, _1, 2, 8) ); - BOOST_FOREACH( int i, c) - { std::cout << i << " "; } - - std::cout << "\nDone" << std::endl; - - return EXIT_SUCCESS; - } - - output: - 2 4 8 16 32 64 128 256 - Done - - -Input iterators are created from coroutines of type `coroutine< void( T) >`. - - - -[heading Exit a __coro_fn__] - -__coro_fn__ is exited with a simple return statement jumping back to the calling -routine. The __coro__ becomes complete, e.g. __coro_bool__ will return 'false'. - - typedef boost::coroutines::coroutine< int(int,int) > coro_t; - - // void power( boost::coroutines::coroutine< boost::tuple< int, int >( int) > & ca, int number, int exponent) - void fn( coro_t::caller_type & ca) - { - int a, b; - boost::tie( a, b) = ca.get(); - boost::tie( a, b) = ca( a + b).get(); - ca( a + b); - } - - int main( int argc, char * argv[]) - { - std::cout << "main(): call coroutine c" << std::endl; - coro_t coro( fn, coro_t::arguments( 3, 7) ); - - BOOST_ASSERT( coro); - int res = coro.get(); - std::cout << "main(): 3 + 7 == " << res << std::endl; - - res = coro( 5, 7).get(); - BOOST_ASSERT( ! coro); - std::cout << "main(): 5 + 7 == " << res << std::endl; - - std::cout << "Done" << std::endl; - - return EXIT_SUCCESS; - } - - output: - main(): call coroutine c - main(): 3 + 7 == 10 - main(): 5 + 7 == 12 - Done - -[important After returning from __coro_fn__ the __coro__ is complete (can not -resumed with __coro_op__).] - - -[heading Exceptions in __coro_fn__] - -An exception thrown inside __coro_fn__ will transferred via exception-pointer -(see __boost_exception__ for details) and re-thrown by constructor or -__coro_op__. - - typedef boost::coroutines::coroutine< void() > coro_t; - - // void fn( boost::coroutines::coroutine< void() > & ca) - void fn( coro_t::caller_type & ca) - { - ca(); - throw std::runtime_error("abc"); - } - - int main( int argc, char * argv[]) - { - coro_t c( f); - try - { - c(); - } - catch ( std::exception const& e) - { - std::cout << "exception catched:" << e.what() << std::endl; - return EXIT_FAILURE; - } - - std::cout << "Done" << std::endl; - - return EXIT_SUCCESS; - } - - output: - exception catched: abc - -[important Code executed by coroutine must not prevent the propagation of the -__forced_unwind__ exception. Absorbing that exception will cause stack -unwinding to fail. Thus, any code that catches all exceptions must re-throw the -pending exception.] - - try - { - // code that might throw - } - catch( forced_unwind) - { - throw; - } - catch(...) - { - // possibly not re-throw pending exception - } - - -[heading Stack unwinding] - -Sometimes it is necessary to unwind the stack of an unfinished coroutine to -destroy local stack variables so they can release allocated resources (RAII -pattern). The third argument of the coroutine constructor, `do_unwind`, -indicates whether the destructor should unwind the stack (stack is unwound by -default). - -Stack unwinding assumes the following preconditions: - -* The coroutine is not __not_a_coro__ -* The coroutine is not complete -* The coroutine is not running -* The coroutine owns a stack - -After unwinding, a __coro__ is complete. - - - typedef boost::coroutines::coroutine< void() > coro_t; - - struct X - { - X() - { std::cout << "X()" << std::endl; } - - ~X() - { std::cout << "~X()" << std::endl; } - }; - - // void fn( boost::coroutines::coroutine< void() > & ca) - void fn( coro_t::caller_type & ca) - { - X x; - - for ( int = 0;; ++i) - { - std::cout << "fn(): " << i << std::endl; - // transfer execution control back to main() - ca(); - } - } - - int main( int argc, char * argv[]) - { - { - coro_t c( fn, - boost::coroutines::attributes( - boost::ctx::default_stacksize(), - boost::coroutines::stack_unwind) ); - - c(); - c(); - c(); - c(); - c(); - - std::cout << "c is complete: " << std::boolalpha << c.is_complete() << "\n"; - } - - std::cout << "Done" << std::endl; - - return EXIT_SUCCESS; - } - - output: - X() - fn(): 0 - fn(): 1 - fn(): 2 - fn(): 3 - fn(): 4 - fn(): 5 - c is complete: false - ~X() - Done - -[important You must not swallow __forced_unwind__ exceptions!] - - -[heading FPU preserving] - -Some applications do not use floating-point registers and can disable preserving -fpu registers for performance reasons. - -[note According to the calling convention the FPU registers are preserved by default.] - - -[section:coroutine Class `coroutine`] - - #include - - template< typename Signature > - class coroutine; - - template< - typename R, - typename ArgTypes... - > - class coroutine< R ( ArgTypes...) > - { - public: - typedef unspec-type caller_type; - typedef unspec-type arguments; - - coroutine(); - - template< - typename Fn, - typename StackAllocator = stack_allocator, - typename Allocator = std::allocator< coroutine > - > - coroutine( Fn fn, attributes const& attr = attributes(), - StackAllocator const& stack_alloc = StackAllocator(), - Allocator const& alloc = Allocator() ); - - template< - typename Fn, - typename StackAllocator = stack_allocator, - typename Allocator = std::allocator< coroutine > - > - coroutine( Fn fn, arguments const& args, - attributes const& attr = attributes(), - StackAllocator const& stack_alloc = StackAllocator(), - Allocator const& alloc = Allocator() ); - - template< - typename Fn, - typename StackAllocator = stack_allocator, - typename Allocator = std::allocator< coroutine > - > - coroutine( Fn && fn, attributes const& attr = attributes(), - StackAllocator stack_alloc = StackAllocator(), - Allocator const& alloc = Allocator() ); - - template< - typename Fn, - typename StackAllocator = stack_allocator, - typename Allocator = std::allocator< coroutine > - > - coroutine( Fn && fn arguments const& args, - attributes const& attr = attributes(), - StackAllocator stack_alloc = StackAllocator(), - Allocator const& alloc = Allocator() ); - - coroutine( coroutine && other); - - coroutine & operator=( coroutine && other); - - operator unspecified-bool-type() const; - - bool operator!() const; - - void swap( coroutine & other); - - bool empty() const; - - coroutine & operator()(A0 a0, ..., A9 a9); - - R get() const; - }; - - template< typename Signature > - void swap( coroutine< Signature > & l, coroutine< Signature > & r); - - template< typename T > - range_iterator< coroutine< T() > >::type begin( coroutine< T() > &); - template< typename T > - range_iterator< coroutine< void(T) > >::type begin( coroutine< void(T) > &); - - template< typename T > - range_iterator< coroutine< T() > >::type end( coroutine< T() > &); - template< typename T > - range_iterator< coroutine< void(T) > >::type end( coroutine< void(T) > &); - -[heading `coroutine()`] -[variablelist -[[Effects:] [Creates a coroutine representing __not_a_coro__.]] -[[Throws:] [Nothing.]] -] - -[heading `template< typename Fn, typename StackAllocator, typename Allocator > - coroutine( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] -[variablelist -[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() -when ! is_stack_unbound().]] -[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` -determines stack clean-up and preserving floating-point registers. -For allocating/deallocating the stack `stack_alloc` is used and internal -data are allocated by Allocator.]] -] - -[heading `template< typename Fn, typename StackAllocator, typename Allocator > - coroutine( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] -[variablelist -[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() -when ! is_stack_unbound().]] -[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` -determines stack clean-up and preserving floating-point registers. -For allocating/deallocating the stack `stack_alloc` is used and internal -data are allocated by Allocator.]] -] - -[heading `coroutine( coroutine && other)`] -[variablelist -[[Effects:] [Moves the internal data of `other` to `*this`. -`other` becomes __not_a_coro__.]] -[[Throws:] [Nothing.]] -] - -[heading `coroutine & operator=( coroutine && other)`] -[variablelist -[[Effects:] [Destroys the internal data of `*this` and moves the -internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] -[[Throws:] [Nothing.]] -] - -[heading `operator unspecified-bool-type() const`] -[variablelist -[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function -has returned (completed), the function returns false. Otherwise true.]] -[[Throws:] [Nothing.]] -] - -[heading `bool operator!() const`] -[variablelist -[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function -has returned (completed), the function returns true. Otherwise false.]] -[[Throws:] [Nothing.]] -] - -[heading `bool empty()`] -[variablelist -[[Returns:] [If `*this` refers to __not_a_coro__, the function returns true. -Otherwise false.]] -[[Throws:] [Nothing.]] -] - -[heading `coroutine<> & operator()(A0 a0, A9 a9)`] -[variablelist -[[Preconditions:] [operator unspecified-bool-type() returns true for `*this`.] -[[Effects:] [Execution control is transferred to __coro_fn__ and the arguments -`a0`,..., are passed to the coroutine-function.]] -[[Throws:] [Exceptions thrown inside __coro_fn__.]] -] - -[heading `R get()()`] -[variablelist -[[Preconditions:] [`*this` is not a __not_a_coro__, `! is_complete()`.]] -[[Returns:] [Returns data transferred from coroutine-function via __coro_op__ -of __coro_caller__.]] -[[Throws:] [Nothing.]] -] - -[heading `void swap( coroutine & other)`] -[variablelist -[[Effects:] [Swaps the internal data from `*this` with the values -of `other`.]] -[[Throws:] [Nothing.]] -] - -[heading `T caller_type::operator()( R)`] -[variablelist -[[Effects:] [Gives execution control back to calling context by returning -a value of type R. The return type of this function is a __tuple__ containing -the arguments passed to __coro_op__.]] -[[Throws:] [Nothing.]] -] - -[heading Non-member function `swap()`] - - template< typename Signature > - void swap( coroutine< Signature > & l, coroutine< Signature > & r); - -[variablelist -[[Effects:] [As if 'l.swap( r)'.]] -] - -[heading Non-member function `begin( coroutine< T() > &)`] - template< typename T > - range_iterator< coroutine< T() > >::type begin( coroutine< T() > &); - -[variablelist -[[Returns:] [Returns a range-iterator (input-iterator).]] -] - -[heading Non-member function `begin( coroutine< void(T) > &)`] - template< typename T > - range_iterator< coroutine< void(T) > >::type begin( coroutine< void(T) > &); - -[variablelist -[[Returns:] [Returns a range-iterator (output-iterator).]] -] - -[heading Non-member function `end( coroutine< T() > &)`] - template< typename T > - range_iterator< coroutine< T() > >::type end( coroutine< T() > &); - -[variablelist -[[Returns:] [Returns a end range-iterator (input-iterator).]] -] - -[heading Non-member function `end( coroutine< void(T) > &)`] - template< typename T > - range_iterator< coroutine< void(T) > >::type end( coroutine< void(T) > &); - -[variablelist -[[Returns:] [Returns a end range-iterator (output-iterator).]] -] - -[endsect] +[include unidirect.qbk] +[include old.qbk] [endsect] diff --git a/doc/old.qbk b/doc/old.qbk new file mode 100644 index 0000000..c2ef881 --- /dev/null +++ b/doc/old.qbk @@ -0,0 +1,809 @@ +[/ + 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 +] + +[section:old Bidirectional coroutine (version 1)] + +[note This interface is deprecated but can be used by compiling the code with +macro BOOST_COROUTINES_OLD.] + +Each instance of __coro__ has its own context of execution (CPU registers and +stack space) or represents __not_a_coro__ (similar to __thread__). +Objects of type __coro__ are moveable but not copyable and can be returned by a +function. + + boost::coroutines::coroutine< void() > f(); + + void g() + { + boost::coroutines::coroutine< void() > c( f() ); + c(); + } + +[note __boost_move__ is used to emulate rvalue references.] + + +[heading Creating a coroutine] + +A new __coro__ is created from a __coro_fn__ (function or functor) which will be +executed in a new __ctx__ (CPU registers and stack space). + +[note __coro_fn__ is required to return ['void] and accept a reference of type +__coro_caller__.] + +The template argument __signature__ determines the data-types transferred to +__coro_fn__ and from __coro_fn__ by calling __coro_op__ and __coro_get__. + + typedef boost::coroutines::coroutine< int( std::string const&) > coro_t; + + // void f( boost::coroutine< std::string const&( int) > & ca) + void f( coro_t::caller_type & ca) + { + ... + // access argument + std::string str( ca.get() ); + ... + ca( 7); + ... + } + + std::string str; + ... + coro_t c( f); + // pass argument + c( str); + // returned value + int res = c.get(); + + +The __coro_fn__ is started at __coro__ construction (similar to __thread__) +in a newly created __coro__ complete with registers, flags, stack and +instruction pointer. +If __coro_fn__ requires some arguments (types defined by __signature__) +on start-up those parameters must be applied to the __coro__ constructor. +A single arguments can be passed as it is: + + typedef boost::coroutines::coroutine< int( std::string const&) > coro_t; + + // void f( boost::coroutine< std::string const&( int) > & ca) + void f( coro_t::caller_type & ca); + + std::string str("abc"); + coro_t c( f, str); + + +For multiple arguments __args__ must be used (it is a typedef of __tuple__): + + typedef boost::coroutines::coroutine< int( int, std::string const&) > coro_t; + + // void f( boost::coroutine< boost::tuple< int, std::string const& >( int) > & ca) + void f( coro_t::caller_type & ca); + + std::string str("abc"); + coro_t c( f, coro_t::arguments( 7, str) ); + + +[note The maximum number of arguments is limited to 10 (limit defined by +__boost_tuple__).] + +[note Parameters bound with __bind__ to __coro_fn__ will not be part of the +__coro_op__ signature.] + +__attrs__, an additional constructor argument of __coro__, defines the stack +size, stack unwinding and floating-point preserving behaviour used for __ctx__ +construction. + +The __coro__ constructor uses the __stack_allocator_concept__ to allocate an +associated stack, and the destructor uses the same __stack_allocator_concept__ +to deallocate the stack. The default __stack_allocator_concept__ is +__stack_allocator__, but a custom stack-allocator can be passed to the +constructor. + + +[heading Calling a coroutine] + +The execution control is transferred to __coro__ at construction (__coro_fn__ +entered) - when control should be returned to the original calling routine, +invoke __coro_op__ on the first argument of type __coro_caller__ inside +__coro_fn__. __coro_caller__ is a typedef of __coro__ with an inverted +__signature__. Inverted __signature__ means that the return type becomes an +argument and vice versa. Multiple arguments are wrapped into __tuple__. + + void f( boost::coroutines::coroutine< std::string const&( int) & ca); + boost::coroutines::coroutine< int( std::string const&) > c1( f); + + void g( boost::coroutines::coroutine< boost::tuple< X, Y >( int) & ca); + boost::coroutines::coroutine< int( X, X) > c2( g); + + +The current coroutine information (registers, flags, and stack and instruction +pointer) is saved and the original context information is restored. Calling +__coro_op__ resumes execution in the coroutine after saving the new state of the +original routine. + + typedef boost::coroutines::coroutine< void() > coro_t; + + // void fn( boost::coroutines::coroutine< void() > & ca, int j) + void fn( coro_t::caller_type & ca, int j) + { + for( int i = 0; i < j; ++i) + { + std::cout << "fn(): local variable i == " << i << std::endl; + + // save current coroutine + // value of local variable is preserved + // transfer execution control back to main() + ca(); + + // coroutine<>::operator()() was called + // execution control transferred back from main() + } + } + + int main( int argc, char * argv[]) + { + // bind parameter '7' to coroutine-fn + coro_t c( boost::bind( fn, _1, 7) ); + + std::cout << "main() starts coroutine c" << std::endl; + + while ( c) + { + std::cout << "main() calls coroutine c" << std::endl; + // execution control is transferred to c + c(); + } + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + main() starts coroutine c + fn(): local variable i == 0 + main() calls coroutine c + fn(): local variable i == 1 + main() calls coroutine c + fn(): local variable i == 2 + main() calls coroutine c + fn(): local variable i == 3 + main() calls coroutine c + fn(): local variable i == 4 + main() calls coroutine c + fn(): local variable i == 5 + main() calls coroutine c + fn(): local variable i == 6 + main() calls coroutine c + Done + +[warning Calling __coro_op__ from inside the [_same] coroutine results in +undefined behaviour.] + + +[heading Transfer of data] + +__signature__, the template argument of __coro__, defines the types transferred +to and returned from the __coro_fn__, e.g. it determines the signature of +__coro_op__ and the return-type of __coro_get__. + +[note __coro_caller__ is not part of __signature__ and __coro_fn__ is required +to return void and accept __coro_caller__ as argument.] + +__coro_op__ accepts arguments as defined in __signature__ and returns a +reference to __coro__. The arguments passed to __coro_op__, in one coroutine, +is returned (as a __tuple__) by __coro_get__ in the other coroutine. +If __coro__ is constructed and arguments are passed to the constructor, the +__coro_fn__ will be entered and the arguments are accessed thorough __coro_get__ +in __coro_fn__ on entry. + +The value given to __coro_op__ of __coro_caller__, in one coroutine, is returned by +__coro_get__ in the other routine. + + typedef boost::coroutines::coroutine< int( int) > coro_t; + + // void fn( boost::coroutines::coroutine< int( int) > & ca) + void fn( coro_t::caller_type & ca) + { + // access the integer argument given to coroutine ctor + int i = ca.get(); + std::cout << "fn(): local variable i == " << i << std::endl; + + // save current coroutine context and + // transfer execution control back to caller + // pass content of variable 'i' to caller + // after execution control is returned back coroutine<>::operator() + // returns and the transferred integer s accessed via coroutine<>::get() + i = ca( i).get(); + + // i == 10 because c( 10) in main() + std::cout << "fn(): local variable i == " << i << std::endl; + ca( i); + } + + int main( int argc, char * argv[]) + { + std::cout << "main(): call coroutine c" << std::endl; + coro_t c( fn, 7); + + int x = c.get(); + std::cout << "main(): transferred value: " << x << std::endl; + + x = c( 10).get(); + std::cout << "main(): transferred value: " << x << std::endl; + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + main(): call coroutine c + fn(): local variable i == 7 + main(): transferred value: 7 + fn(): local variable i == 10 + main(): transferred value: 10 + Done + + +[heading __coro_fn__ with multiple arguments] + +If __coro_fn__ has more than one argument __coro_op__ has the same size of +arguments and __coro_get__ from __coro_caller__ returns a __tuple__ corresponding +to the arguments of __signature__. __tie__ helps to access the values stored in +the __tuple__ returned by __coro_get__. + + typedef boost::coroutines::coroutine< int(int,int) > coro_t; + + // void fn( boost::coroutines::coroutine< boost::tuple< int, int >( int) > & ca) + void fn( coro_t::caller_type & ca) + { + int a, b; + boost::tie( a, b) = ca.get(); + boost::tie( a, b) = ca( a + b).get(); + ca( a + b); + } + + int main( int argc, char * argv[]) + { + std::cout << "main(): call coroutine c" << std::endl; + coro_t coro( fn, coro_t::arguments( 3, 7) ); + + int res = coro.get(); + std::cout << "main(): 3 + 7 == " << res << std::endl; + + res = coro( 5, 7).get(); + std::cout << "main(): 5 + 7 == " << res << std::endl; + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + main(): call coroutine c + main(): 3 + 7 == 10 + main(): 5 + 7 == 12 + Done + + +[heading Transfer of pointers and references] + +You can transfer references and pointers from and to coroutines but as usual +you must take care (scope, no re-assignment of const references etc.). +In the following code `x` points to `local` which is allocated on stack of +`c`. When `c` goes out of scope the stack becomes deallocated. Using `x` +after `c` is gone will fail! + + struct X + { + void g(); + }; + + typedef boost::coroutines::coroutine< X*() > coro_t; + + // void fn( boost::coroutines::coroutine< void( X*) > & ca) + void fn( coro_t::caller_t & ca) { + X local; + ca( & local); + } + + int main() { + X * x = 0; + { + coro_t c( fn); + x = c.get(); // let x point to X on stack owned by c + // stack gets unwound -> X will be destructed + } + x->g(); // segmentation fault! + return EXIT_SUCCESS; + } + + +[heading Range iterators] + +__boost_coroutine__ provides output- and input-iterators using __boost_range__. +`coroutine< T() >` can be used via output-iterators using __begin__ and __end__. + + typedef boost::coroutines::coroutine< int() > coro_t; + typedef boost::range_iterator< coro_t >::type iterator_t; + + // void power( boost::coroutines::coroutine< void( int) > & ca, int number, int exponent) + void power( coro_t::caller_type & ca, int number, int exponent) + { + int counter = 0; + int result = 1; + while ( counter++ < exponent) + { + result = result * number; + ca( result); + } + } + + int main() + { + coro_t c( boost::bind( power, _1, 2, 8) ); + iterator_t e( boost::end( c) ); + for ( iterator_t i( boost::begin( c) ); i != e; ++i) + std::cout << * i << " "; + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; + } + + output: + 2 4 8 16 32 64 128 256 + Done + +`BOOST_FOREACH` can be used to iterate over the coroutine range too. + + typedef boost::coroutines::coroutine< int() > coro_t; + typedef boost::range_iterator< coro_t >::type iterator_t; + + // void power( boost::coroutines::coroutine< void( int) > & ca, int number, int exponent) + void power( coro_t::caller_type & ca, int number, int exponent) + { + int counter = 0; + int result = 1; + while ( counter++ < exponent) + { + result = result * number; + ca( result); + } + } + + int main() + { + coro_t c( boost::bind( power, _1, 2, 8) ); + BOOST_FOREACH( int i, c) + { std::cout << i << " "; } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; + } + + output: + 2 4 8 16 32 64 128 256 + Done + + +Input iterators are created from coroutines of type `coroutine< void( T) >`. + + + +[heading Exit a __coro_fn__] + +__coro_fn__ is exited with a simple return statement jumping back to the calling +routine. The __coro__ becomes complete, e.g. __coro_bool__ will return 'false'. + + typedef boost::coroutines::coroutine< int(int,int) > coro_t; + + // void power( boost::coroutines::coroutine< boost::tuple< int, int >( int) > & ca, int number, int exponent) + void fn( coro_t::caller_type & ca) + { + int a, b; + boost::tie( a, b) = ca.get(); + boost::tie( a, b) = ca( a + b).get(); + ca( a + b); + } + + int main( int argc, char * argv[]) + { + std::cout << "main(): call coroutine c" << std::endl; + coro_t coro( fn, coro_t::arguments( 3, 7) ); + + BOOST_ASSERT( coro); + int res = coro.get(); + std::cout << "main(): 3 + 7 == " << res << std::endl; + + res = coro( 5, 7).get(); + BOOST_ASSERT( ! coro); + std::cout << "main(): 5 + 7 == " << res << std::endl; + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + main(): call coroutine c + main(): 3 + 7 == 10 + main(): 5 + 7 == 12 + Done + +[important After returning from __coro_fn__ the __coro__ is complete (can not +resumed with __coro_op__).] + + +[heading Exceptions in __coro_fn__] + +An exception thrown inside __coro_fn__ will transferred via exception-pointer +(see __boost_exception__ for details) and re-thrown by constructor or +__coro_op__. + + typedef boost::coroutines::coroutine< void() > coro_t; + + // void fn( boost::coroutines::coroutine< void() > & ca) + void fn( coro_t::caller_type & ca) + { + ca(); + throw std::runtime_error("abc"); + } + + int main( int argc, char * argv[]) + { + coro_t c( f); + try + { + c(); + } + catch ( std::exception const& e) + { + std::cout << "exception catched:" << e.what() << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + exception catched: abc + +[important Code executed by coroutine must not prevent the propagation of the +__forced_unwind__ exception. Absorbing that exception will cause stack +unwinding to fail. Thus, any code that catches all exceptions must re-throw the +pending exception.] + + try + { + // code that might throw + } + catch( forced_unwind) + { + throw; + } + catch(...) + { + // possibly not re-throw pending exception + } + + +[heading Stack unwinding] + +Sometimes it is necessary to unwind the stack of an unfinished coroutine to +destroy local stack variables so they can release allocated resources (RAII +pattern). The third argument of the coroutine constructor, `do_unwind`, +indicates whether the destructor should unwind the stack (stack is unwound by +default). + +Stack unwinding assumes the following preconditions: + +* The coroutine is not __not_a_coro__ +* The coroutine is not complete +* The coroutine is not running +* The coroutine owns a stack + +After unwinding, a __coro__ is complete. + + + typedef boost::coroutines::coroutine< void() > coro_t; + + struct X + { + X() + { std::cout << "X()" << std::endl; } + + ~X() + { std::cout << "~X()" << std::endl; } + }; + + // void fn( boost::coroutines::coroutine< void() > & ca) + void fn( coro_t::caller_type & ca) + { + X x; + + for ( int = 0;; ++i) + { + std::cout << "fn(): " << i << std::endl; + // transfer execution control back to main() + ca(); + } + } + + int main( int argc, char * argv[]) + { + { + coro_t c( fn, + boost::coroutines::attributes( + boost::ctx::default_stacksize(), + boost::coroutines::stack_unwind) ); + + c(); + c(); + c(); + c(); + c(); + + std::cout << "c is complete: " << std::boolalpha << c.is_complete() << "\n"; + } + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + X() + fn(): 0 + fn(): 1 + fn(): 2 + fn(): 3 + fn(): 4 + fn(): 5 + c is complete: false + ~X() + Done + +[important You must not swallow __forced_unwind__ exceptions!] + + +[heading FPU preserving] + +Some applications do not use floating-point registers and can disable preserving +fpu registers for performance reasons. + +[note According to the calling convention the FPU registers are preserved by default.] + + +[section:coroutine Class `coroutine`] + + #include + + template< typename Signature > + class coroutine; + + template< + typename R, + typename ArgTypes... + > + class coroutine< R ( ArgTypes...) > + { + public: + typedef unspec-type caller_type; + typedef unspec-type arguments; + + coroutine(); + + template< + typename Fn, + typename StackAllocator = stack_allocator, + typename Allocator = std::allocator< coroutine > + > + coroutine( Fn fn, attributes const& attr = attributes(), + StackAllocator const& stack_alloc = StackAllocator(), + Allocator const& alloc = Allocator() ); + + template< + typename Fn, + typename StackAllocator = stack_allocator, + typename Allocator = std::allocator< coroutine > + > + coroutine( Fn fn, arguments const& args, + attributes const& attr = attributes(), + StackAllocator const& stack_alloc = StackAllocator(), + Allocator const& alloc = Allocator() ); + + template< + typename Fn, + typename StackAllocator = stack_allocator, + typename Allocator = std::allocator< coroutine > + > + coroutine( Fn && fn, attributes const& attr = attributes(), + StackAllocator stack_alloc = StackAllocator(), + Allocator const& alloc = Allocator() ); + + template< + typename Fn, + typename StackAllocator = stack_allocator, + typename Allocator = std::allocator< coroutine > + > + coroutine( Fn && fn arguments const& args, + attributes const& attr = attributes(), + StackAllocator stack_alloc = StackAllocator(), + Allocator const& alloc = Allocator() ); + + coroutine( coroutine && other); + + coroutine & operator=( coroutine && other); + + operator unspecified-bool-type() const; + + bool operator!() const; + + void swap( coroutine & other); + + bool empty() const; + + coroutine & operator()(A0 a0, ..., A9 a9); + + R get() const; + }; + + template< typename Signature > + void swap( coroutine< Signature > & l, coroutine< Signature > & r); + + template< typename T > + range_iterator< coroutine< T() > >::type begin( coroutine< T() > &); + template< typename T > + range_iterator< coroutine< void(T) > >::type begin( coroutine< void(T) > &); + + template< typename T > + range_iterator< coroutine< T() > >::type end( coroutine< T() > &); + template< typename T > + range_iterator< coroutine< void(T) > >::type end( coroutine< void(T) > &); + +[heading `coroutine()`] +[variablelist +[[Effects:] [Creates a coroutine representing __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `template< typename Fn, typename StackAllocator, typename Allocator > + coroutine( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] +[variablelist +[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() +when ! is_stack_unbound().]] +[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` +determines stack clean-up and preserving floating-point registers. +For allocating/deallocating the stack `stack_alloc` is used and internal +data are allocated by Allocator.]] +] + +[heading `template< typename Fn, typename StackAllocator, typename Allocator > + coroutine( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] +[variablelist +[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() +when ! is_stack_unbound().]] +[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` +determines stack clean-up and preserving floating-point registers. +For allocating/deallocating the stack `stack_alloc` is used and internal +data are allocated by Allocator.]] +] + +[heading `coroutine( coroutine && other)`] +[variablelist +[[Effects:] [Moves the internal data of `other` to `*this`. +`other` becomes __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `coroutine & operator=( coroutine && other)`] +[variablelist +[[Effects:] [Destroys the internal data of `*this` and moves the +internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `operator unspecified-bool-type() const`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function +has returned (completed), the function returns false. Otherwise true.]] +[[Throws:] [Nothing.]] +] + +[heading `bool operator!() const`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function +has returned (completed), the function returns true. Otherwise false.]] +[[Throws:] [Nothing.]] +] + +[heading `bool empty()`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__, the function returns true. +Otherwise false.]] +[[Throws:] [Nothing.]] +] + +[heading `coroutine<> & operator()(A0 a0, A9 a9)`] +[variablelist +[[Preconditions:] [operator unspecified-bool-type() returns true for `*this`.] +[[Effects:] [Execution control is transferred to __coro_fn__ and the arguments +`a0`,..., are passed to the coroutine-function.]] +[[Throws:] [Exceptions thrown inside __coro_fn__.]] +] + +[heading `R get()()`] +[variablelist +[[Preconditions:] [`*this` is not a __not_a_coro__, `! is_complete()`.]] +[[Returns:] [Returns data transferred from coroutine-function via __coro_op__ +of __coro_caller__.]] +[[Throws:] [Nothing.]] +] + +[heading `void swap( coroutine & other)`] +[variablelist +[[Effects:] [Swaps the internal data from `*this` with the values +of `other`.]] +[[Throws:] [Nothing.]] +] + +[heading `T caller_type::operator()( R)`] +[variablelist +[[Effects:] [Gives execution control back to calling context by returning +a value of type R. The return type of this function is a __tuple__ containing +the arguments passed to __coro_op__.]] +[[Throws:] [Nothing.]] +] + +[heading Non-member function `swap()`] + + template< typename Signature > + void swap( coroutine< Signature > & l, coroutine< Signature > & r); + +[variablelist +[[Effects:] [As if 'l.swap( r)'.]] +] + +[heading Non-member function `begin( coroutine< T() > &)`] + template< typename T > + range_iterator< coroutine< T() > >::type begin( coroutine< T() > &); + +[variablelist +[[Returns:] [Returns a range-iterator (input-iterator).]] +] + +[heading Non-member function `begin( coroutine< void(T) > &)`] + template< typename T > + range_iterator< coroutine< void(T) > >::type begin( coroutine< void(T) > &); + +[variablelist +[[Returns:] [Returns a range-iterator (output-iterator).]] +] + +[heading Non-member function `end( coroutine< T() > &)`] + template< typename T > + range_iterator< coroutine< T() > >::type end( coroutine< T() > &); + +[variablelist +[[Returns:] [Returns a end range-iterator (input-iterator).]] +] + +[heading Non-member function `end( coroutine< void(T) > &)`] + template< typename T > + range_iterator< coroutine< void(T) > >::type end( coroutine< void(T) > &); + +[variablelist +[[Returns:] [Returns a end range-iterator (output-iterator).]] +] + +[endsect] + +[endsect] diff --git a/doc/unidirect.qbk b/doc/unidirect.qbk new file mode 100644 index 0000000..44a6469 --- /dev/null +++ b/doc/unidirect.qbk @@ -0,0 +1,878 @@ +[/ + 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 +] + +[section:unidirect Unidirectional coroutine (version 2)] + +[note This is the default interface (macro BOOST_COROUTINES_UNIDIRECT).] + +Two kinds of __coros__ are provided - __push_coro__ for transfering data to +and __pull_coro__ for transfering data from the other execution context. +Both coroutine flavours occure in a pair - providing a unidirectional data +transfer. + +Each instance of __coro__ has its own context of execution (CPU registers and +stack space) or represents __not_a_coro__ (similar to __thread__). +Objects of type __coro__ are moveable but not copyable and can be returned by a +function. + + boost::coroutines::push_coroutine< int > f(); + + void g() + { + boost::coroutines::push_coroutine< int > c( f() ); + c( 1); + } + +[note __boost_move__ is used to emulate rvalue references.] + + +[heading Creating a coroutine] + +A new __coro__ is created from a __coro_fn__ (function or functor) which will be +executed in a new __ctx__ (CPU registers and stack space). + +[note __coro_fn__ is required to return ['void] and accept a reference of type +__push_coro__ (if called by __pull_coro__) or vice versa.] + +The template argument determines the data-type transferred to/from +__coro_fn__. + + void f( boost:::coroutines::pull_coroutine< std::string > & c) + { + // access argument + std::string str( c.get() ); + // return to other execution context + c(); + } + + std::string str; + boost::coroutines::push_coroutine< std::string > c( f); + // pass argument + c( str); + + +The __coro_fn__ is started at __coro__ construction (similar to __thread__) +in a newly created __pull_coro__ complete with registers, flags, stack and +instruction pointer. In the case of __push_coro__ the __coro_fn__ is entered +when __push_coro_op__ is called the first time. + +__attrs__, an additional constructor argument of __coro__, defines the stack +size, stack unwinding and floating-point preserving behaviour used for __ctx__ +construction. + +The __coro__ constructor uses the __stack_allocator_concept__ to allocate an +associated stack, and the destructor uses the same __stack_allocator_concept__ +to deallocate the stack. The default __stack_allocator_concept__ is +__stack_allocator__, but a custom stack-allocator can be passed to the +constructor. + + +[heading Calling a coroutine] + +Using __pull_coro__ requires that __coro_fn__ takes __push_coro__ as first +argument and vice versa. +For __pull_coro__ __coro_fn__ is entered at construction and if control should +be returned to the original calling routine __push_coro_op__ (first argument of +__coro_fn__) has to be invoked. + + void f( boost::coroutines::push_coroutine< std::string > & c) + { + c("abc"); + } + + boost::coroutines::pull_coroutine< std::string > c( f); + std::string str = c.get(); + c(); + +Multiple arguments are wrapped into __tuple__. + + void g( boost::coroutines::pull_coroutine< boost::tuple< X, Y > > & c); + boost::coroutines::push_coroutine< boost::tuple< X, Y > > c( g); + + +The current coroutine information (registers, flags, and stack and instruction +pointer) is saved and the original context information is restored. Calling +__push_coro_op__/__pull_coro_op__ resumes execution in the coroutine after +saving the new state of the original routine. + + void fn( boost::coroutines::pull_coroutine< void > & c, int j) + { + for( int i = 0; i < j; ++i) + { + std::cout << "fn(): local variable i == " << i << std::endl; + + // save current coroutine + // value of local variable is preserved + // transfer execution control back to main() + c(); + + // push_coroutine<>::operator()() was called + // execution control transferred back from main() + } + } + + int main( int argc, char * argv[]) + { + // bind parameter '7' to coroutine-fn + boost::coroutines::push_coroutine< void > c( boost::bind( fn, _1, 7) ); + + std::cout << "main() starts coroutine c" << std::endl; + + while ( c) + { + std::cout << "main() calls coroutine c" << std::endl; + // execution control is transferred to c + c(); + } + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + main() starts coroutine c + fn(): local variable i == 0 + main() calls coroutine c + fn(): local variable i == 1 + main() calls coroutine c + fn(): local variable i == 2 + main() calls coroutine c + fn(): local variable i == 3 + main() calls coroutine c + fn(): local variable i == 4 + main() calls coroutine c + fn(): local variable i == 5 + main() calls coroutine c + fn(): local variable i == 6 + main() calls coroutine c + Done + +[warning Calling __push_coro_op__/__pull_coro_op__ from inside the [_same] +coroutine results in undefined behaviour.] + + +[heading Transfer of data] + +The template argument of __push_coro__, defines the types transferred +to and in the case of __pull_coroutine__ the type transfered from +__coro_fn__. + +__push_coro_op__ accepts argument defined as template argument and returns a +refernce to __push_coro__. +The arguments passed to __push_coro_op__, in one coroutine, is returned by +__pull_coro_get__ in the other execution context. + +The value given to __push_coro_op__, in one coroutine, is returned by +__pull_coro_get__ in the other routine. + + void fn( boost::coroutines::pull_coroutine< int > & c) + { + // access the integer argument passed to push_coroutine< int >::operator() + int i = c.get(); + std::cout << "fn(): local variable i == " << i << std::endl; + + // save current coroutine context and + // transfer execution control back to caller + // after execution control returns from pull_coroutine< int >::operator() + // the transferred integer s accessed via pull_coroutine< int >::get() + i = c().get(); + + // i == 10 because c( 10) in main() + std::cout << "fn(): local variable i == " << i << std::endl; + ca( i); + } + + int main( int argc, char * argv[]) + { + std::cout << "main(): call coroutine c" << std::endl; + coro_t c( fn, 7); + + int x = c.get(); + std::cout << "main(): transferred value: " << x << std::endl; + + x = c( 10).get(); + std::cout << "main(): transferred value: " << x << std::endl; + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + main(): call coroutine c + fn(): local variable i == 7 + main(): transferred value: 7 + fn(): local variable i == 10 + main(): transferred value: 10 + Done + + +[heading __coro_fn__ with multiple arguments] + +__tuple__ can be used to transfer mutliple data types. + + void fn( boost::coroutines::pull_coroutine< boost::tuple< int, int > > & c) + { + int a, b; + boost::tie( a, b) = c.get(); + std::cout << "main(): " << a << " + " << b << " == " << a + b << std::endl; + boost::tie( a, b) = c().get(); + std::cout << "main(): " << a << " + " << b << " == " << a + b << std::endl; + } + + int main( int argc, char * argv[]) + { + std::cout << "main(): call coroutine c" << std::endl; + boost::coroutines::push_coroutine< boost::tuple< int, int > c( fn); + + c( boost::make_tuple( 3, 7) ); + c( boost::make_tuple( 5, 7) ); + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + main(): call coroutine c + main(): 3 + 7 == 10 + main(): 5 + 7 == 12 + Done + + +[heading Transfer of pointers and references] + +You can transfer references and pointers from and to coroutines but as usual +you must take care (scope, no re-assignment of const references etc.). +In the following code `x` points to `local` which is allocated on stack of +`c`. When `c` goes out of scope the stack becomes deallocated. Using `x` +after `c` is gone will fail! + + struct X + { + void g(); + }; + + typedef boost::coroutines::pull_coroutine< X* > coro_t; + + // void fn( boost::coroutines::push_coroutine< X* > & ca) + void fn( coro_t::caller_t & ca) { + X local; + ca( & local); + } + + int main() { + X * x = 0; + { + coro_t c( fn); + x = c.get(); // let x point to X on stack owned by c + // stack gets unwound -> X will be destructed + } + x->g(); // segmentation fault! + return EXIT_SUCCESS; + } + + +[heading Range iterators] + +__boost_coroutine__ provides output- and input-iterators using __boost_range__. +__pull_coro__ can be used via output-iterators using __begin__ and __end__. + + typedef boost::coroutines::pull_coroutine< int > coro_t; + typedef boost::range_iterator< coro_t >::type iterator_t; + + 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() + { + coro_t c( boost::bind( power, _1, 2, 8) ); + iterator_t e( boost::end( c) ); + for ( iterator_t i( boost::begin( c) ); i != e; ++i) + std::cout << * i << " "; + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; + } + + output: + 2 4 8 16 32 64 128 256 + Done + +`BOOST_FOREACH` can be used to iterate over the coroutine range too. + + typedef boost::coroutines::pull_coroutine< int > coro_t; + typedef boost::range_iterator< coro_t >::type iterator_t; + + 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() + { + coro_t c( boost::bind( power, _1, 2, 8) ); + BOOST_FOREACH( int i, c) + { std::cout << i << " "; } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; + } + + output: + 2 4 8 16 32 64 128 256 + Done + + +Input iterators can be created from __push_coro__. + + + +[heading Exit a __coro_fn__] + +__coro_fn__ is exited with a simple return statement jumping back to the calling +routine. The __pull_coro__/__push_coro__ becomes complete, e.g. __coro_bool__ +will return 'false'. + + typedef boost::coroutines::coroutine< int(int,int) > coro_t; + + void power( boost::coroutines::pull_coroutine< boost::tuple< int, int > > & c, int number, int exponent) + { + int a, b; + + boost::tie( a, b) = ca.get(); + std::cout << "main(): " << a << " + " << b " == " << a + b << std::endl; + c(); + + boost::tie( a, b) = ca.get(); + std::cout << "main(): " << a << " + " << b " == " << a + b << std::endl; + c(); + } + + int main( int argc, char * argv[]) + { + std::cout << "main(): call coroutine c" << std::endl; + coro_t c( power); + c( boost::make_tuple( 3, 7) ); + BOOST_ASSERT( c); + + c( boot::make_tuple( 5, 7) ); + BOOST_ASSERT( ! c); + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + main(): call coroutine c + main(): 3 + 7 == 10 + main(): 5 + 7 == 12 + Done + +[important After returning from __coro_fn__ the __coro__ is complete (can not +resumed with __coro_op__).] + + +[heading Exceptions in __coro_fn__] + +An exception thrown inside __coro_fn__ will transferred via exception-pointer +(see __boost_exception__ for details) and re-thrown by constructor or +__coro_op__. + + void f( boost::coroutines::push_coroutine< void > & c) + { + c(); + throw std::runtime_error("abc"); + } + + int main( int argc, char * argv[]) + { + boost::coroutines::pull_coroutine< void > c( f); + try + { + c(); + } + catch ( std::exception const& e) + { + std::cout << "exception catched:" << e.what() << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + exception catched: abc + +[important Code executed by coroutine must not prevent the propagation of the +__forced_unwind__ exception. Absorbing that exception will cause stack +unwinding to fail. Thus, any code that catches all exceptions must re-throw the +pending exception.] + + try + { + // code that might throw + } + catch( forced_unwind) + { + throw; + } + catch(...) + { + // possibly not re-throw pending exception + } + + +[heading Stack unwinding] + +Sometimes it is necessary to unwind the stack of an unfinished coroutine to +destroy local stack variables so they can release allocated resources (RAII +pattern). The third argument of the coroutine constructor, `do_unwind`, +indicates whether the destructor should unwind the stack (stack is unwound by +default). + +Stack unwinding assumes the following preconditions: + +* The coroutine is not __not_a_coro__ +* The coroutine is not complete +* The coroutine is not running +* The coroutine owns a stack + +After unwinding, a __coro__ is complete. + + + struct X + { + X() + { std::cout << "X()" << std::endl; } + + ~X() + { std::cout << "~X()" << std::endl; } + }; + + void fn( boost::coroutines::pull_coroutine< void > & c) + { + X x; + + for ( int = 0;; ++i) + { + std::cout << "fn(): " << i << std::endl; + // transfer execution control back to main() + c(); + } + } + + int main( int argc, char * argv[]) + { + { + boost::coroutines::push_coroutine< void > c( fn, + boost::coroutines::attributes( + boost::ctx::default_stacksize(), + boost::coroutines::stack_unwind) ); + + c(); + c(); + c(); + c(); + c(); + + std::cout << "c is complete: " << std::boolalpha << c.is_complete() << "\n"; + } + + std::cout << "Done" << std::endl; + + return EXIT_SUCCESS; + } + + output: + X() + fn(): 0 + fn(): 1 + fn(): 2 + fn(): 3 + fn(): 4 + fn(): 5 + c is complete: false + ~X() + Done + +[important You must not swallow __forced_unwind__ exceptions!] + + +[heading FPU preserving] + +Some applications do not use floating-point registers and can disable preserving +fpu registers for performance reasons. + +[note According to the calling convention the FPU registers are preserved by default.] + + +[section:push_coro Class `push_coroutine`] + + #include + + template< typename Arg > + class push_coroutine + { + public: + push_coroutine(); + + template< + typename Fn, + typename StackAllocator = stack_allocator, + typename Allocator = std::allocator< coroutine > + > + push_coroutine( Fn fn, attributes const& attr = attributes(), + StackAllocator const& stack_alloc = StackAllocator(), + Allocator const& alloc = Allocator() ); + + template< + typename Fn, + typename StackAllocator = stack_allocator, + typename Allocator = std::allocator< coroutine > + > + push_coroutine( Fn && fn, attributes const& attr = attributes(), + StackAllocator stack_alloc = StackAllocator(), + Allocator const& alloc = Allocator() ); + + push_coroutine( push_coroutine && other); + + push_coroutine & operator=( push_coroutine && other); + + operator unspecified-bool-type() const; + + bool operator!() const; + + void swap( push_coroutine & other); + + bool empty() const; + + push_coroutine & operator()( Arg arg); + }; + + template< typename Arg > + void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r); + + template< typename Arg > + range_iterator< push_coroutine< Arg > >::type begin( push_coroutine< Arg > &); + + template< typename Arg > + range_iterator< push_coroutine< Arg > >::type end( push_coroutine< Arg > &); + +[heading `push_coroutine()`] +[variablelist +[[Effects:] [Creates a coroutine representing __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `template< typename Fn, typename StackAllocator, typename Allocator > + push_coroutine( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] +[variablelist +[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() +when ! is_stack_unbound().]] +[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` +determines stack clean-up and preserving floating-point registers. +For allocating/deallocating the stack `stack_alloc` is used and internal +data are allocated by Allocator.]] +] + +[heading `template< typename Fn, typename StackAllocator, typename Allocator > + push_coroutine( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] +[variablelist +[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() +when ! is_stack_unbound().]] +[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` +determines stack clean-up and preserving floating-point registers. +For allocating/deallocating the stack `stack_alloc` is used and internal +data are allocated by Allocator.]] +] + +[heading `push_coroutine( push_coroutine && other)`] +[variablelist +[[Effects:] [Moves the internal data of `other` to `*this`. +`other` becomes __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `push_coroutine & operator=( push_coroutine && other)`] +[variablelist +[[Effects:] [Destroys the internal data of `*this` and moves the +internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `operator unspecified-bool-type() const`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function +has returned (completed), the function returns false. Otherwise true.]] +[[Throws:] [Nothing.]] +] + +[heading `bool operator!() const`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function +has returned (completed), the function returns true. Otherwise false.]] +[[Throws:] [Nothing.]] +] + +[heading `bool empty()`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__, the function returns true. +Otherwise false.]] +[[Throws:] [Nothing.]] +] + +[heading `push_coroutine<> & operator()(Arg arg)`] +[variablelist +[[Preconditions:] [operator unspecified-bool-type() returns true for `*this`.] +[[Effects:] [Execution control is transferred to __coro_fn__ and the argument +`arg` is passed to the coroutine-function.]] +[[Throws:] [Exceptions thrown inside __coro_fn__.]] +] + +[heading `void swap( push_coroutine & other)`] +[variablelist +[[Effects:] [Swaps the internal data from `*this` with the values +of `other`.]] +[[Throws:] [Nothing.]] +] + +[heading `T caller_type::operator()( R)`] +[variablelist +[[Effects:] [Gives execution control back to calling context by returning +a value of type R. The return type of this function is a __tuple__ containing +the arguments passed to __coro_op__.]] +[[Throws:] [Nothing.]] +] + +[heading Non-member function `swap()`] + + template< typename Arg > + void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r); + +[variablelist +[[Effects:] [As if 'l.swap( r)'.]] +] + +[heading Non-member function `begin( push_coroutine< Arg > &)`] + template< typename Arg > + range_iterator< push_coroutine< Arg > >::type begin( push_coroutine< Arg > &); + +[variablelist +[[Returns:] [Returns a range-iterator (output-iterator).]] +] + +[heading Non-member function `end( push_coroutine< Arg > &)`] + template< typename Arg > + range_iterator< push_coroutine< Arg > >::type end( push_coroutine< Arg > &); + +[variablelist +[[Returns:] [Returns a end range-iterator (output-iterator).]] +] + +[endsect] + + +[section:pull_coro Class `pull_coroutine`] + + #include + + template< typename R > + class pull_coroutine + { + public: + pull_coroutine(); + + template< + typename Fn, + typename StackAllocator = stack_allocator, + typename Allocator = std::allocator< coroutine > + > + pull_coroutine( Fn fn, attributes const& attr = attributes(), + StackAllocator const& stack_alloc = StackAllocator(), + Allocator const& alloc = Allocator() ); + + template< + typename Fn, + typename StackAllocator = stack_allocator, + typename Allocator = std::allocator< coroutine > + > + pull_coroutine( Fn && fn, attributes const& attr = attributes(), + StackAllocator stack_alloc = StackAllocator(), + Allocator const& alloc = Allocator() ); + + pull_coroutine( pull_coroutine && other); + + pull_coroutine & operator=( pull_coroutine && other); + + operator unspecified-bool-type() const; + + bool operator!() const; + + void swap( pull_coroutine & other); + + bool empty() const; + + pull_coroutine & operator()(); + + bool has_result() const; + + R get() const; + }; + + template< typename R > + void swap( pull_coroutine< R > & l, pull_coroutine< R > & r); + + template< typename R > + range_iterator< pull_coroutine< R > >::type begin( pull_coroutine< R > &); + + template< typename R > + range_iterator< pull_coroutine< R > >::type end( pull_coroutine< R > &); + +[heading `pull_coroutine()`] +[variablelist +[[Effects:] [Creates a coroutine representing __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `template< typename Fn, typename StackAllocator, typename Allocator > + pull_coroutine( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] +[variablelist +[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() +when ! is_stack_unbound().]] +[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` +determines stack clean-up and preserving floating-point registers. +For allocating/deallocating the stack `stack_alloc` is used and internal +data are allocated by Allocator.]] +[[Throws:] [Exceptions thrown inside __coro_fn__.]] +] + +[heading `template< typename Fn, typename StackAllocator, typename Allocator > + pull_coroutine( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] +[variablelist +[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() +when ! is_stack_unbound().]] +[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr` +determines stack clean-up and preserving floating-point registers. +For allocating/deallocating the stack `stack_alloc` is used and internal +data are allocated by Allocator.]] +[[Throws:] [Exceptions thrown inside __coro_fn__.]] +] + +[heading `pull_coroutine( pull_coroutine && other)`] +[variablelist +[[Effects:] [Moves the internal data of `other` to `*this`. +`other` becomes __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `pull_coroutine & operator=( pull_coroutine && other)`] +[variablelist +[[Effects:] [Destroys the internal data of `*this` and moves the +internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] +[[Throws:] [Nothing.]] +] + +[heading `operator unspecified-bool-type() const`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function +has returned (completed), the function returns false. Otherwise true.]] +[[Throws:] [Nothing.]] +] + +[heading `bool operator!() const`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function +has returned (completed), the function returns true. Otherwise false.]] +[[Throws:] [Nothing.]] +] + +[heading `bool empty()`] +[variablelist +[[Returns:] [If `*this` refers to __not_a_coro__, the function returns true. +Otherwise false.]] +[[Throws:] [Nothing.]] +] + +[heading `pull_coroutine<> & operator()()`] +[variablelist +[[Preconditions:] [`*this` is not a __not_a_coro__.]] +[[Effects:] [Execution control is transferred to __coro_fn__ (no parameter are +passed to the coroutine-function).]] +[[Throws:] [Exceptions thrown inside __coro_fn__.]] +] + +[heading `bool has_result()`] +[variablelist +[[Preconditions:] [`*this` is not a __not_a_coro__.]] +[[Returns:] [If `*this` has a, the function returns true. Otherwise false.]] +[[Throws:] [Nothing.]] +] + +[heading `R get()()`] +[variablelist +[[Preconditions:] [`*this` is not a __not_a_coro__.]] +[[Returns:] [Returns data transferred from coroutine-function via +__push_coro_op__.]] +[[Throws:] [Nothing.]] +] + +[heading `void swap( pull_coroutine & other)`] +[variablelist +[[Effects:] [Swaps the internal data from `*this` with the values +of `other`.]] +[[Throws:] [Nothing.]] +] + +[heading Non-member function `swap()`] + + template< typename R > + void swap( pull_coroutine< R > & l, pull_coroutine< R > & r); + +[variablelist +[[Effects:] [As if 'l.swap( r)'.]] +] + +[heading Non-member function `begin( pull_coroutine< R > &)`] + template< typename R > + range_iterator< pull_coroutine< R > >::type begin( pull_coroutine< R > &); + +[variablelist +[[Returns:] [Returns a range-iterator (input-iterator).]] +] + +[heading Non-member function `end( pull_coroutine< R > &)`] + template< typename R > + range_iterator< pull_coroutine< R > >::type end( pull_coroutine< R > &); + +[variablelist +[[Returns:] [Returns a end range-iterator (input-iterator).]] +] + +[endsect] + +[endsect] diff --git a/example/c++11/fibonacci.cpp b/example/c++11/fibonacci.cpp index a8c20f4..7470d2f 100644 --- a/example/c++11/fibonacci.cpp +++ b/example/c++11/fibonacci.cpp @@ -9,7 +9,7 @@ #include -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT int main() { boost::coroutines::pull_coroutine< int > c( diff --git a/example/c++11/same_fringe.cpp b/example/c++11/same_fringe.cpp index 47cd5e4..29c9f63 100644 --- a/example/c++11/same_fringe.cpp +++ b/example/c++11/same_fringe.cpp @@ -28,7 +28,7 @@ node::ptr_t create_tree2() leaf::create( "C") ); } -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT class coro_visitor : public visitor { private: diff --git a/example/echo.cpp b/example/echo.cpp index 1c48679..a033b1d 100644 --- a/example/echo.cpp +++ b/example/echo.cpp @@ -10,7 +10,7 @@ #include #include -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT typedef boost::coroutines::pull_coroutine< void > pull_coro_t; typedef boost::coroutines::push_coroutine< void > push_coro_t; diff --git a/example/fibonacci.cpp b/example/fibonacci.cpp index aad0c5a..d50cc5a 100644 --- a/example/fibonacci.cpp +++ b/example/fibonacci.cpp @@ -10,7 +10,7 @@ #include #include -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT void fibonacci( boost::coroutines::push_coroutine< int > & c) { int first = 1, second = 1; diff --git a/example/parallel.cpp b/example/parallel.cpp index 5523940..77aaf0a 100644 --- a/example/parallel.cpp +++ b/example/parallel.cpp @@ -10,7 +10,7 @@ #include #include -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT void first( boost::coroutines::push_coroutine< void > & c) { std::cout << "started first! "; diff --git a/example/power.cpp b/example/power.cpp index dc495d5..3302e98 100644 --- a/example/power.cpp +++ b/example/power.cpp @@ -12,7 +12,7 @@ #include #include -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT void power( boost::coroutines::push_coroutine< int > & c, int number, int exponent) { int counter = 0; diff --git a/example/same_fringe.cpp b/example/same_fringe.cpp index 0150a9c..6c6d67f 100644 --- a/example/same_fringe.cpp +++ b/example/same_fringe.cpp @@ -49,7 +49,7 @@ std::pair< node::ptr_t, node::ptr_t > create_diff_trees() return std::make_pair( tree1, tree2); } -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT bool match_trees( boost::coroutines::pull_coroutine< leaf & > & c1, boost::coroutines::pull_coroutine< leaf & > & c2) { diff --git a/example/segmented_stack.cpp b/example/segmented_stack.cpp index 2259793..e823f86 100644 --- a/example/segmented_stack.cpp +++ b/example/segmented_stack.cpp @@ -31,7 +31,7 @@ void bar( int i) } } -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT void foo( boost::coroutines::pull_coroutine< void > & c) { bar( count); diff --git a/example/tree.h b/example/tree.h index 39bb3c8..7a5982c 100644 --- a/example/tree.h +++ b/example/tree.h @@ -91,7 +91,7 @@ inline bool operator!=( leaf const& l, leaf const& r) { return l.value != r.value; } -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT class tree_visitor : public visitor { private: diff --git a/example/unwind.cpp b/example/unwind.cpp index 4bcaa1d..670e087 100644 --- a/example/unwind.cpp +++ b/example/unwind.cpp @@ -10,7 +10,7 @@ #include #include -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT struct X : private boost::noncopyable { X() { std::cout << "X()" << std::endl; } diff --git a/include/boost/coroutine/coroutine.hpp b/include/boost/coroutine/coroutine.hpp index bfb89d9..647faf9 100644 --- a/include/boost/coroutine/coroutine.hpp +++ b/include/boost/coroutine/coroutine.hpp @@ -7,7 +7,7 @@ #ifndef BOOST_COROUTINES_COROUTINE_H #define BOOST_COROUTINES_COROUTINE_H -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT #include #else #include diff --git a/include/boost/coroutine/detail/config.hpp b/include/boost/coroutine/detail/config.hpp index 6d6860a..8b1f04a 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 +#ifndef BOOST_COROUTINES_OLD +# define BOOST_COROUTINES_UNIDIRECT #endif #endif // BOOST_COROUTINES_DETAIL_CONFIG_H diff --git a/include/boost/coroutine/v1/coroutine.hpp b/include/boost/coroutine/v1/coroutine.hpp index 294d81c..ae1374e 100644 --- a/include/boost/coroutine/v1/coroutine.hpp +++ b/include/boost/coroutine/v1/coroutine.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_V1_COROUTINE_H -#define BOOST_COROUTINES_V1_COROUTINE_H +#ifndef BOOST_COROUTINES_OLD_COROUTINE_H +#define BOOST_COROUTINES_OLD_COROUTINE_H #include #include @@ -1427,4 +1427,4 @@ struct range_const_iterator< coroutines::coroutine< Signature > > # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V1_COROUTINE_H +#endif // BOOST_COROUTINES_OLD_COROUTINE_H diff --git a/include/boost/coroutine/v1/detail/arg.hpp b/include/boost/coroutine/v1/detail/arg.hpp index 00b2462..cecefd0 100644 --- a/include/boost/coroutine/v1/detail/arg.hpp +++ b/include/boost/coroutine/v1/detail/arg.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_V1_DETAIL_ARG_H -#define BOOST_COROUTINES_V1_DETAIL_ARG_H +#ifndef BOOST_COROUTINES_OLD_DETAIL_ARG_H +#define BOOST_COROUTINES_OLD_DETAIL_ARG_H #include #include @@ -59,4 +59,4 @@ BOOST_PP_REPEAT_FROM_TO(2,11,BOOST_CONTEXT_TUPLE,~) # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V1_DETAIL_ARG_H +#endif // BOOST_COROUTINES_OLD_DETAIL_ARG_H diff --git a/include/boost/coroutine/v1/detail/coroutine_base.hpp b/include/boost/coroutine/v1/detail/coroutine_base.hpp index a460cf3..07e94f6 100644 --- a/include/boost/coroutine/v1/detail/coroutine_base.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_base.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_V1_DETAIL_COROUTINE_BASE_H -#define BOOST_COROUTINES_V1_DETAIL_COROUTINE_BASE_H +#ifndef BOOST_COROUTINES_OLD_DETAIL_COROUTINE_BASE_H +#define BOOST_COROUTINES_OLD_DETAIL_COROUTINE_BASE_H #include #include @@ -122,4 +122,4 @@ public: # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V1_DETAIL_COROUTINE_BASE_H +#endif // BOOST_COROUTINES_OLD_DETAIL_COROUTINE_BASE_H diff --git a/include/boost/coroutine/v1/detail/coroutine_base_resume.hpp b/include/boost/coroutine/v1/detail/coroutine_base_resume.hpp index 9c8a804..020f97c 100644 --- a/include/boost/coroutine/v1/detail/coroutine_base_resume.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_base_resume.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_V1_DETAIL_COROUTINE_BASE_RESUME_H -#define BOOST_COROUTINES_V1_DETAIL_COROUTINE_BASE_RESUME_H +#ifndef BOOST_COROUTINES_OLD_DETAIL_COROUTINE_BASE_RESUME_H +#define BOOST_COROUTINES_OLD_DETAIL_COROUTINE_BASE_RESUME_H #include @@ -234,4 +234,4 @@ BOOST_PP_REPEAT_FROM_TO(2,11,BOOST_COROUTINE_BASE_RESUME,~) # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V1_DETAIL_coroutine_base_resume_H +#endif // BOOST_COROUTINES_OLD_DETAIL_coroutine_base_resume_H diff --git a/include/boost/coroutine/v1/detail/coroutine_caller.hpp b/include/boost/coroutine/v1/detail/coroutine_caller.hpp index 3796de7..7e0bb9f 100644 --- a/include/boost/coroutine/v1/detail/coroutine_caller.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_caller.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_V1_DETAIL_COROUTINE_CALLER_H -#define BOOST_COROUTINES_V1_DETAIL_COROUTINE_CALLER_H +#ifndef BOOST_COROUTINES_OLD_DETAIL_COROUTINE_CALLER_H +#define BOOST_COROUTINES_OLD_DETAIL_COROUTINE_CALLER_H #include #include @@ -54,4 +54,4 @@ private: # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V1_DETAIL_COROUTINE_CALLER_H +#endif // BOOST_COROUTINES_OLD_DETAIL_COROUTINE_CALLER_H diff --git a/include/boost/coroutine/v1/detail/coroutine_get.hpp b/include/boost/coroutine/v1/detail/coroutine_get.hpp index 62b73bb..26d0406 100644 --- a/include/boost/coroutine/v1/detail/coroutine_get.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_get.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_V1_DETAIL_COROUTINE_GET_H -#define BOOST_COROUTINES_V1_DETAIL_COROUTINE_GET_H +#ifndef BOOST_COROUTINES_OLD_DETAIL_COROUTINE_GET_H +#define BOOST_COROUTINES_OLD_DETAIL_COROUTINE_GET_H #include #include @@ -51,4 +51,4 @@ struct coroutine_get # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V1_DETAIL_COROUTINE_GET_H +#endif // BOOST_COROUTINES_OLD_DETAIL_COROUTINE_GET_H diff --git a/include/boost/coroutine/v1/detail/coroutine_object.hpp b/include/boost/coroutine/v1/detail/coroutine_object.hpp index 17ef4d4..f6348c2 100644 --- a/include/boost/coroutine/v1/detail/coroutine_object.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_object.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_V1_DETAIL_COROUTINE_OBJECT_H -#define BOOST_COROUTINES_V1_DETAIL_COROUTINE_OBJECT_H +#ifndef BOOST_COROUTINES_OLD_DETAIL_COROUTINE_OBJECT_H +#define BOOST_COROUTINES_OLD_DETAIL_COROUTINE_OBJECT_H #include @@ -71,4 +71,4 @@ class coroutine_object; #pragma warning (pop) #endif -#endif // BOOST_COROUTINES_V1_DETAIL_COROUTINE_OBJECT_H +#endif // BOOST_COROUTINES_OLD_DETAIL_COROUTINE_OBJECT_H diff --git a/include/boost/coroutine/v1/detail/coroutine_op.hpp b/include/boost/coroutine/v1/detail/coroutine_op.hpp index 83806ac..b449070 100644 --- a/include/boost/coroutine/v1/detail/coroutine_op.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_op.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_V1_DETAIL_COROUTINE_OP_H -#define BOOST_COROUTINES_V1_DETAIL_COROUTINE_OP_H +#ifndef BOOST_COROUTINES_OLD_DETAIL_COROUTINE_OP_H +#define BOOST_COROUTINES_OLD_DETAIL_COROUTINE_OP_H #include @@ -323,4 +323,4 @@ BOOST_PP_REPEAT_FROM_TO(2,11,BOOST_COROUTINE_OP,~) # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V1_DETAIL_COROUTINE_OP_H +#endif // BOOST_COROUTINES_OLD_DETAIL_COROUTINE_OP_H diff --git a/include/boost/coroutine/v2/coroutine.hpp b/include/boost/coroutine/v2/coroutine.hpp index a8d06f9..48d25f7 100644 --- a/include/boost/coroutine/v2/coroutine.hpp +++ b/include/boost/coroutine/v2/coroutine.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_V2_COROUTINE_H -#define BOOST_COROUTINES_V2_COROUTINE_H +#ifndef BOOST_COROUTINES_UNIDIRECT_COROUTINE_H +#define BOOST_COROUTINES_UNIDIRECT_COROUTINE_H #include #include @@ -2932,4 +2932,4 @@ struct range_const_iterator< coroutines::pull_coroutine< R > > # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V2_COROUTINE_H +#endif // BOOST_COROUTINES_UNIDIRECT_COROUTINE_H diff --git a/include/boost/coroutine/v2/detail/coroutine_object.hpp b/include/boost/coroutine/v2/detail/coroutine_object.hpp deleted file mode 100644 index 4255b85..0000000 --- a/include/boost/coroutine/v2/detail/coroutine_object.hpp +++ /dev/null @@ -1,423 +0,0 @@ - -// 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_V1_DETAIL_COROUTINE_OBJECT_H -#define BOOST_COROUTINES_V1_DETAIL_COROUTINE_OBJECT_H - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -template< - typename Arg, - typename Fn, typename StackAllocator, typename Allocator -> -class coroutine_object< Arg, Fn, StackAllocator, Allocator > : - private stack_tuple< StackAllocator >, - public coroutine_base -{ -public: - typedef typename Allocator::template rebind< - coroutine_object< - Arg, Fn, StackAllocator, Allocator - > - >::other allocator_t; - -private: - typedef stack_tuple< StackAllocator > pbase_type; - typedef coroutine_base base_type; - - Fn fn_; - allocator_t alloc_; - - static void destroy_( allocator_t & alloc, coroutine_object * p) - { - alloc.destroy( p); - alloc.deallocate( p, 1); - } - - coroutine_object( coroutine_object const&); - coroutine_object & operator=( 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; - this->result_ = hldr_from->data; - if ( this->except_) rethrow_exception( this->except_); - } - - void run_( Caller & c) - { - coroutine_context callee; - coroutine_context caller; - try - { - fn_( c); - this->flags_ |= flag_complete; - callee = c.impl_->callee_; - holder< void > hldr_to( & caller); - caller.jump( - callee, - reinterpret_cast< intptr_t >( & hldr_to), - this->preserve_fpu() ); - BOOST_ASSERT_MSG( false, "coroutine is complete"); - } - catch ( forced_unwind const&) - {} - catch (...) - { this->except_ = current_exception(); } - - this->flags_ |= flag_complete; - callee = c.impl_->callee_; - holder< void > hldr_to( & caller); - caller.jump( - callee, - reinterpret_cast< intptr_t >( & hldr_to), - this->preserve_fpu() ); - BOOST_ASSERT_MSG( false, "coroutine is complete"); - } - - 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 - 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< coroutine_object >, - & this->stack_ctx, - stack_unwind == attr.do_unwind, - fpu_preserved == attr.preserve_fpu), - fn_( forward< Fn >( fn) ), - alloc_( alloc) - { enter_(); } -#else - coroutine_object( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc, - allocator_t const& alloc) : - pbase_type( stack_alloc, attr.size), - base_type( - trampoline1< coroutine_object >, - & this->stack_ctx, - stack_unwind == attr.do_unwind, - fpu_preserved == attr.preserve_fpu), - fn_( fn), - alloc_( alloc) - { enter_(); } - - 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< coroutine_object >, - & this->stack_ctx, - stack_unwind == attr.do_unwind, - fpu_preserved == attr.preserve_fpu), - fn_( fn), - alloc_( alloc) - { enter_(); } -#endif - - ~coroutine_object() - { - if ( ! this->is_complete() && this->force_unwind() ) - unwind_stack_(); - } - - void run() - { - Caller c( this->caller_, false, this->preserve_fpu(), alloc_); - run_( c); - } - - void deallocate_object() - { destroy_( alloc_, this); } -}; - -template< - typename Arg, - typename Fn, typename StackAllocator, typename Allocator, - typename Caller, - typename Result -> -class coroutine_object< Arg, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 0 > : - private stack_tuple< StackAllocator >, - public coroutine_base< Arg > -{ -public: - typedef typename Allocator::template rebind< - coroutine_object< - Arg, Fn, StackAllocator, Allocator, Caller, Result, 0 - > - >::other allocator_t; - -private: - typedef stack_tuple< StackAllocator > pbase_type; - typedef coroutine_base< Arg > base_type; - - Fn fn_; - allocator_t alloc_; - - static void destroy_( allocator_t & alloc, coroutine_object * p) - { - alloc.destroy( p); - alloc.deallocate( p, 1); - } - - coroutine_object( coroutine_object const&); - coroutine_object & operator=( coroutine_object const&); - - void enter_() - { - holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( - 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 run_( Caller & c) - { - coroutine_context callee; - coroutine_context caller; - try - { - fn_( c); - this->flags_ |= flag_complete; - callee = c.impl_->callee_; - holder< Result > hldr_to( & caller); - caller.jump( - callee, - reinterpret_cast< intptr_t >( & hldr_to), - this->preserve_fpu() ); - BOOST_ASSERT_MSG( false, "coroutine is complete"); - } - catch ( forced_unwind const&) - {} - catch (...) - { this->except_ = current_exception(); } - - this->flags_ |= flag_complete; - callee = c.impl_->callee_; - holder< Result > hldr_to( & caller); - caller.jump( - callee, - reinterpret_cast< intptr_t >( & hldr_to), - this->preserve_fpu() ); - BOOST_ASSERT_MSG( false, "coroutine is complete"); - } - - 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: - 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< coroutine_object >, - & this->stack_ctx, - stack_unwind == attr.do_unwind, - fpu_preserved == attr.preserve_fpu), - fn_( fn), - alloc_( alloc) - { enter_(); } - - ~coroutine_object() - { - if ( ! this->is_complete() && this->force_unwind() ) - unwind_stack_(); - } - - void run() - { - Caller c( this->caller_, false, this->preserve_fpu(), alloc_); - run_( c); - } - - void deallocate_object() - { destroy_( alloc_, this); } -}; - -template< - typename Arg, - typename Fn, typename StackAllocator, typename Allocator, - typename Caller, - typename Result -> -class coroutine_object< Arg, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 0 > : - private stack_tuple< StackAllocator >, - public coroutine_base< Arg > -{ -public: - typedef typename Allocator::template rebind< - coroutine_object< - Arg, Fn, StackAllocator, Allocator, Caller, Result, 0 - > - >::other allocator_t; - -private: - typedef stack_tuple< StackAllocator > pbase_type; - typedef coroutine_base< Arg > base_type; - - Fn fn_; - allocator_t alloc_; - - static void destroy_( allocator_t & alloc, coroutine_object * p) - { - alloc.destroy( p); - alloc.deallocate( p, 1); - } - - coroutine_object( coroutine_object const&); - coroutine_object & operator=( coroutine_object const&); - - void enter_() - { - holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( - 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 run_( Caller & c) - { - coroutine_context callee; - coroutine_context caller; - try - { - fn_( c); - this->flags_ |= flag_complete; - callee = c.impl_->callee_; - holder< Result > hldr_to( & caller); - caller.jump( - callee, - reinterpret_cast< intptr_t >( & hldr_to), - this->preserve_fpu() ); - BOOST_ASSERT_MSG( false, "coroutine is complete"); - } - catch ( forced_unwind const&) - {} - catch (...) - { this->except_ = current_exception(); } - - this->flags_ |= flag_complete; - callee = c.impl_->callee_; - holder< Result > hldr_to( & caller); - caller.jump( - callee, - reinterpret_cast< intptr_t >( & hldr_to), - this->preserve_fpu() ); - BOOST_ASSERT_MSG( false, "coroutine is complete"); - } - - 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: - 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< coroutine_object >, - & this->stack_ctx, - stack_unwind == attr.do_unwind, - fpu_preserved == attr.preserve_fpu), - fn_( fn), - alloc_( alloc) - { enter_(); } - - ~coroutine_object() - { - if ( ! this->is_complete() && this->force_unwind() ) - unwind_stack_(); - } - - void run() - { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); - run_( c); - } - - void deallocate_object() - { destroy_( alloc_, this); } -}; diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp index f3398fc..5c94175 100644 --- a/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp +++ b/include/boost/coroutine/v2/detail/pull_coroutine_base.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_V2_DETAIL_PULL_COROUTINE_BASE_H -#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H +#ifndef BOOST_COROUTINES_UNIDIRECT_DETAIL_PULL_COROUTINE_BASE_H +#define BOOST_COROUTINES_UNIDIRECT_DETAIL_PULL_COROUTINE_BASE_H #include #include @@ -229,4 +229,4 @@ public: # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H +#endif // BOOST_COROUTINES_UNIDIRECT_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 index 43b3506..6be6226 100644 --- a/include/boost/coroutine/v2/detail/pull_coroutine_caller.hpp +++ b/include/boost/coroutine/v2/detail/pull_coroutine_caller.hpp @@ -3,8 +3,8 @@ // (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 +#ifndef BOOST_COROUTINES_UNIDIRECT_DETAIL_PULL_COROUTINE_CALLER_H +#define BOOST_COROUTINES_UNIDIRECT_DETAIL_PULL_COROUTINE_CALLER_H #include #include @@ -81,4 +81,4 @@ private: # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_CALLER_H +#endif // BOOST_COROUTINES_UNIDIRECT_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 index 1698417..c30d829 100644 --- a/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp +++ b/include/boost/coroutine/v2/detail/pull_coroutine_object.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_V2_DETAIL_PULL_COROUTINE_OBJECT_H -#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_OBJECT_H +#ifndef BOOST_COROUTINES_UNIDIRECT_DETAIL_PULL_COROUTINE_OBJECT_H +#define BOOST_COROUTINES_UNIDIRECT_DETAIL_PULL_COROUTINE_OBJECT_H #include @@ -765,4 +765,4 @@ public: #pragma warning (pop) #endif -#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_OBJECT_H +#endif // BOOST_COROUTINES_UNIDIRECT_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 index 1a4156d..24e2fab 100644 --- a/include/boost/coroutine/v2/detail/push_coroutine_base.hpp +++ b/include/boost/coroutine/v2/detail/push_coroutine_base.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_V2_DETAIL_PUSH_COROUTINE_BASE_H -#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H +#ifndef BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_BASE_H +#define BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_BASE_H #include #include @@ -438,4 +438,4 @@ public: # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H +#endif // BOOST_COROUTINES_UNIDIRECT_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 index 1358250..3c627f7 100644 --- a/include/boost/coroutine/v2/detail/push_coroutine_caller.hpp +++ b/include/boost/coroutine/v2/detail/push_coroutine_caller.hpp @@ -3,8 +3,8 @@ // (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 +#ifndef BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_CALLER_H +#define BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_CALLER_H #include #include @@ -53,4 +53,4 @@ private: # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_CALLER_H +#endif // BOOST_COROUTINES_UNIDIRECT_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 index 2fc439a..08db5a1 100644 --- a/include/boost/coroutine/v2/detail/push_coroutine_object.hpp +++ b/include/boost/coroutine/v2/detail/push_coroutine_object.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_V2_DETAIL_PUSH_COROUTINE_OBJECT_H -#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_OBJECT_H +#ifndef BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_OBJECT_H +#define BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_OBJECT_H #include @@ -820,4 +820,4 @@ public: #pragma warning (pop) #endif -#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_OBJECT_H +#endif // BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_OBJECT_H diff --git a/include/boost/coroutine/v2/pull_corotuine.hpp b/include/boost/coroutine/v2/pull_corotuine.hpp deleted file mode 100644 index fa21476..0000000 --- a/include/boost/coroutine/v2/pull_corotuine.hpp +++ /dev/null @@ -1,355 +0,0 @@ - -// 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_PULL_COROUTINE_H -#define BOOST_COROUTINES_V2_PULL_COROUTINE_H - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines { -namespace detail { - -template< typename R > -class pull_coroutine -{ -private: - 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) - -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 > - > 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 > - > 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 - > 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 > - > 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 > - > 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 - > 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 > - > 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 > - > 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 - > 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_); } - - void operator()() - { - BOOST_ASSERT( * this); - - impl_->resume(); - } - - bool has_result() const - { - BOOST_ASSERT( * this); - - return impl_->has_result(); - } - - R get() const - { - BOOST_ASSERT( * this); - - return impl_->get(); - } -}; - -template< typename R > -void swap( pull_coroutine< R > & l, pull_coroutine< R > & r) BOOST_NOEXCEPT -{ l.swap( r); } -#if 0 -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 R > -struct range_mutable_iterator< coroutines::coroutine< R > > -{ typedef typename coroutines::coroutine< R >::iterator type; }; - -template< typename R > -struct range_const_iterator< coroutines::coroutine< R > > -{ typedef typename coroutines::coroutine< R >::const_iterator type; }; -#endif -} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_COROUTINES_V2_PULL_COROUTINE_H diff --git a/include/boost/coroutine/v2/push_coroutine.hpp b/include/boost/coroutine/v2/push_coroutine.hpp deleted file mode 100644 index a0a63e5..0000000 --- a/include/boost/coroutine/v2/push_coroutine.hpp +++ /dev/null @@ -1,357 +0,0 @@ - -// 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_PUSH_COROUTINE_H -#define BOOST_COROUTINES_V2_PUSH_COROUTINE_H - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines { -namespace detail { - -template< typename Arg > -class push_coroutine -{ -private: - 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) - -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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, stack_allocator, std::allocator< push_coroutine > - > 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 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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, StackAllocator, std::allocator< push_coroutine > - > 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 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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, StackAllocator, Allocator - > 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 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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, stack_allocator, std::allocator< push_coroutine > - > 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 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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, StackAllocator, std::allocator< push_coroutine > - > 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 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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, StackAllocator, Allocator - > 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 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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, stack_allocator, std::allocator< push_coroutine > - > 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 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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, StackAllocator, std::allocator< push_coroutine > - > 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 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) : - impl_() - { - typedef detail::push_coroutine_object< - Arg, Fn, StackAllocator, Allocator - > 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 - - 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 - void operator()( Arg && arg) - { - BOOST_ASSERT( * this); - - impl_->resume( boost::forward< Arg >( arg) ); - } -#else - void operator()( BOOST_RV_REF( Arg) arg) - { - BOOST_ASSERT( * this); - - impl_->resume( boost::forward< Arg >( arg) ); - } -#endif - - void operator()( Arg arg) - { - BOOST_ASSERT( * this); - - impl_->resume( arg); - } -}; - -template< typename Arg > -void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r) BOOST_NOEXCEPT -{ l.swap( r); } -#if 0 -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::coroutine< Arg > > -{ typedef typename coroutines::coroutine< Arg >::iterator type; }; - -template< typename Arg > -struct range_const_iterator< coroutines::coroutine< Arg > > -{ typedef typename coroutines::coroutine< Arg >::const_iterator type; }; -#endif -} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_COROUTINES_V2_PUSH_COROUTINE_H diff --git a/performance/performance.cpp b/performance/performance.cpp index 67ec895..bfa74f4 100644 --- a/performance/performance.cpp +++ b/performance/performance.cpp @@ -32,7 +32,7 @@ namespace coro = boost::coroutines; # define CALL_COROUTINE(z,n,unused) \ c(); -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT void fn( boost::coroutines::push_coroutine< void > & c) { while ( true) c(); } diff --git a/test/test_coroutine.cpp b/test/test_coroutine.cpp index 1361b0c..668a44a 100644 --- a/test/test_coroutine.cpp +++ b/test/test_coroutine.cpp @@ -37,7 +37,7 @@ int& value7 = value1; int value8 = 0; int value9 = 0; -#ifdef BOOST_COROUTINES_V2 +#ifdef BOOST_COROUTINES_UNIDIRECT struct X : private boost::noncopyable { X() { value1 = 7; } @@ -1036,7 +1036,7 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* []) 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 +#ifndef BOOST_COROUTINES_UNIDIRECT test->add( BOOST_TEST_CASE( & test_pre) ); test->add( BOOST_TEST_CASE( & test_post) ); #endif