6 #include <libcopp/utils/config/libcopp_build_features.h>
15 #include <type_traits>
16 #include <unordered_set>
18 #if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
23 #if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
27 #ifdef __cpp_impl_three_way_comparison
38 #if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
40 LIBCOPP_COPP_NAMESPACE_BEGIN
42 enum class LIBCOPP_COPP_API_HEAD_ONLY promise_status : uint8_t {
52 enum class LIBCOPP_COPP_API_HEAD_ONLY promise_flag : uint8_t {
55 kInternalWaitting = 2,
60 template <
class TVALUE,
bool ALLOW_MOVE>
61 struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor;
63 template <
class TVALUE>
64 struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor<TVALUE, true> {
65 UTIL_FORCEINLINE static TVALUE &&return_value(TVALUE &input) noexcept {
return std::move(input); }
68 template <
class TVALUE>
69 struct LIBCOPP_COPP_API_HEAD_ONLY _multiple_callers_constructor<TVALUE, false> {
70 UTIL_FORCEINLINE static const TVALUE &return_value(TVALUE &input) noexcept {
return input; }
73 template <
class TVALUE>
74 struct LIBCOPP_COPP_API_HEAD_ONLY multiple_callers_constructor
75 :
public _multiple_callers_constructor<
76 TVALUE, !(std::is_pointer<TVALUE>::value || std::is_reference<TVALUE>::value ||
77 !std::is_move_constructible<TVALUE>::value ||
78 (std::is_trivially_copyable<TVALUE>::value && sizeof(TVALUE) <= sizeof(std::max_align_t)))> {};
80 class promise_base_type;
82 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
84 concept DerivedPromiseBaseType = std::is_base_of<promise_base_type, T>::value;
87 class promise_caller_manager {
89 promise_caller_manager(const promise_caller_manager &) = delete;
90 promise_caller_manager(promise_caller_manager &&) = delete;
91 promise_caller_manager &operator=(const promise_caller_manager &) = delete;
92 promise_caller_manager &operator=(promise_caller_manager &&) = delete;
95 using type_erased_handle_type = LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<>;
96 struct LIBCOPP_COPP_API_HEAD_ONLY handle_delegate {
97 type_erased_handle_type handle;
98 promise_base_type *promise;
100 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
101 template <DerivedPromiseBaseType TPROMISE>
103 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
105 explicit handle_delegate(
106 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &origin_handle) noexcept
107 : handle{origin_handle} {
109 promise = &origin_handle.promise();
115 explicit handle_delegate(std::nullptr_t) noexcept : handle{nullptr}, promise{nullptr} {}
117 friend inline bool operator==(const handle_delegate &l, const handle_delegate &r) noexcept {
118 return l.handle == r.handle;
120 friend inline bool operator!=(const handle_delegate &l, const handle_delegate &r) noexcept {
121 return l.handle != r.handle;
123 friend inline bool operator<(const handle_delegate &l, const handle_delegate &r) noexcept {
124 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 inline operator bool() const noexcept { return !!handle; }
137 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
138 template <DerivedPromiseBaseType TPROMISE>
140 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
142 inline handle_delegate &operator=(
143 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &origin_handle) noexcept {
144 handle = origin_handle;
146 promise = &origin_handle.promise();
153 inline handle_delegate &operator=(std::nullptr_t) noexcept {
160 LIBCOPP_COPP_API promise_caller_manager();
161 LIBCOPP_COPP_API ~promise_caller_manager();
163 LIBCOPP_COPP_API void add_caller(handle_delegate handle) noexcept;
171 LIBCOPP_COPP_API bool remove_caller(handle_delegate handle) noexcept;
173 LIBCOPP_COPP_API size_t resume_callers();
175 LIBCOPP_COPP_API bool has_multiple_callers() const noexcept;
179 struct LIBCOPP_COPP_API_HEAD_ONLY handle_delegate_hash {
180 inline size_t operator()(const handle_delegate &handle_delegate) const noexcept {
181 return std::hash<void *>()(handle_delegate.handle.address());
185 using multi_caller_set = std::unordered_set<handle_delegate, handle_delegate_hash>;
186 # if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
187 std::variant<handle_delegate, multi_caller_set> callers_;
189 handle_delegate unique_caller_;
191 std::unique_ptr<multi_caller_set> multiple_callers_;
195 class promise_base_type {
197 using handle_type = LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<promise_base_type>;
198 using type_erased_handle_type = promise_caller_manager::type_erased_handle_type;
199 using handle_delegate = promise_caller_manager::handle_delegate;
201 struct pick_promise_status_awaitable {
204 LIBCOPP_COPP_API pick_promise_status_awaitable() noexcept;
205 LIBCOPP_COPP_API pick_promise_status_awaitable(promise_status status) noexcept;
206 LIBCOPP_COPP_API pick_promise_status_awaitable(pick_promise_status_awaitable &&other) noexcept;
207 pick_promise_status_awaitable(const pick_promise_status_awaitable &) = delete;
208 LIBCOPP_COPP_API pick_promise_status_awaitable &operator=(pick_promise_status_awaitable &&) noexcept;
209 pick_promise_status_awaitable &operator=(const pick_promise_status_awaitable &) = delete;
210 LIBCOPP_COPP_API ~pick_promise_status_awaitable();
212 LIBCOPP_COPP_API_HEAD_ONLY inline bool await_ready() const noexcept { return true; }
213 LIBCOPP_COPP_API_HEAD_ONLY inline promise_status await_resume() const noexcept { return data; }
214 LIBCOPP_COPP_API_HEAD_ONLY inline void await_suspend(type_erased_handle_type) noexcept {}
218 LIBCOPP_COPP_API promise_base_type();
219 LIBCOPP_COPP_API ~promise_base_type();
221 LIBCOPP_COPP_API_HEAD_ONLY inline bool set_status(promise_status value, promise_status *expect = nullptr) noexcept {
222 if (nullptr == expect) {
226 if (status_ == *expect) {
235 UTIL_FORCEINLINE LIBCOPP_COPP_API_HEAD_ONLY promise_status get_status() const noexcept { return status_; }
237 LIBCOPP_COPP_API_HEAD_ONLY inline bool check_flag(promise_flag flag) const noexcept {
238 return 0 != (flags_ & (static_cast<uint32_t>(1) << static_cast<uint8_t>(flag)));
241 LIBCOPP_COPP_API_HEAD_ONLY inline void set_flag(promise_flag flag, bool value) noexcept {
242 uint32_t flag_value = static_cast<uint32_t>(1) << static_cast<uint8_t>(flag);
244 flags_ |= flag_value;
246 flags_ &= ~flag_value;
250 LIBCOPP_COPP_API bool is_waiting() const noexcept;
251 LIBCOPP_COPP_API void set_waiting_handle(std::nullptr_t) noexcept;
252 LIBCOPP_COPP_API void set_waiting_handle(handle_delegate handle);
253 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
254 template <DerivedPromiseBaseType TPROMISE>
256 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
258 LIBCOPP_COPP_API_HEAD_ONLY void set_waiting_handle(
259 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle) noexcept {
260 if (nullptr == handle) {
261 set_waiting_handle(nullptr);
263 set_waiting_handle(handle_delegate{handle});
271 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
272 template <DerivedPromiseBaseType TPROMISE>
274 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
276 LIBCOPP_COPP_API_HEAD_ONLY inline void resume_waiting(
277 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle, bool inherit_status) {
278 resume_waiting(handle_delegate{handle}, inherit_status);
281 LIBCOPP_COPP_API void resume_waiting(handle_delegate current_delegate, bool inherit_status);
284 struct LIBCOPP_COPP_API_HEAD_ONLY final_awaitable {
285 inline bool await_ready() const noexcept { return false; }
286 inline void await_resume() const noexcept {}
288 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
289 template <DerivedPromiseBaseType TPROMISE>
291 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
293 inline void await_suspend(LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> self) noexcept {
294 auto &promise = self.promise();
295 promise.set_flag(promise_flag::kFinalSuspend, true);
296 promise.resume_callers();
299 final_awaitable final_suspend() noexcept { return {}; }
301 LIBCOPP_COPP_API void add_caller(handle_delegate handle) noexcept;
302 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
303 template <DerivedPromiseBaseType TPROMISE>
305 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
307 LIBCOPP_COPP_API_HEAD_ONLY void add_caller(
308 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle) noexcept {
309 add_caller(handle_delegate{handle});
312 LIBCOPP_COPP_API void remove_caller(handle_delegate handle, bool inherit_status) noexcept;
313 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
314 template <DerivedPromiseBaseType TPROMISE>
316 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
318 LIBCOPP_COPP_API_HEAD_ONLY void remove_caller(
319 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle, bool inherit_status) noexcept {
320 remove_caller(handle_delegate{handle}, inherit_status);
323 UTIL_FORCEINLINE bool has_multiple_callers() const noexcept { return caller_manager_.has_multiple_callers(); }
325 LIBCOPP_COPP_API pick_promise_status_awaitable yield_value(pick_promise_status_awaitable &&args) const noexcept;
326 static LIBCOPP_COPP_API_HEAD_ONLY inline pick_promise_status_awaitable pick_current_status() noexcept { return {}; }
329 LIBCOPP_COPP_API void resume_callers();
336 promise_status status_;
339 handle_delegate current_waiting_;
342 promise_caller_manager caller_manager_;
345 class awaitable_base_type {
347 LIBCOPP_COPP_API awaitable_base_type();
348 LIBCOPP_COPP_API ~awaitable_base_type();
350 LIBCOPP_COPP_API promise_base_type::handle_delegate get_caller() const noexcept;
352 LIBCOPP_COPP_API void set_caller(promise_base_type::handle_delegate caller) noexcept;
353 LIBCOPP_COPP_API void set_caller(std::nullptr_t) noexcept;
355 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
356 template <DerivedPromiseBaseType TPROMISE>
358 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
360 LIBCOPP_COPP_API_HEAD_ONLY void set_caller(
361 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> &handle) noexcept {
362 if (nullptr == handle) {
365 set_caller(promise_base_type::handle_delegate{handle});
370 promise_base_type::handle_delegate caller_;
373 template <class TDATA>
374 struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform;
377 struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform<void> {
381 template <class TDATA>
382 struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_default_error_transform {
384 type operator()(promise_status in) const { return type{in}; }
387 template <class TDATA>
388 struct LIBCOPP_COPP_API_HEAD_ONLY std_coroutine_integer_error_transform {
390 type operator()(promise_status in) const noexcept {
391 if (in <= promise_status::kCreated) {
392 return static_cast<type>(-1);
394 return static_cast<type>(-static_cast<int8_t>(in));
398 template <class TVALUE>
399 struct LIBCOPP_COPP_API_HEAD_ONLY promise_error_transform
400 : public std::conditional<std::is_integral<TVALUE>::value, std_coroutine_integer_error_transform<TVALUE>,
401 std_coroutine_default_error_transform<TVALUE>>::type {
405 LIBCOPP_COPP_NAMESPACE_END
atomic wrapper fo integers Licensed under the MIT licenses.