coro-generator-consumer.cpp (2825B)
1 #include "coroutine_owner.hpp" // coroutine_owner noop_coroutine suspend_always suspend_never 2 3 #include <exception> // terminate 4 #include <iostream> // cout 5 #include <optional> // optional 6 #include <cassert> // assert 7 8 struct sentry 9 { 10 char const* msg; 11 sentry(char const* m) : msg(m) { std::cout << msg << " {\n"; } 12 ~sentry() { std::cout << "} " << msg << '\n'; } 13 }; 14 15 16 struct symmetric_transfer : std::suspend_always 17 { 18 std::coroutine_handle<> await_suspend(std::coroutine_handle<>) { return h; } 19 20 std::coroutine_handle<> h; 21 }; 22 23 struct generator 24 { 25 struct promise_type; 26 promise_type& promise() { return h->promise(); } 27 28 coroutine_owner<promise_type> h; 29 }; 30 31 struct generator::promise_type 32 { 33 promise_type() { std::cout << __PRETTY_FUNCTION__ << '\n'; } 34 ~promise_type() { std::cout << __PRETTY_FUNCTION__ << '\n'; } 35 generator get_return_object() { return {make_coroutine_owner<promise_type>(*this)}; } 36 std::suspend_always initial_suspend() { return {}; } 37 symmetric_transfer yield_value(unsigned v) 38 { 39 assert(not yielded_value); 40 yielded_value = v; 41 if (yield_to) 42 return {{}, std::exchange(yield_to, {})}; 43 else 44 return {{}, std::noop_coroutine()}; 45 } 46 std::suspend_always final_suspend() noexcept { return {}; } 47 48 bool await_ready() { return yielded_value.has_value(); } 49 std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) 50 { 51 assert(not yield_to); 52 yield_to = h; 53 return std::coroutine_handle<promise_type>::from_promise(*this); 54 } 55 unsigned await_resume() { return *std::exchange(yielded_value, {}); } 56 void unhandled_exception() { std::terminate(); } 57 58 private: 59 std::optional<unsigned> yielded_value; 60 std::coroutine_handle<> yield_to; 61 }; 62 63 64 generator number_generator(unsigned d) 65 { 66 sentry s(__func__); 67 unsigned i = 0; 68 for (;;) 69 co_yield i += d; 70 } 71 72 struct consumer 73 { 74 struct promise_type { 75 promise_type() { std::cout << __PRETTY_FUNCTION__ << '\n'; } 76 ~promise_type() { std::cout << __PRETTY_FUNCTION__ << '\n'; } 77 consumer get_return_object() { return {std::coroutine_handle<promise_type>::from_promise(*this)}; } 78 std::suspend_never initial_suspend() { return {}; } 79 void return_value(unsigned x) { result = x; } 80 std::suspend_always final_suspend() noexcept { return {}; } 81 void unhandled_exception() { std::terminate(); } 82 unsigned result; 83 }; 84 85 ~consumer() { 86 h.destroy(); 87 } 88 unsigned result() const { 89 return h.promise().result; 90 } 91 92 std::coroutine_handle<promise_type> h; 93 }; 94 95 consumer number_consumer(generator::promise_type& g, unsigned i) 96 { 97 sentry s(__func__); 98 unsigned total = 0; 99 while (i--) 100 { 101 unsigned x = co_await g; 102 std::cout << __func__ << ": " << x << '\n'; 103 total += x; 104 } 105 co_return total; 106 } 107 108 int main() 109 { 110 auto g = number_generator(2); 111 auto c = number_consumer(g.promise(), 5); 112 std::cout << __PRETTY_FUNCTION__ << ": " << c.result() << '\n'; 113 }