6#include <libcopp/utils/config/libcopp_build_features.h>
18#include <unordered_map>
20#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
25#if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
29#ifdef __cpp_impl_three_way_comparison
40#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
42LIBCOPP_COPP_NAMESPACE_BEGIN
44enum class LIBCOPP_COPP_API_HEAD_ONLY promise_status : uint8_t {
54enum class LIBCOPP_COPP_API_HEAD_ONLY promise_flag : uint8_t {
57 kInternalWaitting = 2,
62template <
class TVALUE,
bool ALLOW_MOVE>
63struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor;
65template <
class TVALUE>
66struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor<TVALUE, true> {
70template <
class TVALUE>
71struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor<TVALUE, false> {
75template <
class TVALUE>
76struct LIBCOPP_COPP_API_HEAD_ONLY multiple_callers_constructor
77 :
public _multiple_callers_constructor<
78 TVALUE, !(std::is_pointer<TVALUE>::value || std::is_reference<TVALUE>::value ||
79 !std::is_move_constructible<TVALUE>::value ||
80 (std::is_trivially_copyable<TVALUE>::value && sizeof(TVALUE) <= sizeof(std::max_align_t)))> {};
82class promise_base_type;
84# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
86concept DerivedPromiseBaseType = std::is_base_of<promise_base_type, T>::value;
89class promise_caller_manager {
91 promise_caller_manager(const promise_caller_manager &) = delete;
92 promise_caller_manager(promise_caller_manager &&) = delete;
93 promise_caller_manager &operator=(const promise_caller_manager &) = delete;
94 promise_caller_manager &operator=(promise_caller_manager &&) = delete;
97 using type_erased_handle_type = LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<>;
98 struct LIBCOPP_COPP_API_HEAD_ONLY handle_delegate {
99 type_erased_handle_type handle;
100 promise_base_type *promise;
102# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
103 template <DerivedPromiseBaseType TPROMISE>
105 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
107 explicit handle_delegate(
108 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &origin_handle) noexcept
109 : handle{origin_handle} {
111 promise = &origin_handle.promise();
117 explicit handle_delegate(std::nullptr_t) noexcept : handle{nullptr}, promise{nullptr} {}
119 friend inline bool operator==(const handle_delegate &l, const handle_delegate &r) noexcept {
120 return l.handle == r.handle;
122# ifdef __cpp_impl_three_way_comparison
123 friend inline auto operator<=>(const handle_delegate &l, const handle_delegate &r) noexcept {
124 return l.handle <=> r.handle;
127 friend inline bool operator!=(const handle_delegate &l, const handle_delegate &r) noexcept {
128 return l.handle != r.handle;
130 friend inline bool operator<(const handle_delegate &l, const handle_delegate &r) noexcept {
131 return l.handle < r.handle;
133 friend inline bool operator<=(const handle_delegate &l, const handle_delegate &r) noexcept {
134 return l.handle <= r.handle;
136 friend inline bool operator>(const handle_delegate &l, const handle_delegate &r) noexcept {
137 return l.handle > r.handle;
139 friend inline bool operator>=(const handle_delegate &l, const handle_delegate &r) noexcept {
140 return l.handle >= r.handle;
143 inline operator bool() const noexcept { return !!handle; }
145# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
146 template <DerivedPromiseBaseType TPROMISE>
148 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
150 inline handle_delegate &operator=(
151 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &origin_handle) noexcept {
152 handle = origin_handle;
154 promise = &origin_handle.promise();
161 inline handle_delegate &operator=(std::nullptr_t) noexcept {
168 LIBCOPP_COPP_API promise_caller_manager();
169 LIBCOPP_COPP_API ~promise_caller_manager();
171 LIBCOPP_COPP_API void add_caller(handle_delegate handle) noexcept;
179 LIBCOPP_COPP_API bool remove_caller(handle_delegate handle) noexcept;
181 LIBCOPP_COPP_API size_t resume_callers();
183 LIBCOPP_COPP_API bool has_multiple_callers() const noexcept;
187 struct LIBCOPP_COPP_API_HEAD_ONLY handle_delegate_hash {
188 inline size_t operator()(const handle_delegate &handle_delegate) const noexcept {
189 return std::hash<void *>()(handle_delegate.handle.address());
197 struct multi_caller_container {
198 using list_type = std::list<handle_delegate>;
199 using index_type = std::unordered_map<handle_delegate, list_type::iterator, handle_delegate_hash>;
204 inline bool add(const handle_delegate &delegate) {
205 if (index.find(delegate) != index.end()) {
208 auto back_iter = callers.insert(callers.end(), delegate);
209 index.emplace(delegate, back_iter);
213 inline bool remove(const handle_delegate &delegate) {
214 auto iter = index.find(delegate);
215 if (iter == index.end()) {
218 callers.erase(iter->second);
223 inline void
swap(multi_caller_container &other) noexcept {
224 callers.swap(other.callers);
225 index.swap(other.index);
228 inline size_t size() const noexcept {
return index.size(); }
230# if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
231 std::variant<handle_delegate, multi_caller_container> callers_;
233 handle_delegate unique_caller_;
235 std::unique_ptr<multi_caller_container> multiple_callers_;
239class promise_base_type {
242 using type_erased_handle_type = promise_caller_manager::type_erased_handle_type;
243 using handle_delegate = promise_caller_manager::handle_delegate;
245 struct pick_promise_status_awaitable {
248 LIBCOPP_COPP_API pick_promise_status_awaitable() noexcept;
249 LIBCOPP_COPP_API pick_promise_status_awaitable(promise_status status) noexcept;
250 LIBCOPP_COPP_API pick_promise_status_awaitable(pick_promise_status_awaitable &&other) noexcept;
251 pick_promise_status_awaitable(const pick_promise_status_awaitable &) = delete;
252 LIBCOPP_COPP_API pick_promise_status_awaitable &operator=(pick_promise_status_awaitable &&) noexcept;
253 pick_promise_status_awaitable &operator=(const pick_promise_status_awaitable &) = delete;
254 LIBCOPP_COPP_API ~pick_promise_status_awaitable();
256 LIBCOPP_COPP_API_HEAD_ONLY inline
bool await_ready() const noexcept {
return true; }
257 LIBCOPP_COPP_API_HEAD_ONLY
inline promise_status await_resume() const noexcept {
return data; }
258 LIBCOPP_COPP_API_HEAD_ONLY
inline void await_suspend(type_erased_handle_type)
noexcept {}
262 LIBCOPP_COPP_API promise_base_type();
263 LIBCOPP_COPP_API ~promise_base_type();
265 LIBCOPP_COPP_API_HEAD_ONLY
inline bool set_status(promise_status value, promise_status *expect =
nullptr) noexcept {
266 if (
nullptr == expect) {
270 if (status_ == *expect) {
281 LIBCOPP_COPP_API_HEAD_ONLY
inline bool check_flag(promise_flag flag)
const noexcept {
282 return 0 != (flags_ & (
static_cast<uint32_t
>(1) <<
static_cast<uint8_t
>(flag)));
285 LIBCOPP_COPP_API_HEAD_ONLY
inline void set_flag(promise_flag flag,
bool value)
noexcept {
286 uint32_t flag_value =
static_cast<uint32_t
>(1) <<
static_cast<uint8_t
>(flag);
288 flags_ |= flag_value;
290 flags_ &= ~flag_value;
294 LIBCOPP_COPP_API
bool is_waiting() const noexcept;
295 LIBCOPP_COPP_API
void set_waiting_handle(
std::nullptr_t) noexcept;
296 LIBCOPP_COPP_API
void set_waiting_handle(handle_delegate handle);
297# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
298 template <DerivedPromiseBaseType TPROMISE>
300 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
302 LIBCOPP_COPP_API_HEAD_ONLY
void set_waiting_handle(
304 if (
nullptr == handle) {
305 set_waiting_handle(
nullptr);
307 set_waiting_handle(handle_delegate{handle});
315# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
316 template <DerivedPromiseBaseType TPROMISE>
318 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
320 LIBCOPP_COPP_API_HEAD_ONLY
inline void resume_waiting(
322 resume_waiting(handle_delegate{handle}, inherit_status);
325 LIBCOPP_COPP_API
void resume_waiting(handle_delegate current_delegate,
bool inherit_status);
328 struct LIBCOPP_COPP_API_HEAD_ONLY final_awaitable {
329 inline bool await_ready() const noexcept {
return false; }
330 inline void await_resume() const noexcept {}
332# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
333 template <DerivedPromiseBaseType TPROMISE>
335 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
338 auto &promise = self.promise();
339 promise.set_flag(promise_flag::kFinalSuspend,
true);
340 promise.resume_callers();
343 final_awaitable final_suspend() noexcept {
return {}; }
345 LIBCOPP_COPP_API
void add_caller(handle_delegate handle)
noexcept;
346# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
347 template <DerivedPromiseBaseType TPROMISE>
349 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
351 LIBCOPP_COPP_API_HEAD_ONLY
void add_caller(
353 add_caller(handle_delegate{handle});
356 LIBCOPP_COPP_API
void remove_caller(handle_delegate handle,
bool inherit_status)
noexcept;
357# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
358 template <DerivedPromiseBaseType TPROMISE>
360 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
362 LIBCOPP_COPP_API_HEAD_ONLY
void remove_caller(
364 remove_caller(handle_delegate{handle}, inherit_status);
367 LIBCOPP_UTIL_FORCEINLINE bool has_multiple_callers() const noexcept {
return caller_manager_.has_multiple_callers(); }
369 LIBCOPP_COPP_API pick_promise_status_awaitable yield_value(pick_promise_status_awaitable &&args)
const noexcept;
370 static LIBCOPP_COPP_API_HEAD_ONLY
inline pick_promise_status_awaitable pick_current_status() noexcept {
return {}; }
373 LIBCOPP_COPP_API
void resume_callers();
380 promise_status status_;
383 handle_delegate current_waiting_;
386 promise_caller_manager caller_manager_;
389class awaitable_base_type {
391 LIBCOPP_COPP_API awaitable_base_type();
392 LIBCOPP_COPP_API ~awaitable_base_type();
394 LIBCOPP_COPP_API promise_base_type::handle_delegate get_caller() const noexcept;
396 LIBCOPP_COPP_API
void set_caller(promise_base_type::handle_delegate caller) noexcept;
397 LIBCOPP_COPP_API
void set_caller(
std::nullptr_t) noexcept;
399# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
400 template <DerivedPromiseBaseType TPROMISE>
402 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
404 LIBCOPP_COPP_API_HEAD_ONLY
void set_caller(
406 if (
nullptr == handle) {
409 set_caller(promise_base_type::handle_delegate{handle});
414 promise_base_type::handle_delegate caller_;
417template <
class TDATA>
418struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform;
421struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform<void> {
425template <
class TDATA>
426struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform {
428 type operator()(promise_status in)
const {
return type{in}; }
431template <
class TDATA>
432struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_integer_error_transform {
434 type operator()(promise_status in)
const noexcept {
435 if (in <= promise_status::kCreated) {
436 return static_cast<type
>(-1);
438 return static_cast<type
>(-
static_cast<int8_t
>(in));
442template <
class TVALUE>
443struct LIBCOPP_COPP_API_HEAD_ONLY promise_error_transform
444 :
public std::conditional<std::is_integral<TVALUE>::value, std_coroutine_integer_error_transform<TVALUE>,
445 std_coroutine_default_error_transform<TVALUE>>::type {
449LIBCOPP_COPP_NAMESPACE_END
atomic wrapper fo integers Licensed under the MIT licenses.
#define LIBCOPP_UTIL_FORCEINLINE
#define LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE
constexpr auto size(TCONTAINER &&container) -> decltype(container.size())
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
void swap(intrusive_ptr< T > &lhs, intrusive_ptr< T > &rhs)