libcopp 2.3.1
Loading...
Searching...
No Matches
std_coroutine_common.cpp
Go to the documentation of this file.
1// Copyright 2023 owent
2
4
5#include <libcopp/utils/config/libcopp_build_features.h>
6
7// clang-format off
8#include <libcopp/utils/config/stl_include_prefix.h> // NOLINT(build/include_order)
9// clang-format on
10#include <assert.h>
11#include <stdint.h>
12// clang-format off
13#include <libcopp/utils/config/stl_include_suffix.h> // NOLINT(build/include_order)
14// clang-format on
15
16#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
17
18LIBCOPP_COPP_NAMESPACE_BEGIN
19
20LIBCOPP_COPP_API promise_caller_manager::promise_caller_manager()
21 :
22# if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
23 callers_(handle_delegate{nullptr})
24# else
25 unique_caller_(nullptr)
26# endif
27{
28}
29
30LIBCOPP_COPP_API promise_caller_manager::~promise_caller_manager() {}
31
32LIBCOPP_COPP_API void promise_caller_manager::add_caller(handle_delegate delegate) noexcept {
33 if (!delegate.handle || delegate.handle.done()) {
34 return;
35 }
36
37# if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
38 if (std::holds_alternative<multi_caller_set>(callers_)) {
39 std::get<multi_caller_set>(callers_).insert(delegate);
40 return;
41 }
42
43 if (!std::get<handle_delegate>(callers_)) {
44 std::get<handle_delegate>(callers_) = delegate;
45 return;
46 }
47
48 // convert to multiple caller
49 multi_caller_set callers;
50 callers.insert(std::get<handle_delegate>(callers_));
51 callers.insert(delegate);
52 callers_.emplace<multi_caller_set>(std::move(callers));
53# else
54 if (!unique_caller_.handle) {
55 unique_caller_ = delegate;
56 return;
57 }
58
59 if (!multiple_callers_) {
60 multiple_callers_.reset(new multi_caller_set());
61 }
62 multiple_callers_->insert(delegate);
63# endif
64}
65
66LIBCOPP_COPP_API bool promise_caller_manager::remove_caller(handle_delegate delegate) noexcept {
67 bool has_caller = false;
68 do {
69# if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
70 if (std::holds_alternative<multi_caller_set>(callers_)) {
71 has_caller = std::get<multi_caller_set>(callers_).erase(delegate) > 0;
72 break;
73 }
74
75 if (std::get<handle_delegate>(callers_).handle == delegate.handle) {
76 std::get<handle_delegate>(callers_) = nullptr;
77 has_caller = true;
78 }
79# else
80 if (unique_caller_.handle == delegate.handle) {
81 unique_caller_ = nullptr;
82 has_caller = true;
83 break;
84 }
85
86 if (multiple_callers_) {
87 has_caller = multiple_callers_->erase(delegate) > 0;
88 }
89# endif
90 } while (false);
91
92 return has_caller;
93}
94
95LIBCOPP_COPP_API size_t promise_caller_manager::resume_callers() {
96 size_t resume_count = 0;
97# if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
98 if (std::holds_alternative<handle_delegate>(callers_)) {
99 auto caller = std::get<handle_delegate>(callers_);
100 std::get<handle_delegate>(callers_) = nullptr;
101 if (caller.handle && !caller.handle.done() &&
102 (nullptr == caller.promise || !caller.promise->check_flag(promise_flag::kDestroying))) {
103 caller.handle.resume();
104 ++resume_count;
105 }
106 } else if (std::holds_alternative<multi_caller_set>(callers_)) {
107 multi_caller_set callers;
108 callers.swap(std::get<multi_caller_set>(callers_));
109 for (auto &caller : callers) {
110 if (caller.handle && !caller.handle.done() &&
111 (nullptr == caller.promise || !caller.promise->check_flag(promise_flag::kDestroying))) {
112 type_erased_handle_type handle = caller.handle;
113 handle.resume();
114 ++resume_count;
115 }
116 }
117 }
118# else
119 auto unique_caller = unique_caller_;
120 unique_caller_ = nullptr;
121 std::unique_ptr<multi_caller_set> multiple_callers;
122 multiple_callers.swap(multiple_callers_);
123
124 // The promise object may be destroyed after first caller.resume()
125 if (unique_caller.handle && !unique_caller.handle.done() &&
126 (nullptr == unique_caller.promise || !unique_caller.promise->check_flag(promise_flag::kDestroying))) {
127 unique_caller.handle.resume();
128 ++resume_count;
129 }
130
131 if (multiple_callers) {
132 for (auto &caller : *multiple_callers) {
133 if (caller.handle && !caller.handle.done() &&
134 (nullptr == caller.promise || !caller.promise->check_flag(promise_flag::kDestroying))) {
135 type_erased_handle_type handle = caller.handle;
136 handle.resume();
137 ++resume_count;
138 }
139 }
140 }
141# endif
142 return resume_count;
143}
144
145LIBCOPP_COPP_API bool promise_caller_manager::has_multiple_callers() const noexcept {
146# if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
147 if (std::holds_alternative<handle_delegate>(callers_)) {
148 return false;
149 } else if (std::holds_alternative<multi_caller_set>(callers_)) {
150 return std::get<multi_caller_set>(callers_).size() > 1;
151 }
152 return false;
153# else
154 size_t count = 0;
155 if (unique_caller_.handle && !unique_caller_.handle.done() &&
156 (nullptr == unique_caller_.promise || !unique_caller_.promise->check_flag(promise_flag::kDestroying))) {
157 ++count;
158 }
159
160 if (multiple_callers_) {
161 count += multiple_callers_->size();
162 }
163 return count > 1;
164# endif
165}
166
167LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable::pick_promise_status_awaitable() noexcept
168 : data(promise_status::kInvalid) {}
169
170LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable::pick_promise_status_awaitable(
171 promise_status status) noexcept
172 : data(status) {}
173
174LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable::pick_promise_status_awaitable(
175 pick_promise_status_awaitable &&other) noexcept
176 : data(other.data) {}
177
178LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable &
179promise_base_type::pick_promise_status_awaitable::operator=(pick_promise_status_awaitable &&other) noexcept {
180 data = other.data;
181 return *this;
182}
183
184LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable::~pick_promise_status_awaitable() {}
185
186LIBCOPP_COPP_API promise_base_type::promise_base_type()
187 : flags_(0), status_{promise_status::kCreated}, current_waiting_{nullptr} {}
188
189LIBCOPP_COPP_API promise_base_type::~promise_base_type() {}
190
191LIBCOPP_COPP_API bool promise_base_type::is_waiting() const noexcept {
192 return current_waiting_ || check_flag(promise_flag::kInternalWaitting);
193}
194
195LIBCOPP_COPP_API void promise_base_type::set_waiting_handle(std::nullptr_t) noexcept { current_waiting_ = nullptr; }
196
197LIBCOPP_COPP_API void promise_base_type::set_waiting_handle(handle_delegate handle) { current_waiting_ = handle; }
198
199LIBCOPP_COPP_API void promise_base_type::resume_waiting(handle_delegate current_delegate, bool inherit_status) {
200 // Atfer resume(), this object maybe destroyed.
201 auto waiting_delegate = current_waiting_;
202
203 // Resume the waiting promise.
204 if (waiting_delegate.handle && !waiting_delegate.handle.done()) {
205 current_waiting_ = nullptr;
206 // Prevent the waiting coroutine remuse this again.
207 if (nullptr != waiting_delegate.promise) {
208 waiting_delegate.promise->remove_caller(current_delegate, inherit_status);
209 }
210 waiting_delegate.handle.resume();
211 } else if (current_delegate.handle && !current_delegate.handle.done() &&
212 check_flag(promise_flag::kInternalWaitting)) {
213 // If we are waiting for a internal awaitable object, we also allow to resume it.
214 current_delegate.handle.resume();
215 }
216}
217
218LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable promise_base_type::yield_value(
219 pick_promise_status_awaitable &&args) const noexcept {
220 args.data = get_status();
221 return pick_promise_status_awaitable{args.data};
222}
223
224LIBCOPP_COPP_API void promise_base_type::add_caller(handle_delegate delegate) noexcept {
225 caller_manager_.add_caller(delegate);
226}
227
228LIBCOPP_COPP_API void promise_base_type::remove_caller(handle_delegate delegate, bool inherit_status) noexcept {
229 bool remove_caller_success = caller_manager_.remove_caller(delegate);
230 if (remove_caller_success && inherit_status && nullptr != delegate.promise && get_status() < promise_status::kDone &&
231 delegate.promise->get_status() > promise_status::kDone) {
232 set_status(delegate.promise->get_status());
233 }
234}
235
236LIBCOPP_COPP_API void promise_base_type::resume_callers() { caller_manager_.resume_callers(); }
237
238LIBCOPP_COPP_API awaitable_base_type::awaitable_base_type() : caller_{nullptr} {}
239LIBCOPP_COPP_API awaitable_base_type::~awaitable_base_type() {}
240
241LIBCOPP_COPP_API promise_base_type::handle_delegate awaitable_base_type::get_caller() const noexcept { return caller_; }
242
243LIBCOPP_COPP_API void awaitable_base_type::set_caller(promise_base_type::handle_delegate caller) noexcept {
244 caller_ = caller;
245}
246
247LIBCOPP_COPP_API void awaitable_base_type::set_caller(std::nullptr_t) noexcept { caller_ = nullptr; }
248
249LIBCOPP_COPP_NAMESPACE_END
250
251#endif
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
Definition span.h:54