Iros
 
Loading...
Searching...
No Matches
async_generator.h
Go to the documentation of this file.
1#pragma once
2
9#include "di/meta/core.h"
10#include "di/meta/language.h"
11#include "di/util/coroutine.h"
12#include "di/util/exchange.h"
13#include "di/util/immovable.h"
17
18namespace di::execution {
20 template<typename Ref, typename Value>
21 struct AsyncGeneratorT;
22
23 template<typename Ref, typename Value>
25
26 template<typename Ref, typename Value>
28
29 template<typename Ref>
31
32 struct AllocFailed {};
33
34 template<typename Self, typename Ref, typename Value>
35 struct PromiseBaseT {
36 struct Type : WithAwaitableSenders<Self> {
39
40 public:
41 Type() = default;
42
43 auto operator new(usize size) noexcept -> void* { return ::operator new(size, std::nothrow); }
44 void operator delete(void* ptr, usize size) noexcept { ::operator delete(ptr, size); }
45
46 auto initial_suspend() noexcept -> SuspendAlways { return {}; }
47 auto final_suspend() noexcept { return FinalAwaiter {}; }
48
49 struct YieldAwaiter {
50 auto await_ready() noexcept -> bool { return false; }
51
52 template<typename Promise>
54 PromiseBase& current = coroutine.promise();
55 return current.continuation() ? current.continuation() : noop_coroutine();
56 }
57
58 void await_resume() noexcept {}
59 };
60
61 auto yield_value(Yield value) noexcept {
62 m_pointer = util::addressof(value);
63 return YieldAwaiter {};
64 }
65
66 void return_value(types::Void) noexcept {}
67
68 template<typename E>
70 void return_value(vocab::Unexpected<E>&& error) noexcept {
71 m_error = util::move(error).error();
72 }
73
74 void return_value(Stopped) noexcept { m_error = BasicError::OperationCanceled; }
75
77
78 private:
79 template<typename, typename>
80 friend struct AsyncGeneratorT;
81
82 struct FinalAwaiter {
83 auto await_ready() noexcept -> bool { return false; }
84
85 template<typename Promise>
86 auto await_suspend(CoroutineHandle<Promise> coroutine) noexcept -> CoroutineHandle<> {
87 PromiseBase& current = coroutine.promise();
88
89 auto was_error = current.m_error.has_value();
90 if (was_error) {
91 if (current.m_error == BasicError::OperationCanceled) {
92 return current.unhandled_stopped();
93 }
94 return current.unhandled_error(util::move(current.m_error).value());
95 }
96
97 return current.continuation() ? current.continuation() : noop_coroutine();
98 }
99
100 void await_resume() noexcept {}
101 };
102
103 struct AsyncRange : util::Immovable {
105
106 explicit AsyncRange(CoroutineHandle<PromiseBase> coroutine_) noexcept : coroutine(coroutine_) {}
107
108 ~AsyncRange() noexcept {
109 if (coroutine) {
110 coroutine.destroy();
111 }
112 }
113
114 struct NextAwaiter {
116
117 auto await_ready() noexcept -> bool { return false; }
118
119 template<typename OtherPromise>
122
123 coroutine.promise().set_continuation(continuation);
124 return coroutine;
125 }
126
127 auto await_resume() noexcept -> vocab::Optional<Value> {
129
130 auto& promise = coroutine.promise();
131 DI_ASSERT(!promise.m_error.has_value());
132
133 if (coroutine.done()) {
134 return vocab::nullopt;
135 }
136
137 return *promise.m_pointer;
138 }
139 };
140
141 friend auto tag_invoke(types::Tag<next>, AsyncRange& self) { return NextAwaiter { self.coroutine }; }
142 };
143
144 struct Awaiter {
146
147 auto await_ready() noexcept -> bool {
148 // No need to suspend if we have a coroutine.
149 return !!coroutine;
150 }
151
152 template<typename OtherPromise>
153 auto await_suspend(CoroutineHandle<OtherPromise> continuation) noexcept -> CoroutineHandle<> {
154 DI_ASSERT(!coroutine);
155 return continuation.promise().unhandled_error(vocab::Error(BasicError::NotEnoughMemory));
156 }
157
158 auto await_resume() noexcept {
159 DI_ASSERT(coroutine);
160 return AsyncRange(coroutine);
161 }
162 };
163
164 meta::AddPointer<Yield> m_pointer { nullptr };
166 };
167 };
168
169 template<typename Self, typename Ref, typename Value>
171
172 template<typename Ref, typename Value>
173 struct [[nodiscard]] AsyncGeneratorT {
174 struct Type {
175 private:
176 struct Promise;
177
179
180 struct Promise : PromiseBase {
181 auto get_return_object() noexcept -> Type {
183 }
184 static auto get_return_object_on_allocation_failure() noexcept -> Type {
185 return Type { AllocFailed {} };
186 }
187 };
188
189 using Handle = CoroutineHandle<Promise>;
190 using ParentHandle = CoroutineHandle<PromiseBase>;
191 using Awaiter = PromiseBase::Awaiter;
192
193 public:
194 using promise_type = Promise;
195
196 Type(Type&& other) : m_handle(util::exchange(other.m_handle, {})) {}
197
199 if (m_handle) {
200 m_handle.destroy();
201 }
202 }
203
204 auto operator co_await() && -> Awaiter {
205 auto handle = util::exchange(m_handle, {});
206 if (!handle) {
207 return Awaiter { nullptr };
208 }
209 auto& promise = static_cast<PromiseBase&>(handle.promise());
210 return Awaiter { ParentHandle::from_promise(promise) };
211 }
212
213 private:
214 explicit Type(Handle handle) : m_handle(handle) {}
215 explicit Type(AllocFailed) {}
216
217 Handle m_handle {};
218 };
219 };
220}
221
222template<typename Ref, typename Value = void>
224}
225
226namespace di {
228}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition with_awaitable_senders.h:8
auto continuation() const -> CoroutineHandle<>
Definition with_awaitable_senders.h:37
Definition optional_forward_declaration.h:5
Definition unexpected.h:14
Definition operations.h:11
Definition async_generator.h:19
meta::Conditional< concepts::Reference< Ref >, Ref, Ref const & > GeneratorYield
Definition async_generator.h:30
meta::Type< PromiseBaseT< Self, Ref, Value > > PromiseBase
Definition async_generator.h:170
meta::Conditional< concepts::LanguageVoid< Value >, Ref &&, Ref > GeneratorReference
Definition async_generator.h:27
meta::Conditional< concepts::LanguageVoid< Value >, meta::RemoveCVRef< Ref >, Value > GeneratorValue
Definition async_generator.h:24
Definition bulk.h:30
decltype(just_stopped()) Stopped
Definition just.h:90
meta::Type< async_generator_ns::AsyncGeneratorT< Ref, Value > > AsyncGenerator
Definition async_generator.h:223
detail::ConditionalHelper< value, T, U >::Type Conditional
Definition core.h:88
T::Type Type
Definition core.h:26
RemoveCV< RemoveReference< T > > RemoveCVRef
Definition core.h:74
Type< detail::AddPointerHelper< T > > AddPointer
This is a helper template which will convert reference types into their corresponding pointer type,...
Definition language.h:427
size_t usize
Definition integers.h:33
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
Definition vocab.h:96
constexpr auto exchange(T &object, U &&new_value) -> T
Definition exchange.h:8
void unreachable()
Definition unreachable.h:4
Definition lazy.h:165
Optional(T) -> Optional< T >
constexpr auto nullopt
Definition nullopt.h:15
StatusCode< Erased< long > > Error
Definition error.h:8
Definition zstring_parser.h:9
constexpr tag_invoke_detail::TagInvokeFn tag_invoke
Definition tag_invoke.h:22
constexpr auto exchange(T &object, U &&new_value) -> T
Definition exchange.h:8
std::coroutine_handle< Promise > CoroutineHandle
Definition coroutine.h:164
constexpr auto size
Definition size.h:54
std::suspend_always SuspendAlways
Definition coroutine.h:169
Defines the sequence sender concepts and related CPOs.
Definition async_generator.h:32
Type(Type &&other)
Definition async_generator.h:196
Promise promise_type
Definition async_generator.h:194
CoroutineHandle< PromiseBase > coroutine
Definition async_generator.h:115
auto await_ready() noexcept -> bool
Definition async_generator.h:117
auto await_suspend(CoroutineHandle< OtherPromise > continuation) noexcept -> CoroutineHandle<>
Definition async_generator.h:120
auto await_resume() noexcept -> vocab::Optional< Value >
Definition async_generator.h:127
auto await_suspend(CoroutineHandle< Promise > coroutine) noexcept -> CoroutineHandle<>
Definition async_generator.h:53
void await_resume() noexcept
Definition async_generator.h:58
auto await_ready() noexcept -> bool
Definition async_generator.h:50
void return_value(vocab::Unexpected< E > &&error) noexcept
Definition async_generator.h:70
auto yield_value(Yield value) noexcept
Definition async_generator.h:61
friend struct AsyncGeneratorT
Definition async_generator.h:80
void return_value(Stopped) noexcept
Definition async_generator.h:74
auto initial_suspend() noexcept -> SuspendAlways
Definition async_generator.h:46
auto final_suspend() noexcept
Definition async_generator.h:47
void return_value(types::Void) noexcept
Definition async_generator.h:66
void unhandled_exception()
Definition async_generator.h:76
GeneratorYield< Ref > Yield
Definition async_generator.h:38
Type PromiseBase
Definition async_generator.h:37
Definition void.h:6