libcopp 2.3.2
Loading...
Searching...
No Matches
stackful_channel.h
Go to the documentation of this file.
1// Copyright 2026 owent
2
3#pragma once
4
6#include <libcopp/utils/config/libcopp_build_features.h>
7
9
10// clang-format off
11#include <libcopp/utils/config/stl_include_prefix.h> // NOLINT(build/include_order)
12// clang-format on
13
14#include <functional>
15#include <list>
16#include <type_traits>
17#include <unordered_map>
18
19#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
20# include <exception>
21#endif
22
23#if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
24# include <variant>
25#endif
26
27#ifdef __cpp_impl_three_way_comparison
28# include <compare>
29#endif
30
31// clang-format off
32#include <libcopp/utils/config/stl_include_suffix.h> // NOLINT(build/include_order)
33// clang-format on
34
37
38LIBCOPP_COPP_NAMESPACE_BEGIN
39
42#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
43class coroutine_context_fiber;
44#endif
45
47
48template <class TCONTEXT>
50
51template <class TCOROUTINE_OBJECT>
53
54template <class TVALUE>
55class LIBCOPP_COPP_API_HEAD_ONLY stackful_channel_context;
56
57template <class TVALUE>
58class LIBCOPP_COPP_API_HEAD_ONLY stackful_channel_receiver;
59
60template <class TVALUE>
61class LIBCOPP_COPP_API_HEAD_ONLY stackful_channel_sender;
62
63template <>
65 LIBCOPP_COPP_API static int resume(void *invoke_ctx, stackful_channel_context_base *priv_data);
66};
67
68#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
69template <>
70struct stackful_channel_resume_handle<coroutine_context_fiber> {
71 LIBCOPP_COPP_API static int resume(void *invoke_ctx, stackful_channel_context_base *priv_data);
72};
73#endif
74
75template <class TCOROUTINE_OBJECT>
79 if (nullptr != invoke_ctx) {
80 return static_cast<TCOROUTINE_OBJECT *>(invoke_ctx)->resume(reinterpret_cast<void *>(priv_data));
81 }
82
83 return 0;
84 }
85};
86
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");
91
92 LIBCOPP_COPP_API_HEAD_ONLY inline static int resume(void *invoke_ctx, stackful_channel_context_base *priv_data) {
94 reinterpret_cast<coroutine_context_base *>(invoke_ctx), priv_data);
95 }
96};
97
98struct LIBCOPP_COPP_API_HEAD_ONLY stackful_channel_handle_delegate {
100 int (*resume_handle)(void *, stackful_channel_context_base *priv_data);
101
102 LIBCOPP_UTIL_FORCEINLINE stackful_channel_handle_delegate() noexcept : handle_data(nullptr), resume_handle(nullptr) {}
103
105 : handle_data(other.handle_data), resume_handle(other.resume_handle) {}
106
108 : handle_data(other.handle_data), resume_handle(other.resume_handle) {
109 other.handle_data = nullptr;
110 other.resume_handle = nullptr;
111 }
112
114 const stackful_channel_handle_delegate &other) noexcept {
115 handle_data = other.handle_data;
116 resume_handle = other.resume_handle;
117 return *this;
118 }
119
121 stackful_channel_handle_delegate &&other) noexcept {
122 handle_data = other.handle_data;
123 resume_handle = other.resume_handle;
124
125 other.handle_data = nullptr;
126 other.resume_handle = nullptr;
127 return *this;
128 }
129
130 template <class TCOROUTINE_OBJECT>
131 explicit inline stackful_channel_handle_delegate(TCOROUTINE_OBJECT *ctx) noexcept
132 : handle_data{reinterpret_cast<void *>(ctx)}, resume_handle{nullptr} {
133 if (handle_data != nullptr) {
135 }
136 }
137
139 : handle_data{nullptr}, resume_handle{nullptr} {}
140
142 const stackful_channel_handle_delegate &r) noexcept {
143 return l.handle_data == r.handle_data;
144 }
145#ifdef __cpp_impl_three_way_comparison
146 LIBCOPP_UTIL_FORCEINLINE friend auto operator<=>(const stackful_channel_handle_delegate &l,
147 const stackful_channel_handle_delegate &r) noexcept {
148 return l.handle_data <=> r.handle_data;
149 }
150#else
152 const stackful_channel_handle_delegate &r) noexcept {
153 return l.handle_data != r.handle_data;
154 }
156 const stackful_channel_handle_delegate &r) noexcept {
157 return l.handle_data < r.handle_data;
158 }
160 const stackful_channel_handle_delegate &r) noexcept {
161 return l.handle_data <= r.handle_data;
162 }
164 const stackful_channel_handle_delegate &r) noexcept {
165 return l.handle_data > r.handle_data;
166 }
168 const stackful_channel_handle_delegate &r) noexcept {
169 return l.handle_data >= r.handle_data;
170 }
171#endif
172 LIBCOPP_UTIL_FORCEINLINE operator bool() const noexcept { return !!handle_data; }
173
174 template <class TCOROUTINE_OBJECT>
176 handle_data = reinterpret_cast<void *>(ctx);
177 if (handle_data != nullptr) {
179 }
180
181 return *this;
182 }
183
185 handle_data = nullptr;
186 resume_handle = nullptr;
187 return *this;
188 }
189};
190
191// hash for stackful_channel_handle_delegate
192struct LIBCOPP_COPP_API_HEAD_ONLY stackful_channel_handle_delegate_hash {
194 return std::hash<void *>()(stackful_channel_handle_delegate.handle_data);
195 }
196};
197
199 public:
202
203 private:
208
209 protected:
210 LIBCOPP_COPP_API stackful_channel_context_base() noexcept;
211 LIBCOPP_COPP_API ~stackful_channel_context_base();
212
213 public:
214 LIBCOPP_COPP_API void add_caller(handle_delegate handle) noexcept;
215
216 LIBCOPP_COPP_API bool remove_caller(handle_delegate handle) noexcept;
217
218 LIBCOPP_COPP_API size_t resume_callers();
219
220 LIBCOPP_COPP_API bool has_multiple_callers() const noexcept;
221
222 protected:
223 LIBCOPP_COPP_API void wake();
224
225 private:
226 // Keep multiple callers in registration order so resume_callers() wakes them in FIFO order, which
227 // matches the C++20 coroutine backend's promise_caller_manager and is the least surprising
228 // semantics. The list keeps the wake order and allows O(1) removal by iterator, while the hash
229 // index keeps dedup-on-add and passive removal O(1) as well.
231 using list_type = std::list<handle_delegate>;
232 using index_type = std::unordered_map<handle_delegate, list_type::iterator, handle_delegate_hash>;
233
236
237 inline bool add(const handle_delegate &delegate) {
238 if (index.find(delegate) != index.end()) {
239 return false;
240 }
241 auto back_iter = callers.insert(callers.end(), delegate);
242 index.emplace(delegate, back_iter);
243 return true;
244 }
245
246 inline bool remove(const handle_delegate &delegate) {
247 auto iter = index.find(delegate);
248 if (iter == index.end()) {
249 return false;
250 }
251 callers.erase(iter->second);
252 index.erase(iter);
253 return true;
254 }
255
256 inline void swap(multi_caller_container &other) noexcept {
257 callers.swap(other.callers);
258 index.swap(other.index);
259 }
260
261 inline size_t size() const noexcept { return index.size(); }
262 };
263#if defined(LIBCOPP_MACRO_ENABLE_STD_VARIANT) && LIBCOPP_MACRO_ENABLE_STD_VARIANT
264 std::variant<handle_delegate, multi_caller_container> callers_;
265#else
267 // Mostly, there is only one caller for a promise, we needn't container to store one handle
268 std::unique_ptr<multi_caller_container> multiple_callers_;
269#endif
270};
271
272template <class TVALUE>
273class LIBCOPP_COPP_API_HEAD_ONLY stackful_channel_context : public stackful_channel_context_base {
274 public:
275 using value_type = TVALUE;
278
279 public:
281 std::is_nothrow_constructible<future::future<value_type>>::value) {}
282
284 std::is_nothrow_destructible<future::future<value_type>>::value) {}
285
286 public:
287 LIBCOPP_UTIL_FORCEINLINE bool is_ready() const noexcept { return data_.is_ready(); }
288
289 LIBCOPP_UTIL_FORCEINLINE bool is_pending() const noexcept { return data_.is_pending(); }
290
291 LIBCOPP_UTIL_FORCEINLINE void reset_value() noexcept(noexcept(std::declval<future::future<TVALUE>>().reset_data())) {
292 data_.reset_data();
293 }
294
295 template <class U>
296 LIBCOPP_UTIL_FORCEINLINE void set_value(U &&in) noexcept(
297 noexcept(std::declval<future::future<TVALUE>>().reset_data(std::forward<U>(in)))) {
298 data_.reset_data(std::forward<U>(in));
299
300 // Wakeup all waiting coroutines
301 resume_callers();
302 }
303
304 LIBCOPP_UTIL_FORCEINLINE const value_type *get_value() const noexcept { return data_.data(); }
305
306 LIBCOPP_UTIL_FORCEINLINE value_type *get_value() noexcept { return data_.data(); }
307
308 template <
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
313#endif
314 >>
315 LIBCOPP_UTIL_FORCEINLINE value_type inject_await(TCONTEXT *ctx, TERROR_TRANSFORM &&error_transform) noexcept(
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));
318 }
319
320 template <class TERROR_TRANSFORM>
321 LIBCOPP_UTIL_FORCEINLINE value_type inject_await(coroutine_context *ctx, TERROR_TRANSFORM &&error_transform) noexcept(
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));
324 }
325
326#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
327 template <class TERROR_TRANSFORM>
328 LIBCOPP_UTIL_FORCEINLINE value_type
329 inject_await(coroutine_context_fiber *ctx,
330 TERROR_TRANSFORM &&error_transform) noexcept(std::is_nothrow_copy_constructible<value_type>::value &&
331 noexcept(error_transform(COPP_EC_ARGS_ERROR))) {
332 return internal_inject_await<coroutine_context_fiber>(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
333 }
334#endif
335
336 private:
337 template <class TCONTEXT, class TERROR_TRANSFORM>
338 inline value_type internal_inject_await(TCONTEXT *ctx, TERROR_TRANSFORM &&error_transform) noexcept(
339 std::is_nothrow_copy_constructible<value_type>::value && noexcept(error_transform(COPP_EC_ARGS_ERROR))) {
340 if (is_ready()) {
341 return *get_value();
342 }
343
344 if LIBCOPP_UTIL_UNLIKELY_CONDITION (nullptr == ctx) {
345 return error_transform(COPP_EC_ARGS_ERROR);
346 }
347
348 add_caller(handle_delegate{ctx});
349 void *check_ptr = nullptr;
350 int res = ctx->yield(&check_ptr);
351 remove_caller(handle_delegate{ctx});
352
353 if (COPP_EC_SUCCESS != res) {
354 return error_transform(static_cast<copp_error_code>(res));
355 }
356
357 // This means the context is not resume by the sender of this context/receiver
358 // Maybe the context is killed
359 if (check_ptr != reinterpret_cast<void *>(this)) {
360 return error_transform(COPP_EC_OPERATION_CANCLE);
361 }
362
363 if LIBCOPP_UTIL_LIKELY_CONDITION (is_ready()) {
364 return *get_value();
365 }
366
367 return error_transform(COPP_EC_NOT_READY);
368 }
369
370 private:
372};
373
374template <class TVALUE>
375class LIBCOPP_COPP_API_HEAD_ONLY stackful_channel_receiver {
376 public:
378 using context_pointer_type = LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr<context_type>;
380
381 public:
383 : context_(LIBCOPP_COPP_NAMESPACE_ID::memory::default_make_strong<context_type>()) {}
384
385 LIBCOPP_UTIL_FORCEINLINE bool is_ready() const noexcept {
386 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
387 return false;
388 }
389 return context_->is_ready();
390 }
391
392 LIBCOPP_UTIL_FORCEINLINE bool is_pending() const noexcept {
393 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
394 return false;
395 }
396 return context_->is_pending();
397 }
398
399 LIBCOPP_UTIL_FORCEINLINE void reset_value() noexcept(noexcept(std::declval<context_type>().reset_value())) {
400 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
401 return;
402 }
403
404 context_->reset_value();
405 }
406
408 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
409 return nullptr;
410 }
411
412 return context_->get_value();
413 }
414
416 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
417 return nullptr;
418 }
419
420 return context_->get_value();
421 }
422
423 template <class TCONTEXT, class TERROR_TRANSFORM>
424 LIBCOPP_UTIL_FORCEINLINE value_type inject_await(TCONTEXT *ctx, TERROR_TRANSFORM &&error_transform) noexcept(
425 std::is_nothrow_copy_constructible<value_type>::value && noexcept(error_transform(COPP_EC_ARGS_ERROR))) {
426 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
427 return error_transform(COPP_EC_NOT_INITED);
428 }
429
430 return context_->inject_await(ctx, std::forward<TERROR_TRANSFORM>(error_transform));
431 }
432
433 LIBCOPP_UTIL_FORCEINLINE const context_pointer_type &get_context() const noexcept { return context_; }
434
436
437 private:
439};
440
441template <class TVALUE>
442struct LIBCOPP_COPP_API_HEAD_ONLY stackful_inject_awaitable<stackful_channel_receiver<TVALUE>> : ::std::true_type {};
443
444template <class TVALUE>
445class LIBCOPP_COPP_API_HEAD_ONLY stackful_channel_sender {
446 public:
448 using context_pointer_type = LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr<context_type>;
450
451 public:
452 inline stackful_channel_sender(const context_pointer_type &context) noexcept : context_{context} {}
453
454 LIBCOPP_UTIL_FORCEINLINE bool is_ready() const noexcept {
455 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
456 return false;
457 }
458 return context_->is_ready();
459 }
460
461 LIBCOPP_UTIL_FORCEINLINE bool is_pending() const noexcept {
462 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
463 return false;
464 }
465 return context_->is_pending();
466 }
467
468 LIBCOPP_UTIL_FORCEINLINE void reset_value() noexcept(noexcept(std::declval<context_type>().reset_value())) {
469 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
470 return;
471 }
472
473 context_->reset_value();
474 }
475
476 template <class U>
477 LIBCOPP_UTIL_FORCEINLINE void set_value(U &&in) noexcept(
478 noexcept(std::declval<context_type>().set_value(std::forward<U>(in)))) {
479 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
480 return;
481 }
482
483 context_->set_value(std::forward<U>(in));
484 }
485
486 LIBCOPP_UTIL_FORCEINLINE const context_pointer_type &get_context() const noexcept { return context_; }
487
489
490 private:
492};
493
494template <class TVALUE>
495LIBCOPP_UTIL_FORCEINLINE std::pair<stackful_channel_receiver<TVALUE>, stackful_channel_sender<TVALUE>>
499 return std::make_pair(std::move(receiver), std::move(sender));
500}
501
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_
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
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
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_error_code
Definition errno.h:11
@ COPP_EC_OPERATION_CANCLE
COPP_EC_OPERATION_CANCLE.
Definition errno.h:33
@ COPP_EC_SUCCESS
COPP_EC_SUCCESS.
Definition errno.h:12
@ COPP_EC_NOT_READY
COPP_EC_NOT_READY.
Definition errno.h:24
@ COPP_EC_NOT_INITED
COPP_EC_NOT_INITED.
Definition errno.h:21
@ COPP_EC_ARGS_ERROR
COPP_EC_ARGS_ERROR.
Definition errno.h:30
typename ::std::enable_if< B, T >::type enable_if_t
Definition type_traits.h:79
STL namespace.
LIBCOPP_UTIL_FORCEINLINE std::pair< stackful_channel_receiver< TVALUE >, stackful_channel_sender< TVALUE > > make_stackful_channel()
void swap(multi_caller_container &other) noexcept
std::unordered_map< handle_delegate, list_type::iterator, handle_delegate_hash > index_type
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)