YACLib
C++ library for concurrent tasks execution
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
await_awaiter.hpp
Go to the documentation of this file.
1#pragma once
2
10
11namespace yaclib::detail {
12
14 explicit TransferAwaiter(BaseCore& caller) noexcept : _caller{caller} {
15 YACLIB_ASSERT(caller.Empty());
16 }
17
18 constexpr bool await_ready() const noexcept {
19 return false;
20 }
21
22 template <typename Promise>
23 YACLIB_INLINE auto await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
24 _caller.StoreCallback(handle.promise());
25 auto* next = MoveToCaller(&_caller.core);
26#if YACLIB_SYMMETRIC_TRANSFER != 0
27 return next->Next(handle.promise());
28#else
29 return Loop(&handle.promise(), next);
30#endif
31 }
32
33 constexpr void await_resume() const noexcept {
34 }
35
36 private:
37 UniqueHandle _caller;
38};
39
40template <typename V, typename E>
42 explicit TransferSingleAwaiter(UniqueCorePtr<V, E>&& result) noexcept : _result{std::move(result)} {
43 YACLIB_ASSERT(_result != nullptr);
44 YACLIB_ASSERT(_result->Empty());
45 }
46
47 constexpr bool await_ready() const noexcept {
48 return false;
49 }
50
51 template <typename Promise>
52 YACLIB_INLINE auto await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
53 _result->StoreCallback(handle.promise());
54 auto* next = MoveToCaller(_result.Get());
55#if YACLIB_SYMMETRIC_TRANSFER != 0
56 return next->Next(handle.promise());
57#else
58 return Loop(&handle.promise(), next);
59#endif
60 }
61
62 auto await_resume() {
63 return std::move(_result->Get()).Ok();
64 }
65
66 private:
67 UniqueCorePtr<V, E> _result;
68};
69
70template <typename Handle>
72 explicit AwaitAwaiterBase(Handle caller) noexcept : _core{&caller.core} {
73 }
74
76 return !_core->Empty();
77 }
78
79 constexpr void await_resume() const noexcept {
80 }
81
82 protected:
83 // caller core before await_suspend, callee core after
85};
86
87template <typename Handle, bool Sticky>
89
90template <typename Handle>
91struct [[nodiscard]] AwaitAwaiter<Handle, false> final : public AwaitAwaiterBase<Handle> {
92 using AwaitAwaiterBase<Handle>::AwaitAwaiterBase;
93
94 template <typename Promise>
95 YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
96 return Handle{*this->_core}.SetCallback(handle.promise());
97 }
98};
99
100template <typename Handle>
101struct [[nodiscard]] AwaitAwaiter<Handle, true> final : public AwaitAwaiterBase<Handle>, public InlineCore {
102 using AwaitAwaiterBase<Handle>::AwaitAwaiterBase;
103
104 template <typename Promise>
105 YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
106 auto caller_handle = Handle{*this->_core};
107 this->_core = &handle.promise();
108 return caller_handle.SetCallback(*this);
109 }
110
111 void Call() noexcept final {
112 this->_core->_executor->Submit(*this->_core);
113 }
114
115 [[nodiscard]] InlineCore* Here(InlineCore& caller) noexcept final {
116 Call();
117 return nullptr;
118 }
119
120#if YACLIB_SYMMETRIC_TRANSFER != 0
121 [[nodiscard]] yaclib_std::coroutine_handle<> Next(InlineCore& caller) noexcept final {
122 Call();
123 return Noop<true>();
124 }
125#endif
126};
127
128template <bool Sticky>
129class AwaitEvent : public InlineCore, public AtomicCounter<NopeBase, NopeDeleter> {
130 public:
131 using AtomicCounter<NopeBase, NopeDeleter>::AtomicCounter;
132
133 static constexpr auto kShared = false;
134
136 return *this;
137 }
138
139 private:
140 template <bool SymmetricTransfer>
141 [[nodiscard]] YACLIB_INLINE auto Impl(InlineCore& caller) noexcept {
142 if (this->SubEqual(1)) {
143 if constexpr (Sticky) {
144 auto* curr = static_cast<BaseCore*>(next);
146 } else {
147 auto* curr = static_cast<InlineCore*>(next);
148 if constexpr (SymmetricTransfer) {
149 return Step<true>(caller, *curr);
150 } else {
151 curr = curr->Here(caller);
152 YACLIB_ASSERT(curr == nullptr);
153 }
154 }
155 }
157 }
158
159 public:
160 [[nodiscard]] InlineCore* Here(InlineCore& caller) noexcept final {
161 return Impl<false>(caller);
162 }
163
164#if YACLIB_SYMMETRIC_TRANSFER != 0
165 [[nodiscard]] yaclib_std::coroutine_handle<> Next(InlineCore& caller) noexcept final {
166 return Impl<true>(caller);
167 }
168#endif
169};
170
171template <typename Event>
173 public:
174 static constexpr auto kShared = Event::kShared;
175
176 template <typename... Handles>
177 explicit MultiAwaitAwaiter(Handles... handles) noexcept : Event{sizeof...(handles) + 1} {
178 SetCallbacksStatic(*this, handles...);
179 }
180
181 template <typename It>
182 explicit MultiAwaitAwaiter(It it, std::size_t count) noexcept : Event{count + 1} {
183 SetCallbacksDynamic(*this, it, count);
184 }
185
187 return this->Get(std::memory_order_acquire) == 1;
188 }
189
190 template <typename Promise>
191 YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
192 this->next = &handle.promise();
193 return !this->SubEqual(1);
194 }
195
196 constexpr void await_resume() const noexcept {
197 }
198};
199
200template <bool Shared, typename V, typename E>
202
203template <typename V, typename E>
205 public:
206 explicit AwaitSingleAwaiter(UniqueCorePtr<V, E>&& result) noexcept : _result{std::move(result)} {
207 YACLIB_ASSERT(_result != nullptr);
208 }
209
210 YACLIB_INLINE bool await_ready() const noexcept {
211 return !_result->Empty();
212 }
213
214 template <typename Promise>
215 YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
216 return _result->SetCallback(handle.promise());
217 }
218
220 return std::move(_result->Get()).Ok();
221 }
222
223 private:
224 UniqueCorePtr<V, E> _result;
225};
226
227// TODO(ocelaiwo): different overloads for lvalue and rvalue
228template <typename V, typename E>
230 public:
231 explicit AwaitSingleAwaiter(SharedCorePtr<V, E> result) noexcept : _result{std::move(result)} {
232 YACLIB_ASSERT(_result != nullptr);
233 }
234
235 YACLIB_INLINE bool await_ready() const noexcept {
236 return !_result->Empty();
237 }
238
239 template <typename Promise>
240 YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle<Promise> handle) const noexcept {
241 return _result->SetCallback(handle.promise());
242 }
243
244 auto await_resume() const {
245 return std::as_const(_result->Get()).Ok();
246 }
247
248 private:
249 SharedCorePtr<V, E> _result;
250};
251
252} // namespace yaclib::detail
virtual void Submit(Job &job) noexcept=0
Submit given job.
A intrusive pointer to objects with an embedded reference count.
static constexpr auto kShared
InlineCore * Here(InlineCore &caller) noexcept final
AwaitEvent & GetCall() noexcept
AwaitSingleAwaiter(UniqueCorePtr< V, E > &&result) noexcept
YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
YACLIB_INLINE bool await_ready() const noexcept
YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle< Promise > handle) const noexcept
YACLIB_INLINE bool await_ready() const noexcept
AwaitSingleAwaiter(SharedCorePtr< V, E > result) noexcept
bool Empty() const noexcept
Definition base_core.hpp:27
YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
MultiAwaitAwaiter(Handles... handles) noexcept
MultiAwaitAwaiter(It it, std::size_t count) noexcept
constexpr void await_resume() const noexcept
YACLIB_INLINE bool await_ready() const noexcept
#define YACLIB_ASSERT(cond)
Definition log.hpp:85
YACLIB_INLINE BaseCore * MoveToCaller(BaseCore *head) noexcept
Definition core.hpp:94
void SetCallbacksStatic(Event &event, Handles... handles)
YACLIB_INLINE void Loop(InlineCore *prev, InlineCore *curr) noexcept
void SetCallbacksDynamic(Event &event, It it, std::size_t count)
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25
YACLIB_INLINE bool SubEqual(std::size_t n) noexcept
AwaitAwaiterBase(Handle caller) noexcept
YACLIB_INLINE bool await_ready() const noexcept
constexpr void await_resume() const noexcept
YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
InlineCore * Here(InlineCore &caller) noexcept final
YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
constexpr bool await_ready() const noexcept
constexpr void await_resume() const noexcept
TransferAwaiter(BaseCore &caller) noexcept
YACLIB_INLINE auto await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
YACLIB_INLINE auto await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
TransferSingleAwaiter(UniqueCorePtr< V, E > &&result) noexcept
constexpr bool await_ready() const noexcept