Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r85318 - trunk/libs/coroutine/doc
From: oliver.kowalke_at_[hidden]
Date: 2013-08-12 09:23:35


Author: olli
Date: 2013-08-12 09:23:35 EDT (Mon, 12 Aug 2013)
New Revision: 85318
URL: http://svn.boost.org/trac/boost/changeset/85318

Log:
coroutine: add example to documentation

Text files modified:
   trunk/libs/coroutine/doc/motivation.qbk | 129 ++++++++++++++++++++++++++++++++++++++++
   1 files changed, 129 insertions(+), 0 deletions(-)

Modified: trunk/libs/coroutine/doc/motivation.qbk
==============================================================================
--- trunk/libs/coroutine/doc/motivation.qbk Mon Aug 12 08:19:29 2013 (r85317)
+++ trunk/libs/coroutine/doc/motivation.qbk 2013-08-12 09:23:35 EDT (Mon, 12 Aug 2013) (r85318)
@@ -157,6 +157,135 @@
         Done
 
 
+[heading chaining coroutines]
+
+The following example demonstrates how coroutines could be chained.
+
+ typedef boost::coroutines::coroutine<std::string> coro_t;
+
+ // deliver each line of input stream to sink as a separate string
+ void readlines(coro_t::push_type& sink, std::istream& in){
+ std::string line;
+ while(std::getline(in,line))
+ sink(line);
+ }
+
+ void tokenize(coro_t::push_type& sink, coro_t::pull_type& source){
+ // This tokenizer doesn't happen to be stateful: you could reasonably
+ // implement it with a single call to push each new token downstream. But
+ // I've worked with stateful tokenizers, in which the meaning of input
+ // characters depends in part on their position within the input line.
+ BOOST_FOREACH(std::string line, source){
+ std::string::size_type pos = 0;
+ while(pos < line.length()){
+ if (line[pos] == '"'){
+ std::string token;
+ ++pos; // skip open quote
+ while (pos < line.length() && line[pos] != '"')
+ token += line[pos++];
+ ++pos; // skip close quote
+ sink(token); // pass token downstream
+ } else if (std::isspace(line[pos])){
+ ++pos; // outside quotes, ignore whitespace
+ } else if (std::isalpha(line[pos])){
+ std::string token;
+ while (pos < line.length() && std::isalpha(line[pos]))
+ token += line[pos++];
+ sink(token); // pass token downstream
+ } else { // punctuation
+ sink(std::string(1,line[pos++]));
+ }
+ }
+ }
+ }
+
+ void only_words(coro_t::push_type& sink,coro_t::pull_type& source){
+ BOOST_FOREACH(std::string token,source){
+ if (!token.empty() && std::isalpha(token[0]))
+ sink(token);
+ }
+ }
+
+ void trace(coro_t::push_type& sink, coro_t::pull_type& source){
+ BOOST_FOREACH(std::string token,source){
+ std::cout << "trace: '" << token << "'\n";
+ sink(token);
+ }
+ }
+
+ struct FinalEOL{
+ ~FinalEOL(){
+ std::cout << std::endl;
+ }
+ };
+
+ void layout(coro_t::pull_type& source,int num,int width){
+ // Finish the last line when we leave by whatever means
+ FinalEOL eol;
+
+ // Pull values from upstream, lay them out 'num' to a line
+ for (;;){
+ for (int i = 0; i < num; ++i){
+ // when we exhaust the input, stop
+ if (!source) return;
+
+ std::cout << std::setw(width) << source.get();
+ // now that we've handled this item, advance to next
+ source();
+ }
+ // after 'num' items, line break
+ std::cout << std::endl;
+ }
+ }
+
+ // For example purposes, instead of having a separate text file in the
+ // local filesystem, construct an istringstream to read.
+ std::string data(
+ "This is the first line.\n"
+ "This, the second.\n"
+ "The third has \"a phrase\"!\n"
+ );
+
+ {
+ std::cout << "\nfilter:\n";
+ std::istringstream infile(data);
+ coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
+ coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
+ coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
+ coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(filter)));
+ BOOST_FOREACH(std::string token,tracer){
+ // just iterate, we're already pulling through tracer
+ }
+ }
+
+ {
+ std::cout << "\nlayout() as coroutine::push_type:\n";
+ std::istringstream infile(data);
+ coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
+ coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
+ coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
+ coro_t::push_type writer(boost::bind(layout, _1, 5, 15));
+ BOOST_FOREACH(std::string token,filter){
+ writer(token);
+ }
+ }
+
+ {
+ std::cout << "\nfiltering output:\n";
+ std::istringstream infile(data);
+ coro_t::pull_type reader(boost::bind(readlines,_1,boost::ref(infile)));
+ coro_t::pull_type tokenizer(boost::bind(tokenize,_1,boost::ref(reader)));
+ coro_t::push_type writer(boost::bind(layout,_1,5,15));
+ // Because of the symmetry of the API, we can use any of these
+ // chaining functions in a push_type coroutine chain as well.
+ coro_t::push_type filter(boost::bind(only_words,boost::ref(writer),_1));
+ BOOST_FOREACH(std::string token,tokenizer){
+ filter(token);
+ }
+ }
+
+
+
 [heading asynchronous operations with boost.asio]
 
 In the past the code using asio's ['asynchronous operations] was scattered by callbacks.


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk