From 865902f9b5d3fffbb3b22272d241bfcdda339eff Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Wed, 17 Jul 2013 14:09:07 +0000 Subject: [PATCH] coroutine: intro of coroutine<>::pull_type, coroutine<>::push_type [SVN r85058] --- doc/coro.qbk | 13 +- doc/images/fringe.png | Bin 0 -> 7884 bytes doc/intro.qbk | 330 ++++------------------- doc/motivation.qbk | 136 ++++++++++ doc/old.qbk | 4 +- doc/unidirect.qbk | 186 ++++++------- example/cpp03/echo.cpp | 4 +- example/cpp03/echosse.cpp | 8 +- example/cpp03/fibonacci.cpp | 10 +- example/cpp03/parallel.cpp | 8 +- example/cpp03/power.cpp | 10 +- example/cpp03/same_fringe.cpp | 14 +- example/cpp03/segmented_stack.cpp | 4 +- example/cpp03/tree.h | 6 +- example/cpp03/unwind.cpp | 4 +- example/cpp11/await_emu.cpp | 4 +- example/cpp11/fibonacci.cpp | 12 +- example/cpp11/same_fringe.cpp | 14 +- example/cpp11/tree.h | 1 - include/boost/coroutine/v2/coroutine.hpp | 8 + performance/performance.cpp | 10 +- test/test_coroutine.cpp | 98 +++---- 22 files changed, 397 insertions(+), 487 deletions(-) create mode 100644 doc/images/fringe.png create mode 100644 doc/motivation.qbk diff --git a/doc/coro.qbk b/doc/coro.qbk index 31f77c8..89ee0b9 100644 --- a/doc/coro.qbk +++ b/doc/coro.qbk @@ -19,6 +19,7 @@ ] +[def __boost_asio__ [*Boost.Asio]] [def __boost_build__ [*Boost.Build]] [def __boost_context__ [*Boost.Context]] [def __boost_coroutine__ [*Boost.Coroutine]] @@ -39,8 +40,8 @@ [def __ctx__ ['context]] [def __coro__ ['coroutine]] -[def __push_coro__ ['push_coroutine]] -[def __pull_coro__ ['pull_coroutine]] +[def __push_coro__ ['coroutine<>::push_type]] +[def __pull_coro__ ['coroutine<>::pull_type]] [def __coro_fn__ ['coroutine-function]] [def __coros__ ['coroutines]] [def __not_a_coro__ ['not-a-coroutine]] @@ -68,9 +69,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 __pull_coro_get__ ['boost::coroutines::coroutine<>::pull_type::get()]] +[def __pull_coro_op__ ['boost::coroutines::coroutine<>::pull_type::operator()]] +[def __push_coro_op__ ['boost::coroutines::coroutine<>::push_type::operator()]] [def __server__ ['server]] [def __session__ ['session]] [def __stack_context__ ['boost::coroutines::stack_context]] @@ -79,9 +80,11 @@ [def __tie__ ['boost::tie]] [def __tuple__ ['boost::tuple<>]] [def __underflow__ ['stream_buf::underflow()]] +[def __yield_context__ ['boost::asio::yield_context]] [include overview.qbk] [include intro.qbk] +[include motivation.qbk] [include coroutine.qbk] [include attributes.qbk] [include stack.qbk] diff --git a/doc/images/fringe.png b/doc/images/fringe.png new file mode 100644 index 0000000000000000000000000000000000000000..83605b20ea64f08232b330943b4ffca2bf358c9c GIT binary patch literal 7884 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 KpUXO@geCy`zlH4p literal 0 HcmV?d00001 diff --git a/doc/intro.qbk b/doc/intro.qbk index 0d13d46..4cb56db 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -9,17 +9,18 @@ [heading Definition] -In computer science routines are defined as a sequence of operations. -The execution of routines form a parent-child relationship and the child -terminates always before the parent. -Coroutines are a generalization of routines. -The principal difference between coroutines and routines is that a coroutine -enables explicit suspend and resume of their progress via additional operations by -preserving local state, e.g. a coroutine is a kind of continuation. -A continuation is a object representing a suspended execution (registers, -stack). Each coroutine has its own stack and local variables, sub-routine calls -etc. -In this sense coroutines are (actually) a language concept. +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] @@ -41,8 +42,6 @@ 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. -[$../../../../libs/coroutine/doc/images/foo_bar_seq.png [align center]] - 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 @@ -52,284 +51,47 @@ Advantages can be seen particularly clearly with the use of a recursive function, such as traversal of binary trees (see example 'same fringe'). -[heading Example: asio::io_stream with std::stream] +[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: -This section demonstrates how stackfull coroutines help to use standard C++ -IO-streams together with IO-demultiplexer like __io_service__ (using -non-blocking IO). +* 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 - int main( int argc, char * argv[]) - { - ... - { - boost::asio::io_service io_service; - io_service.post( - boost::bind( - & server::start, - server::create( - io_service, port) ) ); - io_service.run(); - } - ... - } +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. -__server__ accepts connection-requests made by clients, creates for each new -connection an instance of type __session__ and invokes __start__ on it. +[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. - class server : public boost::enable_shared_from_this< server > - { - private: - boost::asio::io_service & io_service_; - boost::asio::ip::tcp::acceptor acceptor_; +[$../../../../libs/coroutine/doc/images/foo_bar_seq.png [align center]] - void handle_accept_( session * new_session, boost::system::error_code const& error) - { - if ( ! error) - { - // start asynchronous read - new_session->start(); - - // start asynchronous accept - start(); - } - } - - server( boost::asio::io_service & io_service, short port) : - io_service_( io_service), - acceptor_( - io_service_, - boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4(), port) ) - {} - - public: - typedef boost::shared_ptr< server > ptr_t; - - static ptr_t create( boost::asio::io_service & io_service, short port) - { return ptr_t( new server( io_service, port) ); } - - void start() - { - // create new session which gets started if asynchronous - // accept completes - session * new_session( new session( io_service_) ); - acceptor_.async_accept( - new_session->socket(), - boost::bind( & server::handle_accept_, this->shared_from_this(), - new_session, boost::asio::placeholders::error) ); - } - }; +Both concepts are equivalent and a coroutine library can provide either +symmetric or asymmetric coroutines. -Each __session__ communicates with the connected client and handles the -requests. -The application protocol in this example uses TCP-sockets as channel and -'newline' to separate the messages in the byte stream. -An application protocol is a set of rules for the order in which messages are -exchanged. -['std::istream] is used to extract the messages from the character stream . -Message 'exit' terminates the session. - - class session : private boost::noncopyable - { - private: - void handle_read_( coro_t::caller_type & self) - { - // create stream-buffer reading from socket - inbuf buf( socket_); - std::istream s( & buf); - - // messages are separated by 'newline' - std::string msg; - std::getline( s, msg); - std::cout << msg << std::endl; - - // terminate session for message 'exit' - // else do asynchronous read - if ( "exit" == msg) - io_service_.post( - boost::bind( - & session::destroy_, this) ); - else - start(); - } - - void destroy_() - { delete this; } - - boost::asio::io_service & io_service_; - boost::asio::ip::tcp::socket socket_; - - public: - session( boost::asio::io_service & io_service) : - io_service_( io_service), - socket_( io_service_) - { std::cout << "service(): " << socket_.remote_endpoint() << std::endl; } - - ~session() - { std::cout << "~service(): " << socket_.remote_endpoint() << std::endl; } - - boost::asio::ip::tcp::socket & socket() - { return socket_; } - - void start() - { - // register on io_service for asynchronous read - io_service_.async_read( - socket_, - boost::bind( - & session::handle_read_, this->shared_from_this(), _1, _2) ); - } - }; - - -Function __getline__ returns only if a 'newline' was read from the socket. -Therefore the application will block until 'newline' is received by the socket. -The stream-buffer used by the stream maintains an internal buffer which gets -(re-)filled by its function __underflow__. __underflow__ does the -read-operation on the socket. The C++ IO-streams framework does not provide an -easy way to create an continuation which represents reading bytes from the socket. - - -Coroutines help in this case to make the application non-blocking even if no -'newline' was received. -Class ['session] creates a coroutine which uses __handle_read__ as -__coro_fn__. On a new created ['session] ['start()] called starting the -coroutine. In the __coro_fn__ __handle_read__ the messages are received -via __getline__ in a loop until 'exit' is delivered. - - class session : private boost::noncopyable - { - private: - void handle_read_( coro_t::caller_type & ca) - { - // create stream-buffer with coroutine - inbuf buf( socket_, coro_, ca); - std::istream s( & buf); - - std::string msg; - do - { - // read message - // we not block if no newline was received yet - std::getline( s, msg); - std::cout << msg << std::endl; - } while ( msg != "exit"); - io_service_.post( - boost::bind( - & session::destroy_, this) ); - } - - void destroy_() - { delete this; } - - coro_t coro_; - boost::asio::io_service & io_service_; - boost::asio::ip::tcp::socket socket_; - - public: - session( boost::asio::io_service & io_service) : - coro_(), - io_service_( io_service), - socket_( io_service_) - { std::cout << "service(): " << socket_.remote_endpoint() << std::endl; } - - ~session() - { std::cout << "~service(): " << socket_.remote_endpoint() << std::endl; } - - boost::asio::ip::tcp::socket & socket() - { return socket_; } - - void start() - { - // create and start a coroutine - // handle_read_() is used as coroutine-function - coro_ = coro_t( boost::bind( & session::handle_read_, this, _1) ); - } - }; - - -The stream-buffer is created with __coro_caller__ and handles suspend/resume of this -code path depending on if bytes can be read from the socket. - - class inbuf : public std::streambuf, - private boost::noncopyable - { - private: - static const std::streamsize pb_size; - - enum - { bf_size = 16 }; - - int fetch_() - { - std::streamsize num = std::min( - static_cast< std::streamsize >( gptr() - eback() ), pb_size); - - std::memmove( - buffer_ + ( pb_size - num), - gptr() - num, num); - - // read bytes from the socket into internal buffer 'buffer_' - // make coro_t::operator() as callback, invoked if some - // bytes are read into 'buffer_' - s_.async_read_some( - boost::asio::buffer( buffer_ + pb_size, bf_size - pb_size), - boost::bind( & coro_t::operator(), & coro_, _1, _2) ); - // suspend this coroutine - ca_(); - - // coroutine was resumed by boost::asio::io_sevice - boost::system::error_code ec; - std::size_t n = 0; - - // check arguments - boost::tie( ec, n) = ca_.get(); - - // check if an error occurred - if ( ec) - { - setg( 0, 0, 0); - return -1; - } - - setg( buffer_ + pb_size - num, buffer_ + pb_size, buffer_ + pb_size + n); - return n; - } - - boost::asio::ip::tcp::socket & s_; - coro_t & coro_; - coro_t::caller_type & ca_; - char buffer_[bf_size]; - - protected: - virtual int underflow() - { - if ( gptr() < egptr() ) - return traits_type::to_int_type( * gptr() ); - - if ( 0 > fetch_() ) - return traits_type::eof(); - else - return traits_type::to_int_type( * gptr() ); - } - - public: - inbuf( - boost::asio::ip::tcp::socket & s, - coro_t & coro, - coro_t::caller_type & ca) : - s_( s), coro_( coro), ca_( ca), buffer_() - { setg( buffer_ + 4, buffer_ + 4, buffer_ + 4); } - }; - const std::streamsize inbuf::pb_size = 4; - - -__fetch__ uses __coro_op__ as callback for the asynchronous read-operation on the -socket and suspends itself (['ca_()] jumps back to __start__). If some bytes are -available in the socket receive buffer __io_service__ copies the bytes to the -internal buffer ['buffer_] and invokes the callback which resumes the coroutine -(['ca_()] returns). - +[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 itself suspend. This prohibits +providing suspend/resume operations in routines within a general-purpose library. [endsect] diff --git a/doc/motivation.qbk b/doc/motivation.qbk new file mode 100644 index 0000000..847759e --- /dev/null +++ b/doc/motivation.qbk @@ -0,0 +1,136 @@ +[/ + 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:motivation Motivation] + +In order to support a broad range of execution control behaviour __push_coro__ and +__pull_coro__ can be used to ['escape-and-reenter] loops, to ['escape-and-reenter] +recursive computations and for ['cooperative] multitasking +helping to solve problems in a much simpler and more elegant way than with only +a single flow of control. + + +[heading 'same fringe' problem] + +The advantages can be seen particularly clearly with the use of a recursive +function, such as traversal of trees. +If traversing two different trees in the same deterministic order produces the +same list of leaf nodes, then both trees have the same fringe. + +[$../../../../libs/coroutine/doc/images/fringe.png [align center]] + +Both trees in the picture have the same fringe even though the structure of the +trees is different. + +The same fringe problem could be solved using coroutines by iterating over the +leaf nodes and comparing this sequence via \cpp{std::equal()}. The range of leaf +nodes is generated by a visitor which recursively traverses the tree and passes +leaf nodes to its coroutine. + + node::ptr_t create_tree1(){ + return branch::create( + leaf::create("a"), + branch::create( + leaf::create("b"), + leaf::create("c"))); + } + + node::ptr_t create_tree2(){ + return branch::create( + branch::create( + leaf::create("a"), + leaf::create("b")), + leaf::create("c")); + } + + // create tree t1 + node::ptr_t t1=create_tree1(); + // create a coroutine, recursivly iterates trough t1 + // returning leaf nodes + std::coroutine::pull_type c1( + [&](std::coroutine::push_type& c){ + // create visitor, attached to coroutine + coro_visitor v(c); + // traverse t1 recursivly + t1->accept(v); + }); + + // create tree t2 + node::ptr_t t2=create_tree2(); + // create a coroutine, recursivly iterates trough t2 + // returning leaf nodes + std::coroutine::pull_type c2( + [&](std::coroutine::push_type& c){ + // create visitor, attached to coroutine + coro_visitor v(c); + // traverse t2 recursivly + t2->accept(v); + }); + + // compare leaf node ranges of t1 and t2 + bool result = std::equal( + std::begin(c1), + std::end(c1), + std::begin(c2)); + + std::cout << std::boolalpha << "same fringe == " << result; + +A tree consists of branch and leaf nodes. Each branch node has two children; +leaf nodes have none. Trees t1 and t2 have a different tree structure but the +same fringe. +For each tree a __pull_coro__ is created while in the associated __coro_fn__ +['coro_visitor] traverses the tree. +__pull_coro__-iterator, created from __pull_coro__, steps over the leaf nodes of its tree +and ['std::equal()] compares the iterator ranges. + + class coro_visitor : public visitor + { + private: + // coroutine used to pass leaf node back to caller + std::coroutine::push_type & c_; + + public: + coro_visitor(std::coroutine::push_type& c) : + c_(c) + {} + + void visit(branch & b){ + // traverse tree + if (b.left) b.left->accept(*this); + if (b.right) b.right->accept(*this); + } + + void visit(leaf & l){ + // return leaf node to caller + c_(l); + } + }; + +The visitor inspects recursively the tree - on each leaf node it escapes the +recursive computation and makes the leaf node available to the iterator (via +__push_coro__). After re-entering the visitor the recursive traversing of the tree +continues. + + +[heading asynchronous operations with boost.asio] + +In the past the code using asio's ['asynchronous operations] was scattered by callbacks. +__boost_asio__ provides with its new ['asynchronous result] feature a new way to simplify the +code and make it easier to read. +__yield_context__ uses internally __boost_coroutine__: + + void echo(boost::asio::ip::tcp::socket& socket,boost::asio::yield_context yield){ + char data[128]; + // read asynchronous data from socket + // execution context will be suspended until + // some bytes are read from socket + std::size_t n=socket.async_read_some(boost::asio::buffer(data),yield); + // write some bytes asynchronously + boost::asio::async_write(socket,boost::asio::buffer(data,n),yield); + } + +[endsect] diff --git a/doc/old.qbk b/doc/old.qbk index c2ef881..8f14ddd 100644 --- a/doc/old.qbk +++ b/doc/old.qbk @@ -5,7 +5,7 @@ http://www.boost.org/LICENSE_1_0.txt ] -[section:old Bidirectional coroutine (version 1)] +[section:old Bidirectional coroutine (['deprecated])] [note This interface is deprecated but can be used by compiling the code with macro BOOST_COROUTINES_OLD.] @@ -542,7 +542,7 @@ After unwinding, a __coro__ is complete. { coro_t c( fn, boost::coroutines::attributes( - boost::ctx::default_stacksize(), + boost::context::default_stacksize(), boost::coroutines::stack_unwind) ); c(); diff --git a/doc/unidirect.qbk b/doc/unidirect.qbk index 44a6469..9616986 100644 --- a/doc/unidirect.qbk +++ b/doc/unidirect.qbk @@ -5,7 +5,7 @@ http://www.boost.org/LICENSE_1_0.txt ] -[section:unidirect Unidirectional coroutine (version 2)] +[section:unidirect Unidirectional coroutine] [note This is the default interface (macro BOOST_COROUTINES_UNIDIRECT).] @@ -19,11 +19,11 @@ 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(); + boost::coroutines::coroutine< int >::push_type f(); void g() { - boost::coroutines::push_coroutine< int > c( f() ); + boost::coroutines::coroutine< int >::push_type c( f() ); c( 1); } @@ -41,7 +41,7 @@ __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) + void f( boost:::coroutines::coroutine< std::string >::pull_type & c) { // access argument std::string str( c.get() ); @@ -50,7 +50,7 @@ __coro_fn__. } std::string str; - boost::coroutines::push_coroutine< std::string > c( f); + boost::coroutines::coroutine< std::string >::push_type c( f); // pass argument c( str); @@ -79,19 +79,19 @@ 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) + void f( boost::coroutines::coroutine< std::string >::push_type & c) { c("abc"); } - boost::coroutines::pull_coroutine< std::string > c( f); + boost::coroutines::coroutine< std::string >::pull_type 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); + void g( boost::coroutines::coroutine< boost::tuple< X, Y > >::pull_type & c); + boost::coroutines::coroutine< boost::tuple< X, Y > >::push_type c( g); The current coroutine information (registers, flags, and stack and instruction @@ -99,7 +99,7 @@ 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) + void fn( boost::coroutines::coroutine< void >::pull_type & c, int j) { for( int i = 0; i < j; ++i) { @@ -110,7 +110,7 @@ saving the new state of the original routine. // transfer execution control back to main() c(); - // push_coroutine<>::operator()() was called + // coroutine<>::push_type<>::operator()() was called // execution control transferred back from main() } } @@ -118,7 +118,7 @@ saving the new state of the original routine. int main( int argc, char * argv[]) { // bind parameter '7' to coroutine-fn - boost::coroutines::push_coroutine< void > c( boost::bind( fn, _1, 7) ); + boost::coroutines::coroutine< void >::push_type c( boost::bind( fn, _1, 7) ); std::cout << "main() starts coroutine c" << std::endl; @@ -159,7 +159,7 @@ 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 +to and in the case of __pull_coro__ the type transfered from __coro_fn__. __push_coro_op__ accepts argument defined as template argument and returns a @@ -170,33 +170,29 @@ __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) + void fn( boost::coroutines::coroutine< int >::pull_type & c) { - // access the integer argument passed to push_coroutine< int >::operator() + // access the integer argument passed to coroutine< int >::push_type::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() + // after execution control returns from coroutine< int >::pull_type::operator() + // the transferred integer s accessed via coroutine< int >::pull_type::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); + boost::coroutines::coroutine< int >::push_type c( fn); - int x = c.get(); - std::cout << "main(): transferred value: " << x << std::endl; - - x = c( 10).get(); - std::cout << "main(): transferred value: " << x << std::endl; + c( 7); + c( 10); std::cout << "Done" << std::endl; @@ -206,9 +202,7 @@ __pull_coro_get__ in the other routine. output: main(): call coroutine c fn(): local variable i == 7 - main(): transferred value: 7 fn(): local variable i == 10 - main(): transferred value: 10 Done @@ -216,7 +210,7 @@ __pull_coro_get__ in the other routine. __tuple__ can be used to transfer mutliple data types. - void fn( boost::coroutines::pull_coroutine< boost::tuple< int, int > > & c) + void fn( boost::coroutines::coroutine< boost::tuple< int, int > >::pull_type & c) { int a, b; boost::tie( a, b) = c.get(); @@ -228,7 +222,7 @@ __tuple__ can be used to transfer mutliple data types. int main( int argc, char * argv[]) { std::cout << "main(): call coroutine c" << std::endl; - boost::coroutines::push_coroutine< boost::tuple< int, int > c( fn); + boost::coroutines::coroutine< boost::tuple< int, int > >::push_typec( fn); c( boost::make_tuple( 3, 7) ); c( boost::make_tuple( 5, 7) ); @@ -258,10 +252,8 @@ after `c` is gone will fail! 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) { + void fn( boost::coroutines::coroutine< X* >::push_type & ca) { X local; ca( & local); } @@ -269,7 +261,7 @@ after `c` is gone will fail! int main() { X * x = 0; { - coro_t c( fn); + boost::coroutines::coroutine< X* >::pull_type c( fn); x = c.get(); // let x point to X on stack owned by c // stack gets unwound -> X will be destructed } @@ -283,10 +275,11 @@ after `c` is gone will fail! __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; + typedef boost::range_iterator< + boost::coroutines::coroutine< int >::pull_type + >::type iterator_t; - void power( boost::coroutines::push_coroutine< int > & c, int number, int exponent) + void power( boost::coroutines::coroutine< int >::push_type & c, int number, int exponent) { int counter = 0; int result = 1; @@ -299,7 +292,7 @@ __pull_coro__ can be used via output-iterators using __begin__ and __end__. int main() { - coro_t c( boost::bind( power, _1, 2, 8) ); + boost::coroutines::coroutine< int >::pull_type 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 << " "; @@ -315,10 +308,11 @@ __pull_coro__ can be used via output-iterators using __begin__ and __end__. `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; + typedef boost::range_iterator< + boost::coroutines::coroutine< int >::pull_type + >::type iterator_t; - void power( boost::coroutines::push_coroutine< int > & c, int number, int exponent) + void power( boost::coroutines::coroutine< int >::push_type & c, int number, int exponent) { int counter = 0; int result = 1; @@ -331,7 +325,7 @@ __pull_coro__ can be used via output-iterators using __begin__ and __end__. int main() { - coro_t c( boost::bind( power, _1, 2, 8) ); + boost::coroutines::coroutine< int >::pull_type c( boost::bind( power, _1, 2, 8) ); BOOST_FOREACH( int i, c) { std::cout << i << " "; } @@ -355,9 +349,7 @@ __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) + void power( boost::coroutines::coroutine< boost::tuple< int, int > >::pull_type & c, int number, int exponent) { int a, b; @@ -373,7 +365,7 @@ will return 'false'. int main( int argc, char * argv[]) { std::cout << "main(): call coroutine c" << std::endl; - coro_t c( power); + boost::coroutines::coroutine< boost::tuple< int, int > >::push_type c( power); c( boost::make_tuple( 3, 7) ); BOOST_ASSERT( c); @@ -401,7 +393,7 @@ 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) + void f( boost::coroutines::coroutine< void >::push_type & c) { c(); throw std::runtime_error("abc"); @@ -409,7 +401,7 @@ __coro_op__. int main( int argc, char * argv[]) { - boost::coroutines::pull_coroutine< void > c( f); + boost::coroutines::coroutine< void >::pull_type c( f); try { c(); @@ -474,7 +466,7 @@ After unwinding, a __coro__ is complete. { std::cout << "~X()" << std::endl; } }; - void fn( boost::coroutines::pull_coroutine< void > & c) + void fn( boost::coroutines::coroutine< void >::pull_type & c) { X x; @@ -489,9 +481,9 @@ After unwinding, a __coro__ is complete. int main( int argc, char * argv[]) { { - boost::coroutines::push_coroutine< void > c( fn, + boost::coroutines::coroutine< void >::push_type c( fn, boost::coroutines::attributes( - boost::ctx::default_stacksize(), + boost::context::default_stacksize(), boost::coroutines::stack_unwind) ); c(); @@ -531,22 +523,22 @@ fpu registers for performance reasons. [note According to the calling convention the FPU registers are preserved by default.] -[section:push_coro Class `push_coroutine`] +[section:push_coro Class `coroutine<>::push_type`] #include template< typename Arg > - class push_coroutine + class coroutine<>::push_type { public: - push_coroutine(); + push_type(); template< typename Fn, typename StackAllocator = stack_allocator, typename Allocator = std::allocator< coroutine > > - push_coroutine( Fn fn, attributes const& attr = attributes(), + push_type( Fn fn, attributes const& attr = attributes(), StackAllocator const& stack_alloc = StackAllocator(), Allocator const& alloc = Allocator() ); @@ -555,42 +547,42 @@ fpu registers for performance reasons. typename StackAllocator = stack_allocator, typename Allocator = std::allocator< coroutine > > - push_coroutine( Fn && fn, attributes const& attr = attributes(), + push_type( Fn && fn, attributes const& attr = attributes(), StackAllocator stack_alloc = StackAllocator(), Allocator const& alloc = Allocator() ); - push_coroutine( push_coroutine && other); + push_type( push_type && other); - push_coroutine & operator=( push_coroutine && other); + push_type & operator=( push_type && other); operator unspecified-bool-type() const; bool operator!() const; - void swap( push_coroutine & other); + void swap( push_type & other); bool empty() const; - push_coroutine & operator()( Arg arg); + push_type & operator()( Arg arg); }; template< typename Arg > - void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r); + void swap( push_type< Arg > & l, push_type< Arg > & r); template< typename Arg > - range_iterator< push_coroutine< Arg > >::type begin( push_coroutine< Arg > &); + range_iterator< push_type< Arg > >::type begin( push_type< Arg > &); template< typename Arg > - range_iterator< push_coroutine< Arg > >::type end( push_coroutine< Arg > &); + range_iterator< push_type< Arg > >::type end( push_type< Arg > &); -[heading `push_coroutine()`] +[heading `push_type()`] [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)`] + push_type( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] [variablelist [[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() when ! is_stack_unbound().]] @@ -601,7 +593,7 @@ 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)`] + push_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] [variablelist [[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() when ! is_stack_unbound().]] @@ -611,14 +603,14 @@ For allocating/deallocating the stack `stack_alloc` is used and internal data are allocated by Allocator.]] ] -[heading `push_coroutine( push_coroutine && other)`] +[heading `push_type( push_type && 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)`] +[heading `push_type & operator=( push_type && other)`] [variablelist [[Effects:] [Destroys the internal data of `*this` and moves the internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] @@ -646,7 +638,7 @@ Otherwise false.]] [[Throws:] [Nothing.]] ] -[heading `push_coroutine<> & operator()(Arg arg)`] +[heading `push_type<> & operator()(Arg arg)`] [variablelist [[Preconditions:] [operator unspecified-bool-type() returns true for `*this`.] [[Effects:] [Execution control is transferred to __coro_fn__ and the argument @@ -654,7 +646,7 @@ Otherwise false.]] [[Throws:] [Exceptions thrown inside __coro_fn__.]] ] -[heading `void swap( push_coroutine & other)`] +[heading `void swap( push_type & other)`] [variablelist [[Effects:] [Swaps the internal data from `*this` with the values of `other`.]] @@ -672,23 +664,23 @@ the arguments passed to __coro_op__.]] [heading Non-member function `swap()`] template< typename Arg > - void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r); + void swap( push_type< Arg > & l, push_type< Arg > & r); [variablelist [[Effects:] [As if 'l.swap( r)'.]] ] -[heading Non-member function `begin( push_coroutine< Arg > &)`] +[heading Non-member function `begin( push_type< Arg > &)`] template< typename Arg > - range_iterator< push_coroutine< Arg > >::type begin( push_coroutine< Arg > &); + range_iterator< push_type< Arg > >::type begin( push_type< Arg > &); [variablelist [[Returns:] [Returns a range-iterator (output-iterator).]] ] -[heading Non-member function `end( push_coroutine< Arg > &)`] +[heading Non-member function `end( push_type< Arg > &)`] template< typename Arg > - range_iterator< push_coroutine< Arg > >::type end( push_coroutine< Arg > &); + range_iterator< push_type< Arg > >::type end( push_type< Arg > &); [variablelist [[Returns:] [Returns a end range-iterator (output-iterator).]] @@ -697,22 +689,22 @@ the arguments passed to __coro_op__.]] [endsect] -[section:pull_coro Class `pull_coroutine`] +[section:pull_coro Class `coroutine<>::pull_type`] #include template< typename R > - class pull_coroutine + class coroutine<>::pull_type { public: - pull_coroutine(); + pull_type(); template< typename Fn, typename StackAllocator = stack_allocator, typename Allocator = std::allocator< coroutine > > - pull_coroutine( Fn fn, attributes const& attr = attributes(), + pull_type( Fn fn, attributes const& attr = attributes(), StackAllocator const& stack_alloc = StackAllocator(), Allocator const& alloc = Allocator() ); @@ -721,23 +713,23 @@ the arguments passed to __coro_op__.]] typename StackAllocator = stack_allocator, typename Allocator = std::allocator< coroutine > > - pull_coroutine( Fn && fn, attributes const& attr = attributes(), + pull_type( Fn && fn, attributes const& attr = attributes(), StackAllocator stack_alloc = StackAllocator(), Allocator const& alloc = Allocator() ); - pull_coroutine( pull_coroutine && other); + pull_type( pull_type && other); - pull_coroutine & operator=( pull_coroutine && other); + pull_type & operator=( pull_type && other); operator unspecified-bool-type() const; bool operator!() const; - void swap( pull_coroutine & other); + void swap( pull_type & other); bool empty() const; - pull_coroutine & operator()(); + pull_type & operator()(); bool has_result() const; @@ -745,22 +737,22 @@ the arguments passed to __coro_op__.]] }; template< typename R > - void swap( pull_coroutine< R > & l, pull_coroutine< R > & r); + void swap( pull_type< R > & l, pull_type< R > & r); template< typename R > - range_iterator< pull_coroutine< R > >::type begin( pull_coroutine< R > &); + range_iterator< pull_type< R > >::type begin( pull_type< R > &); template< typename R > - range_iterator< pull_coroutine< R > >::type end( pull_coroutine< R > &); + range_iterator< pull_type< R > >::type end( pull_type< R > &); -[heading `pull_coroutine()`] +[heading `pull_type()`] [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)`] + pull_type( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] [variablelist [[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() when ! is_stack_unbound().]] @@ -772,7 +764,7 @@ data are allocated by Allocator.]] ] [heading `template< typename Fn, typename StackAllocator, typename Allocator > - pull_coroutine( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] + pull_type( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`] [variablelist [[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize() when ! is_stack_unbound().]] @@ -783,14 +775,14 @@ data are allocated by Allocator.]] [[Throws:] [Exceptions thrown inside __coro_fn__.]] ] -[heading `pull_coroutine( pull_coroutine && other)`] +[heading `pull_type( pull_type && 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)`] +[heading `pull_type & operator=( pull_type && other)`] [variablelist [[Effects:] [Destroys the internal data of `*this` and moves the internal data of `other` to `*this`. `other` becomes __not_a_coro__.]] @@ -818,7 +810,7 @@ Otherwise false.]] [[Throws:] [Nothing.]] ] -[heading `pull_coroutine<> & operator()()`] +[heading `pull_type<> & operator()()`] [variablelist [[Preconditions:] [`*this` is not a __not_a_coro__.]] [[Effects:] [Execution control is transferred to __coro_fn__ (no parameter are @@ -841,7 +833,7 @@ __push_coro_op__.]] [[Throws:] [Nothing.]] ] -[heading `void swap( pull_coroutine & other)`] +[heading `void swap( pull_type & other)`] [variablelist [[Effects:] [Swaps the internal data from `*this` with the values of `other`.]] @@ -851,23 +843,23 @@ of `other`.]] [heading Non-member function `swap()`] template< typename R > - void swap( pull_coroutine< R > & l, pull_coroutine< R > & r); + void swap( pull_type< R > & l, pull_type< R > & r); [variablelist [[Effects:] [As if 'l.swap( r)'.]] ] -[heading Non-member function `begin( pull_coroutine< R > &)`] +[heading Non-member function `begin( pull_type< R > &)`] template< typename R > - range_iterator< pull_coroutine< R > >::type begin( pull_coroutine< R > &); + range_iterator< pull_type< R > >::type begin( pull_type< R > &); [variablelist [[Returns:] [Returns a range-iterator (input-iterator).]] ] -[heading Non-member function `end( pull_coroutine< R > &)`] +[heading Non-member function `end( pull_type< R > &)`] template< typename R > - range_iterator< pull_coroutine< R > >::type end( pull_coroutine< R > &); + range_iterator< pull_type< R > >::type end( pull_type< R > &); [variablelist [[Returns:] [Returns a end range-iterator (input-iterator).]] diff --git a/example/cpp03/echo.cpp b/example/cpp03/echo.cpp index a033b1d..e2b19f6 100644 --- a/example/cpp03/echo.cpp +++ b/example/cpp03/echo.cpp @@ -11,8 +11,8 @@ #include #ifdef BOOST_COROUTINES_UNIDIRECT -typedef boost::coroutines::pull_coroutine< void > pull_coro_t; -typedef boost::coroutines::push_coroutine< void > push_coro_t; +typedef boost::coroutines::coroutine< void >::pull_type pull_coro_t; +typedef boost::coroutines::coroutine< void >::push_type push_coro_t; void echo( pull_coro_t & c, int i) { diff --git a/example/cpp03/echosse.cpp b/example/cpp03/echosse.cpp index d43190d..bfdfa76 100644 --- a/example/cpp03/echosse.cpp +++ b/example/cpp03/echosse.cpp @@ -25,19 +25,19 @@ void echoSSE( int i) std::cout << v32[3]; } -void echo( boost::coroutines::push_coroutine< void > & c, int i) +void echo( boost::coroutines::coroutine< void >::push_type & c, int i) { std::cout << i << ":"; echoSSE(i); c(); } -void runit( boost::coroutines::push_coroutine< void > & ca) +void runit( boost::coroutines::coroutine< void >::push_type & ca) { std::cout << "started! "; for ( int i = 0; i < 10; ++i) { - boost::coroutines::pull_coroutine< void > c( boost::bind( echo, _1, i) ); + boost::coroutines::coroutine< void >::pull_type c( boost::bind( echo, _1, i) ); while ( c) c(); ca(); @@ -47,7 +47,7 @@ void runit( boost::coroutines::push_coroutine< void > & ca) int main( int argc, char * argv[]) { { - boost::coroutines::pull_coroutine< void > c( runit); + boost::coroutines::coroutine< void >::pull_type c( runit); while ( c) { std::cout << "-"; c(); diff --git a/example/cpp03/fibonacci.cpp b/example/cpp03/fibonacci.cpp index d50cc5a..9154a6c 100644 --- a/example/cpp03/fibonacci.cpp +++ b/example/cpp03/fibonacci.cpp @@ -11,9 +11,11 @@ #include #ifdef BOOST_COROUTINES_UNIDIRECT -void fibonacci( boost::coroutines::push_coroutine< int > & c) +void fibonacci( boost::coroutines::coroutine< int >::push_type & c) { int first = 1, second = 1; + c( first); + c( second); while ( true) { int third = first + second; @@ -25,9 +27,9 @@ void fibonacci( boost::coroutines::push_coroutine< int > & c) int main() { - boost::coroutines::pull_coroutine< int > c( fibonacci); + boost::coroutines::coroutine< int >::pull_type c( fibonacci); boost::range_iterator< - boost::coroutines::pull_coroutine< int > + boost::coroutines::coroutine< int >::pull_type >::type it( boost::begin( c) ); for ( int i = 0; i < 10; ++i) { @@ -43,6 +45,8 @@ int main() void fibonacci( boost::coroutines::coroutine< void( int) > & c) { int first = 1, second = 1; + c( first); + c( second); while ( true) { int third = first + second; diff --git a/example/cpp03/parallel.cpp b/example/cpp03/parallel.cpp index 77aaf0a..7c952f7 100644 --- a/example/cpp03/parallel.cpp +++ b/example/cpp03/parallel.cpp @@ -11,7 +11,7 @@ #include #ifdef BOOST_COROUTINES_UNIDIRECT -void first( boost::coroutines::push_coroutine< void > & c) +void first( boost::coroutines::coroutine< void >::push_type & c) { std::cout << "started first! "; for ( int i = 0; i < 10; ++i) @@ -21,7 +21,7 @@ void first( boost::coroutines::push_coroutine< void > & c) } } -void second( boost::coroutines::push_coroutine< void > & c) +void second( boost::coroutines::coroutine< void >::push_type & c) { std::cout << "started second! "; for ( int i = 0; i < 10; ++i) @@ -34,8 +34,8 @@ void second( boost::coroutines::push_coroutine< void > & c) int main( int argc, char * argv[]) { { - boost::coroutines::pull_coroutine< void > c1( boost::bind( first, _1) ); - boost::coroutines::pull_coroutine< void > c2( boost::bind( second, _1) ); + boost::coroutines::coroutine< void >::pull_type c1( boost::bind( first, _1) ); + boost::coroutines::coroutine< void >::pull_type c2( boost::bind( second, _1) ); while ( c1 && c2) { c1(); std::cout << " "; diff --git a/example/cpp03/power.cpp b/example/cpp03/power.cpp index 3302e98..370da0f 100644 --- a/example/cpp03/power.cpp +++ b/example/cpp03/power.cpp @@ -13,7 +13,7 @@ #include #ifdef BOOST_COROUTINES_UNIDIRECT -void power( boost::coroutines::push_coroutine< int > & c, int number, int exponent) +void power( boost::coroutines::coroutine< int >::push_type & c, int number, int exponent) { int counter = 0; int result = 1; @@ -28,16 +28,16 @@ int main() { { std::cout << "using range functions" << std::endl; - boost::coroutines::pull_coroutine< int > c( boost::bind( power, _1, 2, 8) ); - boost::coroutines::pull_coroutine< int >::iterator e( boost::end( c) ); - for ( boost::coroutines::pull_coroutine< int >::iterator i( boost::begin( c) ); + boost::coroutines::coroutine< int >::pull_type c( boost::bind( power, _1, 2, 8) ); + boost::coroutines::coroutine< int >::pull_type::iterator e( boost::end( c) ); + for ( boost::coroutines::coroutine< int >::pull_type::iterator i( boost::begin( c) ); i != e; ++i) std::cout << * i << " "; } { std::cout << "\nusing BOOST_FOREACH" << std::endl; - boost::coroutines::pull_coroutine< int > c( boost::bind( power, _1, 2, 8) ); + boost::coroutines::coroutine< int >::pull_type c( boost::bind( power, _1, 2, 8) ); BOOST_FOREACH( int i, c) { std::cout << i << " "; } } diff --git a/example/cpp03/same_fringe.cpp b/example/cpp03/same_fringe.cpp index 6c6d67f..a2df612 100644 --- a/example/cpp03/same_fringe.cpp +++ b/example/cpp03/same_fringe.cpp @@ -50,10 +50,10 @@ std::pair< node::ptr_t, node::ptr_t > create_diff_trees() } #ifdef BOOST_COROUTINES_UNIDIRECT -bool match_trees( boost::coroutines::pull_coroutine< leaf & > & c1, - boost::coroutines::pull_coroutine< leaf & > & c2) +bool match_trees( boost::coroutines::coroutine< leaf & >::pull_type & c1, + boost::coroutines::coroutine< leaf & >::pull_type & c2) { - typedef boost::range_iterator< boost::coroutines::pull_coroutine< leaf & > >::type iterator_t; + typedef boost::range_iterator< boost::coroutines::coroutine< leaf & >::pull_type >::type iterator_t; iterator_t i1( boost::begin( c1) ); iterator_t e1( boost::end( c1) ); iterator_t i2( boost::begin( c2) ); @@ -64,15 +64,15 @@ int main() { { std::pair< node::ptr_t, node::ptr_t > pt = create_eq_trees(); - boost::coroutines::pull_coroutine< leaf & > te1( boost::bind( enumerate_leafs, _1, pt.first) ); - boost::coroutines::pull_coroutine< leaf & > te2( boost::bind( enumerate_leafs, _1, pt.second) ); + boost::coroutines::coroutine< leaf & >::pull_type te1( boost::bind( enumerate_leafs, _1, pt.first) ); + boost::coroutines::coroutine< leaf & >::pull_type te2( boost::bind( enumerate_leafs, _1, pt.second) ); bool result = match_trees( te1, te2); std::cout << std::boolalpha << "eq. trees matched == " << result << std::endl; } { std::pair< node::ptr_t, node::ptr_t > pt = create_diff_trees(); - boost::coroutines::pull_coroutine< leaf & > te1( boost::bind( enumerate_leafs, _1, pt.first) ); - boost::coroutines::pull_coroutine< leaf & > te2( boost::bind( enumerate_leafs, _1, pt.second) ); + boost::coroutines::coroutine< leaf & >::pull_type te1( boost::bind( enumerate_leafs, _1, pt.first) ); + boost::coroutines::coroutine< leaf & >::pull_type te2( boost::bind( enumerate_leafs, _1, pt.second) ); bool result = match_trees( te1, te2); std::cout << std::boolalpha << "diff. trees matched == " << result << std::endl; } diff --git a/example/cpp03/segmented_stack.cpp b/example/cpp03/segmented_stack.cpp index e823f86..814a5a0 100644 --- a/example/cpp03/segmented_stack.cpp +++ b/example/cpp03/segmented_stack.cpp @@ -32,7 +32,7 @@ void bar( int i) } #ifdef BOOST_COROUTINES_UNIDIRECT -void foo( boost::coroutines::pull_coroutine< void > & c) +void foo( boost::coroutines::coroutine< void >::pull_type & c) { bar( count); c(); @@ -41,7 +41,7 @@ void foo( boost::coroutines::pull_coroutine< void > & c) void thread_fn() { { - boost::coroutines::push_coroutine< void > c( foo); + boost::coroutines::coroutine< void >::push_type c( foo); c(); } } diff --git a/example/cpp03/tree.h b/example/cpp03/tree.h index 7a5982c..81a3348 100644 --- a/example/cpp03/tree.h +++ b/example/cpp03/tree.h @@ -95,10 +95,10 @@ bool operator!=( leaf const& l, leaf const& r) class tree_visitor : public visitor { private: - boost::coroutines::push_coroutine< leaf & > & c_; + boost::coroutines::coroutine< leaf & >::push_type & c_; public: - tree_visitor( boost::coroutines::push_coroutine< leaf & > & c) : + tree_visitor( boost::coroutines::coroutine< leaf & >::push_type & c) : c_( c) {} @@ -112,7 +112,7 @@ public: { c_( l); } }; -void enumerate_leafs( boost::coroutines::push_coroutine< leaf & > & c, node::ptr_t root) +void enumerate_leafs( boost::coroutines::coroutine< leaf & >::push_type & c, node::ptr_t root) { tree_visitor v( c); root->accept( v); diff --git a/example/cpp03/unwind.cpp b/example/cpp03/unwind.cpp index 670e087..91b7e6c 100644 --- a/example/cpp03/unwind.cpp +++ b/example/cpp03/unwind.cpp @@ -17,7 +17,7 @@ struct X : private boost::noncopyable ~X() { std::cout << "~X()" << std::endl; } }; -void fn( boost::coroutines::push_coroutine< void > & c) +void fn( boost::coroutines::coroutine< void >::push_type & c) { X x; int i = 0; @@ -31,7 +31,7 @@ void fn( boost::coroutines::push_coroutine< void > & c) int main( int argc, char * argv[]) { { - boost::coroutines::pull_coroutine< void > c( fn); + boost::coroutines::coroutine< void >::pull_type c( fn); for ( int k = 0; k < 3; ++k) { c(); diff --git a/example/cpp11/await_emu.cpp b/example/cpp11/await_emu.cpp index 8e149dd..1260851 100644 --- a/example/cpp11/await_emu.cpp +++ b/example/cpp11/await_emu.cpp @@ -71,8 +71,8 @@ void reschedule() // ___________________________________________________________ // #ifdef BOOST_COROUTINES_UNIDIRECT -typedef coroutines::pull_coroutine coro_pull; -typedef coroutines::push_coroutine coro_push; +typedef coroutines::coroutine::pull_type coro_pull; +typedef coroutines::coroutine::push_type coro_push; #else typedef coroutines::coroutine coro_pull; typedef coroutines::coroutine::caller_type coro_push; diff --git a/example/cpp11/fibonacci.cpp b/example/cpp11/fibonacci.cpp index 7470d2f..c6545d7 100644 --- a/example/cpp11/fibonacci.cpp +++ b/example/cpp11/fibonacci.cpp @@ -12,10 +12,12 @@ #ifdef BOOST_COROUTINES_UNIDIRECT int main() { - boost::coroutines::pull_coroutine< int > c( - [&]( boost::coroutines::push_coroutine< int > & c) { + boost::coroutines::coroutine< int >::pull_type c( + [&]( boost::coroutines::coroutine< int >::push_type & c) { int first = 1, second = 1; - for ( int i = 0; i < 10; ++i) + c( first); + c( second); + for ( int i = 0; i < 8; ++i) { int third = first + second; first = second; @@ -37,7 +39,9 @@ int main() boost::coroutines::coroutine< int() > c( [&]( boost::coroutines::coroutine< void( int) > & c) { int first = 1, second = 1; - for ( int i = 0; i < 10; ++i) + c( first); + c( second); + for ( int i = 0; i < 8; ++i) { int third = first + second; first = second; diff --git a/example/cpp11/same_fringe.cpp b/example/cpp11/same_fringe.cpp index 29c9f63..fb0b903 100644 --- a/example/cpp11/same_fringe.cpp +++ b/example/cpp11/same_fringe.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "tree.h" node::ptr_t create_tree1() @@ -32,10 +34,10 @@ node::ptr_t create_tree2() class coro_visitor : public visitor { private: - boost::coroutines::push_coroutine< leaf& > & c_; + boost::coroutines::coroutine< leaf& >::push_type & c_; public: - coro_visitor( boost::coroutines::push_coroutine< leaf& > & c) : + coro_visitor( boost::coroutines::coroutine< leaf& >::push_type & c) : c_( c) {} @@ -52,15 +54,15 @@ public: int main() { node::ptr_t t1 = create_tree1(); - boost::coroutines::pull_coroutine< leaf& > c1( - [&]( boost::coroutines::push_coroutine< leaf & > & c) { + boost::coroutines::coroutine< leaf& >::pull_type c1( + [&]( boost::coroutines::coroutine< leaf & >::push_type & c) { coro_visitor v( c); t1->accept( v); }); node::ptr_t t2 = create_tree2(); - boost::coroutines::pull_coroutine< leaf& > c2( - [&]( boost::coroutines::push_coroutine< leaf & > & c) { + boost::coroutines::coroutine< leaf& >::pull_type c2( + [&]( boost::coroutines::coroutine< leaf & >::push_type & c) { coro_visitor v( c); t2->accept( v); }); diff --git a/example/cpp11/tree.h b/example/cpp11/tree.h index 292550b..243455e 100644 --- a/example/cpp11/tree.h +++ b/example/cpp11/tree.h @@ -12,7 +12,6 @@ #include #include -#include #include # if defined(BOOST_MSVC) diff --git a/include/boost/coroutine/v2/coroutine.hpp b/include/boost/coroutine/v2/coroutine.hpp index 48d25f7..ac8b10e 100644 --- a/include/boost/coroutine/v2/coroutine.hpp +++ b/include/boost/coroutine/v2/coroutine.hpp @@ -2908,6 +2908,14 @@ typename push_coroutine< Arg >::const_iterator end( push_coroutine< Arg > const& c) { return boost::const_end( c); } + +template< typename T > +struct coroutine +{ + typedef push_coroutine< T > push_type; + typedef pull_coroutine< T > pull_type; +}; + } template< typename Arg > diff --git a/performance/performance.cpp b/performance/performance.cpp index bfa74f4..04c4b7f 100644 --- a/performance/performance.cpp +++ b/performance/performance.cpp @@ -33,17 +33,17 @@ namespace coro = boost::coroutines; c(); #ifdef BOOST_COROUTINES_UNIDIRECT -void fn( boost::coroutines::push_coroutine< void > & c) +void fn( boost::coroutines::coroutine< void >::push_type & c) { while ( true) c(); } # ifdef BOOST_CONTEXT_CYCLE cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu) { # if defined(BOOST_USE_SEGMENTED_STACKS) - boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu) ); + boost::coroutines::coroutine< void >::pull_type c( fn, coro::attributes( preserve_fpu) ); # else coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; - boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu), alloc); + boost::coroutines::coroutine< void >::pull_type c( fn, coro::attributes( preserve_fpu), alloc); # endif // cache warum-up @@ -66,10 +66,10 @@ BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu) { # if defined(BOOST_USE_SEGMENTED_STACKS) - boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu) ); + boost::coroutines::coroutine< void >::pull_type c( fn, coro::attributes( preserve_fpu) ); # else coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; - boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu), alloc); + boost::coroutines::coroutine< void >::pull_type c( fn, coro::attributes( preserve_fpu), alloc); # endif // cache warum-up diff --git a/test/test_coroutine.cpp b/test/test_coroutine.cpp index 668a44a..1a82e86 100644 --- a/test/test_coroutine.cpp +++ b/test/test_coroutine.cpp @@ -57,7 +57,7 @@ public: state( true) {} - void operator()( coro::push_coroutine< int > &) + void operator()( coro::coroutine< int >::push_type &) { value3 = state; } }; @@ -89,32 +89,32 @@ public: return * this; } - void operator()( coro::push_coroutine< int > &) + void operator()( coro::coroutine< int >::push_type &) { value3 = state; } }; struct my_exception {}; -void f1( coro::push_coroutine< void > & c) +void f1( coro::coroutine< void >::push_type & c) { c(); } -void f2( coro::push_coroutine< void > &) +void f2( coro::coroutine< void >::push_type &) { ++value1; } -void f3( coro::push_coroutine< void > & c) +void f3( coro::coroutine< void >::push_type & c) { ++value1; c(); ++value1; } -void f4( coro::push_coroutine< int > & c) +void f4( coro::coroutine< int >::push_type & c) { c( 3); c( 7); } -void f5( coro::push_coroutine< std::string > & c) +void f5( coro::coroutine< std::string >::push_type & c) { std::string res("abc"); c( res); @@ -122,13 +122,13 @@ void f5( coro::push_coroutine< std::string > & c) c( res); } -void f6( coro::pull_coroutine< int > & c) +void f6( coro::coroutine< int >::pull_type & c) { value1 = c.get(); } -void f7( coro::pull_coroutine< std::string > & c) +void f7( coro::coroutine< std::string >::pull_type & c) { value2 = c.get(); } -void f8( coro::pull_coroutine< boost::tuple< double, double > > & c) +void f8( coro::coroutine< boost::tuple< double, double > >::pull_type & c) { double x = 0, y = 0; boost::tie( x, y) = c.get(); @@ -138,30 +138,30 @@ void f8( coro::pull_coroutine< boost::tuple< double, double > > & c) value4 = x + y; } -void f9( coro::pull_coroutine< int * > & c) +void f9( coro::coroutine< int * >::pull_type & c) { value5 = c.get(); } -void f91( coro::pull_coroutine< int const* > & c) +void f91( coro::coroutine< int const* >::pull_type & c) { value5 = const_cast< int * >( c.get() ); } -void f10( coro::pull_coroutine< int & > & c) +void f10( coro::coroutine< int & >::pull_type & c) { int const& i = c.get(); value5 = const_cast< int * >( & i); } -void f101( coro::pull_coroutine< int const& > & c) +void f101( coro::coroutine< int const& >::pull_type & c) { int const& i = c.get(); value5 = const_cast< int * >( & i); } -void f11( coro::pull_coroutine< boost::tuple< int, int > > & c) +void f11( coro::coroutine< boost::tuple< int, int > >::pull_type & c) { boost::tie( value8, value9) = c.get(); } -void f12( coro::pull_coroutine< void > & c) +void f12( coro::coroutine< void >::pull_type & c) { X x_; c(); @@ -169,10 +169,10 @@ void f12( coro::pull_coroutine< void > & c) } template< typename E > -void f14( coro::pull_coroutine< void > &, E const& e) +void f14( coro::coroutine< void >::pull_type &, E const& e) { throw e; } -void f16( coro::push_coroutine< int > & c) +void f16( coro::coroutine< int >::push_type & c) { c( 1); c( 2); @@ -181,7 +181,7 @@ void f16( coro::push_coroutine< int > & c) c( 5); } -void f17( coro::pull_coroutine< int > & c, std::vector< int > & vec) +void f17( coro::coroutine< int >::pull_type & c, std::vector< int > & vec) { int x = c.get(); while ( 5 > x) @@ -191,7 +191,7 @@ void f17( coro::pull_coroutine< int > & c, std::vector< int > & vec) } } -void f19( coro::push_coroutine< const int* > & c, std::vector< const int * > & vec) +void f19( coro::coroutine< const int* >::push_type & c, std::vector< const int * > & vec) { BOOST_FOREACH( const int * ptr, vec) { c( ptr); } @@ -200,8 +200,8 @@ void f19( coro::push_coroutine< const int* > & c, std::vector< const int * > & v void test_move() { { - coro::pull_coroutine< void > coro1; - coro::pull_coroutine< void > coro2( f1); + coro::coroutine< void >::pull_type coro1; + coro::coroutine< void >::pull_type coro2( f1); BOOST_CHECK( ! coro1); BOOST_CHECK( coro1.empty() ); BOOST_CHECK( coro2); @@ -218,7 +218,7 @@ void test_move() copyable cp( 3); BOOST_CHECK( cp.state); BOOST_CHECK( ! value3); - coro::pull_coroutine< int > coro( cp); + coro::coroutine< int >::pull_type coro( cp); BOOST_CHECK( cp.state); BOOST_CHECK( value3); } @@ -228,7 +228,7 @@ void test_move() moveable mv( 7); BOOST_CHECK( mv.state); BOOST_CHECK( ! value3); - coro::pull_coroutine< int > coro( boost::move( mv) ); + coro::coroutine< int >::pull_type coro( boost::move( mv) ); BOOST_CHECK( ! mv.state); BOOST_CHECK( value3); } @@ -238,7 +238,7 @@ void test_complete() { value1 = 0; - coro::pull_coroutine< void > coro( f2); + coro::coroutine< void >::pull_type coro( f2); BOOST_CHECK( ! coro); BOOST_CHECK_EQUAL( ( int)1, value1); } @@ -247,7 +247,7 @@ void test_jump() { value1 = 0; - coro::pull_coroutine< void > coro( f3); + coro::coroutine< void >::pull_type coro( f3); BOOST_CHECK( coro); BOOST_CHECK_EQUAL( ( int)1, value1); coro(); @@ -257,7 +257,7 @@ void test_jump() void test_result_int() { - coro::pull_coroutine< int > coro( f4); + coro::coroutine< int >::pull_type coro( f4); BOOST_CHECK( coro); int result = coro.get(); BOOST_CHECK( coro); @@ -271,7 +271,7 @@ void test_result_int() void test_result_string() { - coro::pull_coroutine< std::string > coro( f5); + coro::coroutine< std::string >::pull_type coro( f5); BOOST_CHECK( coro); std::string result = coro.get(); BOOST_CHECK( coro); @@ -287,7 +287,7 @@ void test_arg_int() { value1 = 0; - coro::push_coroutine< int > coro( f6); + coro::coroutine< int >::push_type coro( f6); BOOST_CHECK( coro); coro( 3); BOOST_CHECK( ! coro); @@ -298,7 +298,7 @@ void test_arg_string() { value2 = ""; - coro::push_coroutine< std::string > coro( f7); + coro::coroutine< std::string >::push_type coro( f7); BOOST_CHECK( coro); coro( std::string("abc") ); BOOST_CHECK( ! coro); @@ -309,7 +309,7 @@ void test_fp() { value4 = 0; - coro::push_coroutine< boost::tuple< double, double > > coro( f8); + coro::coroutine< boost::tuple< double, double > >::push_type coro( f8); BOOST_CHECK( coro); coro( boost::make_tuple( 7.35, 3.14) ); BOOST_CHECK( coro); @@ -326,7 +326,7 @@ void test_ptr() value5 = 0; int a = 3; - coro::push_coroutine< int * > coro( f9); + coro::coroutine< int * >::push_type coro( f9); BOOST_CHECK( coro); coro( & a); BOOST_CHECK( ! coro); @@ -338,7 +338,7 @@ void test_const_ptr() value5 = 0; int a = 3; - coro::push_coroutine< int const* > coro( f91); + coro::coroutine< int const* >::push_type coro( f91); BOOST_CHECK( coro); coro( & a); BOOST_CHECK( ! coro); @@ -350,7 +350,7 @@ void test_ref() value5 = 0; int a = 3; - coro::push_coroutine< int & > coro( f10); + coro::coroutine< int & >::push_type coro( f10); BOOST_CHECK( coro); coro( a); BOOST_CHECK( ! coro); @@ -362,7 +362,7 @@ void test_const_ref() value5 = 0; int a = 3; - coro::push_coroutine< int const& > coro( f101); + coro::coroutine< int const& >::push_type coro( f101); BOOST_CHECK( coro); coro( a); BOOST_CHECK( ! coro); @@ -378,7 +378,7 @@ void test_tuple() boost::tuple< int, int > tpl( a, b); BOOST_CHECK_EQUAL( a, tpl.get< 0 >() ); BOOST_CHECK_EQUAL( b, tpl.get< 1 >() ); - coro::push_coroutine< boost::tuple< int, int > > coro( f11); + coro::coroutine< boost::tuple< int, int > >::push_type coro( f11); BOOST_CHECK( coro); coro( tpl); BOOST_CHECK( ! coro); @@ -390,7 +390,7 @@ void test_unwind() { value1 = 0; { - coro::push_coroutine< void > coro( f12); + coro::coroutine< void >::push_type coro( f12); BOOST_CHECK( coro); BOOST_CHECK_EQUAL( ( int) 0, value1); coro(); @@ -406,7 +406,7 @@ void test_no_unwind() { value1 = 0; { - coro::push_coroutine< void > coro( + coro::coroutine< void >::push_type coro( f12, coro::attributes( coro::stack_allocator::default_stacksize(), @@ -428,7 +428,7 @@ void test_exceptions() std::runtime_error ex("abc"); try { - coro::push_coroutine< void > coro( boost::bind( f14< std::runtime_error >, _1, ex) ); + coro::coroutine< void >::push_type coro( boost::bind( f14< std::runtime_error >, _1, ex) ); BOOST_CHECK( coro); coro(); BOOST_CHECK( ! coro); @@ -447,7 +447,7 @@ void test_output_iterator() { { std::vector< int > vec; - coro::pull_coroutine< int > coro( f16); + coro::coroutine< int >::pull_type coro( f16); BOOST_FOREACH( int i, coro) { vec.push_back( i); } BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() ); @@ -459,10 +459,10 @@ void test_output_iterator() } { std::vector< int > vec; - coro::pull_coroutine< int > coro( f16); - coro::pull_coroutine< int >::iterator e = boost::end( coro); + coro::coroutine< int >::pull_type coro( f16); + coro::coroutine< int >::pull_type::iterator e = boost::end( coro); for ( - coro::pull_coroutine< int >::iterator i = boost::begin( coro); + coro::coroutine< int >::pull_type::iterator i = boost::begin( coro); i != e; ++i) { vec.push_back( * i); } BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() ); @@ -479,10 +479,10 @@ void test_output_iterator() vec_in.push_back( & i2); vec_in.push_back( & i3); std::vector< const int* > vec_out; - coro::pull_coroutine< const int* > coro( boost::bind( f19, _1, boost::ref( vec_in) ) ); - coro::pull_coroutine< const int* >::const_iterator e = boost::const_end( coro); + coro::coroutine< const int* >::pull_type coro( boost::bind( f19, _1, boost::ref( vec_in) ) ); + coro::coroutine< const int* >::pull_type::const_iterator e = boost::const_end( coro); for ( - coro::pull_coroutine< const int* >::const_iterator i = boost::const_begin( coro); + coro::coroutine< const int* >::pull_type::const_iterator i = boost::const_begin( coro); i != e; ++i) { vec_out.push_back( * i); } BOOST_CHECK_EQUAL( ( std::size_t)3, vec_out.size() ); @@ -496,10 +496,10 @@ void test_input_iterator() { int counter = 0; std::vector< int > vec; - coro::push_coroutine< int > coro( + coro::coroutine< int >::push_type coro( boost::bind( f17, _1, boost::ref( vec) ) ); - coro::push_coroutine< int >::iterator e( boost::end( coro) ); - for ( coro::push_coroutine< int >::iterator i( boost::begin( coro) ); + coro::coroutine< int >::push_type::iterator e( boost::end( coro) ); + for ( coro::coroutine< int >::push_type::iterator i( boost::begin( coro) ); i != e; ++i) { i = ++counter;