diff --git a/doc/architectures.qbk b/doc/architectures.qbk index 4150c43..384ee9a 100644 --- a/doc/architectures.qbk +++ b/doc/architectures.qbk @@ -1,13 +1,13 @@ -[/ - 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:architextues Architectures] -__boost_coroutine__ depends on __boost_context__ witch supports this -[@boost:/libs/context/architectures.html architectures]. -[endsect] + + + + + + + + + + diff --git a/doc/coro.qbk b/doc/coro.qbk index e432077..75ba504 100644 --- a/doc/coro.qbk +++ b/doc/coro.qbk @@ -39,6 +39,7 @@ [def __boost_utility__ [*Boost.Utility]] [def __boost_version__ [*Boost-1.52.0]] +[def __call_coro___ ['symmetric_coroutine<>::call_type]] [def __coro__ ['coroutine]] [def __coro_fn__ ['coroutine-function]] [def __coros__ ['coroutines]] @@ -46,19 +47,20 @@ [def __not_a_coro__ ['not-a-coroutine]] [def __pull_coro__ ['asymmetric_coroutine<>::pull_type]] [def __push_coro__ ['asymmetric_coroutine<>::push_type]] -[def __scoro__ ['symmetric_coroutine<>]] [def __segmented_stack__ ['segemented-stack]] -[def __yield_scoro__ ['symmetric_coroutine<>::yield_type]] [def __signature__ ['Signature]] [def __stack_allocator_concept__ ['stack-allocator concept]] [def __stack_allocator__ ['stack-allocator]] [def __stack__ ['stack]] [def __tls__ ['thread-local-storage]] +[def __yield_coro__ ['symmetric_coroutine<>::yield_type]] [def __args__ ['boost::coroutines::asymmetric_coroutine<>::arguments]] [def __attrs__ ['boost::coroutines::attributes]] [def __begin__ ['boost::begin()]] [def __bind__ ['boost::bind()]] +[def __call_coro_bool__ ['boost::coroutines::symmetric_coroutine<>::operator bool]] +[def __call_coro_op__ ['boost::coroutines::symmetric_coroutine<>::operator()]] [def __coro_allocator__ ['boost::coroutines::stack_allocator]] [def __coro_ns__ ['boost::coroutines]] [def __end__ ['boost::end()]] @@ -75,11 +77,7 @@ [def __pull_coro_op__ ['boost::coroutines::asymmetric_coroutine<>::pull_type::operator()]] [def __push_coro_bool__ ['boost::coroutines::asymmetric_coroutine<>::push_type::operator bool]] [def __push_coro_op__ ['boost::coroutines::asymmetric_coroutine<>::push_type::operator()]] -[def __scoro_bool__ ['boost::coroutines::symmetric_coroutine<>::operator bool]] -[def __scoro_op__ ['boost::coroutines::symmetric_coroutine<>::operator()]] [def __segmented_allocator__ ['boost::coroutines::segmented_stack_allocator]] -[def __yield_scoro_get__ ['boost::coroutines::symmetric_coroutine<>::yield_type::get()]] -[def __yield_scoro_op__ ['boost::coroutines::symmetric_coroutine<>::yield_type::operator()]] [def __server__ ['server]] [def __session__ ['session]] [def __stack_context__ ['boost::coroutines::stack_context]] @@ -91,6 +89,9 @@ [def __tuple__ ['boost::tuple<>]] [def __underflow__ ['stream_buf::underflow()]] [def __yield_context__ ['boost::asio::yield_context]] +[def __yield_coro_bool__ ['boost::coroutines::symmetric_coroutine<>::yield_type::operator bool]] +[def __yield_coro_get__ ['boost::coroutines::symmetric_coroutine<>::yield_type::get()]] +[def __yield_coro_op__ ['boost::coroutines::symmetric_coroutine<>::yield_type::operator()]] [include overview.qbk] [include intro.qbk] diff --git a/doc/coroutine.qbk b/doc/coroutine.qbk index 91e3dcd..f43da6a 100644 --- a/doc/coroutine.qbk +++ b/doc/coroutine.qbk @@ -1,91 +1,91 @@ -[/ - 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:coroutine Coroutine] - -__boost_coroutine__ provides two classes - implementations of asymmetric and -symmetric coroutines. - -'Coroutine mechanisms that support concurrent programming usually provide -symmetric coroutines to represent independent units of execution. On the other -hand, coroutine mechanisms intended for implementing constructs that produce -sequences of values typically provide asymmetric coroutines.' -[footnote Moura, Ana Lucia De and Ierusalimschy, Roberto. -"Revisiting coroutines". ACM Trans. Program. Lang. Syst., Volume 31 Issue 2, -February 2009, Article No. 6]. -[heading stackful] -Each instance of a coroutine has its own stack. - -In contrast to stackless coroutines, stackful coroutines allow invoking the -suspend operation out of arbitrary sub-stackframes, enabling escape-and-reenter -recursive operations. -[heading move-only] -A coroutine is moveable-only. - -If it were copyable, then its stack with all the objects allocated on it -would be copied too. That would force undefined behaviour if some of these -objects were RAII-classes (manage a resource via RAII pattern). When the first -of the coroutine copies terminates (unwinds its stack), the RAII class -destructors will release their managed resources. When the second copy -terminates, the same destructors will try to doubly-release the same resources, -leading to undefined behavior. -[heading clean-up] -On coroutine destruction the associated stack will be unwound. - -The constructor of coroutine allows to pass an customized ['stack-allocator]. -['stack-allocator] is free to deallocate the stack or cache it for future usage -(for coroutines created later). -[heading segmented stack] -__scoro__, __push_coro__ and __pull_coro__ does support segmented stacks -(growing on demand). - -It is not always possible to estimated the required stack size - in most cases -too much memory is allocated (waste of virtual address-space). - -At construction a coroutine starts with a default (minimal) stack size. This -minimal stack size is the maximum of page size and the canonical size for signal -stack (macro SIGSTKSZ on POSIX). - -At this time of writing only GCC (4.7)\cite{gccsplit} is known to support -segmented stacks. With version 1.54 __boost_coroutine__ provides support for -segmented stacks. - -The destructor releases the associated stack. The implementer is free to -deallocate the stack or to cache it for later usage. -[heading context switch] -A coroutine saves and restores registers according to the underlying ABI on -each context switch. - -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.] - -On POSIX systems, the coroutine context switch does not preserve signal masks -for performance reasons. - -A context switch is done via __push_coro_op__ and __pull_coro_op__. - -[warning Calling __scoro_op__/__push_coro_op__/__pull_coro_op__ from inside the -[_same] coroutine results in undefined behaviour.] -[include asymmetric.qbk] -[include symmetric.qbk] -[endsect] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/intro.qbk b/doc/intro.qbk index 8bb595b..a26ecbb 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -1,107 +1,107 @@ -[/ - 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:intro Introduction] - -[heading Definition] - -In computer science routines are defined as a sequence of operations. The -execution of routines forms a parent-child relationship and the child terminates -always before the parent. Coroutines (the term was introduced by Melvin -Conway [footnote Conway, Melvin E.. "Design of a Separable Transition-Diagram Compiler". -Commun. ACM, Volume 6 Issue 7, July 1963, Articale No. 7]), -are a generalization of routines (Donald Knuth [footnote Knuth, Donald Ervin (1997). -"Fundamental Algorithms. The Art of Computer Programming 1", (3rd ed.)]. -The principal difference between coroutines and routines -is that a coroutine enables explicit suspend and resume of its progress via -additional operations by preserving execution state and thus provides an -[*enhanced control flow] (maintaining the execution context). -[heading How it works] - -Functions foo() and bar() are supposed to alternate their execution (leave and -enter function body). - -[$../../../../libs/coroutine/doc/images/foo_bar.png [align center]] - -If coroutines would be called such as routines, the stack would grow with -every call and will never be degraded. A jump into the middle of a coroutine -would not be possible, because the return address would have been on top of -stack entries. - -The solution is that each coroutine has its own stack and control-block -(__fcontext__ from __boost_context__). -Before the coroutine gets suspended, the non-volatile registers (including stack -and instruction/program pointer) of the currently active coroutine are stored in -coroutine's control-block. -The registers of the newly activated coroutine must be restored from its -associated control-block before it can continue with their work. - -The context switch requires no system privileges and provides cooperative -multitasking on the level of language. Coroutines provide quasi parallelism. -When a program is supposed to do several things at the same time, coroutines -help to do this much simpler and more elegant than with only a single flow of -control. -Advantages can be seen particularly clearly with the use of a recursive -function, such as traversal of binary trees (see example 'same fringe'). -[heading characteristics] -Characteristics [footnote Moura, Ana Lucia De and Ierusalimschy, Roberto. -"Revisiting coroutines". ACM Trans. Program. Lang. Syst., Volume 31 Issue 2, -February 2009, Article No. 6] of a coroutine are: - -* values of local data persist between successive calls (context switches) -* execution is suspended as control leaves coroutine and resumed at certain time later -* symmetric or asymmetric control-transfer mechanism -* first-class object (can be passed as argument, returned by procedures, - stored in a data structure to be used later or freely manipulated by - the developer) -* stackful or stackless - -Coroutines are useful in simulation, artificial intelligence, concurrent -programming, text processing and data manipulation, supporting -the implementation of components such as cooperative tasks (fibers), iterators, -generators, infinite lists, pipes etc. -[heading execution-transfer mechanism] -Two categories of coroutines exist: symmetric and asymmetric coroutines. -A symmetric coroutine transfers the execution control only via one operation. -The target coroutine must be explicitly specified in the transfer operation. -Asymmetric coroutines provide two transfer operations: -the ['suspend]-operation returns to the invoker by preserving the -execution context and the ['resume]-operation restores the execution -context, e.g. re-enters the coroutine at the same point as it was suspended -before. - -[$../../../../libs/coroutine/doc/images/foo_bar_seq.png [align center]] - -Both concepts are equivalent and a coroutine library can provide either -symmetric or asymmetric coroutines. -[heading stackfulness] -In contrast to a stackless coroutine a stackful coroutine allows to suspend -from nested stackframes. The execution resumes at exact the same point in the -code as it was suspended before. -With a stackless coroutine, only the top-level routine may be suspended. Any -routine called by that top-level routine may not ityield suspend. This prohibits -providing suspend/resume operations in routines within a general-purpose library. -[heading first-class continuation] -A first-class continuation can be passed as an argument, returned by a -function and stored in a data structure to be used later. -In some implementations (for instance C# ['yield]) the continuation can -not be directly accessed or directly manipulated. -Without stackfulness and first-class semantics some useful execution control -flows cannot be supported (for instance cooperative multitasking or -checkpointing). -[endsect] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/overview.qbk b/doc/overview.qbk index d5ddb10..bf87144 100644 --- a/doc/overview.qbk +++ b/doc/overview.qbk @@ -1,39 +1,39 @@ -[/ - 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:overview Overview] -__boost_coroutine__ provides templates for generalized subroutines which allow -multiple entry points for suspending and resuming execution at certain -locations. -It preserves the local state of execution and allows re-entering subroutines more -than once (useful if state must be kept across function calls). -Coroutines can be viewed as a language-level construct providing a special kind -of control flow. -In contrast to threads, which are pre-emptive, __coro__ switches are -cooperative (programmer controls when a switch will happen). The kernel is not -involved in the coroutine switches. -The implementation uses __boost_context__ for context switching. -This library is a follow-up on -[@http://www.crystalclearsoftware.com/soc/coroutine/ Boost.Coroutine] -by Giovanni P. Deretta. -In order to use the classes and functions described here, you can either include -the specific headers specified by the descriptions of each class or function, or -include the master library header: - #include -which includes all the other headers in turn. -All functions and classes are contained in the namespace __coro_ns__. -[endsect] + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/symmetric.qbk b/doc/symmetric.qbk index 6012ecc..ff880fa 100644 --- a/doc/symmetric.qbk +++ b/doc/symmetric.qbk @@ -13,59 +13,49 @@ to any other (symmetric) coroutine. E.g. a symmetric coroutine is not required to return to its caller. -[heading __scoro__] -__scoro__ starts a symmetric coroutine and transfers parameter to its __coro_fn__. +[heading __call_coro___] +__call_coro___ starts a symmetric coroutine and transfers parameter to its +__coro_fn__. The first template parameter defining the transferred parameter type. -The constructor of __scoro__ takes a function (__coro_fn__) accepting a -reference to a __yield_scoro__ as argument. Instantiating a __scoro__ does +The constructor of __call_coro___ takes a function (__coro_fn__) accepting a +reference to a __yield_coro__ as argument. Instantiating a __call_coro___ does not pass the control of execution to __coro_fn__ - instead the first call of -__scoro_op__ synthesizes a __yield_scoro__ passed it as reference to __coro_fn__. +__call_coro_op__ synthesizes a __yield_coro__ passed it as reference to +__coro_fn__. The interface does not contain a ['get()]-function: you can not retrieve values from another execution context with this kind of coroutine. -[heading __yield_scoro__] -__yield_scoro_op__ ist used to transfers data to another execution context - -which might be a __scoro__ or called with no argument back to the excecution -context were the chain of symmetric coroutines has been started (invocation of -__scoro_op__). +[heading __yield_coro__] +__yield_coro_op__ ist used to transfers data and execution control to another +context - which might be a __call_coro___ or called with no argument back to the +excecution context were the chain of symmetric coroutines has been started +(invocation of __call_coro_op__). The class has only one template parameter defining the transferred parameter type. -Data transferred to the coroutine are accessed through __yield_scoro_get__. +Data transferred to the coroutine are accessed through __yield_coro_get__. [heading coroutine-function] -The __coro_fn__ returns ['void] and takes __yield_scoro__, providing +The __coro_fn__ returns ['void] and takes __yield_coro__, providing coroutine functionality inside the coroutine-fn, as argument, so that using this instance passed as argument to __coro_fn__ is the only way to transfer data and execution control. -__scoro__ does not enter the __coro_fn__ at __scoro__ construction but entered -by the first invocation of __scoro_op__. - - -[heading passing data from a pull-coroutine to main-context] -In order to transfer data from a __pull_coro__ to the main-context the framework -synthesizes a __push_coro__ associated with the __pull_coro__ instance in the -main-context. The synthesized __push_coro__ is passed as argument to __coro_fn__.\\ -The __coro_fn__ must call this __push_coro_op__ in order to transfer each -data value back to the main-context. -In the main-context, the __pull_coro_bool__ determines whether the coroutine is -still valid and a data value is available or __coro_fn__ has terminated -(__pull_coro__ is invalid; no data value available). Access to the transferred -data value is given by __pull_coro_get__. +__call_coro___ does not enter the __coro_fn__ at __call_coro___ construction but +entered by the first invocation of __call_coro_op__. [heading passing data from main-context to a symmetric-coroutine] -In order to transfer data to a __scoro__ from the main-context the framework -synthesizes a __yield_scoro__ associated with the __scoro__ instance in the -main-context. The synthesized __yield_scoro__ is passed as argument to +In order to transfer data to a __call_coro___ from the main-context the framework +synthesizes a __yield_coro__ associated with the __call_coro___ instance in the +main-context. The synthesized __yield_coro__ is passed as argument to __coro_fn__. -The main-context must call __scoro_op__ in order to transfer each data value +The main-context must call __call_coro_op__ in order to transfer each data value into the __coro_fn__. -Access to the transferred data value is given by __yield_scoro_get__. +Access to the transferred data value is given by __yield_coro_get__. - boost::coroutines::symmetric_coroutine coro( // constructor does NOT enter coroutine-function + boost::coroutines::symmetric_coroutine::call_type coro( // constructor does NOT enter coroutine-function [&](boost::coroutines::symmetric_coroutine::yield_type& yield){ for (;;) { std::cout << yield.get() << " "; @@ -81,7 +71,7 @@ Access to the transferred data value is given by __yield_scoro_get__. [heading exceptions] -An exception thrown and not catched inside a __scoro__'s __coro_fn__ will call +An exception thrown and not catched inside a __call_coro___'s __coro_fn__ will call __terminate__. [important Code executed by coroutine must not prevent the propagation of the @@ -124,10 +114,10 @@ After unwinding, a __coro__ is complete. } }; - boost::coroutines::symmetric_coroutine other_coro(...); + boost::coroutines::symmetric_coroutine::call_type other_coro(...); { - boost::coroutines::symmetric_coroutine coro( + boost::coroutines::symmetric_coroutine::call_type coro( [&](boost::coroutines::symmetric_coroutine::yield_type& yield){ X x; std::cout<<"fn()"<::yield_type::get(); - R& symmetric_oroutine::yield_type::get(); - void symmetric_oroutineyield_type::get()=delete; + R symmetric_coroutine::yield_type::get(); + R& symmetric_coroutine::yield_type::get(); + void symmetric_coroutineyield_type::get()=delete; [variablelist [[Preconditions:] [`*this` is not a __not_a_coro__.]] @@ -266,48 +256,48 @@ of `other`.]] #include template< typename Arg, typename StackAllocator = standard_stack_allocator > - class symmetric_coroutine<> + class symmetric_coroutine<>::call_type { public: - symmetric_coroutine(); + call_type(); template< typename Fn > - symmetric_coroutine( Fn fn, attributes const& attr = attributes() ); + call_type( Fn fn, attributes const& attr = attributes() ); template< typename Fn > - symmetric_coroutine( Fn && fn, attributes const& attr = attributes(), + call_type( Fn && fn, attributes const& attr = attributes(), StackAllocator stack_alloc = StackAllocator() ); - symmetric_coroutine( symmetric_coroutine cosnt& other)=delete; + call_type( call_type cosnt& other)=delete; - symmetric_coroutine & operator=( symmetric_coroutine const& other)=delete; + call_type & operator=( call_type const& other)=delete; - symmetric_coroutine( symmetric_coroutine && other); + call_type( call_type && other); - symmetric_coroutine & operator=( symmetric_coroutine && other); + call_type & operator=( call_type && other); - ~symmetric_coroutine(); + ~call_type(); operator unspecified-bool-type() const; bool operator!() const; - void swap( symmetric_coroutine & other); + void swap( call_type & other); - symmetric_coroutine & operator()( Arg&& arg); + call_type & operator()( Arg&& arg); }; template< typename Arg > - void swap( symmetric_coroutine< Arg > & l, symmetric_coroutine< Arg > & r); + void swap( symmetric_coroutine< Arg >::call_type & l, symmetric_coroutine< Arg >::call_type & r); -[heading `symmetric_coroutine()`] +[heading `call_type()`] [variablelist [[Effects:] [Creates a coroutine representing __not_a_coro__.]] [[Throws:] [Nothing.]] ] [heading `template< typename Fn, typename StackAllocator > - symmetric_coroutine( Fn fn, attributes const& attr, StackAllocator const& stack_alloc)`] + call_type( Fn fn, attributes const& attr, StackAllocator const& stack_alloc)`] [variablelist [[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() when ! is_stack_unbound().]] @@ -317,7 +307,7 @@ For allocating/deallocating the stack `stack_alloc` is used.]] ] [heading `template< typename Fn, typename StackAllocator > - symmetric_coroutine( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`] + call_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc)`] [variablelist [[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() when ! is_stack_unbound().]] @@ -326,14 +316,14 @@ determines stack clean-up and preserving floating-point registers. For allocating/deallocating the stack `stack_alloc` is used.]] ] -[heading `symmetric_coroutine( symmetric_coroutine && other)`] +[heading `call_type( call_type && other)`] [variablelist [[Effects:] [Moves the internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] [[Throws:] [Nothing.]] ] -[heading `symmetric_coroutine & operator=( symmetric_coroutine && other)`] +[heading `call_type & operator=( call_type && other)`] [variablelist [[Effects:] [Destroys the internal data of `*this` and moves the internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] @@ -354,12 +344,12 @@ has returned (completed), the function returns true. Otherwise false.]] [[Throws:] [Nothing.]] ] -[heading `symmetric_coroutine<> & operator()(Arg&& arg)`] +[heading `call_type<> & operator()(Arg&& arg)`] - symmetric_coroutine& coroutine::operator()(const Arg&); - symmetric_coroutine& coroutine::operator()(Arg&&); - symmetric_coroutine& coroutine::operator()(Arg&); - symmetric_coroutine& coroutine::operator()(); + symmetric_coroutine::call_type& coroutine::call_type::operator()(const Arg&); + symmetric_coroutine::call_type& coroutine::call_type::operator()(Arg&&); + symmetric_coroutine::call_type& coroutine::call_type::operator()(Arg&); + symmetric_coroutine::call_type& coroutine::call_type::operator()(); [variablelist [[Preconditions:] [operator unspecified-bool-type() returns true for `*this`.]] @@ -368,7 +358,7 @@ has returned (completed), the function returns true. Otherwise false.]] [[Throws:] [Exceptions thrown inside __coro_fn__.]] ] -[heading `void swap( symmetric_coroutine & other)`] +[heading `void swap( call_type & other)`] [variablelist [[Effects:] [Swaps the internal data from `*this` with the values of `other`.]] @@ -378,7 +368,7 @@ of `other`.]] [heading Non-member function `swap()`] template< typename Arg > - void swap( symmetric_coroutine< Arg > & l, symmetric_coroutine< Arg > & r); + void swap( symmetric_coroutine< Arg >::call_type & l, symmetric_coroutine< Arg >::call_type & r); [variablelist [[Effects:] [As if 'l.swap( r)'.]] diff --git a/example/cpp03/symmetric/dice_game.cpp b/example/cpp03/symmetric/dice_game.cpp index 90de50c..d8e96d6 100644 --- a/example/cpp03/symmetric/dice_game.cpp +++ b/example/cpp03/symmetric/dice_game.cpp @@ -38,7 +38,7 @@ private: public: int id; player * nxt; - coro_t coro; + coro_t::call_type coro; boost::random::random_device gen; player( int id_) : diff --git a/example/cpp03/symmetric/merge_arrays.cpp b/example/cpp03/symmetric/merge_arrays.cpp index 78c983e..1c415ad 100644 --- a/example/cpp03/symmetric/merge_arrays.cpp +++ b/example/cpp03/symmetric/merge_arrays.cpp @@ -40,7 +40,7 @@ public: std::vector< int > const& from; std::size_t idx; merger * other; - coro_t coro; + coro_t::call_type coro; merger( std::vector< int > const& from_, std::vector< int > & to, std::size_t max) : max_( max), diff --git a/example/cpp03/symmetric/simple.cpp b/example/cpp03/symmetric/simple.cpp index e9e78b2..a4ab311 100644 --- a/example/cpp03/symmetric/simple.cpp +++ b/example/cpp03/symmetric/simple.cpp @@ -12,8 +12,8 @@ typedef boost::coroutines::symmetric_coroutine< void > coro_t; -coro_t * c1 = 0; -coro_t * c2 = 0; +coro_t::call_type * c1 = 0; +coro_t::call_type * c2 = 0; void foo( coro_t::yield_type & yield) { @@ -35,8 +35,8 @@ void bar( coro_t::yield_type & yield) int main( int argc, char * argv[]) { - coro_t coro1( foo); - coro_t coro2( bar); + coro_t::call_type coro1( foo); + coro_t::call_type coro2( bar); c1 = & coro1; c2 = & coro2; coro1(); diff --git a/example/cpp11/symmetric/merge_arrays.cpp b/example/cpp11/symmetric/merge_arrays.cpp index df50f6b..99b6420 100644 --- a/example/cpp11/symmetric/merge_arrays.cpp +++ b/example/cpp11/symmetric/merge_arrays.cpp @@ -17,9 +17,9 @@ std::vector< int > merge( std::vector< int > const& a, std::vector< int > const& { std::vector< int > c; std::size_t idx_a = 0, idx_b = 0; - coro_t * other_a = 0, * other_b = 0; + coro_t::call_type * other_a = 0, * other_b = 0; - coro_t coro_a( + coro_t::call_type coro_a( [&]( coro_t::yield_type & yield) { while ( idx_a < a.size() ) { @@ -31,7 +31,7 @@ std::vector< int > merge( std::vector< int > const& a, std::vector< int > const& c.push_back( b[idx_b]); }); - coro_t coro_b( + coro_t::call_type coro_b( [&]( coro_t::yield_type & yield) { while ( idx_b < b.size() ) { diff --git a/example/cpp11/symmetric/simple.cpp b/example/cpp11/symmetric/simple.cpp index 098f69b..2bc41db 100644 --- a/example/cpp11/symmetric/simple.cpp +++ b/example/cpp11/symmetric/simple.cpp @@ -13,10 +13,10 @@ typedef boost::coroutines::symmetric_coroutine< void > coro_t; int main( int argc, char * argv[]) { - coro_t * other1 = 0; - coro_t * other2 = 0; + coro_t::call_type * other1 = 0; + coro_t::call_type * other2 = 0; - coro_t coro1( + coro_t::call_type coro1( [&]( coro_t::yield_type & yield) { std::cout << "foo1" << std::endl; yield( * other2); @@ -24,7 +24,7 @@ int main( int argc, char * argv[]) yield( * other2); std::cout << "foo3" << std::endl; }); - coro_t coro2( + coro_t::call_type coro2( [&]( coro_t::yield_type & yield) { std::cout << "bar1" << std::endl; yield( * other1); diff --git a/include/boost/coroutine/detail/symmetric_coroutine_call.hpp b/include/boost/coroutine/detail/symmetric_coroutine_call.hpp new file mode 100644 index 0000000..dba03ff --- /dev/null +++ b/include/boost/coroutine/detail/symmetric_coroutine_call.hpp @@ -0,0 +1,892 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H +#define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H + +#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, typename StackAllocator > +class symmetric_coroutine_call +{ +private: + template< typename X > + friend class symmetric_coroutine_yield; + + typedef symmetric_coroutine_impl< Arg > impl_type; + typedef parameters< Arg > param_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call) + + struct dummy {}; + + impl_type * impl_; + StackAllocator stack_alloc_; + stack_context stack_ctx_; + coroutine_context caller_; + coroutine_context callee_; + +public: + typedef Arg value_type; + typedef symmetric_coroutine_yield< Arg > yield_type; + + symmetric_coroutine_call() BOOST_NOEXCEPT : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( yield_type &); + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attr = attributes() ) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< coroutine_fn, impl_type, yield_type >, + & stack_ctx_); + setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attr, + StackAllocator const& stack_alloc) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< coroutine_fn, impl_type, yield_type >, + & stack_ctx_); + setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +# endif + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr = attributes() ) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr, + StackAllocator const& stack_alloc) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +#else + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attr = attributes(), + typename disable_if< + is_convertible< Fn&, BOOST_RV_REF(Fn) >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + typename disable_if< + is_convertible< Fn&, BOOST_RV_REF(Fn) >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr = attributes(), + typename disable_if< + is_same< typename decay< Fn >::type, symmetric_coroutine_call >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr, + StackAllocator const& stack_alloc, + typename disable_if< + is_same< typename decay< Fn >::type, symmetric_coroutine_call >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +#endif + + ~symmetric_coroutine_call() BOOST_NOEXCEPT + { + if ( 0 != stack_ctx_.sp) + { + BOOST_ASSERT( 0 != impl_); + impl_->unwind_stack(); + stack_alloc_.deallocate( stack_ctx_); + impl_ = 0; + } + } + + symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { swap( other); } + + symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT + { + symmetric_coroutine_call tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT + { + std::swap( impl_, other.impl_); + std::swap( stack_alloc_, other.stack_alloc_); + std::swap( stack_ctx_, other.stack_ctx_); + std::swap( caller_, other.caller_); + std::swap( callee_, other.callee_); + } + + symmetric_coroutine_call & operator()( Arg arg) BOOST_NOEXCEPT + { + BOOST_ASSERT( * this); + + impl_->run( arg); + return * this; + } + + symmetric_coroutine_call & operator()( BOOST_RV_REF( Arg) arg) BOOST_NOEXCEPT + { + BOOST_ASSERT( * this); + + impl_->run( forward< Arg >( arg) ); + return * this; + } +}; + +template< typename Arg, typename StackAllocator > +class symmetric_coroutine_call< Arg &, StackAllocator > +{ +private: + template< typename X > + friend class symmetric_coroutine_yield; + + typedef symmetric_coroutine_impl< Arg & > impl_type; + typedef parameters< Arg & > param_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call) + + struct dummy {}; + + impl_type * impl_; + StackAllocator stack_alloc_; + stack_context stack_ctx_; + coroutine_context caller_; + coroutine_context callee_; + +public: + typedef Arg value_type; + typedef symmetric_coroutine_yield< Arg & > yield_type; + + symmetric_coroutine_call() BOOST_NOEXCEPT : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( yield_type &); + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attr = attributes() ) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< coroutine_fn, impl_type, yield_type >, + & stack_ctx_); + setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attr, + StackAllocator const& stack_alloc) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< coroutine_fn, impl_type, yield_type >, + & stack_ctx_); + setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +# endif + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr = attributes() ) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr, + StackAllocator const& stack_alloc) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +#else + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attr = attributes(), + typename disable_if< + is_convertible< Fn&, BOOST_RV_REF(Fn) >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + typename disable_if< + is_convertible< Fn&, BOOST_RV_REF(Fn) >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr = attributes(), + typename disable_if< + is_same< typename decay< Fn >::type, symmetric_coroutine_call >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr, + StackAllocator const& stack_alloc, + typename disable_if< + is_same< typename decay< Fn >::type, symmetric_coroutine_call >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +#endif + + ~symmetric_coroutine_call() BOOST_NOEXCEPT + { + if ( 0 != stack_ctx_.sp) + { + BOOST_ASSERT( 0 != impl_); + impl_->unwind_stack(); + stack_alloc_.deallocate( stack_ctx_); + impl_ = 0; + } + } + + symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { swap( other); } + + symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT + { + symmetric_coroutine_call tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT + { + std::swap( impl_, other.impl_); + std::swap( stack_alloc_, other.stack_alloc_); + std::swap( stack_ctx_, other.stack_ctx_); + std::swap( caller_, other.caller_); + std::swap( callee_, other.callee_); + } + + symmetric_coroutine_call & operator()( Arg & arg) BOOST_NOEXCEPT + { + BOOST_ASSERT( * this); + + impl_->run( arg); + return * this; + } +}; + +template< typename StackAllocator > +class symmetric_coroutine_call< void, StackAllocator > +{ +private: + template< typename X > + friend class symmetric_coroutine_yield; + + typedef symmetric_coroutine_impl< void > impl_type; + typedef parameters< void > param_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call) + + struct dummy {}; + + impl_type * impl_; + StackAllocator stack_alloc_; + stack_context stack_ctx_; + coroutine_context caller_; + coroutine_context callee_; + +public: + typedef void value_type; + typedef symmetric_coroutine_yield< void > yield_type; + + symmetric_coroutine_call() BOOST_NOEXCEPT : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# ifdef BOOST_MSVC + typedef void ( * coroutine_fn)( yield_type &); + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attr = attributes() ) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline_void< coroutine_fn, impl_type, yield_type >, + & stack_ctx_); + setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + explicit symmetric_coroutine_call( coroutine_fn fn, + attributes const& attr, + StackAllocator const& stack_alloc) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline_void< coroutine_fn, impl_type, yield_type >, + & stack_ctx_); + setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +# endif + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr = attributes() ) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline_void< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr, + StackAllocator const& stack_alloc) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline_void< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +#else + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, + attributes const& attr = attributes(), + typename disable_if< + is_convertible< Fn&, BOOST_RV_REF(Fn) >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline_void< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( Fn fn, attributes const& attr, + StackAllocator const& stack_alloc, + typename disable_if< + is_convertible< Fn&, BOOST_RV_REF(Fn) >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline_void< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr = attributes(), + typename disable_if< + is_same< typename decay< Fn >::type, symmetric_coroutine_call >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline_void< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } + + template< typename Fn > + explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn, + attributes const& attr, + StackAllocator const& stack_alloc, + typename disable_if< + is_same< typename decay< Fn >::type, symmetric_coroutine_call >, + dummy* + >::type = 0) : + impl_( 0), + stack_alloc_( stack_alloc), + stack_ctx_(), + caller_(), + callee_() + { + stack_alloc_.allocate( stack_ctx_, attr.size); + callee_ = coroutine_context( + trampoline_void< Fn, impl_type, yield_type >, + & stack_ctx_); + setup< Fn > to( fn, & caller_, & callee_, attr); + impl_ = reinterpret_cast< impl_type * >( + caller_.jump( + callee_, + reinterpret_cast< intptr_t >( & to), + fpu_preserved == attr.preserve_fpu) ); + BOOST_ASSERT( impl_); + } +#endif + + ~symmetric_coroutine_call() BOOST_NOEXCEPT + { + if ( 0 != stack_ctx_.sp) + { + BOOST_ASSERT( 0 != impl_); + impl_->unwind_stack(); + stack_alloc_.deallocate( stack_ctx_); + impl_ = 0; + } + } + + symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT : + impl_( 0), + stack_alloc_(), + stack_ctx_(), + caller_(), + callee_() + { swap( other); } + + symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT + { + symmetric_coroutine_call tmp( boost::move( other) ); + swap( tmp); + return * this; + } + + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_ || impl_->is_complete(); } + + void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT + { + std::swap( impl_, other.impl_); + std::swap( stack_alloc_, other.stack_alloc_); + std::swap( stack_ctx_, other.stack_ctx_); + std::swap( caller_, other.caller_); + std::swap( callee_, other.callee_); + } + + symmetric_coroutine_call & operator()() BOOST_NOEXCEPT + { + BOOST_ASSERT( * this); + + impl_->run(); + return * this; + } +}; + +template< typename Arg, typename StackAllocator > +void swap( symmetric_coroutine_call< Arg, StackAllocator > & l, + symmetric_coroutine_call< Arg, StackAllocator > & r) +{ l.swap( r); } + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H diff --git a/include/boost/coroutine/symmetric_coroutine.hpp b/include/boost/coroutine/symmetric_coroutine.hpp index 9bdd8c8..1f807de 100644 --- a/include/boost/coroutine/symmetric_coroutine.hpp +++ b/include/boost/coroutine/symmetric_coroutine.hpp @@ -7,23 +7,10 @@ #ifndef BOOST_COROUTINES_SYMMETRIC_COROUTINE_H #define BOOST_COROUTINES_SYMMETRIC_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 @@ -33,849 +20,11 @@ namespace boost { namespace coroutines { -template< typename Arg, typename StackAllocator = standard_stack_allocator > -class symmetric_coroutine +template< typename T, typename StackAllocator = standard_stack_allocator > +struct symmetric_coroutine { -private: - template< typename X > - friend class detail::symmetric_coroutine_yield; - - typedef detail::symmetric_coroutine_impl< Arg > impl_type; - typedef detail::parameters< Arg > param_type; - - BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine) - - struct dummy {}; - - impl_type * impl_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; - detail::coroutine_context caller_; - detail::coroutine_context callee_; - -public: - typedef Arg value_type; - typedef detail::symmetric_coroutine_yield< Arg > yield_type; - - symmetric_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - {} - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES -# ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( yield_type &); - - explicit symmetric_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< coroutine_fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - explicit symmetric_coroutine( coroutine_fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< coroutine_fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -# endif - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -#else - template< typename Fn > - explicit symmetric_coroutine( Fn fn, - attributes const& attr = attributes(), - typename disable_if< - is_convertible< Fn&, BOOST_RV_REF(Fn) >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc, - typename disable_if< - is_convertible< Fn&, BOOST_RV_REF(Fn) >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes(), - typename disable_if< - is_same< typename decay< Fn >::type, symmetric_coroutine >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc, - typename disable_if< - is_same< typename decay< Fn >::type, symmetric_coroutine >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -#endif - - ~symmetric_coroutine() BOOST_NOEXCEPT - { - if ( 0 != stack_ctx_.sp) - { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); - impl_ = 0; - } - } - - symmetric_coroutine( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { swap( other); } - - symmetric_coroutine & operator=( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT - { - symmetric_coroutine tmp( boost::move( other) ); - swap( tmp); - return * this; - } - - BOOST_EXPLICIT_OPERATOR_BOOL(); - - bool operator!() const BOOST_NOEXCEPT - { return 0 == impl_ || impl_->is_complete(); } - - void swap( symmetric_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - std::swap( caller_, other.caller_); - std::swap( callee_, other.callee_); - } - - symmetric_coroutine & operator()( Arg arg) BOOST_NOEXCEPT - { - BOOST_ASSERT( * this); - - impl_->run( arg); - return * this; - } - - symmetric_coroutine & operator()( BOOST_RV_REF( Arg) arg) BOOST_NOEXCEPT - { - BOOST_ASSERT( * this); - - impl_->run( forward< Arg >( arg) ); - return * this; - } -}; - -template< typename Arg, typename StackAllocator > -class symmetric_coroutine< Arg &, StackAllocator > -{ -private: - template< typename X > - friend class detail::symmetric_coroutine_yield; - - typedef detail::symmetric_coroutine_impl< Arg & > impl_type; - typedef detail::parameters< Arg & > param_type; - - BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine) - - struct dummy {}; - - impl_type * impl_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; - detail::coroutine_context caller_; - detail::coroutine_context callee_; - -public: - typedef Arg value_type; - typedef detail::symmetric_coroutine_yield< Arg & > yield_type; - - symmetric_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - {} - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES -# ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( yield_type &); - - explicit symmetric_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< coroutine_fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - explicit symmetric_coroutine( coroutine_fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< coroutine_fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -# endif - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -#else - template< typename Fn > - explicit symmetric_coroutine( Fn fn, - attributes const& attr = attributes(), - typename disable_if< - is_convertible< Fn&, BOOST_RV_REF(Fn) >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc, - typename disable_if< - is_convertible< Fn&, BOOST_RV_REF(Fn) >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes(), - typename disable_if< - is_same< typename decay< Fn >::type, symmetric_coroutine >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc, - typename disable_if< - is_same< typename decay< Fn >::type, symmetric_coroutine >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -#endif - - ~symmetric_coroutine() BOOST_NOEXCEPT - { - if ( 0 != stack_ctx_.sp) - { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); - impl_ = 0; - } - } - - symmetric_coroutine( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { swap( other); } - - symmetric_coroutine & operator=( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT - { - symmetric_coroutine tmp( boost::move( other) ); - swap( tmp); - return * this; - } - - BOOST_EXPLICIT_OPERATOR_BOOL(); - - bool operator!() const BOOST_NOEXCEPT - { return 0 == impl_ || impl_->is_complete(); } - - void swap( symmetric_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - std::swap( caller_, other.caller_); - std::swap( callee_, other.callee_); - } - - symmetric_coroutine & operator()( Arg & arg) BOOST_NOEXCEPT - { - BOOST_ASSERT( * this); - - impl_->run( arg); - return * this; - } -}; - -template< typename StackAllocator > -class symmetric_coroutine< void, StackAllocator > -{ -private: - template< typename X > - friend class detail::symmetric_coroutine_yield; - - typedef detail::symmetric_coroutine_impl< void > impl_type; - typedef detail::parameters< void > param_type; - - BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine) - - struct dummy {}; - - impl_type * impl_; - StackAllocator stack_alloc_; - stack_context stack_ctx_; - detail::coroutine_context caller_; - detail::coroutine_context callee_; - -public: - typedef void value_type; - typedef detail::symmetric_coroutine_yield< void > yield_type; - - symmetric_coroutine() BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - {} - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES -# ifdef BOOST_MSVC - typedef void ( * coroutine_fn)( yield_type &); - - explicit symmetric_coroutine( coroutine_fn fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline_void< coroutine_fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - explicit symmetric_coroutine( coroutine_fn fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline_void< coroutine_fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< coroutine_fn > to( forward< coroutine_fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -# endif - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes() ) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline_void< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline_void< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( forward< Fn >( fn), & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -#else - template< typename Fn > - explicit symmetric_coroutine( Fn fn, - attributes const& attr = attributes(), - typename disable_if< - is_convertible< Fn&, BOOST_RV_REF(Fn) >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline_void< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc, - typename disable_if< - is_convertible< Fn&, BOOST_RV_REF(Fn) >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline_void< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr = attributes(), - typename disable_if< - is_same< typename decay< Fn >::type, symmetric_coroutine >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline_void< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } - - template< typename Fn > - explicit symmetric_coroutine( BOOST_RV_REF( Fn) fn, - attributes const& attr, - StackAllocator const& stack_alloc, - typename disable_if< - is_same< typename decay< Fn >::type, symmetric_coroutine >, - dummy* - >::type = 0) : - impl_( 0), - stack_alloc_( stack_alloc), - stack_ctx_(), - caller_(), - callee_() - { - stack_alloc_.allocate( stack_ctx_, attr.size); - callee_ = detail::coroutine_context( - detail::trampoline_void< Fn, impl_type, yield_type >, - & stack_ctx_); - detail::setup< Fn > to( fn, & caller_, & callee_, attr); - impl_ = reinterpret_cast< impl_type * >( - caller_.jump( - callee_, - reinterpret_cast< intptr_t >( & to), - fpu_preserved == attr.preserve_fpu) ); - BOOST_ASSERT( impl_); - } -#endif - - ~symmetric_coroutine() BOOST_NOEXCEPT - { - if ( 0 != stack_ctx_.sp) - { - BOOST_ASSERT( 0 != impl_); - impl_->unwind_stack(); - stack_alloc_.deallocate( stack_ctx_); - impl_ = 0; - } - } - - symmetric_coroutine( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT : - impl_( 0), - stack_alloc_(), - stack_ctx_(), - caller_(), - callee_() - { swap( other); } - - symmetric_coroutine & operator=( BOOST_RV_REF( symmetric_coroutine) other) BOOST_NOEXCEPT - { - symmetric_coroutine tmp( boost::move( other) ); - swap( tmp); - return * this; - } - - BOOST_EXPLICIT_OPERATOR_BOOL(); - - bool operator!() const BOOST_NOEXCEPT - { return 0 == impl_ || impl_->is_complete(); } - - void swap( symmetric_coroutine & other) BOOST_NOEXCEPT - { - std::swap( impl_, other.impl_); - std::swap( stack_alloc_, other.stack_alloc_); - std::swap( stack_ctx_, other.stack_ctx_); - std::swap( caller_, other.caller_); - std::swap( callee_, other.callee_); - } - - symmetric_coroutine & operator()() BOOST_NOEXCEPT - { - BOOST_ASSERT( * this); - - impl_->run(); - return * this; - } + typedef detail::symmetric_coroutine_call< T, StackAllocator > call_type; + typedef detail::symmetric_coroutine_yield< T > yield_type; }; }} diff --git a/performance/symmetric/performance_create_prealloc.cpp b/performance/symmetric/performance_create_prealloc.cpp index 8934f1d..f738131 100644 --- a/performance/symmetric/performance_create_prealloc.cpp +++ b/performance/symmetric/performance_create_prealloc.cpp @@ -33,7 +33,7 @@ duration_type measure_time( duration_type overhead) time_point_type start( clock_type::now() ); for ( std::size_t i = 0; i < jobs; ++i) { - coro_type c( fn, + coro_type::call_type c( fn, boost::coroutines::attributes( stack_allocator::default_stacksize(), unwind_stack, preserve_fpu), stack_alloc); } @@ -51,7 +51,7 @@ cycle_type measure_cycles( cycle_type overhead) cycle_type start( cycles() ); for ( std::size_t i = 0; i < jobs; ++i) { - coro_type c( fn, + coro_type::call_type c( fn, boost::coroutines::attributes( stack_allocator::default_stacksize(), unwind_stack, preserve_fpu), stack_alloc); } diff --git a/performance/symmetric/performance_create_protected.cpp b/performance/symmetric/performance_create_protected.cpp index 34e87b3..b8021f1 100644 --- a/performance/symmetric/performance_create_protected.cpp +++ b/performance/symmetric/performance_create_protected.cpp @@ -32,7 +32,7 @@ duration_type measure_time( duration_type overhead) time_point_type start( clock_type::now() ); for ( std::size_t i = 0; i < jobs; ++i) { - coro_type c( fn, + coro_type::call_type c( fn, boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); } duration_type total = clock_type::now() - start; @@ -49,7 +49,7 @@ cycle_type measure_cycles( cycle_type overhead) cycle_type start( cycles() ); for ( std::size_t i = 0; i < jobs; ++i) { - coro_type c( fn, + coro_type::call_type c( fn, boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); } cycle_type total = cycles() - start; diff --git a/performance/symmetric/performance_create_standard.cpp b/performance/symmetric/performance_create_standard.cpp index 220ea4a..a62dee1 100644 --- a/performance/symmetric/performance_create_standard.cpp +++ b/performance/symmetric/performance_create_standard.cpp @@ -32,7 +32,7 @@ duration_type measure_time( duration_type overhead) time_point_type start( clock_type::now() ); for ( std::size_t i = 0; i < jobs; ++i) { - coro_type c( fn, + coro_type::call_type c( fn, boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); } duration_type total = clock_type::now() - start; @@ -49,7 +49,7 @@ cycle_type measure_cycles( cycle_type overhead) cycle_type start( cycles() ); for ( std::size_t i = 0; i < jobs; ++i) { - coro_type c( fn, + coro_type::call_type c( fn, boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); } cycle_type total = cycles() - start; diff --git a/performance/symmetric/performance_switch.cpp b/performance/symmetric/performance_switch.cpp index 853cd3c..16ca494 100644 --- a/performance/symmetric/performance_switch.cpp +++ b/performance/symmetric/performance_switch.cpp @@ -46,7 +46,7 @@ duration_type measure_time_void( duration_type overhead) { duration_type total = duration_type::zero(); for ( std::size_t i = 0; i < jobs; ++i) { - boost::coroutines::symmetric_coroutine< void > c( fn_void, + boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void, boost::coroutines::attributes( preserve_fpu) ); time_point_type start( clock_type::now() ); c(); @@ -64,7 +64,7 @@ duration_type measure_time_int( duration_type overhead) int i = 3; duration_type total = duration_type::zero(); for ( std::size_t i = 0; i < jobs; ++i) { - boost::coroutines::symmetric_coroutine< int > c( fn_int, + boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int, boost::coroutines::attributes( preserve_fpu) ); time_point_type start( clock_type::now() ); c( i); @@ -82,7 +82,7 @@ duration_type measure_time_x( duration_type overhead) X x("abc"); duration_type total = duration_type::zero(); for ( std::size_t i = 0; i < jobs; ++i) { - boost::coroutines::symmetric_coroutine< X > c( fn_x, + boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x, boost::coroutines::attributes( preserve_fpu) ); time_point_type start( clock_type::now() ); c( x); @@ -100,7 +100,7 @@ cycle_type measure_cycles_void( cycle_type overhead) { cycle_type total = 0; for ( std::size_t i = 0; i < jobs; ++i) { - boost::coroutines::symmetric_coroutine< void > c( fn_void, + boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void, boost::coroutines::attributes( preserve_fpu) ); cycle_type start( cycles() ); c(); @@ -118,7 +118,7 @@ cycle_type measure_cycles_int( cycle_type overhead) int i = 3; cycle_type total = 0; for ( std::size_t i = 0; i < jobs; ++i) { - boost::coroutines::symmetric_coroutine< int > c( fn_int, + boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int, boost::coroutines::attributes( preserve_fpu) ); cycle_type start( cycles() ); c( i); @@ -136,7 +136,7 @@ cycle_type measure_cycles_x( cycle_type overhead) X x("abc"); cycle_type total = 0; for ( std::size_t i = 0; i < jobs; ++i) { - boost::coroutines::symmetric_coroutine< X > c( fn_x, + boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x, boost::coroutines::attributes( preserve_fpu) ); cycle_type start( cycles() ); c( x); diff --git a/performance/symmetric/segmented/performance_create_segmented.cpp b/performance/symmetric/segmented/performance_create_segmented.cpp index d5d0ca7..6e68a7f 100644 --- a/performance/symmetric/segmented/performance_create_segmented.cpp +++ b/performance/symmetric/segmented/performance_create_segmented.cpp @@ -26,7 +26,7 @@ duration_type measure_time( duration_type overhead) { time_point_type start( clock_type::now() ); for ( std::size_t i = 0; i < jobs; ++i) { - boost::coroutines::symmetric_coroutine< void > c( fn, + boost::coroutines::symmetric_coroutine< void >::call_type c( fn, boost::coroutines::attributes( preserve_fpu) ); } duration_type total = clock_type::now() - start; @@ -41,7 +41,7 @@ cycle_type measure_cycles( cycle_type overhead) { cycle_type start( cycles() ); for ( std::size_t i = 0; i < jobs; ++i) { - boost::coroutines::symmetric_coroutine< void > c( fn, + boost::coroutines::symmetric_coroutine< void >::call_type c( fn, boost::coroutines::attributes( preserve_fpu) ); } cycle_type total = cycles() - start; diff --git a/test/test_symmetric_coroutine.cpp b/test/test_symmetric_coroutine.cpp index 8b4f866..024e79c 100644 --- a/test/test_symmetric_coroutine.cpp +++ b/test/test_symmetric_coroutine.cpp @@ -32,7 +32,7 @@ bool value1 = false; int value2 = 0; std::string value3; -coro::symmetric_coroutine< void > * term_coro = 0; +coro::symmetric_coroutine< void >::call_type * term_coro = 0; struct X { @@ -142,7 +142,7 @@ void f9( coro::symmetric_coroutine< void >::yield_type &, E const& e) { throw e; } void f10( coro::symmetric_coroutine< int >::yield_type & yield, - coro::symmetric_coroutine< int > & other) + coro::symmetric_coroutine< int >::call_type & other) { int i = yield.get(); yield( other, i); @@ -153,7 +153,7 @@ void f101( coro::symmetric_coroutine< int >::yield_type & yield) { value2 = yield.get(); } void f11( coro::symmetric_coroutine< void >::yield_type & yield, - coro::symmetric_coroutine< void > & other) + coro::symmetric_coroutine< void >::call_type & other) { yield( other); value2 = 7; @@ -163,7 +163,7 @@ void f111( coro::symmetric_coroutine< void >::yield_type &) { value2 = 3; } void f12( coro::symmetric_coroutine< X& >::yield_type & yield, - coro::symmetric_coroutine< X& > & other) + coro::symmetric_coroutine< X& >::call_type & other) { yield( other, yield.get()); p = & yield.get(); @@ -173,7 +173,7 @@ void f121( coro::symmetric_coroutine< X& >::yield_type & yield) { p = & yield.get(); } void f14( coro::symmetric_coroutine< int >::yield_type & yield, - coro::symmetric_coroutine< std::string > & other) + coro::symmetric_coroutine< std::string >::call_type & other) { std::string str( boost::lexical_cast< std::string >( yield.get() ) ); yield( other, str); @@ -185,7 +185,7 @@ void f141( coro::symmetric_coroutine< std::string >::yield_type & yield) void f15( coro::symmetric_coroutine< int >::yield_type & yield, int offset, - coro::symmetric_coroutine< int > & other) + coro::symmetric_coroutine< int >::call_type & other) { int x = yield.get(); value2 += x + offset; @@ -208,8 +208,8 @@ void f151( coro::symmetric_coroutine< int >::yield_type & yield, void test_move() { { - coro::symmetric_coroutine< void > coro1; - coro::symmetric_coroutine< void > coro2( empty); + coro::symmetric_coroutine< void >::call_type coro1; + coro::symmetric_coroutine< void >::call_type coro2( empty); BOOST_CHECK( ! coro1); BOOST_CHECK( coro2); coro1 = boost::move( coro2); @@ -222,7 +222,7 @@ void test_move() copyable cp( 3); BOOST_CHECK( cp.state); BOOST_CHECK( ! value1); - coro::symmetric_coroutine< int > coro( cp); + coro::symmetric_coroutine< int >::call_type coro( cp); coro( 3); BOOST_CHECK( cp.state); BOOST_CHECK( value1); @@ -233,7 +233,7 @@ void test_move() moveable mv( 7); BOOST_CHECK( mv.state); BOOST_CHECK( ! value1); - coro::symmetric_coroutine< int > coro( boost::move( mv) ); + coro::symmetric_coroutine< int >::call_type coro( boost::move( mv) ); coro( 7); BOOST_CHECK( ! mv.state); BOOST_CHECK( value1); @@ -244,7 +244,7 @@ void test_complete() { value2 = 0; - coro::symmetric_coroutine< void > coro( f2); + coro::symmetric_coroutine< void >::call_type coro( f2); BOOST_CHECK( coro); coro(); BOOST_CHECK( ! coro); @@ -255,13 +255,13 @@ void test_yield() { value2 = 0; - coro::symmetric_coroutine< int > coro3( + coro::symmetric_coroutine< int >::call_type coro3( boost::bind( f151, _1, 3) ); BOOST_CHECK( coro3); - coro::symmetric_coroutine< int > coro2( + coro::symmetric_coroutine< int >::call_type coro2( boost::bind( f15, _1, 2, boost::ref( coro3) ) ); BOOST_CHECK( coro2); - coro::symmetric_coroutine< int > coro1( + coro::symmetric_coroutine< int >::call_type coro1( boost::bind( f15, _1, 1, boost::ref( coro2) ) ); BOOST_CHECK( coro1); @@ -285,7 +285,7 @@ void test_pass_value() X x(7); BOOST_CHECK_EQUAL( ( int)7, x.i); BOOST_CHECK_EQUAL( 0, value2); - coro::symmetric_coroutine< X > coro( f3); + coro::symmetric_coroutine< X >::call_type coro( f3); BOOST_CHECK( coro); coro(7); BOOST_CHECK( ! coro); @@ -298,7 +298,7 @@ void test_pass_reference() p = 0; X x; - coro::symmetric_coroutine< X& > coro( f4); + coro::symmetric_coroutine< X& >::call_type coro( f4); BOOST_CHECK( coro); coro( x); BOOST_CHECK( ! coro); @@ -310,7 +310,7 @@ void test_pass_pointer() p = 0; X x; - coro::symmetric_coroutine< X* > coro( f5); + coro::symmetric_coroutine< X* >::call_type coro( f5); BOOST_CHECK( coro); coro( & x); BOOST_CHECK( ! coro); @@ -321,8 +321,8 @@ void test_unwind() { value2 = 0; { - coro::symmetric_coroutine< void > coro( f6); - coro::symmetric_coroutine< void > coro_e( empty); + coro::symmetric_coroutine< void >::call_type coro( f6); + coro::symmetric_coroutine< void >::call_type coro_e( empty); BOOST_CHECK( coro); BOOST_CHECK( coro_e); term_coro = & coro_e; @@ -338,11 +338,11 @@ void test_no_unwind() { value2 = 0; { - coro::symmetric_coroutine< void > coro( f6, + coro::symmetric_coroutine< void >::call_type coro( f6, coro::attributes( coro::stack_allocator::default_stacksize(), coro::no_stack_unwind) ); - coro::symmetric_coroutine< void > coro_e( empty); + coro::symmetric_coroutine< void >::call_type coro_e( empty); BOOST_CHECK( coro); BOOST_CHECK( coro_e); term_coro = & coro_e; @@ -358,8 +358,8 @@ void test_termination() { value2 = 0; - coro::symmetric_coroutine< int > coro( f7); - coro::symmetric_coroutine< void > coro_e( empty); + coro::symmetric_coroutine< int >::call_type coro( f7); + coro::symmetric_coroutine< void >::call_type coro_e( empty); BOOST_CHECK( coro); BOOST_CHECK( coro_e); term_coro = & coro_e; @@ -376,8 +376,8 @@ void test_yield_to_void() { value2 = 0; - coro::symmetric_coroutine< void > coro_other( f111); - coro::symmetric_coroutine< void > coro( boost::bind( f11, _1, boost::ref( coro_other) ) ); + coro::symmetric_coroutine< void >::call_type coro_other( f111); + coro::symmetric_coroutine< void >::call_type coro( boost::bind( f11, _1, boost::ref( coro_other) ) ); BOOST_CHECK( coro_other); BOOST_CHECK( coro); BOOST_CHECK_EQUAL( ( int) 0, value2); @@ -395,8 +395,8 @@ void test_yield_to_int() { value2 = 0; - coro::symmetric_coroutine< int > coro_other( f101); - coro::symmetric_coroutine< int > coro( boost::bind( f10, _1, boost::ref( coro_other) ) ); + coro::symmetric_coroutine< int >::call_type coro_other( f101); + coro::symmetric_coroutine< int >::call_type coro( boost::bind( f10, _1, boost::ref( coro_other) ) ); BOOST_CHECK( coro_other); BOOST_CHECK( coro); BOOST_CHECK_EQUAL( ( int) 0, value2); @@ -414,8 +414,8 @@ void test_yield_to_ref() { p = 0; - coro::symmetric_coroutine< X& > coro_other( f121); - coro::symmetric_coroutine< X& > coro( boost::bind( f12, _1, boost::ref( coro_other) ) ); + coro::symmetric_coroutine< X& >::call_type coro_other( f121); + coro::symmetric_coroutine< X& >::call_type coro( boost::bind( f12, _1, boost::ref( coro_other) ) ); BOOST_CHECK( coro_other); BOOST_CHECK( coro); BOOST_CHECK( 0 == p); @@ -438,8 +438,8 @@ void test_yield_to_different() value2 = 0; value3 = ""; - coro::symmetric_coroutine< std::string > coro_other( f141); - coro::symmetric_coroutine< int > coro( boost::bind( f14, _1, boost::ref( coro_other) ) ); + coro::symmetric_coroutine< std::string >::call_type coro_other( f141); + coro::symmetric_coroutine< int >::call_type coro( boost::bind( f14, _1, boost::ref( coro_other) ) ); BOOST_CHECK( coro_other); BOOST_CHECK( coro); BOOST_CHECK_EQUAL( ( int) 0, value2);