YACLib
C++ library for concurrent tasks execution
Loading...
Searching...
No Matches
await_awaiter.hpp
Go to the documentation of this file.
1#pragma once
2
8
9namespace yaclib::detail {
10
12 explicit TransferAwaiter(BaseCore& caller) noexcept : _caller{caller} {
13 YACLIB_ASSERT(caller.Empty());
14 }
15
16 constexpr bool await_ready() const noexcept {
17 return false;
18 }
19
20 template <typename Promise>
21 YACLIB_INLINE auto await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
22 _caller.StoreCallback(handle.promise());
23 auto* next = MoveToCaller(&_caller);
24#if YACLIB_SYMMETRIC_TRANSFER != 0
25 return next->Next(handle.promise());
26#else
27 return Loop(&handle.promise(), next);
28#endif
29 }
30
31 constexpr void await_resume() const noexcept {
32 }
33
34 private:
35 BaseCore& _caller;
36};
37
38template <typename V, typename E>
40 explicit TransferSingleAwaiter(ResultCorePtr<V, E>&& result) noexcept : _result{std::move(result)} {
41 YACLIB_ASSERT(_result != nullptr);
42 YACLIB_ASSERT(_result->Empty());
43 }
44
45 constexpr bool await_ready() const noexcept {
46 return false;
47 }
48
49 template <typename Promise>
50 YACLIB_INLINE auto await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
51 _result->StoreCallback(handle.promise());
52 auto* next = MoveToCaller(_result.Get());
53#if YACLIB_SYMMETRIC_TRANSFER != 0
54 return next->Next(handle.promise());
55#else
56 return Loop(&handle.promise(), next);
57#endif
58 }
59
60 auto await_resume() {
61 return std::move(_result->Get()).Ok();
62 }
63
64 private:
65 ResultCorePtr<V, E> _result;
66};
67
68/**
69 * TODO(mkornaukhov03) Add doxygen docs
70 */
71template <bool Single>
73 explicit AwaitAwaiter(BaseCore& caller) noexcept : _caller{caller} {
74 }
75
76 YACLIB_INLINE bool await_ready() const noexcept {
77 return !_caller.Empty();
78 }
79
80 template <typename Promise>
81 YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
82 return _caller.SetCallback(handle.promise());
83 }
84
85 constexpr void await_resume() const noexcept {
86 }
87
88 private:
89 BaseCore& _caller;
90};
91
92class AwaitEvent final : public InlineCore, public AtomicCounter<NopeBase, NopeDeleter> {
93 public:
94 using AtomicCounter<NopeBase, NopeDeleter>::AtomicCounter;
95
96 private:
97 template <bool SymmetricTransfer>
98 [[nodiscard]] YACLIB_INLINE auto Impl(InlineCore& caller) noexcept {
99 if (this->SubEqual(1)) {
100 auto* curr = static_cast<InlineCore*>(next);
101 if constexpr (SymmetricTransfer) {
102 return Step<true>(caller, *curr);
103 } else {
104 curr = curr->Here(caller);
105 YACLIB_ASSERT(curr == nullptr);
106 }
107 }
109 }
110 [[nodiscard]] InlineCore* Here(InlineCore& caller) noexcept final {
111 return Impl<false>(caller);
112 }
113#if YACLIB_SYMMETRIC_TRANSFER != 0
114 [[nodiscard]] yaclib_std::coroutine_handle<> Next(InlineCore& caller) noexcept final {
115 return Impl<true>(caller);
116 }
117#endif
118};
119
120template <>
122 public:
123 template <typename... Cores>
124 explicit AwaitAwaiter(Cores&... cores) noexcept;
125
126 template <typename It>
127 explicit AwaitAwaiter(It it, std::size_t count) noexcept;
128
129 YACLIB_INLINE bool await_ready() const noexcept {
130 return _event.Get(std::memory_order_acquire) == 1;
131 }
132
133 template <typename Promise>
134 YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
135 _event.next = &handle.promise();
136 return !_event.SubEqual(1);
137 }
138
139 constexpr void await_resume() const noexcept {
140 }
141
142 private:
143 AwaitEvent _event;
144};
145
146template <typename... Cores>
147AwaitAwaiter<false>::AwaitAwaiter(Cores&... cores) noexcept : _event{sizeof...(cores) + 1} {
148 static_assert(sizeof...(cores) >= 2, "Number of futures must be at least two");
149 static_assert((... && std::is_same_v<BaseCore, Cores>), "Futures must be Future in Wait function");
150 const auto wait_count = (... + static_cast<std::size_t>(cores.SetCallback(_event)));
151 _event.count.fetch_sub(sizeof...(cores) - wait_count, std::memory_order_relaxed);
152}
153
154template <typename It>
155AwaitAwaiter<false>::AwaitAwaiter(It it, std::size_t count) noexcept : _event{count + 1} {
156 std::size_t wait_count = 0;
157 for (std::size_t i = 0; i != count; ++i) {
158 YACLIB_ASSERT(it->Valid());
159 wait_count += static_cast<std::size_t>(it->GetCore()->SetCallback(_event));
160 ++it;
161 }
162 _event.count.fetch_sub(count - wait_count, std::memory_order_relaxed);
163}
164
165template <typename V, typename E>
167 public:
168 explicit AwaitSingleAwaiter(ResultCorePtr<V, E>&& result) noexcept : _result{std::move(result)} {
169 YACLIB_ASSERT(_result != nullptr);
170 }
171
172 YACLIB_INLINE bool await_ready() const noexcept {
173 return !_result->Empty();
174 }
175
176 template <typename Promise>
177 YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle<Promise> handle) noexcept {
178 return _result->SetCallback(handle.promise());
179 }
180
182 return std::move(_result->Get()).Ok();
183 }
184
185 private:
186 ResultCorePtr<V, E> _result;
187};
188
189} // namespace yaclib::detail
A intrusive pointer to objects with an embedded reference count.
YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
YACLIB_INLINE bool await_ready() const noexcept
constexpr void await_resume() const noexcept
AwaitSingleAwaiter(ResultCorePtr< V, E > &&result) noexcept
YACLIB_INLINE bool await_ready() const noexcept
YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
#define YACLIB_ASSERT(cond)
Definition log.hpp:85
YACLIB_INLINE BaseCore * MoveToCaller(BaseCore *head) noexcept
Definition core.hpp:36
YACLIB_INLINE void Loop(InlineCore *prev, InlineCore *curr) noexcept
Definition base_core.hpp:69
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25
YACLIB_INLINE bool SubEqual(std::size_t n) noexcept
yaclib_std::atomic_size_t count
TODO(mkornaukhov03) Add doxygen docs.
YACLIB_INLINE bool await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
AwaitAwaiter(BaseCore &caller) noexcept
YACLIB_INLINE bool await_ready() const noexcept
constexpr void await_resume() const 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
TransferSingleAwaiter(ResultCorePtr< V, E > &&result) noexcept
YACLIB_INLINE auto await_suspend(yaclib_std::coroutine_handle< Promise > handle) noexcept
constexpr bool await_ready() const noexcept