LeviLamina
Loading...
Searching...
No Matches
CallbackTransformer.h
1#pragma once
2
3#include <coroutine>
4#include <optional>
5#include <semaphore>
6
7#include "ll/api/coro/Executor.h"
8
9namespace ll::coro {
10template <class T>
12 using ValueStorage = std::conditional_t<std::is_lvalue_reference_v<T>, std::add_pointer_t<T>, std::optional<T>>;
13 struct Data {
14 ExecutorRef exec;
15 std::coroutine_handle<> handle;
16 ValueStorage value{};
17 std::binary_semaphore sem{0};
18 std::atomic_bool finished{false};
19
20 void reset() {
21 if constexpr (std::is_lvalue_reference_v<T>) {
22 value = nullptr;
23 } else {
24 value.reset();
25 }
26 }
27 void execute() {
28 if (auto h = exchange(handle, nullptr)) {
29 exec->execute(h);
30 }
31 }
32 };
33
34 std::shared_ptr<Data> data;
35
36public:
38 std::shared_ptr<Data> data;
39
40 public:
41 explicit ValueSetter(CallbackTransformer const& t) : data(t.data) {}
42
43 ValueSetter(ValueSetter const&) = delete;
44 ValueSetter& operator=(ValueSetter const&) = delete;
45 ValueSetter(ValueSetter&&) = default;
46 ValueSetter& operator=(ValueSetter&&) = default;
47
48 bool finished() const { return data->finished; }
49 void finish() const { data->finished.store(true); }
50
51 template <class... Args>
52 requires(!std::is_lvalue_reference_v<T>)
53 constexpr void emplace(Args&&... args) const {
54 data->sem.acquire();
55 data->value.emplace(std::forward<Args>(args)...);
56 data->execute();
57 }
58
59 constexpr void emplace(T& t) const
60 requires(std::is_lvalue_reference_v<T>)
61 {
62 data->sem.acquire();
63 data->value = std::addressof(t);
64 data->execute();
65 }
66
67 ~ValueSetter() {
68 if (data) {
69 finish();
70 data->execute();
71 }
72 }
73 };
74
75 class Iterator {
76 std::shared_ptr<Data> data;
77
78 class IncAwaiter {
79 Iterator& iter;
80
81 public:
82 IncAwaiter(Iterator& iter) : iter(iter) {}
83
84 constexpr bool await_ready() const noexcept { return iter.data == nullptr || iter.data->finished; }
85 void await_suspend(std::coroutine_handle<> handle) {
86 iter.data->handle = handle;
87 iter.data->reset();
88 iter.data->sem.release();
89 }
90 constexpr Iterator& await_resume() const noexcept {
91 if (iter.data && iter.data->finished && !iter.data->value) {
92 iter.data.reset();
93 }
94 return iter;
95 }
96 };
97
98 public:
99 Iterator() = default;
100 explicit Iterator(CallbackTransformer const& t) : data(t.data) {}
101
102 Iterator(Iterator const&) = delete;
103 Iterator& operator=(Iterator const&) = delete;
104 Iterator(Iterator&&) = default;
105 Iterator& operator=(Iterator&&) = default;
106
107 [[nodiscard]] IncAwaiter operator++() { return IncAwaiter{*this}; }
108
109 [[nodiscard]] bool operator==(Iterator const& other) const noexcept { return data == other.data; }
110
111 [[nodiscard]] bool operator==(std::nullptr_t) const noexcept { return data == nullptr; }
112
113 [[nodiscard]] operator bool() const noexcept { return data != nullptr; }
114
115 [[nodiscard]] T&& operator*() const noexcept { return static_cast<T&&>(*data->value); }
116
117 [[nodiscard]] std::add_pointer_t<T> operator->() const noexcept { return std::addressof(*data->value); }
118
119 ~Iterator() {
120 if (data) {
121 data->finished.store(true);
122 data->sem.release();
123 }
124 }
125 };
126
127 CallbackTransformer() : data(std::make_shared<Data>()) {}
128
130 CallbackTransformer& operator=(CallbackTransformer const&) = delete;
132 CallbackTransformer& operator=(CallbackTransformer&&) = default;
133
134 ValueSetter getValueSetter() const { return ValueSetter{*this}; }
135
136 [[nodiscard]] Iterator end() noexcept { return {}; }
137
138 [[nodiscard]] auto begin() noexcept {
139 class BeginAwaiter {
140 CallbackTransformer& ct;
141
142 public:
143 BeginAwaiter(CallbackTransformer& ct) : ct(ct) {}
144
145 constexpr bool await_ready() const noexcept { return ct.data->finished; }
146 void await_suspend(std::coroutine_handle<> handle) {
147 ct.data->handle = handle;
148 ct.data->sem.release();
149 }
150 constexpr Iterator await_resume() const noexcept {
151 if (ct.data->finished && !ct.data->value) {
152 return {};
153 }
154 return Iterator{ct};
155 }
156 constexpr void setExecutor(ExecutorRef ex) { ct.data->exec = ex; }
157 };
158 return BeginAwaiter{*this};
159 }
160
161 ~CallbackTransformer() {
162 if (data) {
163 data->finished.store(true);
164 data->execute();
165 }
166 }
167};
168} // namespace ll::coro
Definition CallbackTransformer.h:75
Definition CallbackTransformer.h:37
Definition CallbackTransformer.h:11
Definition optional_ref.h:10
STL namespace.