diff options
Diffstat (limited to 'aisa/coroutine.h')
| -rw-r--r-- | aisa/coroutine.h | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/aisa/coroutine.h b/aisa/coroutine.h new file mode 100644 index 0000000..40a6982 --- /dev/null +++ b/aisa/coroutine.h | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <coroutine> | ||
| 4 | |||
| 5 | namespace aisa { | ||
| 6 | |||
| 7 | inline auto suspend() noexcept { return std::suspend_always{}; } | ||
| 8 | |||
| 9 | template<typename result_t> struct promise; | ||
| 10 | |||
| 11 | template<typename result_t> struct task : public std::coroutine_handle<promise<result_t>> { | ||
| 12 | using handle = std::coroutine_handle<struct promise<result_t>>; | ||
| 13 | using promise_type = struct promise<result_t>; | ||
| 14 | bool await_ready() const noexcept { return handle::done(); } | ||
| 15 | result_t await_resume() const noexcept; | ||
| 16 | template<typename other_t> void await_suspend(std::coroutine_handle<struct promise<other_t>> h) const noexcept; | ||
| 17 | std::optional<result_t> operator()() noexcept; | ||
| 18 | }; | ||
| 19 | |||
| 20 | template<> struct task<void> : public std::coroutine_handle<promise<void>> { | ||
| 21 | using handle = std::coroutine_handle<struct promise<void>>; | ||
| 22 | using promise_type = struct promise<void>; | ||
| 23 | bool await_ready() const noexcept { return handle::done(); } | ||
| 24 | void await_resume() const noexcept; | ||
| 25 | template<typename other_t> void await_suspend(std::coroutine_handle<struct promise<other_t>> h) const noexcept; | ||
| 26 | bool operator()() noexcept; | ||
| 27 | }; | ||
| 28 | |||
| 29 | template<typename result_t> struct promise { | ||
| 30 | std::coroutine_handle<> precursor; | ||
| 31 | std::optional<result_t> result; | ||
| 32 | promise() = default; | ||
| 33 | promise(const promise &) = delete; | ||
| 34 | task<result_t> get_return_object() noexcept { return task<result_t>{std::coroutine_handle<promise<result_t>>::from_promise(*this)}; } | ||
| 35 | std::suspend_never initial_suspend() const noexcept { return {}; } | ||
| 36 | std::suspend_always final_suspend() const noexcept { return {}; } | ||
| 37 | void unhandled_exception() { } | ||
| 38 | void return_value(result_t x) noexcept { result = std::move(x); } | ||
| 39 | }; | ||
| 40 | |||
| 41 | template<> struct promise<void> { | ||
| 42 | std::coroutine_handle<> precursor; | ||
| 43 | promise() = default; | ||
| 44 | promise(const promise &) = delete; | ||
| 45 | task<void> get_return_object() noexcept { return task<void>{std::coroutine_handle<promise<void>>::from_promise(*this)}; } | ||
| 46 | std::suspend_never initial_suspend() const noexcept { return {}; } | ||
| 47 | std::suspend_always final_suspend() const noexcept { return {}; } | ||
| 48 | void unhandled_exception() { } | ||
| 49 | void return_void() noexcept { } | ||
| 50 | }; | ||
| 51 | |||
| 52 | template<typename result_t> result_t task<result_t>::await_resume() const noexcept | ||
| 53 | { | ||
| 54 | auto x = std::move(handle::promise().result.value()); | ||
| 55 | handle::destroy(); | ||
| 56 | return std::move(x); | ||
| 57 | } | ||
| 58 | |||
| 59 | template<typename result_t> template<typename other_t> void task<result_t>::await_suspend(std::coroutine_handle<struct promise<other_t>> h) const noexcept | ||
| 60 | { | ||
| 61 | h.promise().precursor = *this; | ||
| 62 | } | ||
| 63 | |||
| 64 | template<typename result_t> std::optional<result_t> task<result_t>::operator()() noexcept | ||
| 65 | { | ||
| 66 | if (!handle::operator bool()) | ||
| 67 | return {}; | ||
| 68 | if (!handle::done()) { | ||
| 69 | auto &precursor = handle::promise().precursor; | ||
| 70 | if (precursor) { | ||
| 71 | if (!precursor.done()) | ||
| 72 | precursor.resume(); | ||
| 73 | if (precursor.done()) | ||
| 74 | precursor = nullptr; | ||
| 75 | } | ||
| 76 | if (!precursor) | ||
| 77 | handle::resume(); | ||
| 78 | } | ||
| 79 | if (handle::done()) { | ||
| 80 | auto x = await_resume(); | ||
| 81 | handle::operator=(nullptr); | ||
| 82 | return std::move(x); | ||
| 83 | } | ||
| 84 | return {}; | ||
| 85 | } | ||
| 86 | |||
| 87 | inline void task<void>::await_resume() const noexcept | ||
| 88 | { | ||
| 89 | handle::destroy(); | ||
| 90 | } | ||
| 91 | |||
| 92 | template<typename other_t> void task<void>::await_suspend(std::coroutine_handle<struct promise<other_t>> h) const noexcept | ||
| 93 | { | ||
| 94 | h.promise().precursor = *this; | ||
| 95 | } | ||
| 96 | |||
| 97 | inline bool task<void>::operator()() noexcept | ||
| 98 | { | ||
| 99 | if (!handle::operator bool()) | ||
| 100 | return true; | ||
| 101 | if (!handle::done()) { | ||
| 102 | auto &precursor = handle::promise().precursor; | ||
| 103 | if (precursor) { | ||
| 104 | if (!precursor.done()) | ||
| 105 | precursor.resume(); | ||
| 106 | if (precursor.done()) | ||
| 107 | precursor = nullptr; | ||
| 108 | } | ||
| 109 | if (!precursor) | ||
| 110 | handle::resume(); | ||
| 111 | } | ||
| 112 | if (handle::done()) { | ||
| 113 | await_resume(); | ||
| 114 | handle::operator=(nullptr); | ||
| 115 | return true; | ||
| 116 | } | ||
| 117 | return false; | ||
| 118 | } | ||
| 119 | |||
| 120 | } | ||
