LeviLamina
Loading...
Searching...
No Matches
CoroTask.h
1#pragma once
2
3#include <semaphore>
4
5#include "ll/api/coro/Collect.h"
6#include "ll/api/coro/CoroPromise.h"
7#include "ll/api/coro/CoroTaskAwaiter.h"
8
9namespace ll::coro {
10
11class ViaContinuation {
12public:
13 struct promise_type {
14 constexpr ViaContinuation get_return_object() noexcept {
15 return ViaContinuation{std::coroutine_handle<promise_type>::from_promise(*this)};
16 }
17 constexpr std::suspend_always initial_suspend() noexcept { return {}; }
18 constexpr std::suspend_never final_suspend() noexcept { return {}; }
19 constexpr void return_void() noexcept {}
20 [[noreturn]] void unhandled_exception() noexcept { std::terminate(); }
21 };
22
23 using Handle = std::coroutine_handle<promise_type>;
24
25 ViaContinuation(ViaContinuation const&) = delete;
26 ViaContinuation& operator=(ViaContinuation const&) = delete;
27
28 constexpr explicit ViaContinuation(Handle h) noexcept : handle(h) {}
29 constexpr ViaContinuation(ViaContinuation&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
30
31 constexpr ~ViaContinuation() {
32 if (handle) {
33 std::exchange(handle, nullptr).destroy();
34 }
35 }
36
37 constexpr std::coroutine_handle<> get() const noexcept { return handle; }
38 constexpr void release() noexcept { handle = nullptr; }
39
40private:
41 Handle handle;
42};
43
44template <class T = void>
45class CoroTask {
46public:
47 using promise_type = CoroPromise<T>;
48 using Handle = std::coroutine_handle<promise_type>;
49
50 using Result = T;
51
52 using ExpectedResult = typename CoroPromise<T>::ExpectedResult;
53
54 friend promise_type;
55
56private:
57 Handle handle;
58
59 constexpr explicit CoroTask(Handle h) noexcept : handle(h) {}
60
61 using AwaiterBase = CoroTaskAwaiter<T>;
62
63public:
64 struct ExpectedAwaiter : public AwaiterBase {
65 constexpr void setExecutor(ExecutorRef ex) { AwaiterBase::handle.promise().exec = ex; }
66 constexpr ExpectedAwaiter(Handle h) : AwaiterBase(h) {}
67 constexpr ExpectedResult await_resume() noexcept { return AwaiterBase::getResult(); }
68 };
69
70 struct ValueAwaiter : public AwaiterBase {
71 constexpr ValueAwaiter(Handle h) : AwaiterBase(h) {}
72 constexpr T await_resume() {
73 if constexpr (std::is_same_v<T, ExpectedResult>) {
74 return AwaiterBase::getResult();
75 } else {
76 return AwaiterBase::getResult().value();
77 }
78 }
79 };
80
81 struct ViaAwaiter : public ValueAwaiter {
82 constexpr ViaAwaiter(Handle h, NonNullExecutorRef executor) : ValueAwaiter(h) {
83 AwaiterBase::handle.promise().exec = executor;
84 }
85
86 template <std::derived_from<CoroPromiseBase> P>
87 void await_suspend(std::coroutine_handle<P> continuation) {
88 auto resumeCaller = [](NonNullExecutorRef executor,
89 std::coroutine_handle<> continuation) -> ViaContinuation {
90 executor.execute(continuation);
91 co_return;
92 }(continuation.promise().exec.value(), continuation);
93 auto& promise = AwaiterBase::handle.promise();
94 promise.handle = resumeCaller.get();
95 promise.local = continuation.promise().local;
96 promise.exec->execute(AwaiterBase::handle);
97 resumeCaller.release();
98 }
99 };
100
101private:
102 struct Launcher {
103 struct promise_type : public CoroPromiseBase {
104 constexpr ExpectedAwaiter&& await_transform(ExpectedAwaiter&& a) { return std::move(a); }
105 constexpr std::suspend_never initial_suspend() noexcept { return {}; }
106 constexpr std::suspend_never final_suspend() noexcept { return {}; }
107 constexpr void return_void() noexcept {}
108 constexpr void unhandled_exception() { std::rethrow_exception(std::current_exception()); }
109 constexpr Launcher get_return_object() noexcept { return {}; }
110 };
111 };
112
113public:
114 CoroTask(CoroTask const&) = delete;
115 CoroTask& operator=(CoroTask const&) = delete;
116
117 CoroTask(CoroTask&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
118
119 constexpr ~CoroTask() {
120 if (handle) {
121 std::exchange(handle, nullptr).destroy();
122 }
123 }
124
125 constexpr void setExecutor(ExecutorRef ex) { handle.promise().exec = ex; }
126
127 constexpr ExecutorRef getExecutor() { return handle.promise().exec; }
128
129 bool done() const { return !handle || handle.done(); }
130
131 auto operator co_await() { return ValueAwaiter(std::exchange(handle, nullptr)); }
132
133 auto via(NonNullExecutorRef executor) { return ViaAwaiter(std::exchange(handle, nullptr), executor); }
134
135 auto tryGet() { return ExpectedAwaiter(std::exchange(handle, nullptr)); }
136
137 template <std::invocable<ExpectedResult> F>
138 void launch(NonNullExecutorRef executor, F&& callback) noexcept try {
139 setExecutor(executor);
140 [](CoroTask lazy, std::decay_t<F> cb) -> Launcher {
141 std::invoke(cb, co_await lazy.tryGet());
142 }(std::move(*this), std::forward<F>(callback));
143 } catch (...) {
144 std::invoke(std::forward<F>(callback), makeExceptionError());
145 }
146 void launch(NonNullExecutorRef executor) noexcept {
147 launch(executor, [](auto&&) {});
148 }
149 ExpectedResult syncLaunch(NonNullExecutorRef executor) noexcept {
150 ExpectedResult value;
151 std::binary_semaphore cond{0};
152 launch(executor, [&](ExpectedResult&& result) {
153 value = std::move(result);
154 cond.release();
155 });
156 cond.acquire();
157 return value;
158 }
159};
160
161template <class T>
162constexpr CoroTask<T> CoroPromise<T>::get_return_object() noexcept {
164}
165constexpr CoroTask<void> CoroPromise<void>::get_return_object() noexcept {
167}
168template <class T, class Alloc>
169inline auto collectAll(std::vector<CoroTask<T>, Alloc>&& tasks) {
170 return CollectAllAwaiter<std::vector<CoroTask<T>, Alloc>>(std::move(tasks));
171}
172template <typename... Ts>
173inline auto collectAll(CoroTask<Ts>... tasks)
174 requires(sizeof...(Ts) > 0)
175{
176 return CollectAllTupleAwaiter<CoroTask, Ts...>(std::move(tasks)...);
177}
178template <class F, class... Args>
179 requires(traits::is_specialization_of_v<std::invoke_result_t<F, Args...>, CoroTask>)
180auto keepThis(F f, Args... args) -> std::invoke_result_t<F, Args...> {
181 co_return co_await std::invoke(f, std::move(args)...);
182}
183
184} // namespace ll::coro
Definition Collect.h:56
Definition CoroTask.h:45
Definition CoroTask.h:11
Definition Collect.h:10
Definition CoroPromise.h:56
Definition CoroTaskAwaiter.h:7
Definition CoroTask.h:64
Definition CoroTask.h:70
Definition CoroTask.h:81