@@ -26,52 +26,86 @@ SOFTWARE.
2626
2727#pragma once
2828
29- #if defined(__APPLE__) && (__clang_major__ < 15)
30- // Why has Apple become the Microsoft of Software Engineering?
31- #include < experimental/coroutine>
32- #else
3329#include < coroutine>
34- #endif
3530#include < type_traits>
31+ #include < utility>
3632
3733namespace PCSX {
3834
3935template <typename T = void >
4036struct Coroutine {
41- #if defined(__APPLE__) && (__clang_major__ < 15)
42- template <typename U>
43- using CoroutineHandle = std::experimental::coroutine_handle<U>;
44- using CoroutineHandleVoid = std::experimental::coroutine_handle<void >;
45- #else
46- template <typename U>
47- using CoroutineHandle = std::coroutine_handle<U>;
48- using CoroutineHandleVoid = std::coroutine_handle<void >;
49- #endif
5037 struct Empty {};
5138 typedef typename std::conditional<std::is_void<T>::value, Empty, T>::type SafeT;
5239
5340 Coroutine () = default ;
54- Coroutine (Coroutine &&other) = default ;
55- Coroutine &operator =(Coroutine &&other) = default ;
41+
42+ Coroutine (Coroutine &&other)
43+ : m_handle(std::exchange(other.m_handle, nullptr )),
44+ m_value (std::move(other.m_value)),
45+ m_suspended(other.m_suspended),
46+ m_earlyResume(other.m_earlyResume) {
47+ other.m_suspended = true ;
48+ other.m_earlyResume = false ;
49+ }
50+
51+ Coroutine &operator =(Coroutine &&other) {
52+ if (this != &other) {
53+ if (m_handle) m_handle.destroy ();
54+ m_handle = std::exchange (other.m_handle , nullptr );
55+ m_value = std::move (other.m_value );
56+ m_suspended = other.m_suspended ;
57+ m_earlyResume = other.m_earlyResume ;
58+ other.m_suspended = true ;
59+ other.m_earlyResume = false ;
60+ }
61+ return *this ;
62+ }
63+
5664 Coroutine (Coroutine const &) = delete ;
5765 Coroutine &operator =(Coroutine const &) = delete ;
66+ ~Coroutine () {
67+ if (m_handle) m_handle.destroy ();
68+ m_handle = nullptr ;
69+ }
5870
5971 struct Awaiter {
60- constexpr bool await_ready () const noexcept { return false ; }
61- constexpr void await_suspend (CoroutineHandleVoid) const noexcept {}
72+ Awaiter (Awaiter &&other) = default ;
73+ Awaiter &operator =(Awaiter &&other) = default ;
74+ Awaiter (Awaiter const &) = default ;
75+ Awaiter &operator =(Awaiter const &) = default ;
76+ constexpr bool await_ready () const noexcept {
77+ bool ret = m_coroutine->m_earlyResume ;
78+ m_coroutine->m_earlyResume = false ;
79+ return ret;
80+ }
81+ constexpr void await_suspend (std::coroutine_handle<> h) { m_coroutine->m_suspended = true ; }
6282 constexpr void await_resume () const noexcept {}
83+
84+ private:
85+ Awaiter (Coroutine *coroutine) : m_coroutine(coroutine) {}
86+ Coroutine *m_coroutine;
87+ friend struct Coroutine ;
6388 };
6489
65- Awaiter awaiter () { return {}; }
90+ Awaiter awaiter () & { return Awaiter (this ); }
91+
6692 void resume () {
6793 if (!m_handle) return ;
94+ if (!m_suspended) {
95+ m_earlyResume = true ;
96+ return ;
97+ }
98+ m_suspended = false ;
6899 m_handle.resume ();
69100 }
70101
71102 bool done () {
72103 if (!m_handle) return true ;
73104 bool isDone = m_handle.done ();
74105 if (isDone) {
106+ if constexpr (!std::is_void<T>::value) {
107+ m_value = std::move (m_handle.promise ().m_value );
108+ }
75109 m_handle.destroy ();
76110 m_handle = nullptr ;
77111 }
@@ -82,38 +116,106 @@ struct Coroutine {
82116
83117 private:
84118 struct PromiseVoid {
85- Coroutine<T> get_return_object () { return Coroutine{std::move (CoroutineHandle<Promise>::from_promise (*this ))}; }
86- Awaiter initial_suspend () { return {}; }
87- Awaiter final_suspend () noexcept { return {}; }
119+ struct FinalAwaiter {
120+ bool await_ready () const noexcept { return false ; }
121+ std::coroutine_handle<> await_suspend (std::coroutine_handle<PromiseVoid> h) const noexcept {
122+ auto next = h.promise ().m_awaitingCoroutine ;
123+ return next ? next : std::noop_coroutine ();
124+ }
125+ void await_resume () const noexcept {}
126+ };
127+ Coroutine<> get_return_object () {
128+ return Coroutine<>{std::move (std::coroutine_handle<Promise>::from_promise (*this ))};
129+ }
130+ std::suspend_always initial_suspend () { return {}; }
131+ FinalAwaiter final_suspend () noexcept { return {}; }
88132 void unhandled_exception () {}
89133 template <typename From>
90- Awaiter yield_value (From &&from) {
91- return {} ;
134+ From yield_value (From &&from) {
135+ return std::forward<From>(from) ;
92136 }
93137 void return_void () {}
138+ [[no_unique_address]] Empty m_value;
139+ std::coroutine_handle<> m_awaitingCoroutine;
94140 };
141+
95142 struct PromiseValue {
96- PromiseValue (Coroutine<T> *c) : coroutine(c) {}
97- Coroutine<T> get_return_object () { return Coroutine{std::move (CoroutineHandle<Promise>::from_promise (*this ))}; }
98- Awaiter initial_suspend () { return {}; }
99- Awaiter final_suspend () noexcept { return {}; }
143+ struct FinalAwaiter {
144+ bool await_ready () const noexcept { return false ; }
145+ std::coroutine_handle<> await_suspend (std::coroutine_handle<PromiseValue> h) const noexcept {
146+ auto next = h.promise ().m_awaitingCoroutine ;
147+ return next ? next : std::noop_coroutine ();
148+ }
149+ void await_resume () const noexcept {}
150+ };
151+ Coroutine<T> get_return_object () {
152+ return Coroutine{std::move (std::coroutine_handle<Promise>::from_promise (*this ))};
153+ }
154+ std::suspend_always initial_suspend () { return {}; }
155+ FinalAwaiter final_suspend () noexcept { return {}; }
100156 void unhandled_exception () {}
101- // This should be an std::convertible_to<T>, but Apple still doesn't have a fully C++-20 conformant library.
102157 template <typename From>
103- Awaiter yield_value (From &&from) {
104- coroutine->m_value = std::forward<From>(from);
105- return {};
158+ From yield_value (From &&from) {
159+ return std::forward<From>(from);
160+ }
161+ void return_value (T &&value) {
162+ m_value = std::move (value);
106163 }
107- void return_value (T &&value) { coroutine-> m_value = std::forward (value); }
108- Coroutine<T> *coroutine = nullptr ;
164+ T m_value;
165+ std::coroutine_handle<> m_awaitingCoroutine ;
109166 };
167+
110168 typedef typename std::conditional<std::is_void<T>::value, PromiseVoid, PromiseValue>::type Promise;
111- Coroutine (CoroutineHandle<Promise> &&handle) : m_handle(std::move(handle)) {}
112- CoroutineHandle<Promise> m_handle;
169+
170+ Coroutine (std::coroutine_handle<Promise> &&handle) : m_handle(std::move(handle)) {}
171+
172+ std::coroutine_handle<Promise> m_handle;
113173 [[no_unique_address]] SafeT m_value;
174+ bool m_suspended = true ;
175+ bool m_earlyResume = false ;
114176
115177 public:
116178 using promise_type = Promise;
179+
180+ struct ChainAwaiter {
181+ std::coroutine_handle<Promise> handle;
182+
183+ explicit ChainAwaiter (std::coroutine_handle<Promise> h) : handle(h) {}
184+ ~ChainAwaiter () {
185+ if (handle) handle.destroy ();
186+ }
187+
188+ ChainAwaiter (ChainAwaiter &&other) : handle(other.handle) { other.handle = nullptr ; }
189+ ChainAwaiter &operator =(ChainAwaiter &&) = delete ;
190+ ChainAwaiter (const ChainAwaiter &) = delete ;
191+ ChainAwaiter &operator =(const ChainAwaiter &) = delete ;
192+
193+ constexpr bool await_ready () { return handle.done (); }
194+
195+ void await_suspend (std::coroutine_handle<> h) {
196+ handle.promise ().m_awaitingCoroutine = h;
197+ if (!handle.done ()) handle.resume ();
198+ }
199+
200+ constexpr T await_resume () {
201+ if constexpr (std::is_void<T>::value) {
202+ handle.destroy ();
203+ handle = nullptr ;
204+ return ;
205+ } else {
206+ auto val = std::move (handle.promise ().m_value );
207+ handle.destroy ();
208+ handle = nullptr ;
209+ return val;
210+ }
211+ }
212+ };
213+
214+ ChainAwaiter operator co_await () && {
215+ auto h = m_handle;
216+ m_handle = nullptr ;
217+ return ChainAwaiter{h};
218+ }
117219};
118220
119221} // namespace PCSX
0 commit comments