9namespace Lightweight::Async
12template <
typename T =
void>
18#if defined(__GNUC__) && !defined(__clang__)
20 struct SymmetricTransferState
23 std::coroutine_handle<> running {};
25 std::coroutine_handle<> next {};
29 [[nodiscard]]
inline SymmetricTransferState& ThreadSymmetricTransferState() noexcept
31 thread_local SymmetricTransferState state;
51 [[nodiscard]]
inline std::coroutine_handle<> SymmetricTransfer([[maybe_unused]] std::coroutine_handle<> from,
52 std::coroutine_handle<> to)
noexcept
54#if defined(__GNUC__) && !defined(__clang__)
55 auto& state = ThreadSymmetricTransferState();
56 if (state.running == from)
59 return std::noop_coroutine();
62 auto const enclosingState = state;
66 state.running = std::exchange(state.next, {});
67 state.running.resume();
69 state = enclosingState;
70 return std::noop_coroutine();
81 struct TaskFinalAwaiter
83 [[nodiscard]]
bool await_ready() const noexcept
88 template <
typename Promise>
89 [[nodiscard]] std::coroutine_handle<> await_suspend(std::coroutine_handle<Promise> coro)
const noexcept
91 return SymmetricTransfer(coro, coro.promise().Continuation());
94 void await_resume() const noexcept {}
102 [[nodiscard]] std::suspend_always initial_suspend() noexcept
107 [[nodiscard]] TaskFinalAwaiter final_suspend() noexcept
113 void SetContinuation(std::coroutine_handle<> continuation)
noexcept
115 _continuation = continuation;
119 [[nodiscard]] std::coroutine_handle<> Continuation() const noexcept
121 return _continuation ? _continuation : std::noop_coroutine();
125 std::coroutine_handle<> _continuation {};
136 template <
typename T>
137 class CoroutineResult
141 void SetException() noexcept
143 _result.template emplace<2>(std::current_exception());
147 void SetValue(T
const& value)
149 _result.template emplace<1>(value);
153 void SetValue(T&& value)
noexcept(std::is_nothrow_move_constructible_v<T>)
155 _result.template emplace<1>(std::move(value));
159 [[nodiscard]] T Take()
161 if (_result.index() == 2)
162 std::rethrow_exception(std::get<2>(_result));
163 return std::move(std::get<1>(_result));
167 std::variant<std::monostate, T, std::exception_ptr> _result;
172 class CoroutineResult<void>
176 void SetException() noexcept
178 _exception = std::current_exception();
185 std::rethrow_exception(_exception);
189 std::exception_ptr _exception {};
195 template <
typename T>
196 class TaskPromise final:
public TaskPromiseBase
199 Task<T> get_return_object() noexcept;
201 void unhandled_exception() noexcept
203 _result.SetException();
206 void return_value(T
const& value)
208 _result.SetValue(value);
211 void return_value(T&& value)
noexcept(std::is_nothrow_move_constructible_v<T>)
213 _result.SetValue(std::move(value));
217 [[nodiscard]] T Take()
219 return _result.Take();
223 CoroutineResult<T> _result;
228 class TaskPromise<void> final:
public TaskPromiseBase
231 Task<void> get_return_object() noexcept;
233 void unhandled_exception() noexcept
235 _result.SetException();
238 void return_void() noexcept {}
247 CoroutineResult<void> _result;
271 using Handle = std::coroutine_handle<promise_type>;
286 _handle { std::exchange(other._handle, {}) }
299 _handle = std::exchange(other._handle, {});
305 Task& operator=(
Task const&) =
delete;
316 return static_cast<bool>(_handle);
322 return !_handle || _handle.done();
334 auto operator co_await() &&
noexcept
340 [[nodiscard]]
bool await_ready()
const noexcept
342 return !coro || coro.done();
345 [[nodiscard]] std::coroutine_handle<> await_suspend(std::coroutine_handle<> awaiting)
noexcept
347 coro.promise().SetContinuation(awaiting);
348 return detail::SymmetricTransfer(awaiting, coro);
351 decltype(
auto) await_resume()
353 return coro.promise().Take();
356 return Awaiter { _handle };
365 template <
typename T>
366 Task<T> TaskPromise<T>::get_return_object() noexcept
368 return Task<T> { std::coroutine_handle<TaskPromise<T>>::from_promise(*
this) };
371 inline Task<void> TaskPromise<void>::get_return_object() noexcept
373 return Task<void> { std::coroutine_handle<TaskPromise<void>>::from_promise(*
this) };
detail::TaskPromise< T > promise_type
The coroutine promise type required by the C++ coroutine machinery.
Handle GetHandle() const noexcept
bool IsReady() const noexcept
Task() noexcept=default
Constructs an empty Task that owns no coroutine.
bool IsValid() const noexcept
Task & operator=(Task &&other) noexcept
std::coroutine_handle< promise_type > Handle
The typed coroutine handle owned by this Task.
Task(Task &&other) noexcept