6#include <libcopp/utils/config/libcopp_build_features.h>
17#include <unordered_set>
19#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
24#if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
28#ifdef __cpp_impl_three_way_comparison
39#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
41LIBCOPP_COPP_NAMESPACE_BEGIN
43enum class LIBCOPP_COPP_API_HEAD_ONLY promise_status : uint8_t {
53enum class LIBCOPP_COPP_API_HEAD_ONLY promise_flag : uint8_t {
56 kInternalWaitting = 2,
61template <
class TVALUE,
bool ALLOW_MOVE>
62struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor;
64template <
class TVALUE>
65struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor<TVALUE, true> {
69template <
class TVALUE>
70struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor<TVALUE, false> {
74template <
class TVALUE>
75struct LIBCOPP_COPP_API_HEAD_ONLY multiple_callers_constructor
76 :
public _multiple_callers_constructor<
77 TVALUE, !(std::is_pointer<TVALUE>::value || std::is_reference<TVALUE>::value ||
78 !std::is_move_constructible<TVALUE>::value ||
79 (std::is_trivially_copyable<TVALUE>::value && sizeof(TVALUE) <= sizeof(std::max_align_t)))> {};
81class promise_base_type;
83# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
85concept DerivedPromiseBaseType = std::is_base_of<promise_base_type, T>::value;
88class promise_caller_manager {
90 promise_caller_manager(const promise_caller_manager &) = delete;
91 promise_caller_manager(promise_caller_manager &&) = delete;
92 promise_caller_manager &operator=(const promise_caller_manager &) = delete;
93 promise_caller_manager &operator=(promise_caller_manager &&) = delete;
96 using type_erased_handle_type = LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<>;
97 struct LIBCOPP_COPP_API_HEAD_ONLY handle_delegate {
98 type_erased_handle_type handle;
99 promise_base_type *promise;
101# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
102 template <DerivedPromiseBaseType TPROMISE>
104 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
106 explicit handle_delegate(
107 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &origin_handle) noexcept
108 : handle{origin_handle} {
110 promise = &origin_handle.promise();
116 explicit handle_delegate(std::nullptr_t) noexcept : handle{nullptr}, promise{nullptr} {}
118 friend inline bool operator==(const handle_delegate &l, const handle_delegate &r) noexcept {
119 return l.handle == r.handle;
121# ifdef __cpp_impl_three_way_comparison
122 friend inline auto operator<=>(const handle_delegate &l, const handle_delegate &r) noexcept {
123 return l.handle <=> r.handle;
126 friend inline bool operator!=(const handle_delegate &l, const handle_delegate &r) noexcept {
127 return l.handle != r.handle;
129 friend inline bool operator<(const handle_delegate &l, const handle_delegate &r) noexcept {
130 return l.handle < r.handle;
132 friend inline bool operator<=(const handle_delegate &l, const handle_delegate &r) noexcept {
133 return l.handle <= r.handle;
135 friend inline bool operator>(const handle_delegate &l, const handle_delegate &r) noexcept {
136 return l.handle > r.handle;
138 friend inline bool operator>=(const handle_delegate &l, const handle_delegate &r) noexcept {
139 return l.handle >= r.handle;
142 inline operator bool() const noexcept { return !!handle; }
144# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
145 template <DerivedPromiseBaseType TPROMISE>
147 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
149 inline handle_delegate &operator=(
150 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &origin_handle) noexcept {
151 handle = origin_handle;
153 promise = &origin_handle.promise();
160 inline handle_delegate &operator=(std::nullptr_t) noexcept {
167 LIBCOPP_COPP_API promise_caller_manager();
168 LIBCOPP_COPP_API ~promise_caller_manager();
170 LIBCOPP_COPP_API void add_caller(handle_delegate handle) noexcept;
178 LIBCOPP_COPP_API bool remove_caller(handle_delegate handle) noexcept;
180 LIBCOPP_COPP_API size_t resume_callers();
182 LIBCOPP_COPP_API bool has_multiple_callers() const noexcept;
186 struct LIBCOPP_COPP_API_HEAD_ONLY handle_delegate_hash {
187 inline size_t operator()(const handle_delegate &handle_delegate) const noexcept {
188 return std::hash<void *>()(handle_delegate.handle.address());
192 using multi_caller_set = std::unordered_set<handle_delegate, handle_delegate_hash>;
193# if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
194 std::variant<handle_delegate, multi_caller_set> callers_;
196 handle_delegate unique_caller_;
198 std::unique_ptr<multi_caller_set> multiple_callers_;
202class promise_base_type {
204 using handle_type = LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<promise_base_type>;
205 using type_erased_handle_type = promise_caller_manager::type_erased_handle_type;
206 using handle_delegate = promise_caller_manager::handle_delegate;
208 struct pick_promise_status_awaitable {
211 LIBCOPP_COPP_API pick_promise_status_awaitable() noexcept;
212 LIBCOPP_COPP_API pick_promise_status_awaitable(promise_status status) noexcept;
213 LIBCOPP_COPP_API pick_promise_status_awaitable(pick_promise_status_awaitable &&other) noexcept;
214 pick_promise_status_awaitable(const pick_promise_status_awaitable &) = delete;
215 LIBCOPP_COPP_API pick_promise_status_awaitable &operator=(pick_promise_status_awaitable &&) noexcept;
216 pick_promise_status_awaitable &operator=(const pick_promise_status_awaitable &) = delete;
217 LIBCOPP_COPP_API ~pick_promise_status_awaitable();
219 LIBCOPP_COPP_API_HEAD_ONLY inline bool await_ready() const noexcept { return true; }
220 LIBCOPP_COPP_API_HEAD_ONLY inline promise_status await_resume() const noexcept { return data; }
221 LIBCOPP_COPP_API_HEAD_ONLY inline void await_suspend(type_erased_handle_type) noexcept {}
225 LIBCOPP_COPP_API promise_base_type();
226 LIBCOPP_COPP_API ~promise_base_type();
228 LIBCOPP_COPP_API_HEAD_ONLY inline bool set_status(promise_status value, promise_status *expect = nullptr) noexcept {
229 if (nullptr == expect) {
233 if (status_ == *expect) {
242 LIBCOPP_UTIL_FORCEINLINE LIBCOPP_COPP_API_HEAD_ONLY promise_status get_status() const noexcept { return status_; }
244 LIBCOPP_COPP_API_HEAD_ONLY inline bool check_flag(promise_flag flag) const noexcept {
245 return 0 != (flags_ & (static_cast<uint32_t>(1) << static_cast<uint8_t>(flag)));
248 LIBCOPP_COPP_API_HEAD_ONLY inline void set_flag(promise_flag flag, bool value) noexcept {
249 uint32_t flag_value = static_cast<uint32_t>(1) << static_cast<uint8_t>(flag);
251 flags_ |= flag_value;
253 flags_ &= ~flag_value;
257 LIBCOPP_COPP_API bool is_waiting() const noexcept;
258 LIBCOPP_COPP_API void set_waiting_handle(std::nullptr_t) noexcept;
259 LIBCOPP_COPP_API void set_waiting_handle(handle_delegate handle);
260# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
261 template <DerivedPromiseBaseType TPROMISE>
263 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
265 LIBCOPP_COPP_API_HEAD_ONLY void set_waiting_handle(
266 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle) noexcept {
267 if (nullptr == handle) {
268 set_waiting_handle(nullptr);
270 set_waiting_handle(handle_delegate{handle});
278# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
279 template <DerivedPromiseBaseType TPROMISE>
281 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
283 LIBCOPP_COPP_API_HEAD_ONLY inline void resume_waiting(
284 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle, bool inherit_status) {
285 resume_waiting(handle_delegate{handle}, inherit_status);
288 LIBCOPP_COPP_API void resume_waiting(handle_delegate current_delegate, bool inherit_status);
291 struct LIBCOPP_COPP_API_HEAD_ONLY final_awaitable {
292 inline bool await_ready() const noexcept { return false; }
293 inline void await_resume() const noexcept {}
295# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
296 template <DerivedPromiseBaseType TPROMISE>
298 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
300 inline void await_suspend(LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> self) noexcept {
301 auto &promise = self.promise();
302 promise.set_flag(promise_flag::kFinalSuspend, true);
303 promise.resume_callers();
306 final_awaitable final_suspend() noexcept { return {}; }
308 LIBCOPP_COPP_API void add_caller(handle_delegate handle) noexcept;
309# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
310 template <DerivedPromiseBaseType TPROMISE>
312 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
314 LIBCOPP_COPP_API_HEAD_ONLY void add_caller(
315 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle) noexcept {
316 add_caller(handle_delegate{handle});
319 LIBCOPP_COPP_API void remove_caller(handle_delegate handle, bool inherit_status) noexcept;
320# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
321 template <DerivedPromiseBaseType TPROMISE>
323 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
325 LIBCOPP_COPP_API_HEAD_ONLY void remove_caller(
326 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle, bool inherit_status) noexcept {
327 remove_caller(handle_delegate{handle}, inherit_status);
330 LIBCOPP_UTIL_FORCEINLINE bool has_multiple_callers() const noexcept { return caller_manager_.has_multiple_callers(); }
332 LIBCOPP_COPP_API pick_promise_status_awaitable yield_value(pick_promise_status_awaitable &&args) const noexcept;
333 static LIBCOPP_COPP_API_HEAD_ONLY inline pick_promise_status_awaitable pick_current_status() noexcept { return {}; }
336 LIBCOPP_COPP_API void resume_callers();
343 promise_status status_;
346 handle_delegate current_waiting_;
349 promise_caller_manager caller_manager_;
352class awaitable_base_type {
354 LIBCOPP_COPP_API awaitable_base_type();
355 LIBCOPP_COPP_API ~awaitable_base_type();
357 LIBCOPP_COPP_API promise_base_type::handle_delegate get_caller() const noexcept;
359 LIBCOPP_COPP_API void set_caller(promise_base_type::handle_delegate caller) noexcept;
360 LIBCOPP_COPP_API void set_caller(std::nullptr_t) noexcept;
362# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
363 template <DerivedPromiseBaseType TPROMISE>
365 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
367 LIBCOPP_COPP_API_HEAD_ONLY void set_caller(
368 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle) noexcept {
369 if (nullptr == handle) {
372 set_caller(promise_base_type::handle_delegate{handle});
377 promise_base_type::handle_delegate caller_;
380template <class TDATA>
381struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform;
384struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform<void> {
388template <class TDATA>
389struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform {
391 type operator()(promise_status in) const { return type{in}; }
394template <class TDATA>
395struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_integer_error_transform {
397 type operator()(promise_status in) const noexcept {
398 if (in <= promise_status::kCreated) {
399 return static_cast<type>(-1);
401 return static_cast<type>(-static_cast<int8_t>(in));
405template <class TVALUE>
406struct LIBCOPP_COPP_API_HEAD_ONLY promise_error_transform
407 : public std::conditional<std::is_integral<TVALUE>::value, std_coroutine_integer_error_transform<TVALUE>,
408 std_coroutine_default_error_transform<TVALUE>>::type {
412LIBCOPP_COPP_NAMESPACE_END
atomic wrapper fo integers Licensed under the MIT licenses.
#define LIBCOPP_UTIL_FORCEINLINE