6#include <libcopp/utils/config/libcopp_build_features.h>
17#include <unordered_map>
19#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
38LIBCOPP_COPP_NAMESPACE_BEGIN
42#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
43class coroutine_context_fiber;
48template <
class TCONTEXT>
51template <
class TCOROUTINE_OBJECT>
54template <
class TVALUE>
57template <
class TVALUE>
60template <
class TVALUE>
68#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
75template <
class TCOROUTINE_OBJECT>
79 if (
nullptr != invoke_ctx) {
80 return static_cast<TCOROUTINE_OBJECT *
>(invoke_ctx)->
resume(
reinterpret_cast<void *
>(priv_data));
87template <
class TCOROUTINE_OBJECT>
89 static_assert(::std::is_base_of<coroutine_context_base, TCOROUTINE_OBJECT>::value,
90 "TCOROUTINE_OBJECT must be coroutine_context_base or it's derived class");
105 : handle_data(other.handle_data), resume_handle(other.resume_handle) {}
108 : handle_data(other.handle_data), resume_handle(other.resume_handle) {
109 other.handle_data =
nullptr;
110 other.resume_handle =
nullptr;
116 resume_handle = other.resume_handle;
123 resume_handle = other.resume_handle;
125 other.handle_data =
nullptr;
126 other.resume_handle =
nullptr;
130 template <
class TCOROUTINE_OBJECT>
132 : handle_data{
reinterpret_cast<void *
>(ctx)}, resume_handle{
nullptr} {
133 if (handle_data !=
nullptr) {
139 : handle_data{
nullptr}, resume_handle{
nullptr} {}
143 return l.handle_data == r.handle_data;
145#ifdef __cpp_impl_three_way_comparison
148 return l.handle_data <=> r.handle_data;
153 return l.handle_data != r.handle_data;
157 return l.handle_data < r.handle_data;
161 return l.handle_data <= r.handle_data;
165 return l.handle_data > r.handle_data;
169 return l.handle_data >= r.handle_data;
174 template <
class TCOROUTINE_OBJECT>
176 handle_data =
reinterpret_cast<void *
>(ctx);
177 if (handle_data !=
nullptr) {
185 handle_data =
nullptr;
186 resume_handle =
nullptr;
223 LIBCOPP_COPP_API
void wake();
232 using index_type = std::unordered_map<handle_delegate, list_type::iterator, handle_delegate_hash>;
238 if (index.find(delegate) != index.end()) {
241 auto back_iter = callers.insert(callers.end(), delegate);
242 index.emplace(delegate, back_iter);
247 auto iter = index.find(delegate);
248 if (iter == index.end()) {
251 callers.erase(iter->second);
257 callers.swap(other.callers);
258 index.swap(other.index);
261 inline size_t size() const noexcept {
return index.size(); }
263#if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
264 std::variant<handle_delegate, multi_caller_container> callers_;
272template <
class TVALUE>
297 noexcept(std::declval<future::future<TVALUE>>().reset_data(std::forward<U>(in)))) {
298 data_.reset_data(std::forward<U>(in));
309 class TCONTEXT,
class TERROR_TRANSFORM,
311#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
312 && !std::is_base_of<coroutine_context_fiber, nostd::remove_cvref_t<TCONTEXT>>::value
316 std::is_nothrow_copy_constructible<value_type>::value &&
noexcept(error_transform(
COPP_EC_ARGS_ERROR))) {
317 return internal_inject_await<TCONTEXT>(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
320 template <
class TERROR_TRANSFORM>
322 std::is_nothrow_copy_constructible<value_type>::value &&
noexcept(error_transform(
COPP_EC_ARGS_ERROR))) {
323 return internal_inject_await<coroutine_context>(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
326#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
327 template <
class TERROR_TRANSFORM>
329 inject_await(coroutine_context_fiber *ctx,
330 TERROR_TRANSFORM &&error_transform)
noexcept(std::is_nothrow_copy_constructible<value_type>::value &&
332 return internal_inject_await<coroutine_context_fiber>(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
337 template <
class TCONTEXT,
class TERROR_TRANSFORM>
339 std::is_nothrow_copy_constructible<value_type>::value &&
noexcept(error_transform(
COPP_EC_ARGS_ERROR))) {
349 void *check_ptr =
nullptr;
350 int res = ctx->yield(&check_ptr);
359 if (check_ptr !=
reinterpret_cast<void *
>(
this)) {
374template <
class TVALUE>
389 return context_->is_ready();
396 return context_->is_pending();
404 context_->reset_value();
412 return context_->get_value();
420 return context_->get_value();
423 template <
class TCONTEXT,
class TERROR_TRANSFORM>
425 std::is_nothrow_copy_constructible<value_type>::value &&
noexcept(error_transform(
COPP_EC_ARGS_ERROR))) {
430 return context_->inject_await(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
441template <
class TVALUE>
444template <
class TVALUE>
458 return context_->is_ready();
465 return context_->is_pending();
473 context_->reset_value();
478 noexcept(std::declval<context_type>().set_value(std::forward<U>(in)))) {
483 context_->set_value(std::forward<U>(in));
494template <
class TVALUE>
499 return std::make_pair(std::move(receiver), std::move(sender));
502LIBCOPP_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
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_container > 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.
typename ::std::enable_if< B, T >::type enable_if_t
LIBCOPP_UTIL_FORCEINLINE std::pair< stackful_channel_receiver< TVALUE >, stackful_channel_sender< TVALUE > > make_stackful_channel()
size_t size() const noexcept
std::list< handle_delegate > list_type
bool remove(const handle_delegate &delegate)
void swap(multi_caller_container &other) noexcept
std::unordered_map< handle_delegate, list_type::iterator, handle_delegate_hash > index_type
bool add(const handle_delegate &delegate)
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)