summaryrefslogtreecommitdiff
path: root/aisa/coroutine.h
diff options
context:
space:
mode:
authorJulian Blake Kongslie2022-06-25 10:16:12 -0700
committerJulian Blake Kongslie2022-06-25 10:16:12 -0700
commitd80e0dbd20bb8597afe92f770e39d20440557d1f (patch)
tree3a2a89d3e8b0a7dd8f9a26f166825cef7c62795d /aisa/coroutine.h
parentMove get-git-tag to a tools subdirectory. (diff)
downloadissim-d80e0dbd20bb8597afe92f770e39d20440557d1f.tar.xz
Demo for a coroutine-based step evaluator.
Diffstat (limited to 'aisa/coroutine.h')
-rw-r--r--aisa/coroutine.h120
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
5namespace 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}