examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

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 }