coro-state-machine.cpp (2224B)
1 #include "coroutine_owner.hpp" 2 3 #include <exception> 4 #include <cassert> 5 #include <iostream> 6 7 using std::cerr, std::endl; 8 9 struct task 10 { 11 struct promise_type 12 { 13 task get_return_object() { return make_coroutine_owner(*this); } 14 std::suspend_never initial_suspend() { return {}; } 15 void return_value(task); 16 void unhandled_exception() { std::terminate(); } 17 std::suspend_always final_suspend() noexcept { return {}; } 18 coroutine_owner<promise_type> continuation; 19 }; 20 21 task() = default; 22 task(coroutine_owner<promise_type> c) 23 : h{std::move(c)} 24 {} 25 26 coroutine_owner<promise_type> h; 27 28 struct await_done 29 { 30 bool await_ready(); 31 void await_suspend(std::coroutine_handle<> s); 32 coroutine_owner<promise_type> await_resume(); 33 std::coroutine_handle<> awaiting; 34 promise_type& promise; 35 }; 36 await_done done() { return {{}, h->promise()}; } 37 }; 38 39 void task::promise_type::return_value(task t) { continuation = std::move(t.h); } 40 41 42 bool task::await_done::await_ready() 43 { 44 return false; 45 } 46 void task::await_done::await_suspend(std::coroutine_handle<> s) 47 { 48 assert(not awaiting); 49 awaiting = s; 50 } 51 coroutine_owner<task::promise_type> task::await_done::await_resume() 52 { 53 awaiting = {}; 54 return std::exchange(promise.continuation, {}); 55 } 56 57 struct awaitable 58 { 59 std::coroutine_handle<> awaiting; 60 bool await_ready() { return false; } 61 void await_suspend(std::coroutine_handle<> s) { assert(not std::exchange(awaiting, s)); } 62 void await_resume() {} 63 64 void event() { 65 std::exchange(awaiting, {}).resume(); 66 } 67 }; 68 69 task state_machine(awaitable& event); 70 71 task loop_machine(awaitable& event) 72 { 73 cerr << "init loop\n"; 74 for (unsigned i = 0; i < 3; ++i) 75 { 76 co_await event; 77 cerr << "loop!\n"; 78 } 79 co_return state_machine(event); 80 } 81 82 task state_machine(awaitable& event) 83 { 84 cerr << "init\n"; 85 co_await event; 86 cerr << "button pressed\n"; 87 co_await event; 88 cerr << "button pressed 2\n"; 89 co_await event; 90 cerr << "button pressed 3\n"; 91 co_return loop_machine(event); 92 } 93 94 task state_engine(task t) 95 { 96 cerr << "se init\n"; 97 for (;;) 98 t = task{co_await t.done()}; 99 } 100 101 int main() 102 { 103 awaitable event; 104 auto h = state_machine(event); 105 auto e = state_engine(std::move(h)); 106 for (unsigned i = 0; i < 10; ++i) 107 event.event(); 108 cerr << "Done!\n"; 109 }