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
11template <class T = void>
12class CoroTask {
13public:
15 using Handle = std::coroutine_handle<promise_type>;
16
17 using Result = T;
18
19 using ExpectedResult = typename CoroPromise<T>::ExpectedResult;
20
21 friend promise_type;
22
23private:
24 Handle handle;
25
26 constexpr explicit CoroTask(Handle h) noexcept : handle(h) {}
27
29
30public:
31 struct ExpectedAwaiter : public AwaiterBase {
32 constexpr void setExecutor(ExecutorRef ex) { AwaiterBase::handle.promise().exec = ex; }
33 constexpr ExpectedAwaiter(Handle h) : AwaiterBase(h) {}
34 constexpr ExpectedResult await_resume() noexcept { return AwaiterBase::getResult(); }
35 };
36
37 struct ValueAwaiter : public AwaiterBase {
38 constexpr ValueAwaiter(Handle h) : AwaiterBase(h) {}
39 constexpr T await_resume() {
40 if constexpr (std::is_same_v<T, ExpectedResult>) {
41 return AwaiterBase::getResult();
42 } else {
43 return AwaiterBase::getResult().value();
44 }
45 }
46 };
47
48private:
49 struct Launcher {
50 struct promise_type : public CoroPromiseBase {
51 constexpr ExpectedAwaiter&& await_transform(ExpectedAwaiter&& a) { return std::move(a); }
52 constexpr std::suspend_never initial_suspend() noexcept { return {}; }
53 constexpr std::suspend_never final_suspend() noexcept { return {}; }
54 constexpr void return_void() noexcept {}
55 constexpr void unhandled_exception() { std::rethrow_exception(std::current_exception()); }
56 constexpr Launcher get_return_object() noexcept { return {}; }
57 };
58 };
59
60public:
61 CoroTask(CoroTask const&) = delete;
62 CoroTask& operator=(CoroTask const&) = delete;
63
64 CoroTask(CoroTask&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
65
66 constexpr ~CoroTask() {
67 if (handle) {
68 std::exchange(handle, nullptr).destroy();
69 }
70 }
71
72 constexpr void setExecutor(ExecutorRef ex) { handle.promise().exec = ex; }
73
74 constexpr ExecutorRef getExecutor() { return handle.promise().exec; }
75
76 bool done() const { return !handle || handle.done(); }
77
78 auto operator co_await() { return ValueAwaiter(std::exchange(handle, nullptr)); }
79
80 auto tryGet() { return ExpectedAwaiter(std::exchange(handle, nullptr)); }
81
82 template <std::invocable<ExpectedResult> F>
83 void launch(NonNullExecutorRef executor, F&& callback) noexcept try {
84 setExecutor(executor);
85 [](CoroTask lazy, std::decay_t<F> cb) -> Launcher {
86 std::invoke(cb, co_await lazy.tryGet());
87 }(std::move(*this), std::forward<F>(callback));
88 } catch (...) {
89 std::invoke(std::forward<F>(callback), makeExceptionError());
90 }
91 void launch(NonNullExecutorRef executor) noexcept {
92 launch(executor, [](auto&&) {});
93 }
94 ExpectedResult syncLaunch(NonNullExecutorRef executor) noexcept {
95 ExpectedResult value;
96 std::binary_semaphore cond{0};
97 launch(executor, [&](ExpectedResult&& result) {
98 value = std::move(result);
99 cond.release();
100 });
101 cond.acquire();
102 return value;
103 }
104};
105
106template <class T>
107constexpr CoroTask<T> CoroPromise<T>::get_return_object() noexcept {
108 return CoroTask<T>(CoroTask<T>::Handle::from_promise(*this));
109}
110constexpr CoroTask<void> CoroPromise<void>::get_return_object() noexcept {
111 return CoroTask<void>(CoroTask<void>::Handle::from_promise(*this));
112}
113template <class T, class Alloc>
114inline auto collectAll(std::vector<CoroTask<T>, Alloc>&& tasks) {
115 return CollectAllAwaiter<std::vector<CoroTask<T>, Alloc>>(std::move(tasks));
116}
117template <typename... Ts>
118inline auto collectAll(CoroTask<Ts>... tasks)
119 requires(sizeof...(Ts) > 0)
120{
121 return CollectAllTupleAwaiter<CoroTask, Ts...>(std::move(tasks)...);
122}
123template <class F, class... Args>
124 requires(traits::is_specialization_of_v<std::invoke_result_t<F, Args...>, CoroTask>)
125auto keepThis(F f, Args... args) -> std::invoke_result_t<F, Args...> {
126 co_return co_await std::invoke(f, std::move(args)...);
127}
128
129} // namespace ll::coro
Definition CoroTask.h:12
Definition optional_ref.h:10
Definition CoroPromise.h:16
Definition CoroPromise.h:56
Definition CoroTaskAwaiter.h:7
Definition CoroTask.h:31
Definition CoroTask.h:37