6#include <libcopp/utils/config/libcopp_build_features.h>
16#include <unordered_set>
18#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
22#if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
26#ifdef __cpp_impl_three_way_comparison
37LIBCOPP_COPP_NAMESPACE_BEGIN
41#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
42class coroutine_context_fiber;
47template <
class TCONTEXT>
50template <
class TCOROUTINE_OBJECT>
53template <
class TVALUE>
56template <
class TVALUE>
59template <
class TVALUE>
67#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
74template <
class TCOROUTINE_OBJECT>
78 if (
nullptr != invoke_ctx) {
79 return static_cast<TCOROUTINE_OBJECT *
>(invoke_ctx)->
resume(
reinterpret_cast<void *
>(priv_data));
86template <
class TCOROUTINE_OBJECT>
88 static_assert(::std::is_base_of<coroutine_context_base, TCOROUTINE_OBJECT>::value,
89 "TCOROUTINE_OBJECT must be coroutine_context_base or it's derived class");
104 : handle_data(other.handle_data), resume_handle(other.resume_handle) {}
107 : handle_data(other.handle_data), resume_handle(other.resume_handle) {
108 other.handle_data =
nullptr;
109 other.resume_handle =
nullptr;
115 resume_handle = other.resume_handle;
122 resume_handle = other.resume_handle;
124 other.handle_data =
nullptr;
125 other.resume_handle =
nullptr;
129 template <
class TCOROUTINE_OBJECT>
131 : handle_data{
reinterpret_cast<void *
>(ctx)}, resume_handle{
nullptr} {
132 if (handle_data !=
nullptr) {
138 : handle_data{
nullptr}, resume_handle{
nullptr} {}
142 return l.handle_data == r.handle_data;
144#ifdef __cpp_impl_three_way_comparison
147 return l.handle_data <=> r.handle_data;
152 return l.handle_data != r.handle_data;
156 return l.handle_data < r.handle_data;
160 return l.handle_data <= r.handle_data;
164 return l.handle_data > r.handle_data;
168 return l.handle_data >= r.handle_data;
173 template <
class TCOROUTINE_OBJECT>
175 handle_data =
reinterpret_cast<void *
>(ctx);
176 if (handle_data !=
nullptr) {
184 handle_data =
nullptr;
185 resume_handle =
nullptr;
222 LIBCOPP_COPP_API
void wake();
226#if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
227 std::variant<handle_delegate, multi_caller_set> callers_;
235template <
class TVALUE>
260 noexcept(std::declval<future::future<TVALUE>>().reset_data(std::forward<U>(in)))) {
261 data_.reset_data(std::forward<U>(in));
272 class TCONTEXT,
class TERROR_TRANSFORM,
273 class = nostd::enable_if_t<!std::is_base_of<coroutine_context, nostd::remove_cvref_t<TCONTEXT>>::value
274#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
275 && !std::is_base_of<coroutine_context_fiber, nostd::remove_cvref_t<TCONTEXT>>::value
279 std::is_nothrow_copy_constructible<value_type>::value &&
noexcept(error_transform(
COPP_EC_ARGS_ERROR))) {
280 return internal_inject_await<TCONTEXT>(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
283 template <
class TERROR_TRANSFORM>
285 std::is_nothrow_copy_constructible<value_type>::value &&
noexcept(error_transform(
COPP_EC_ARGS_ERROR))) {
286 return internal_inject_await<coroutine_context>(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
289#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
290 template <
class TERROR_TRANSFORM>
292 inject_await(coroutine_context_fiber *ctx,
293 TERROR_TRANSFORM &&error_transform)
noexcept(std::is_nothrow_copy_constructible<value_type>::value &&
295 return internal_inject_await<coroutine_context_fiber>(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
300 template <
class TCONTEXT,
class TERROR_TRANSFORM>
302 std::is_nothrow_copy_constructible<value_type>::value &&
noexcept(error_transform(
COPP_EC_ARGS_ERROR))) {
312 void *check_ptr =
nullptr;
313 int res = ctx->yield(&check_ptr);
322 if (check_ptr !=
reinterpret_cast<void *
>(
this)) {
337template <
class TVALUE>
352 return context_->is_ready();
359 return context_->is_pending();
367 context_->reset_value();
375 return context_->get_value();
383 return context_->get_value();
386 template <
class TCONTEXT,
class TERROR_TRANSFORM>
388 std::is_nothrow_copy_constructible<value_type>::value &&
noexcept(error_transform(
COPP_EC_ARGS_ERROR))) {
393 return context_->inject_await(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
404template <
class TVALUE>
407template <
class TVALUE>
421 return context_->is_ready();
428 return context_->is_pending();
436 context_->reset_value();
441 noexcept(std::declval<context_type>().set_value(std::forward<U>(in)))) {
446 context_->set_value(std::forward<U>(in));
457template <
class TVALUE>
461 return std::make_pair(std::move(receiver), std::move(sender));
464LIBCOPP_COPP_NAMESPACE_END
base type of all coroutine context
base type of all stackful coroutine context
LIBCOPP_COPP_API bool remove_caller(handle_delegate handle) noexcept
stackful_channel_handle_delegate handle_delegate
LIBCOPP_COPP_API stackful_channel_context_base() noexcept
LIBCOPP_COPP_API bool has_multiple_callers() const noexcept
stackful_channel_context_base & operator=(stackful_channel_context_base &&)=delete
stackful_channel_handle_delegate_hash handle_delegate_hash
std::unordered_set< handle_delegate, handle_delegate_hash > multi_caller_set
LIBCOPP_COPP_API void add_caller(handle_delegate handle) noexcept
stackful_channel_context_base & operator=(const stackful_channel_context_base &)=delete
std::unique_ptr< multi_caller_set > multiple_callers_
LIBCOPP_COPP_API void wake()
stackful_channel_context_base(stackful_channel_context_base &&)=delete
LIBCOPP_COPP_API size_t resume_callers()
stackful_channel_context_base(const stackful_channel_context_base &)=delete
handle_delegate unique_caller_
future::future< TVALUE > data_
LIBCOPP_UTIL_FORCEINLINE value_type inject_await(coroutine_context *ctx, TERROR_TRANSFORM &&error_transform) noexcept(std::is_nothrow_copy_constructible< value_type >::value &&noexcept(error_transform(COPP_EC_ARGS_ERROR)))
LIBCOPP_UTIL_FORCEINLINE ~stackful_channel_context() noexcept(std::is_nothrow_destructible< future::future< value_type > >::value)
LIBCOPP_UTIL_FORCEINLINE value_type * get_value() noexcept
LIBCOPP_UTIL_FORCEINLINE bool is_ready() const noexcept
value_type internal_inject_await(TCONTEXT *ctx, TERROR_TRANSFORM &&error_transform) noexcept(std::is_nothrow_copy_constructible< value_type >::value &&noexcept(error_transform(COPP_EC_ARGS_ERROR)))
LIBCOPP_UTIL_FORCEINLINE bool is_pending() const noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_context() noexcept(std::is_nothrow_constructible< future::future< value_type > >::value)
LIBCOPP_UTIL_FORCEINLINE value_type inject_await(TCONTEXT *ctx, TERROR_TRANSFORM &&error_transform) noexcept(std::is_nothrow_copy_constructible< value_type >::value &&noexcept(error_transform(COPP_EC_ARGS_ERROR)))
LIBCOPP_UTIL_FORCEINLINE void reset_value() noexcept(noexcept(std::declval< future::future< TVALUE > >().reset_data()))
LIBCOPP_UTIL_FORCEINLINE const value_type * get_value() const noexcept
LIBCOPP_UTIL_FORCEINLINE void set_value(U &&in) noexcept(noexcept(std::declval< future::future< TVALUE > >().reset_data(std::forward< U >(in))))
LIBCOPP_UTIL_FORCEINLINE context_pointer_type & get_context() noexcept
LIBCOPP_UTIL_FORCEINLINE bool is_ready() const noexcept
stackful_channel_receiver() noexcept
context_pointer_type context_
LIBCOPP_UTIL_FORCEINLINE void reset_value() noexcept(noexcept(std::declval< context_type >().reset_value()))
LIBCOPP_UTIL_FORCEINLINE value_type * get_value() noexcept
typename context_type::value_type value_type
LIBCOPP_UTIL_FORCEINLINE bool is_pending() const noexcept
LIBCOPP_UTIL_FORCEINLINE value_type inject_await(TCONTEXT *ctx, TERROR_TRANSFORM &&error_transform) noexcept(std::is_nothrow_copy_constructible< value_type >::value &&noexcept(error_transform(COPP_EC_ARGS_ERROR)))
LIBCOPP_UTIL_FORCEINLINE const context_pointer_type & get_context() const noexcept
LIBCOPP_UTIL_FORCEINLINE const value_type * get_value() const noexcept
LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr< context_type > context_pointer_type
LIBCOPP_UTIL_FORCEINLINE void set_value(U &&in) noexcept(noexcept(std::declval< context_type >().set_value(std::forward< U >(in))))
LIBCOPP_UTIL_FORCEINLINE bool is_ready() const noexcept
typename context_type::value_type value_type
context_pointer_type context_
stackful_channel_sender(const context_pointer_type &context) noexcept
LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr< context_type > context_pointer_type
LIBCOPP_UTIL_FORCEINLINE bool is_pending() const noexcept
LIBCOPP_UTIL_FORCEINLINE const context_pointer_type & get_context() const noexcept
LIBCOPP_UTIL_FORCEINLINE void reset_value() noexcept(noexcept(std::declval< context_type >().reset_value()))
LIBCOPP_UTIL_FORCEINLINE context_pointer_type & get_context() noexcept
#define LIBCOPP_UTIL_FORCEINLINE
#define LIBCOPP_UTIL_LIKELY_CONDITION(__C)
#define LIBCOPP_UTIL_UNLIKELY_CONDITION(__C)
@ COPP_EC_OPERATION_CANCLE
COPP_EC_OPERATION_CANCLE.
@ COPP_EC_SUCCESS
COPP_EC_SUCCESS.
@ COPP_EC_NOT_READY
COPP_EC_NOT_READY.
@ COPP_EC_NOT_INITED
COPP_EC_NOT_INITED.
@ COPP_EC_ARGS_ERROR
COPP_EC_ARGS_ERROR.
std::pair< stackful_channel_receiver< TVALUE >, stackful_channel_sender< TVALUE > > make_stackful_channel()
size_t operator()(const stackful_channel_handle_delegate &stackful_channel_handle_delegate) const noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate(stackful_channel_handle_delegate &&other) noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate & operator=(std::nullptr_t) noexcept
LIBCOPP_UTIL_FORCEINLINE friend bool operator<(const stackful_channel_handle_delegate &l, const stackful_channel_handle_delegate &r) noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate() noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate & operator=(const stackful_channel_handle_delegate &other) noexcept
LIBCOPP_UTIL_FORCEINLINE friend bool operator<=(const stackful_channel_handle_delegate &l, const stackful_channel_handle_delegate &r) noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate(std::nullptr_t) noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate & operator=(TCOROUTINE_OBJECT *ctx) noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate & operator=(stackful_channel_handle_delegate &&other) noexcept
LIBCOPP_UTIL_FORCEINLINE friend bool operator>(const stackful_channel_handle_delegate &l, const stackful_channel_handle_delegate &r) noexcept
stackful_channel_handle_delegate(TCOROUTINE_OBJECT *ctx) noexcept
LIBCOPP_UTIL_FORCEINLINE friend bool operator==(const stackful_channel_handle_delegate &l, const stackful_channel_handle_delegate &r) noexcept
LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate(const stackful_channel_handle_delegate &other) noexcept
LIBCOPP_UTIL_FORCEINLINE friend bool operator>=(const stackful_channel_handle_delegate &l, const stackful_channel_handle_delegate &r) noexcept
LIBCOPP_UTIL_FORCEINLINE friend bool operator!=(const stackful_channel_handle_delegate &l, const stackful_channel_handle_delegate &r) noexcept
static LIBCOPP_COPP_API_HEAD_ONLY int resume(void *invoke_ctx, stackful_channel_context_base *priv_data)
static LIBCOPP_UTIL_FORCEINLINE int resume(coroutine_context_base *invoke_ctx, stackful_channel_context_base *priv_data)