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