]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/coroutine/example/asymmetric/chaining.cpp
4a4dd99796787f6751f88dc46b79672fb128f432
2 // Copyright Nat Goodspeed 2013.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 #include <boost/coroutine/all.hpp>
15 #include <boost/bind.hpp>
16 #include <boost/foreach.hpp>
18 typedef boost::coroutines::asymmetric_coroutine
<std::string
> coro_t
;
20 // deliver each line of input stream to sink as a separate string
21 void readlines(coro_t::push_type
& sink
, std::istream
& in
)
24 while (std::getline(in
, line
))
28 void tokenize(coro_t::push_type
& sink
, coro_t::pull_type
& source
)
30 // This tokenizer doesn't happen to be stateful: you could reasonably
31 // implement it with a single call to push each new token downstream. But
32 // I've worked with stateful tokenizers, in which the meaning of input
33 // characters depends in part on their position within the input line. At
34 // the time, I wished for a way to resume at the suspend point!
35 BOOST_FOREACH(std::string line
, source
)
37 std::string::size_type pos
= 0;
38 while (pos
< line
.length())
43 ++pos
; // skip open quote
44 while (pos
< line
.length() && line
[pos
] != '"')
46 ++pos
; // skip close quote
47 sink(token
); // pass token downstream
49 else if (std::isspace(line
[pos
]))
51 ++pos
; // outside quotes, ignore whitespace
53 else if (std::isalpha(line
[pos
]))
56 while (pos
< line
.length() && std::isalpha(line
[pos
]))
58 sink(token
); // pass token downstream
62 sink(std::string(1, line
[pos
++]));
68 void only_words(coro_t::push_type
& sink
, coro_t::pull_type
& source
)
70 BOOST_FOREACH(std::string token
, source
)
72 if (! token
.empty() && std::isalpha(token
[0]))
77 void trace(coro_t::push_type
& sink
, coro_t::pull_type
& source
)
79 BOOST_FOREACH(std::string token
, source
)
81 std::cout
<< "trace: '" << token
<< "'\n";
88 ~FinalEOL() { std::cout
<< std::endl
; }
91 void layout(coro_t::pull_type
& source
, int num
, int width
)
93 // Finish the last line when we leave by whatever means
96 // Pull values from upstream, lay them out 'num' to a line
99 for (int i
= 0; i
< num
; ++i
)
101 // when we exhaust the input, stop
105 std::cout
<< std::setw(width
) << source
.get();
106 // now that we've handled this item, advance to next
109 // after 'num' items, line break
110 std::cout
<< std::endl
;
114 int main(int argc
, char *argv
[])
116 // For example purposes, instead of having a separate text file in the
117 // local filesystem, construct an istringstream to read.
119 "This is the first line.\n"
120 "This, the second.\n"
121 "The third has \"a phrase\"!\n"
125 std::cout
<< "\nreadlines:\n";
126 std::istringstream
infile(data
);
127 // Each coroutine-function has a small, specific job to do. Instead of
128 // adding conditional logic to a large, complex input function, the
129 // caller composes smaller functions into the desired processing
131 coro_t::pull_type
reader(boost::bind(readlines
, _1
, boost::ref(infile
)));
132 coro_t::pull_type
tracer(boost::bind(trace
, _1
, boost::ref(reader
)));
133 BOOST_FOREACH(std::string line
, tracer
)
135 std::cout
<< "got: " << line
<< "\n";
140 std::cout
<< "\ncompose a chain:\n";
141 std::istringstream
infile(data
);
142 coro_t::pull_type
reader(boost::bind(readlines
, _1
, boost::ref(infile
)));
143 coro_t::pull_type
tokenizer(boost::bind(tokenize
, _1
, boost::ref(reader
)));
144 coro_t::pull_type
tracer(boost::bind(trace
, _1
, boost::ref(tokenizer
)));
145 BOOST_FOREACH(std::string token
, tracer
)
147 // just iterate, we're already pulling through tracer
152 std::cout
<< "\nfilter:\n";
153 std::istringstream
infile(data
);
154 coro_t::pull_type
reader(boost::bind(readlines
, _1
, boost::ref(infile
)));
155 coro_t::pull_type
tokenizer(boost::bind(tokenize
, _1
, boost::ref(reader
)));
156 coro_t::pull_type
filter(boost::bind(only_words
, _1
, boost::ref(tokenizer
)));
157 coro_t::pull_type
tracer(boost::bind(trace
, _1
, boost::ref(filter
)));
158 BOOST_FOREACH(std::string token
, tracer
)
160 // just iterate, we're already pulling through tracer
165 std::cout
<< "\nlayout() as coroutine::push_type:\n";
166 std::istringstream
infile(data
);
167 coro_t::pull_type
reader(boost::bind(readlines
, _1
, boost::ref(infile
)));
168 coro_t::pull_type
tokenizer(boost::bind(tokenize
, _1
, boost::ref(reader
)));
169 coro_t::pull_type
filter(boost::bind(only_words
, _1
, boost::ref(tokenizer
)));
170 coro_t::push_type
writer(boost::bind(layout
, _1
, 5, 15));
171 BOOST_FOREACH(std::string token
, filter
)
178 std::cout
<< "\ncalling layout() directly:\n";
179 std::istringstream
infile(data
);
180 coro_t::pull_type
reader(boost::bind(readlines
, _1
, boost::ref(infile
)));
181 coro_t::pull_type
tokenizer(boost::bind(tokenize
, _1
, boost::ref(reader
)));
182 coro_t::pull_type
filter(boost::bind(only_words
, _1
, boost::ref(tokenizer
)));
183 // Because of the symmetry of the API, we can directly call layout()
184 // instead of using it as a coroutine-function.
185 layout(filter
, 5, 15);
189 std::cout
<< "\nfiltering output:\n";
190 std::istringstream
infile(data
);
191 coro_t::pull_type
reader(boost::bind(readlines
, _1
, boost::ref(infile
)));
192 coro_t::pull_type
tokenizer(boost::bind(tokenize
, _1
, boost::ref(reader
)));
193 coro_t::push_type
writer(boost::bind(layout
, _1
, 5, 15));
194 // Because of the symmetry of the API, we can use any of these
195 // chaining functions in a push_type coroutine chain as well.
196 coro_t::push_type
filter(boost::bind(only_words
, boost::ref(writer
), _1
));
197 BOOST_FOREACH(std::string token
, tokenizer
)
203 std::cout
<< "\nDone" << std::endl
;