Nugget
Loading...
Searching...
No Matches
coroutine.hh
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2022 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27#pragma once
28
29#include <coroutine>
30#include <type_traits>
31
33
34namespace psyqo {
35
48template <typename T = void>
49struct Coroutine {
50 struct Empty {};
51 typedef typename std::conditional<std::is_void<T>::value, Empty, T>::type SafeT;
52
53 Coroutine() = default;
54 Coroutine(Coroutine &&other) = default;
55 Coroutine &operator=(Coroutine &&other) = default;
56 Coroutine(Coroutine const &) = delete;
57 Coroutine &operator=(Coroutine const &) = delete;
58
67 struct Awaiter {
68 Awaiter(Awaiter &&other) = default;
69 Awaiter &operator=(Awaiter &&other) = default;
70 Awaiter(Awaiter const &) = default;
71 Awaiter &operator=(Awaiter const &) = default;
72 constexpr bool await_ready() const noexcept {
73 bool ret = m_coroutine->m_earlyResume;
74 m_coroutine->m_earlyResume = false;
75 return ret;
76 }
77 constexpr void await_suspend(std::coroutine_handle<> h) { m_coroutine->m_suspended = true; }
78 constexpr void await_resume() const noexcept {}
79
80 private:
81 Awaiter(Coroutine *coroutine) : m_coroutine(coroutine) {}
82 Coroutine *m_coroutine;
83 friend struct Coroutine;
84 };
85
92 Awaiter awaiter() { return Awaiter(this); }
93
103 void resume() {
104 if (!m_handle) return;
105 if (!m_suspended) {
106 m_earlyResume = true;
107 return;
108 }
109 m_suspended = false;
110 m_handle.resume();
111 }
112
122 bool done() {
123 if (!m_handle) return true;
124 bool isDone = m_handle.done();
125 if (isDone) {
126 if constexpr (!std::is_void<T>::value) {
127 m_value = eastl::move(m_handle.promise().m_value);
128 }
129 m_handle.destroy();
130 m_handle = nullptr;
131 }
132 return isDone;
133 }
134
146 const SafeT &value() const { return m_value; }
147
148 private:
149 struct PromiseVoid {
150 Coroutine<> get_return_object() {
151 return Coroutine<>{eastl::move(std::coroutine_handle<Promise>::from_promise(*this))};
152 }
153 std::suspend_always initial_suspend() { return {}; }
154 std::suspend_always final_suspend() noexcept { return {}; }
155 void unhandled_exception() {}
156 void return_void() {
157 auto awaitingCoroutine = m_awaitingCoroutine;
158 if (awaitingCoroutine) {
159 // This doesn't feel right, but I don't know how to do it otherwise,
160 // since the coroutine is a template and I can't forward the type.
161 __builtin_coro_resume(awaitingCoroutine);
162 }
163 }
164 [[no_unique_address]] Empty m_value;
165 void *m_awaitingCoroutine = nullptr;
166 };
167 struct PromiseValue {
168 Coroutine<T> get_return_object() {
169 return Coroutine{eastl::move(std::coroutine_handle<Promise>::from_promise(*this))};
170 }
171 std::suspend_always initial_suspend() { return {}; }
172 std::suspend_always final_suspend() noexcept { return {}; }
173 void unhandled_exception() {}
174 void return_value(T &&value) {
175 m_value = eastl::move(value);
176 auto awaitingCoroutine = m_awaitingCoroutine;
177 if (awaitingCoroutine) {
178 // This doesn't feel right, but I don't know how to do it otherwise,
179 // since the coroutine is a template and I can't forward the type.
180 __builtin_coro_resume(awaitingCoroutine);
181 }
182 }
183 T m_value;
184 void *m_awaitingCoroutine = nullptr;
185 };
186 typedef typename std::conditional<std::is_void<T>::value, PromiseVoid, PromiseValue>::type Promise;
187 Coroutine(std::coroutine_handle<Promise> &&handle) : m_handle(eastl::move(handle)) {}
188 std::coroutine_handle<Promise> m_handle;
189 [[no_unique_address]] SafeT m_value;
190 void *m_awaitingCoroutine = nullptr;
191 bool m_suspended = true;
192 bool m_earlyResume = false;
193
194 public:
195 using promise_type = Promise;
196
197 constexpr bool await_ready() { return m_handle.done(); }
198 template <typename U>
199 constexpr void await_suspend(std::coroutine_handle<U> h) {
200 auto &promise = m_handle.promise();
201 promise.m_awaitingCoroutine = h.address();
202 resume();
203 }
204 constexpr SafeT await_resume() {
205 SafeT value = eastl::move(m_handle.promise().m_value);
206 m_handle.destroy();
207 return value;
208 }
209};
210
211} // namespace psyqo
constexpr uint32_t move(Reg tgt, Reg src)
Definition encoder.hh:243
Definition cdrom-loader.hh:39
The awaiter type.
Definition coroutine.hh:67
Awaiter(Awaiter &&other)=default
Awaiter(Awaiter const &)=default
constexpr void await_suspend(std::coroutine_handle<> h)
Definition coroutine.hh:77
Awaiter & operator=(Awaiter const &)=default
constexpr void await_resume() const noexcept
Definition coroutine.hh:78
constexpr bool await_ready() const noexcept
Definition coroutine.hh:72
Awaiter & operator=(Awaiter &&other)=default
Definition coroutine.hh:50
A suitable type to hold and return a C++20 coroutine.
Definition coroutine.hh:49
Coroutine(Coroutine const &)=delete
Awaiter awaiter()
Creates an Awaiter object.
Definition coroutine.hh:92
Coroutine & operator=(Coroutine const &)=delete
Coroutine & operator=(Coroutine &&other)=default
constexpr bool await_ready()
Definition coroutine.hh:197
Promise promise_type
Definition coroutine.hh:195
const SafeT & value() const
Returns the value returned by the coroutine.
Definition coroutine.hh:146
Coroutine()=default
std::conditional< std::is_void< T >::value, Empty, T >::type SafeT
Definition coroutine.hh:51
void resume()
Resumes the coroutine.
Definition coroutine.hh:103
bool done()
Returns the status of the coroutine.
Definition coroutine.hh:122
constexpr void await_suspend(std::coroutine_handle< U > h)
Definition coroutine.hh:199
constexpr SafeT await_resume()
Definition coroutine.hh:204
Coroutine(Coroutine &&other)=default
static int ret
Definition syscalls.h:72