Example: the producer/consumer pattern
Generators can be used to straightforwardly model the producer/consumer pattern. In
this scenario one function generates values and another consumes
them. The solution presented here is consumer driven, that is, the
consumer dictates the speed at witch the producer generates
values. In this example the producer generates all permutations of a
given string, while the consumer simply print the output:
typedef coro::generator<int> generator_type;
const std::string& producer(generator_type::self& self, std::string base) {
std::sort(base.begin(), base.end());
do {
self.yield(base);
} while (std::next_permutation(base.begin(), base.end()));
self.exit();
}
template<typename Producer>
void consumer(Producer producer) {
do {
std::cout <<*producer << "\n";
} while(++producer);
}
...
consumer
(generator_type
(boost::bind
(producer, _1, std::string("hello"))));
...
Filters
This pattern is very useful and can be extended to insert another
filter function between the producer and the consumer. This filter is
both a producer and a consumer: it return the result of a call to the
parameter producer with the string " world"
appended:
struct filter {
typedef const std::string& result_type;
template<typename Producer>
const std::string& operator()
(generator_type::self& self, Producer producer) {
do {
self.yield(*producer + " world");
} while(++producer);
self.exit();
}
};
consumer
(generator_type
(boost::bind
(filter(),
_1,
generator_type
(boost::bind
producer, _1, std::string("hello"))))));
You can obviously have as many filters functions as you want.