libcopp  2.2.0
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 
18 LIBCOPP_COPP_NAMESPACE_BEGIN
19 
20 LIBCOPP_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 
30 LIBCOPP_COPP_API promise_caller_manager::~promise_caller_manager() {}
31 
32 LIBCOPP_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 
66 LIBCOPP_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 
95 LIBCOPP_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 
145 LIBCOPP_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 
167 LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable::pick_promise_status_awaitable() noexcept
168  : data(promise_status::kInvalid) {}
169 
170 LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable::pick_promise_status_awaitable(
171  promise_status status) noexcept
172  : data(status) {}
173 
174 LIBCOPP_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 
178 LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable &
179 promise_base_type::pick_promise_status_awaitable::operator=(pick_promise_status_awaitable &&other) noexcept {
180  data = other.data;
181  return *this;
182 }
183 
184 LIBCOPP_COPP_API promise_base_type::pick_promise_status_awaitable::~pick_promise_status_awaitable() {}
185 
186 LIBCOPP_COPP_API promise_base_type::promise_base_type()
187  : flags_(0), status_{promise_status::kCreated}, current_waiting_{nullptr} {}
188 
189 LIBCOPP_COPP_API promise_base_type::~promise_base_type() {}
190 
191 LIBCOPP_COPP_API bool promise_base_type::is_waiting() const noexcept {
192  return current_waiting_ || check_flag(promise_flag::kInternalWaitting);
193 }
194 
195 LIBCOPP_COPP_API void promise_base_type::set_waiting_handle(std::nullptr_t) noexcept { current_waiting_ = nullptr; }
196 
197 LIBCOPP_COPP_API void promise_base_type::set_waiting_handle(handle_delegate handle) { current_waiting_ = handle; }
198 
199 LIBCOPP_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 
218 LIBCOPP_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 
224 LIBCOPP_COPP_API void promise_base_type::add_caller(handle_delegate delegate) noexcept {
225  caller_manager_.add_caller(delegate);
226 }
227 
228 LIBCOPP_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 
236 LIBCOPP_COPP_API void promise_base_type::resume_callers() { caller_manager_.resume_callers(); }
237 
238 LIBCOPP_COPP_API awaitable_base_type::awaitable_base_type() : caller_{nullptr} {}
239 LIBCOPP_COPP_API awaitable_base_type::~awaitable_base_type() {}
240 
241 LIBCOPP_COPP_API promise_base_type::handle_delegate awaitable_base_type::get_caller() const noexcept { return caller_; }
242 
243 LIBCOPP_COPP_API void awaitable_base_type::set_caller(promise_base_type::handle_delegate caller) noexcept {
244  caller_ = caller;
245 }
246 
247 LIBCOPP_COPP_API void awaitable_base_type::set_caller(std::nullptr_t) noexcept { caller_ = nullptr; }
248 
249 LIBCOPP_COPP_NAMESPACE_END
250 
251 #endif
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
Definition: span.h:54