libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
task_promise.h
Go to the documentation of this file.
1// Copyright 2023 owent
2
3#pragma once
4
9#include <libcopp/utils/config/libcopp_build_features.h>
14
15// clang-format off
16#include <libcopp/utils/config/stl_include_prefix.h> // NOLINT(build/include_order)
17// clang-format on
18#include <assert.h>
19#include <cstdlib>
20#include <functional>
21#include <type_traits>
22
23#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
24# include <exception>
25#endif
26// clang-format off
27#include <libcopp/utils/config/stl_include_suffix.h> // NOLINT(build/include_order)
28// clang-format on
29
30#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
31
32LIBCOPP_COTASK_NAMESPACE_BEGIN
33
34template <class TVALUE>
35class LIBCOPP_COTASK_API_HEAD_ONLY task_context_base;
36
37template <class TVALUE, class TERROR_TRANSFORM, bool RETURN_VOID>
38class LIBCOPP_COTASK_API_HEAD_ONLY task_context_delegate;
39
40template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
41class LIBCOPP_COTASK_API_HEAD_ONLY task_context;
42
43template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
44class LIBCOPP_COTASK_API_HEAD_ONLY task_future_base;
45
46template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
47class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
48
49template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM, bool RETURN_VOID>
50class LIBCOPP_COTASK_API_HEAD_ONLY task_promise_base;
51
52template <class TCONTEXT>
53class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base;
54
55template <class TCONTEXT, bool RETURN_VOID>
56class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable;
57
58template <class TVALUE>
59class LIBCOPP_COTASK_API_HEAD_ONLY task_context_base {
60 public:
61 using value_type = TVALUE;
62 using id_type = LIBCOPP_COPP_NAMESPACE_ID::util::uint64_id_allocator::value_type;
63 using id_allocator_type = LIBCOPP_COPP_NAMESPACE_ID::util::uint64_id_allocator;
64 using handle_delegate = LIBCOPP_COPP_NAMESPACE_ID::promise_caller_manager::handle_delegate;
65 using task_status_type = LIBCOPP_COPP_NAMESPACE_ID::promise_status;
66 using promise_flag = LIBCOPP_COPP_NAMESPACE_ID::promise_flag;
67
68 private:
69 task_context_base(const task_context_base&) = delete;
70 task_context_base(task_context_base&&) = delete;
71 task_context_base& operator=(const task_context_base&) = delete;
72 task_context_base& operator=(task_context_base&&) = delete;
73
74 public:
75 task_context_base() noexcept
76 : current_handle_(nullptr)
77# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
78 ,
79 binding_manager_ptr_(nullptr),
80 binding_manager_fn_(nullptr)
81# endif
82 {
83 id_allocator_type id_allocator;
84 id_ = id_allocator.allocate();
85 }
86
87 ~task_context_base() noexcept {
88 force_finish();
89 force_destroy();
90 }
91
92 LIBCOPP_UTIL_FORCEINLINE bool is_ready() const noexcept {
93 if (nullptr != current_handle_.promise && current_handle_.promise->check_flag(promise_flag::kHasReturned)) {
94 return true;
95 }
96
97 return data_.is_ready();
98 }
99
100 LIBCOPP_UTIL_FORCEINLINE bool is_pending() const noexcept { return data_.is_pending(); }
101
102 inline task_status_type get_status() const noexcept {
103 if (current_handle_.promise) {
104 return current_handle_.promise->get_status();
105 }
106
107 return task_status_type::kInvalid;
108 }
109
110 LIBCOPP_UTIL_FORCEINLINE id_type get_id() const noexcept { return id_; }
111
112 LIBCOPP_UTIL_FORCEINLINE bool has_multiple_callers() const noexcept {
113 if (nullptr != current_handle_.promise) {
114 return current_handle_.promise->has_multiple_callers();
115 }
116
117 return false;
118 }
119
120 protected:
121 LIBCOPP_UTIL_FORCEINLINE void add_caller(handle_delegate handle) noexcept {
122 if (nullptr != current_handle_.promise) {
123 current_handle_.promise->add_caller(handle);
124 }
125 }
126
127# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
128 template <LIBCOPP_COPP_NAMESPACE_ID::DerivedPromiseBaseType TPROMISE>
129# else
130 template <class TPROMISE,
131 typename = std::enable_if_t<std::is_base_of<LIBCOPP_COPP_NAMESPACE_ID::promise_base_type, TPROMISE>::value>>
132# endif
133 LIBCOPP_UTIL_FORCEINLINE LIBCOPP_COTASK_API_HEAD_ONLY void add_caller(
134 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE>& handle) noexcept {
135 add_caller(handle_delegate{handle});
136 }
137
138 LIBCOPP_UTIL_FORCEINLINE void remove_caller(handle_delegate handle) noexcept {
139 if (nullptr != current_handle_.promise) {
140 current_handle_.promise->remove_caller(handle, false);
141 }
142 }
143
144# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
145 template <LIBCOPP_COPP_NAMESPACE_ID::DerivedPromiseBaseType TPROMISE>
146# else
147 template <class TPROMISE,
148 typename = std::enable_if_t<std::is_base_of<LIBCOPP_COPP_NAMESPACE_ID::promise_base_type, TPROMISE>::value>>
149# endif
150 LIBCOPP_UTIL_FORCEINLINE LIBCOPP_COTASK_API_HEAD_ONLY void remove_caller(
151 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE>& handle, bool inherit_status) noexcept {
152 remove_caller(handle_delegate{handle}, inherit_status);
153 }
154
155# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
156 LIBCOPP_UTIL_FORCEINLINE void unbind_from_manager() {
157 void* manager_ptr = binding_manager_ptr_;
158 void (*manager_fn)(void*, task_context_base<value_type>&) = binding_manager_fn_;
159 binding_manager_ptr_ = nullptr;
160 binding_manager_fn_ = nullptr;
161
162 // finally, notify manager to cleanup(maybe start or resume with task's API but not task_manager's)
163 if (nullptr != manager_ptr && nullptr != manager_fn) {
164 (*manager_fn)(manager_ptr, *this);
165 }
166 }
167# endif
168
169 private:
170 template <class, class, class, bool>
171 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_promise_base;
172
173 template <class, class, class>
174 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future_base;
175
176 template <class, class, class>
177 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
178
179 template <class TCONTEXT>
180 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base;
181
182 inline void force_finish() noexcept {
183 if LIBCOPP_UTIL_LIKELY_CONDITION (nullptr != current_handle_.promise) {
184 if (current_handle_.promise->get_status() < task_status_type::kDone) {
185 current_handle_.promise->set_status(task_status_type::kKilled);
186 }
187 }
188
189 // Move unhandled_exception
190 while (current_handle_.handle && !current_handle_.handle.done() && current_handle_.promise &&
191 !current_handle_.promise->check_flag(promise_flag::kHasReturned)) {
192 current_handle_.handle.resume();
193 }
194 }
195
196 inline void force_destroy() noexcept {
197 // Move current_handle_ to stack here to allow recursive call of force_destroy
198 handle_delegate current_handle = current_handle_;
199 current_handle_ = nullptr;
200
201 if (nullptr != current_handle.promise) {
202 current_handle.promise->set_flag(promise_flag::kDestroying, true);
203 }
204 if (current_handle.handle) {
205 current_handle.handle.destroy();
206 }
207 }
208
209 LIBCOPP_UTIL_FORCEINLINE void initialize_handle(handle_delegate handle) noexcept { current_handle_ = handle; }
210
211 LIBCOPP_UTIL_FORCEINLINE handle_delegate& get_handle_delegate() noexcept { return current_handle_; }
212 LIBCOPP_UTIL_FORCEINLINE const handle_delegate& get_handle_delegate() const noexcept { return current_handle_; }
213
214 protected:
215 LIBCOPP_COPP_NAMESPACE_ID::future::future<TVALUE> data_;
216
217# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
218 public:
219 class LIBCOPP_COTASK_API_HEAD_ONLY task_manager_helper {
220 private:
221 template <class>
222 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_manager;
223 static bool setup_task_manager(task_context_base<value_type>& context, void* manager_ptr,
224 void (*fn)(void*, task_context_base<value_type>&)) {
225 if (context.binding_manager_ptr_ != nullptr) {
226 return false;
227 }
228
229 context.binding_manager_ptr_ = manager_ptr;
230 context.binding_manager_fn_ = fn;
231 return true;
232 }
233
234 static bool cleanup_task_manager(task_context_base<value_type>& context, void* manager_ptr) {
235 if (context.binding_manager_ptr_ != manager_ptr) {
236 return false;
237 }
238
239 context.binding_manager_ptr_ = nullptr;
240 context.binding_manager_fn_ = nullptr;
241 return true;
242 }
243 };
244# endif
245
246 private:
247 id_type id_;
248 LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<
249# if LIBCOPP_MACRO_ENABLE_MULTI_THREAD
250 size_t
251# else
252 LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type<size_t>
253# endif
254 >
255 future_counter_;
256 LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock internal_operation_lock_;
257 handle_delegate current_handle_;
258# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
259 void* binding_manager_ptr_;
260 void (*binding_manager_fn_)(void*, task_context_base<value_type>&);
261# endif
262};
263
264template <class TVALUE, class TERROR_TRANSFORM>
265class LIBCOPP_COTASK_API_HEAD_ONLY task_context_delegate<TVALUE, TERROR_TRANSFORM, true>
266 : public task_context_base<TVALUE> {
267 public:
268 using base_type = task_context_base<TVALUE>;
269 using id_type = typename base_type::id_type;
270 using value_type = typename base_type::value_type;
271 using handle_delegate = typename base_type::handle_delegate;
272 using task_status_type = typename base_type::task_status_type;
273 using promise_flag = typename base_type::promise_flag;
274 using error_transform = TERROR_TRANSFORM;
275
276 public:
277 ~task_context_delegate() {}
278
279 using base_type::is_pending;
280 using base_type::is_ready;
281
282 LIBCOPP_UTIL_FORCEINLINE void set_value() { data_.reset_data(true); }
283
284 private:
285 template <class TCONTEXT>
286 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base;
287
288 template <class, class, class>
289 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
290
291 template <class, class, class>
292 friend struct LIBCOPP_COTASK_API_HEAD_ONLY some_delegate_task_action;
293
294 using base_type::add_caller;
295 using base_type::data_;
296 using base_type::remove_caller;
297# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
298 using base_type::unbind_from_manager;
299# endif
300};
301
302template <class TVALUE, class TERROR_TRANSFORM>
303class LIBCOPP_COTASK_API_HEAD_ONLY task_context_delegate<TVALUE, TERROR_TRANSFORM, false>
304 : public task_context_base<TVALUE> {
305 public:
306 using base_type = task_context_base<TVALUE>;
307 using id_type = typename base_type::id_type;
308 using value_type = typename base_type::value_type;
309 using handle_delegate = typename base_type::handle_delegate;
310 using task_status_type = typename base_type::task_status_type;
311 using promise_flag = typename base_type::promise_flag;
312 using error_transform = TERROR_TRANSFORM;
313
314 public:
315 using base_type::is_pending;
316 using base_type::is_ready;
317
318 ~task_context_delegate() {
319 if (is_pending()) {
320 set_value(error_transform()(task_status_type::kKilled));
321 }
322 }
323
324 LIBCOPP_UTIL_FORCEINLINE const value_type* data() const noexcept {
325 if (!is_ready()) {
326 return nullptr;
327 }
328
329 return data_.data();
330 }
331
333 if (!is_ready()) {
334 return nullptr;
335 }
336
337 return data_.data();
338 }
339
340 template <class U>
341 LIBCOPP_UTIL_FORCEINLINE void set_value(U&& in) {
342 data_.reset_data(std::forward<U>(in));
343 }
344
345 private:
346 template <class TCONTEXT>
347 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base;
348
349 template <class, class, class>
350 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
351
352 template <class, class, class>
353 friend struct LIBCOPP_COTASK_API_HEAD_ONLY some_delegate_task_action;
354
355 using base_type::add_caller;
356 using base_type::data_;
357 using base_type::remove_caller;
358# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
359 using base_type::unbind_from_manager;
360# endif
361};
362
363template <class TPRIVATE_DATA>
364class LIBCOPP_COTASK_API_HEAD_ONLY task_private_data {
365 public:
366 inline task_private_data() noexcept : data_(nullptr) {}
367 inline task_private_data(TPRIVATE_DATA* input) noexcept : data_(input) {}
368 inline task_private_data(task_private_data&& other) noexcept = default;
369 inline task_private_data& operator=(task_private_data&&) noexcept = default;
370 inline task_private_data(const task_private_data&) = delete;
371 inline task_private_data& operator=(const task_private_data&) = delete;
372 inline ~task_private_data() {}
373
374 inline bool await_ready() const noexcept { return true; }
375 inline TPRIVATE_DATA* await_resume() const noexcept { return data_; }
376 inline void await_suspend(LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::type_erased_handle_type) noexcept {}
377
378 private:
379 template <class, class, class>
380 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_context;
381
382 template <class, class, class>
383 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
384
385 TPRIVATE_DATA* data_;
386};
387
388template <class TID>
389class LIBCOPP_COTASK_API_HEAD_ONLY task_pick_id {
390 public:
391 inline task_pick_id() noexcept : data_(0) {}
392 inline task_pick_id(TID input) noexcept : data_(input) {}
393 inline task_pick_id(task_pick_id&& other) noexcept = default;
394 inline task_pick_id& operator=(task_pick_id&&) noexcept = default;
395 inline task_pick_id(const task_pick_id&) = delete;
396 inline task_pick_id& operator=(const task_pick_id&) = delete;
397 inline ~task_pick_id() {}
398
399 inline bool await_ready() const noexcept { return true; }
400 inline TID await_resume() const noexcept { return data_; }
401 inline void await_suspend(LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::type_erased_handle_type) noexcept {}
402
403 private:
404 template <class, class, class>
405 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_context;
406
407 template <class, class, class>
408 friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
409
410 TID data_;
411};
412
413template <class TVALUE, class TERROR_TRANSFORM>
414class LIBCOPP_COTASK_API_HEAD_ONLY task_context<TVALUE, void, TERROR_TRANSFORM>
415 : public task_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value> {
416 public:
417 using base_type =
418 task_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value>;
419 using value_type = typename base_type::value_type;
420 using id_type = typename base_type::id_type;
421 using private_data_type = void;
422 using handle_delegate = typename base_type::handle_delegate;
423 using task_status_type = typename base_type::task_status_type;
424 using promise_flag = typename base_type::promise_flag;
425 using error_transform = typename base_type::error_transform;
426
427 public:
428 using base_type::is_pending;
429 using base_type::is_ready;
430 using base_type::set_value;
431
432 template <class... TARGS>
433 task_context(TARGS&&...) {}
434};
435
436template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
437class LIBCOPP_COTASK_API_HEAD_ONLY task_context
438 : public task_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value> {
439 public:
440 using base_type =
441 task_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value>;
442 using value_type = typename base_type::value_type;
443 using private_data_type = TPRIVATE_DATA;
444 using handle_delegate = typename base_type::handle_delegate;
445 using task_status_type = typename base_type::task_status_type;
446 using promise_flag = typename base_type::promise_flag;
447 using error_transform = typename base_type::error_transform;
448
449 public:
450 using base_type::is_pending;
451 using base_type::is_ready;
452 using base_type::set_value;
453
454 template <class... TARGS>
455 task_context(TARGS&&... args)
456 : private_data_(
457 LIBCOPP_COPP_NAMESPACE_ID::callable_promise_value_constructor<
458 private_data_type,
459 !std::is_constructible<private_data_type, TARGS...>::value>::construct(std::forward<TARGS>(args)...)) {}
460
461 private_data_type& get_private_data() noexcept { return private_data_; }
462 const private_data_type& get_private_data() const noexcept { return private_data_; }
463
464 private:
465 private_data_type private_data_;
466};
467
468template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
469class LIBCOPP_COTASK_API_HEAD_ONLY task_promise_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, true>
470 : public LIBCOPP_COPP_NAMESPACE_ID::promise_base_type {
471 public:
472 using value_type = TVALUE;
473 using context_type = task_context<value_type, TPRIVATE_DATA, TERROR_TRANSFORM>;
474 using private_data_type = typename context_type::private_data_type;
475 using context_pointer_type = LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr<context_type>;
476 using handle_delegate = typename context_type::handle_delegate;
477 using task_status_type = LIBCOPP_COPP_NAMESPACE_ID::promise_status;
478
479 template <class... TARGS>
480 task_promise_base(TARGS&&... args)
481 : context_strong_ref_(
482 LIBCOPP_COPP_NAMESPACE_ID::memory::default_make_strong<context_type>(std::forward<TARGS>(args)...)) {}
483
484 void return_void() noexcept {
485 set_flag(LIBCOPP_COPP_NAMESPACE_ID::promise_flag::kHasReturned, true);
486
487 if (get_status() < task_status_type::kDone) {
488 set_status(task_status_type::kDone);
489 }
490
491 if LIBCOPP_UTIL_LIKELY_CONDITION (get_context()) {
492 get_context()->set_value();
493 }
494 }
495
496 protected:
497 LIBCOPP_UTIL_FORCEINLINE context_pointer_type move_context() noexcept {
498 context_pointer_type ret = std::move(context_strong_ref_);
499 context_strong_ref_.reset();
500 return ret;
501 }
502
503 LIBCOPP_UTIL_FORCEINLINE const context_pointer_type& get_context() noexcept { return context_strong_ref_; }
504
505 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<
506 task_promise_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, true>, TPROMISE>::value>>
507 LIBCOPP_UTIL_FORCEINLINE void initialize_promise(
508 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE>& origin_handle) noexcept {
509 if LIBCOPP_UTIL_LIKELY_CONDITION (get_context()) {
510 get_context()->initialize_handle(handle_delegate{origin_handle});
511 }
512 }
513
514 private:
515 context_pointer_type context_strong_ref_;
516};
517
518template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
519class LIBCOPP_COTASK_API_HEAD_ONLY task_promise_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, false>
520 : public LIBCOPP_COPP_NAMESPACE_ID::promise_base_type {
521 public:
522 using value_type = TVALUE;
523 using context_type = task_context<value_type, TPRIVATE_DATA, TERROR_TRANSFORM>;
524 using private_data_type = typename context_type::private_data_type;
525 using context_pointer_type = LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr<context_type>;
526 using task_status_type = LIBCOPP_COPP_NAMESPACE_ID::promise_status;
527
528 template <class... TARGS>
529 task_promise_base(TARGS&&... args)
530 : context_strong_ref_(
531 LIBCOPP_COPP_NAMESPACE_ID::memory::default_make_strong<context_type>(std::forward<TARGS>(args)...)) {}
532
533 void return_value(value_type value) {
534 set_flag(LIBCOPP_COPP_NAMESPACE_ID::promise_flag::kHasReturned, true);
535
536 if (get_status() < task_status_type::kDone) {
537 set_status(task_status_type::kDone);
538 }
539 if LIBCOPP_UTIL_LIKELY_CONDITION (get_context()) {
540 get_context()->set_value(std::move(value));
541 }
542 }
543
545 if LIBCOPP_UTIL_LIKELY_CONDITION (get_context()) {
546 return get_context()->data();
547 }
548 return nullptr;
549 }
550
551 LIBCOPP_UTIL_FORCEINLINE const value_type* data() const noexcept {
552 if LIBCOPP_UTIL_LIKELY_CONDITION (get_context()) {
553 return get_context()->data();
554 }
555 return nullptr;
556 }
557
558 protected:
559 LIBCOPP_UTIL_FORCEINLINE context_pointer_type move_context() noexcept {
560 context_pointer_type ret = std::move(context_strong_ref_);
561 context_strong_ref_.reset();
562 return ret;
563 }
564
565 LIBCOPP_UTIL_FORCEINLINE const context_pointer_type& get_context() noexcept { return context_strong_ref_; }
566
567 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<
568 task_promise_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, false>, TPROMISE>::value>>
569 LIBCOPP_UTIL_FORCEINLINE void initialize_promise(
570 const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE>& origin_handle) noexcept {
571 if LIBCOPP_UTIL_LIKELY_CONDITION (get_context()) {
572 get_context()->initialize_handle(handle_delegate{origin_handle});
573 }
574 }
575
576 private:
577 context_pointer_type context_strong_ref_;
578};
579
580template <class TCONTEXT>
581class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base : public LIBCOPP_COPP_NAMESPACE_ID::awaitable_base_type {
582 public:
583 using context_type = TCONTEXT;
584 using context_pointer_type = LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr<context_type>;
585 using value_type = typename context_type::value_type;
586 using task_status_type = LIBCOPP_COPP_NAMESPACE_ID::promise_status;
587 using promise_flag = LIBCOPP_COPP_NAMESPACE_ID::promise_flag;
588
589 public:
590 task_awaitable_base(context_type* context) : context_{context} {}
591
592 inline bool await_ready() noexcept {
593 if LIBCOPP_UTIL_UNLIKELY_CONDITION (nullptr == context_) {
594 return true;
595 }
596
597 if (context_->is_ready()) {
598 return true;
599 }
600
601 if (nullptr == context_->get_handle_delegate().promise) {
602 return true;
603 }
604
605 if (context_->get_handle_delegate().promise->get_status() >= task_status_type::kDone) {
606 return true;
607 }
608
609 return false;
610 }
611
612# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
613 template <LIBCOPP_COPP_NAMESPACE_ID::DerivedPromiseBaseType TCPROMISE>
614# else
615 template <class TCPROMISE, typename = std::enable_if_t<
616 std::is_base_of<LIBCOPP_COPP_NAMESPACE_ID::promise_base_type, TCPROMISE>::value>>
617# endif
618 inline bool await_suspend(LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TCPROMISE> caller) noexcept {
619 if (nullptr != context_ && caller.promise().get_status() < task_status_type::kDone) {
620 set_caller(caller);
621 context_->add_caller(caller);
622
623 // Allow kill resume to forward error information
624 caller.promise().set_flag(promise_flag::kInternalWaitting, true);
625 return true;
626 } else {
627 // Already done and can not suspend again
628 // caller.resume();
629 return false;
630 }
631 }
632
633 protected:
634 task_status_type detach() noexcept {
635 task_status_type result_status;
636 if LIBCOPP_UTIL_UNLIKELY_CONDITION (nullptr == context_) {
637 result_status = task_status_type::kInvalid;
638 } else if (context_->is_ready()) {
639 result_status = task_status_type::kDone;
640 } else {
641 result_status = task_status_type::kKilled;
642 }
643
644 // caller maybe null if the callable is already ready when co_await
645 auto caller = get_caller();
646
647 if (caller) {
648 if (nullptr != caller.promise) {
649 caller.promise->set_flag(promise_flag::kInternalWaitting, false);
650 }
651 if LIBCOPP_UTIL_LIKELY_CONDITION (nullptr != context_) {
652 if (!context_->is_ready() && nullptr != caller.promise) {
653 result_status = caller.promise->get_status();
654 }
655
656 context_->remove_caller(caller);
657 set_caller(nullptr);
658 } else {
659 set_caller(nullptr);
660 }
661 }
662
663 return result_status;
664 }
665
672 LIBCOPP_UTIL_FORCEINLINE context_type* get_context() noexcept { return context_; }
673
674 private:
675 context_type* context_;
676};
677
678template <class TCONTEXT>
679class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable<TCONTEXT, true> : public task_awaitable_base<TCONTEXT> {
680 public:
681 using base_type = task_awaitable_base<TCONTEXT>;
682 using value_type = typename base_type::value_type;
683 using context_type = typename base_type::context_type;
684 using context_pointer_type = typename base_type::context_pointer_type;
685 using task_status_type = typename base_type::task_status_type;
686 using promise_flag = typename base_type::promise_flag;
687 using error_transform = typename context_type::error_transform;
688
689 public:
690 using base_type::await_ready;
691 using base_type::await_suspend;
692 using base_type::get_caller;
693 using base_type::set_caller;
694 task_awaitable(context_type* context) : base_type(context) {}
695
696 inline void await_resume() { detach(); }
697
698 private:
699 using base_type::detach;
700 using base_type::get_context;
701};
702
703template <class TCONTEXT>
704class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable<TCONTEXT, false> : public task_awaitable_base<TCONTEXT> {
705 public:
706 using base_type = task_awaitable_base<TCONTEXT>;
707 using value_type = typename base_type::value_type;
708 using context_type = typename base_type::context_type;
709 using context_pointer_type = typename base_type::context_pointer_type;
710 using task_status_type = typename base_type::task_status_type;
711 using promise_flag = typename base_type::promise_flag;
712 using error_transform = typename context_type::error_transform;
713
714 public:
715 using base_type::await_ready;
716 using base_type::await_suspend;
717 using base_type::get_caller;
718 using base_type::set_caller;
719 task_awaitable(context_type* context) : base_type(context) {}
720
721 inline value_type await_resume() {
722 bool has_multiple_callers;
723 if LIBCOPP_UTIL_LIKELY_CONDITION (nullptr != get_context()) {
724 has_multiple_callers = get_context()->has_multiple_callers();
725 } else {
726 has_multiple_callers = false;
727 }
728 task_status_type result_status = detach();
729
730 if (task_status_type::kDone != result_status) {
731 return error_transform()(result_status);
732 }
733
734 if LIBCOPP_UTIL_LIKELY_CONDITION (nullptr != get_context()) {
735 if (has_multiple_callers) {
736 return *get_context()->data();
737 } else {
738 return LIBCOPP_COPP_NAMESPACE_ID::multiple_callers_constructor<value_type>::return_value(
739 *get_context()->data());
740 }
741 } else {
742 return error_transform()(task_status_type::kInvalid);
743 }
744 }
745
746 private:
747 using base_type::detach;
748 using base_type::get_context;
749};
750
751template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
752class LIBCOPP_COTASK_API_HEAD_ONLY task_future_base {
753 public:
754 using value_type = TVALUE;
755 using context_type = task_context<value_type, TPRIVATE_DATA, TERROR_TRANSFORM>;
756 using id_type = typename context_type::id_type;
757 using private_data_type = typename context_type::private_data_type;
758 using context_pointer_type = LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr<context_type>;
759 using task_status_type = typename context_type::task_status_type;
760 using promise_flag = typename context_type::promise_flag;
761
762 public:
763 task_future_base() noexcept = default;
764
765 task_future_base(context_pointer_type context) noexcept : context_{context} {
766 if LIBCOPP_UTIL_LIKELY_CONDITION (context_) {
767 ++context_->future_counter_;
768 }
769 }
770
771 task_future_base(const task_future_base& other) noexcept : context_{other.context_} {
772 if LIBCOPP_UTIL_LIKELY_CONDITION (context_) {
773 ++context_->future_counter_;
774 }
775 }
776
777 task_future_base(task_future_base&& other) noexcept : context_{std::move(other.context_)} { other.context_.reset(); }
778
779 task_future_base& operator=(const task_future_base& other) noexcept {
780 assign(other);
781 return *this;
782 }
783
784 task_future_base& operator=(task_future_base&& other) noexcept {
785 assign(std::move(other));
786 return *this;
787 }
788
789 ~task_future_base() {
790 // resume callers
791 reset();
792 }
793
794 inline friend bool operator==(const task_future_base& l, const task_future_base& r) noexcept {
795 return l.context_ == r.context_;
796 }
797
798 inline friend bool operator!=(const task_future_base& l, const task_future_base& r) noexcept {
799 return l.context_ != r.context_;
800 }
801
802 inline operator bool() const noexcept { return valid(); }
803
804 void assign(const task_future_base& other) noexcept {
805 if (this == &other || context_ == other.context_) {
806 return;
807 }
808
809 reset();
810
811 if LIBCOPP_UTIL_LIKELY_CONDITION (other.context_) {
812 ++other.context_->future_counter_;
813 }
814 context_ = other.context_;
815 }
816
817 void assign(task_future_base&& other) noexcept {
818 if (this == &other || context_ == other.context_) {
819 return;
820 }
821
822 reset();
823 context_.swap(other.context_);
824
825 return;
826 }
827
828 void reset() {
829 if (context_) {
830 context_pointer_type context;
831 context.swap(context_);
832 size_t future_counter = --context->future_counter_;
833 // Destroy context when future_counter decrease to 0
834 if (0 == future_counter) {
835 context->force_finish();
836 }
837 }
838 }
839
840 size_t get_ref_future_count() const noexcept {
841 if LIBCOPP_UTIL_LIKELY_CONDITION (context_) {
842 return context_->future_counter_.load();
843 }
844
845 return 0;
846 }
847
848 inline task_status_type get_status() const noexcept {
849 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
850 return task_status_type::kInvalid;
851 }
852
853 return context_->get_status();
854 }
855
856 LIBCOPP_UTIL_FORCEINLINE bool is_canceled() const noexcept { return task_status_type::kCancle == get_status(); }
857 inline bool is_completed() const noexcept {
858 if (false == is_exiting()) {
859 return false;
860 }
861
862 if (!context_) {
863 return true;
864 }
865
866 auto& handle = context_->get_handle_delegate().handle;
868 return true;
869 }
870
871 if (handle.done()) {
872 return true;
873 }
874
875 auto promise = context_->get_handle_delegate().promise;
876 if LIBCOPP_UTIL_UNLIKELY_CONDITION (nullptr == promise) {
877 return true;
878 }
879
880 if (promise->check_flag(promise_flag::kHasReturned)) {
881 return true;
882 }
883
884 return false;
885 }
886
887 LIBCOPP_UTIL_FORCEINLINE bool is_faulted() const noexcept { return task_status_type::kKilled <= get_status(); }
888 LIBCOPP_UTIL_FORCEINLINE bool is_timeout() const noexcept { return task_status_type::kTimeout <= get_status(); }
889 LIBCOPP_UTIL_FORCEINLINE bool is_exiting() const noexcept {
890 task_status_type status = get_status();
891 return task_status_type::kDone <= status || task_status_type::kInvalid == status;
892 }
893
894 LIBCOPP_UTIL_FORCEINLINE static auto yield_status() noexcept {
895 return LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::pick_current_status();
896 }
897
898 LIBCOPP_UTIL_FORCEINLINE static auto yield_private_data() noexcept { return task_private_data<TPRIVATE_DATA>{}; }
899
900 LIBCOPP_UTIL_FORCEINLINE static auto yield_task_id() noexcept { return task_pick_id<id_type>{}; }
901
908 bool start() noexcept {
909 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
910 return false;
911 }
912
913 LIBCOPP_COPP_NAMESPACE_ID::util::lock::lock_holder<
914 LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock,
915 LIBCOPP_COPP_NAMESPACE_ID::util::lock::detail::default_try_lock_action<
916 LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock>,
917 LIBCOPP_COPP_NAMESPACE_ID::util::lock::detail::default_try_unlock_action<
918 LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock>>
919 lock_holder{context_->internal_operation_lock_};
920
921 if (!lock_holder.is_available()) {
922 return false;
923 }
924
925 auto& handle = context_->get_handle_delegate().handle;
927 return false;
928 }
929
930 if (handle.done()) {
931 return false;
932 }
933
934 auto promise = context_->get_handle_delegate().promise;
935 if LIBCOPP_UTIL_UNLIKELY_CONDITION (nullptr == promise) {
936 return false;
937 }
938
939 task_status_type expect_status = task_status_type::kCreated;
940 if (!promise->set_status(task_status_type::kRunning, &expect_status)) {
941 return false;
942 }
943
944 lock_holder.reset();
945
946 if (!promise->check_flag(promise_flag::kHasReturned) && !promise->check_flag(promise_flag::kDestroying)) {
947 // rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
948 // We may enable exception in the future
949# if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
950 std::exception_ptr unhandled_exception;
951 try {
952# endif
953 handle.resume();
954 // rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
955 // We may enable exception in the future
956# if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
957 } catch (...) {
958 unhandled_exception = std::current_exception();
959 }
960# endif
961 }
962
963 return true;
964 }
965
974 bool kill(task_status_type target_status = task_status_type::kKilled, bool force_resume = false) noexcept {
975 if (target_status < task_status_type::kDone) {
976 return false;
977 }
978
979 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
980 return false;
981 }
982
983 LIBCOPP_COPP_NAMESPACE_ID::util::lock::lock_holder<
984 LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock,
985 LIBCOPP_COPP_NAMESPACE_ID::util::lock::detail::default_try_lock_action<
986 LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock>,
987 LIBCOPP_COPP_NAMESPACE_ID::util::lock::detail::default_try_unlock_action<
988 LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock>>
989 lock_holder{context_->internal_operation_lock_};
990
991 if (!lock_holder.is_available()) {
992 return false;
993 }
994
995 auto& handle = context_->get_handle_delegate().handle;
997 return false;
998 }
999
1000 bool ret = true;
1001 while (context_) {
1002 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!handle) {
1003 ret = false;
1004 break;
1005 }
1006
1007 if (handle.done()) {
1008 ret = false;
1009 break;
1010 }
1011
1012 task_status_type current_status = get_status();
1013 if (current_status >= task_status_type::kDone) {
1014 ret = false;
1015 break;
1016 }
1017
1018 auto promise = context_->get_handle_delegate().promise;
1019 if LIBCOPP_UTIL_UNLIKELY_CONDITION (nullptr == promise) {
1020 return false;
1021 }
1022
1023 if (!promise->set_status(target_status, &current_status)) {
1024 continue;
1025 }
1026
1027 if ((force_resume || promise->is_waiting()) && !promise->check_flag(promise_flag::kHasReturned) &&
1028 !promise->check_flag(promise_flag::kDestroying)) {
1029 // rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
1030 // We may enable exception in the future
1031# if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
1032 std::exception_ptr unhandled_exception;
1033 try {
1034# endif
1035 handle.resume();
1036 // rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
1037 // We may enable exception in the future
1038# if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
1039 }
1040 catch (...) {
1041 unhandled_exception = std::current_exception();
1042 }
1043# endif
1044 }
1045 break;
1046 }
1047
1048 return ret;
1049 }
1050
1051 LIBCOPP_UTIL_FORCEINLINE bool kill(bool force_resume) { return kill(task_status_type::kKilled, force_resume); }
1052
1053 LIBCOPP_UTIL_FORCEINLINE bool cancel(bool force_resume = false) {
1054 return kill(task_status_type::kCancle, force_resume);
1055 }
1056
1057 LIBCOPP_UTIL_FORCEINLINE const context_pointer_type& get_context() const noexcept { return context_; }
1058
1059 LIBCOPP_UTIL_FORCEINLINE context_pointer_type& get_context() noexcept { return context_; }
1060
1061 inline id_type get_id() const noexcept {
1062 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!context_) {
1063 return 0;
1064 }
1065
1066 return context_->get_id();
1067 }
1068
1069 LIBCOPP_UTIL_FORCEINLINE bool valid() const noexcept { return !!context_; }
1070
1071 private:
1072 context_pointer_type context_;
1073};
1074
1075template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM, bool NO_PRIVATE_DATA>
1076class LIBCOPP_COTASK_API_HEAD_ONLY task_future_delegate;
1077
1078template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
1079class LIBCOPP_COTASK_API_HEAD_ONLY task_future_delegate<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, false>
1080 : public task_future_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM> {
1081 public:
1082 using base_type = task_future_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>;
1083 using value_type = typename base_type::value_type;
1084 using context_type = typename base_type::context_type;
1085 using id_type = typename base_type::id_type;
1086 using private_data_type = typename base_type::private_data_type;
1087 using context_pointer_type = typename base_type::context_pointer_type;
1088 using task_status_type = typename base_type::task_status_type;
1089 using promise_flag = typename base_type::promise_flag;
1090
1091 public:
1092 task_future_delegate() noexcept = default;
1093 task_future_delegate(context_pointer_type context) noexcept : base_type{context} {}
1094 task_future_delegate(const task_future_delegate& other) noexcept : base_type{other} {}
1095 task_future_delegate(task_future_delegate&& other) noexcept : base_type{std::move(other)} {}
1096 task_future_delegate& operator=(const task_future_delegate& other) noexcept {
1097 assign(other);
1098 return *this;
1099 }
1100
1101 task_future_delegate& operator=(task_future_delegate&& other) noexcept {
1102 assign(std::move(other));
1103 return *this;
1104 }
1105
1106 using base_type::assign;
1107 using base_type::get_context;
1108
1109 inline private_data_type* get_private_data() noexcept {
1110 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!get_context()) {
1111 return nullptr;
1112 }
1113
1114 return &get_context()->get_private_data();
1115 }
1116
1117 inline const private_data_type* get_private_data() const noexcept {
1118 if LIBCOPP_UTIL_UNLIKELY_CONDITION (!get_context()) {
1119 return nullptr;
1120 }
1121
1122 return &get_context()->get_private_data();
1123 }
1124};
1125
1126template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
1127class LIBCOPP_COTASK_API_HEAD_ONLY task_future_delegate<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, true>
1128 : public task_future_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM> {
1129 public:
1130 using base_type = task_future_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>;
1131 using value_type = typename base_type::value_type;
1132 using context_type = typename base_type::context_type;
1133 using id_type = typename base_type::id_type;
1134 using private_data_type = typename base_type::private_data_type;
1135 using context_pointer_type = typename base_type::context_pointer_type;
1136 using task_status_type = typename base_type::task_status_type;
1137 using promise_flag = typename base_type::promise_flag;
1138
1139 public:
1140 task_future_delegate() noexcept = default;
1141 task_future_delegate(context_pointer_type context) noexcept : base_type{context} {}
1142 task_future_delegate(const task_future_delegate& other) noexcept : base_type{other} {}
1143 task_future_delegate(task_future_delegate&& other) noexcept : base_type{std::move(other)} {}
1144 task_future_delegate& operator=(const task_future_delegate& other) noexcept {
1145 assign(other);
1146 return *this;
1147 }
1148
1149 task_future_delegate& operator=(task_future_delegate&& other) noexcept {
1150 assign(std::move(other));
1151 return *this;
1152 }
1153
1154 using base_type::assign;
1155 using base_type::get_context;
1156};
1157
1158template <class TVALUE, class TPRIVATE_DATA,
1159 class TERROR_TRANSFORM = LIBCOPP_COPP_NAMESPACE_ID::promise_error_transform<TVALUE>>
1160class LIBCOPP_COTASK_API_HEAD_ONLY task_future
1161 : public task_future_delegate<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, std::is_same<TPRIVATE_DATA, void>::value> {
1162 public:
1163 using error_transform = TERROR_TRANSFORM;
1164 using self_type = task_future<TVALUE, TPRIVATE_DATA, error_transform>;
1165 using base_type =
1166 task_future_delegate<TVALUE, TPRIVATE_DATA, error_transform, std::is_same<TPRIVATE_DATA, void>::value>;
1167 using value_type = typename base_type::value_type;
1168 using context_type = typename base_type::context_type;
1169 using id_type = typename base_type::id_type;
1170 using private_data_type = typename base_type::private_data_type;
1171 using context_pointer_type = typename base_type::context_pointer_type;
1172 using task_status_type = typename base_type::task_status_type;
1173 using promise_flag = typename base_type::promise_flag;
1174
1175 using promise_base_type = task_promise_base<value_type, private_data_type, error_transform,
1176 std::is_void<typename std::decay<value_type>::type>::value>;
1177 class promise_type : public promise_base_type {
1178 public:
1179# if defined(__GNUC__) && !defined(__clang__)
1180 template <class... TARGS>
1181 promise_type(TARGS&&... args) : promise_base_type(args...) {}
1182# else
1183 template <class... TARGS>
1184 promise_type(TARGS&&... args) : promise_base_type(std::forward<TARGS>(args)...) {}
1185# endif
1186
1187 using promise_base_type::get_context;
1188 using promise_base_type::move_context;
1189
1190 auto get_return_object() noexcept { return self_type{get_context()}; }
1191
1192 struct initial_awaitable {
1193 inline bool await_ready() const noexcept { return false; }
1194
1195 inline void await_resume() const noexcept {
1196 if (handle.promise().get_status() == task_status_type::kCreated) {
1197 task_status_type excepted = task_status_type::kCreated;
1198 handle.promise().set_status(task_status_type::kRunning, &excepted);
1199 }
1200 }
1201
1202 inline void await_suspend(LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<promise_type> caller) noexcept {
1203 handle = caller;
1204 caller.promise().initialize_promise(caller);
1205 }
1206
1207 LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<promise_type> handle;
1208 };
1209 initial_awaitable initial_suspend() noexcept { return {}; }
1210
1211 // C++20 coroutine
1212 struct LIBCOPP_COTASK_API_HEAD_ONLY final_awaitable
1213 : public LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::final_awaitable {
1214# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
1215 template <std::derived_from<promise_base_type> TPROMISE>
1216# else
1217 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
1218# endif
1219 inline void await_suspend(LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> self) noexcept {
1220 // Move out context from promise
1221 context_pointer_type context = self.promise().move_context();
1222
1223# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
1224 context->unbind_from_manager();
1225# endif
1226
1227 // Notify callers
1228 LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::final_awaitable::await_suspend(self);
1229
1230 // At last it may be destroyed after all callers and managers is unbind.
1231 }
1232 };
1233
1234 final_awaitable final_suspend() noexcept { return {}; }
1235
1236# if defined(LIBCOPP_MACRO_ENABLE_EXCEPTION) && LIBCOPP_MACRO_ENABLE_EXCEPTION
1237 void unhandled_exception() {
1238 throw;
1239 // get_context()->last_exception_ = std::current_exception();
1240 }
1241# else
1242 void unhandled_exception() { std::abort(); }
1243# endif
1244
1245 template <class TCONVERT_PRIVATE_DATA>
1246 inline task_private_data<TCONVERT_PRIVATE_DATA> yield_value(
1247 task_private_data<TCONVERT_PRIVATE_DATA>&& input) noexcept {
1248 if (get_context()) {
1249 input.data_ = &get_context()->get_private_data();
1250 } else {
1251 input.data_ = nullptr;
1252 }
1253 return task_private_data<TCONVERT_PRIVATE_DATA>(input.data_);
1254 }
1255
1256 inline task_pick_id<id_type> yield_value(task_pick_id<id_type>&& input) noexcept {
1257 if (get_context()) {
1258 input.data_ = get_context()->get_id();
1259 } else {
1260 input.data_ = 0;
1261 }
1262 return task_pick_id<id_type>(input.data_);
1263 }
1264
1265 using promise_base_type::yield_value;
1266 };
1267 using handle_type = LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<promise_type>;
1268 using awaitable_type = task_awaitable<context_type, std::is_void<typename std::decay<value_type>::type>::value>;
1269
1270# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
1271 using task_manager_helper = typename context_type::task_manager_helper;
1272# endif
1273
1274 public:
1275 task_future() noexcept = default;
1276 task_future(context_pointer_type context) noexcept : base_type{context} {}
1277 task_future(const task_future& other) noexcept : base_type{other} {}
1278 task_future(task_future&& other) noexcept : base_type{std::move(other)} {}
1279 task_future& operator=(const task_future& other) noexcept {
1280 assign(other);
1281 return *this;
1282 }
1283
1284 task_future& operator=(task_future&& other) noexcept {
1285 assign(std::move(other));
1286 return *this;
1287 }
1288
1289 using base_type::assign;
1290 using base_type::get_context;
1291
1292 inline awaitable_type operator co_await() { return awaitable_type{get_context().get()}; }
1293
1294 private:
1295 template <class TTHENABLE_VALUE>
1296 struct _thenable_return_traits_value_type;
1297
1298 template <class TCALLABLE_VALUE, class TTASK_ERROR_TRANSFORM>
1299 struct _thenable_return_traits_value_type<
1300 LIBCOPP_COPP_NAMESPACE_ID::callable_future<TCALLABLE_VALUE, TTASK_ERROR_TRANSFORM>> : public std::true_type {
1301 using type =
1302 typename LIBCOPP_COPP_NAMESPACE_ID::callable_future<TCALLABLE_VALUE, TTASK_ERROR_TRANSFORM>::value_type;
1303 using error_transform = TTASK_ERROR_TRANSFORM;
1304
1305 template <class TINPUT>
1306 LIBCOPP_UTIL_FORCEINLINE static LIBCOPP_COPP_NAMESPACE_ID::callable_future<TCALLABLE_VALUE, TTASK_ERROR_TRANSFORM>
1307 start_thenable(TINPUT&& c) {
1308 return {std::forward<TINPUT>(c)};
1309 }
1310 };
1311
1312 template <class TTASK_VALUE, class TTASK_PRIVATE_DATA, class TTASK_ERROR_TRANSFORM>
1313 struct _thenable_return_traits_value_type<task_future<TTASK_VALUE, TTASK_PRIVATE_DATA, TTASK_ERROR_TRANSFORM>>
1314 : public std::true_type {
1315 using type = typename task_future<TTASK_VALUE, TTASK_PRIVATE_DATA, TTASK_ERROR_TRANSFORM>::value_type;
1316 using error_transform = TTASK_ERROR_TRANSFORM;
1317
1318 template <class TINPUT>
1319 LIBCOPP_UTIL_FORCEINLINE static task_future<TTASK_VALUE, TTASK_PRIVATE_DATA, TTASK_ERROR_TRANSFORM> start_thenable(
1320 TINPUT&& task) {
1321 task.start();
1322 return {std::forward<TINPUT>(task)};
1323 }
1324 };
1325
1326 template <class TTHENABLE_VALUE>
1327 struct _thenable_return_traits_value_type : public std::false_type {
1328 using type = TTHENABLE_VALUE;
1329 };
1330
1331 template <class TTHENABLE, bool TASK_RETURN_VOID>
1332 struct _thenable_return_traits_return_type;
1333
1334 template <class TTHENABLE>
1335 struct _thenable_return_traits_return_type<TTHENABLE, true>
1336 : public _thenable_return_traits_value_type<typename std::invoke_result<TTHENABLE, context_pointer_type>::type> {
1337 };
1338
1339 template <class TTHENABLE>
1340 struct _thenable_return_traits_return_type<TTHENABLE, false>
1341 : public _thenable_return_traits_value_type<
1342 typename std::invoke_result<TTHENABLE, context_pointer_type, value_type>::type> {};
1343
1344 template <class TTHENABLE>
1345 struct thenable_return_traits
1346 : public _thenable_return_traits_return_type<TTHENABLE, std::is_void<value_type>::value> {};
1347
1348 template <class TTHENABLE, bool THENABLE_RETURN_COROUTINE>
1349 struct _thenable_default_error_transform;
1350
1351 template <class TTHENABLE>
1352 struct _thenable_default_error_transform<TTHENABLE, true> {
1353 using type = typename thenable_return_traits<TTHENABLE>::error_transform;
1354 };
1355
1356 template <class TTHENABLE>
1357 struct _thenable_default_error_transform<TTHENABLE, false> {
1358 using type = LIBCOPP_COPP_NAMESPACE_ID::promise_error_transform<typename thenable_return_traits<TTHENABLE>::type>;
1359 };
1360
1361 template <class TTHENABLE>
1362 struct thenable_error_transform_traits
1363 : public _thenable_default_error_transform<TTHENABLE, thenable_return_traits<TTHENABLE>::value> {};
1364
1365 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM, bool THENABLE_RETURN_COROUTINE, bool THENABLE_RETURN_VOID,
1366 bool TASK_RETURN_VOID>
1367 struct thenable_traits;
1368
1369 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1370 struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, true, false, false> {
1371 using callable_thenable_type =
1372 LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1373 TTHENABLE_ERROR_TRANSFORM>;
1374
1375 template <class TTHENABLE_PRIVATE_DATA>
1376 struct task_thenable_type {
1377 using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1378 TTHENABLE_ERROR_TRANSFORM>;
1379 };
1380
1381 inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1382 co_return (co_await thenable_return_traits<TTHENABLE>::start_thenable(
1383 thenable(context_pointer_type(self.get_context()), co_await self)));
1384 }
1385
1386 template <class TTHENABLE_PRIVATE_DATA>
1387 inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1388 TTHENABLE thenable) {
1389 co_return (co_await thenable_return_traits<TTHENABLE>::start_thenable(
1390 thenable(context_pointer_type(self.get_context()), co_await self)));
1391 }
1392 };
1393
1394 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1395 struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, true, false, true> {
1396 using callable_thenable_type =
1397 LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1398 TTHENABLE_ERROR_TRANSFORM>;
1399
1400 template <class TTHENABLE_PRIVATE_DATA>
1401 struct task_thenable_type {
1402 using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1403 TTHENABLE_ERROR_TRANSFORM>;
1404 };
1405
1406 inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1407 co_await self;
1408 co_return (co_await thenable_return_traits<TTHENABLE>::start_thenable(
1409 thenable(context_pointer_type(self.get_context()))));
1410 }
1411
1412 template <class TTHENABLE_PRIVATE_DATA>
1413 inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1414 TTHENABLE thenable) {
1415 co_await self;
1416 co_return (co_await thenable_return_traits<TTHENABLE>::start_thenable(
1417 thenable(context_pointer_type(self.get_context()))));
1418 }
1419 };
1420
1421 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1422 struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, true, true, false> {
1423 using callable_thenable_type =
1424 LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1425 TTHENABLE_ERROR_TRANSFORM>;
1426
1427 template <class TTHENABLE_PRIVATE_DATA>
1428 struct task_thenable_type {
1429 using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1430 TTHENABLE_ERROR_TRANSFORM>;
1431 };
1432
1433 inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1434 co_await thenable_return_traits<TTHENABLE>::start_thenable(
1435 thenable(context_pointer_type(self.get_context()), co_await self));
1436 co_return;
1437 }
1438
1439 template <class TTHENABLE_PRIVATE_DATA>
1440 inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1441 TTHENABLE thenable) {
1442 co_await thenable_return_traits<TTHENABLE>::start_thenable(
1443 thenable(context_pointer_type(self.get_context()), co_await self));
1444 co_return;
1445 }
1446 };
1447
1448 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1449 struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, true, true, true> {
1450 using callable_thenable_type =
1451 LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1452 TTHENABLE_ERROR_TRANSFORM>;
1453
1454 template <class TTHENABLE_PRIVATE_DATA>
1455 struct task_thenable_type {
1456 using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1457 TTHENABLE_ERROR_TRANSFORM>;
1458 };
1459
1460 inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1461 co_await self;
1462 co_await thenable_return_traits<TTHENABLE>::start_thenable(thenable(context_pointer_type(self.get_context())));
1463 co_return;
1464 }
1465
1466 template <class TTHENABLE_PRIVATE_DATA>
1467 inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1468 TTHENABLE thenable) {
1469 co_await self;
1470 co_await thenable_return_traits<TTHENABLE>::start_thenable(thenable(context_pointer_type(self.get_context())));
1471 co_return;
1472 }
1473 };
1474
1475 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1476 struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, false, true, false> {
1477 using callable_thenable_type =
1478 LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1479 TTHENABLE_ERROR_TRANSFORM>;
1480
1481 template <class TTHENABLE_PRIVATE_DATA>
1482 struct task_thenable_type {
1483 using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1484 TTHENABLE_ERROR_TRANSFORM>;
1485 };
1486
1487 inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1488 thenable(context_pointer_type(self.get_context()), co_await self);
1489 co_return;
1490 }
1491
1492 template <class TTHENABLE_PRIVATE_DATA>
1493 inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1494 TTHENABLE thenable) {
1495 thenable(context_pointer_type(self.get_context()), co_await self);
1496 co_return;
1497 }
1498 };
1499
1500 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1501 struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, false, true, true> {
1502 using callable_thenable_type =
1503 LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1504 TTHENABLE_ERROR_TRANSFORM>;
1505
1506 template <class TTHENABLE_PRIVATE_DATA>
1507 struct task_thenable_type {
1508 using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1509 TTHENABLE_ERROR_TRANSFORM>;
1510 };
1511
1512 inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1513 co_await self;
1514 thenable(context_pointer_type(self.get_context()));
1515 co_return;
1516 }
1517
1518 template <class TTHENABLE_PRIVATE_DATA>
1519 inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1520 TTHENABLE thenable) {
1521 co_await self;
1522 thenable(context_pointer_type(self.get_context()));
1523 co_return;
1524 }
1525 };
1526
1527 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1528 struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, false, false, false> {
1529 using callable_thenable_type =
1530 LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1531 TTHENABLE_ERROR_TRANSFORM>;
1532
1533 template <class TTHENABLE_PRIVATE_DATA>
1534 struct task_thenable_type {
1535 using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1536 TTHENABLE_ERROR_TRANSFORM>;
1537 };
1538
1539 inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1540 co_return thenable(context_pointer_type(self.get_context()), co_await self);
1541 }
1542
1543 template <class TTHENABLE_PRIVATE_DATA>
1544 inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1545 TTHENABLE thenable) {
1546 co_return thenable(context_pointer_type(self.get_context()), co_await self);
1547 }
1548 };
1549
1550 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1551 struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, false, false, true> {
1552 using callable_thenable_type =
1553 LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1554 TTHENABLE_ERROR_TRANSFORM>;
1555
1556 template <class TTHENABLE_PRIVATE_DATA>
1557 struct task_thenable_type {
1558 using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1559 TTHENABLE_ERROR_TRANSFORM>;
1560 };
1561
1562 inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1563 co_await self;
1564 co_return thenable(context_pointer_type(self.get_context()));
1565 }
1566
1567 template <class TTHENABLE_PRIVATE_DATA>
1568 inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1569 TTHENABLE thenable) {
1570 co_await self;
1571 co_return thenable(context_pointer_type(self.get_context()));
1572 }
1573 };
1574
1575 public:
1576 template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1577 struct callable_thenable_trait {
1578 using trait_type = thenable_traits<
1579 typename std::decay<TTHENABLE>::type, TTHENABLE_ERROR_TRANSFORM,
1580 thenable_return_traits<typename std::decay<TTHENABLE>::type>::value,
1581 std::is_same<typename thenable_return_traits<typename std::decay<TTHENABLE>::type>::type, void>::value,
1582 std::is_void<value_type>::value>;
1583
1584 using callable_thenable_type = typename trait_type::callable_thenable_type;
1585 };
1586
1587 template <class TTHENABLE, class TTHENABLE_PRIVATE_DATA, class TTHENABLE_ERROR_TRANSFORM>
1588 struct task_thenable_trait {
1589 using trait_type = thenable_traits<
1590 typename std::decay<TTHENABLE>::type, TTHENABLE_ERROR_TRANSFORM,
1591 thenable_return_traits<typename std::decay<TTHENABLE>::type>::value,
1592 std::is_same<typename thenable_return_traits<typename std::decay<TTHENABLE>::type>::type, void>::value,
1593 std::is_void<value_type>::value>;
1594
1595 using task_thenable_wrapper = typename trait_type::template task_thenable_type<TTHENABLE_PRIVATE_DATA>;
1596 using task_thenable_type = typename task_thenable_wrapper::task_type;
1597 };
1598
1620 template <class TTHENABLE,
1621 class TTHENABLE_ERROR_TRANSFORM = typename thenable_error_transform_traits<TTHENABLE>::type>
1622 typename callable_thenable_trait<TTHENABLE, TTHENABLE_ERROR_TRANSFORM>::callable_thenable_type then(
1623 TTHENABLE&& thenable) {
1624 using trait_type = typename callable_thenable_trait<TTHENABLE, TTHENABLE_ERROR_TRANSFORM>::trait_type;
1625 return trait_type::invoke_callable(*this, std::forward<TTHENABLE>(thenable));
1626 }
1627
1654 template <class TTHENABLE, class TTHENABLE_PRIVATE_DATA,
1655 class TTHENABLE_ERROR_TRANSFORM = typename thenable_error_transform_traits<TTHENABLE>::type>
1656 typename task_thenable_trait<TTHENABLE, typename std::decay<TTHENABLE_PRIVATE_DATA>::type,
1657 TTHENABLE_ERROR_TRANSFORM>::task_thenable_type
1658 then(TTHENABLE&& thenable, TTHENABLE_PRIVATE_DATA&& private_data) {
1659 using trait_type = typename task_thenable_trait<TTHENABLE, typename std::decay<TTHENABLE_PRIVATE_DATA>::type,
1660 TTHENABLE_ERROR_TRANSFORM>::trait_type;
1661 auto result = trait_type::template invoke_task<typename std::decay<TTHENABLE_PRIVATE_DATA>::type>(
1662 *this, std::forward<TTHENABLE>(thenable));
1663 *result.get_private_data() = std::forward<TTHENABLE_PRIVATE_DATA>(private_data);
1664 result.start();
1665 return result;
1666 }
1667
1694 template <class TTHENABLE,
1695 class TTHENABLE_ERROR_TRANSFORM = typename thenable_error_transform_traits<TTHENABLE>::type>
1696 typename task_thenable_trait<TTHENABLE, void, TTHENABLE_ERROR_TRANSFORM>::task_thenable_type then(
1697 TTHENABLE&& thenable, std::nullptr_t) {
1698 using trait_type = typename task_thenable_trait<TTHENABLE, void, TTHENABLE_ERROR_TRANSFORM>::trait_type;
1699 auto result = trait_type::template invoke_task<void>(*this, std::forward<TTHENABLE>(thenable));
1700 result.start();
1701 return result;
1702 }
1703};
1704
1705// some
1706template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
1707struct LIBCOPP_COTASK_API_HEAD_ONLY some_delegate_task_action {
1708 using future_type = task_future<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>;
1709 using context_type = LIBCOPP_COPP_NAMESPACE_ID::some_delegate_context<future_type>;
1710
1711 inline static void suspend_future(const LIBCOPP_COPP_NAMESPACE_ID::promise_caller_manager::handle_delegate& caller,
1712 future_type& task_object) {
1713 if (task_object.get_context()) {
1714 task_object.get_context()->add_caller(caller);
1715 }
1716 }
1717
1718 inline static void resume_future(const LIBCOPP_COPP_NAMESPACE_ID::promise_caller_manager::handle_delegate& caller,
1719 future_type& task_object) {
1720 if (task_object.get_context()) {
1721 task_object.get_context()->remove_caller(caller);
1722 }
1723 }
1724
1725 inline static bool is_pending(future_type& future_object) noexcept { return !future_object.is_exiting(); }
1726};
1727
1728LIBCOPP_COTASK_NAMESPACE_END
1729
1730LIBCOPP_COPP_NAMESPACE_BEGIN
1731// some
1732template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
1733class LIBCOPP_COTASK_API_HEAD_ONLY some_delegate<cotask::task_future<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>>
1734 : public some_delegate_base<cotask::task_future<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>,
1735 cotask::some_delegate_task_action<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>> {
1736 public:
1737 using base_type = some_delegate_base<cotask::task_future<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>,
1738 cotask::some_delegate_task_action<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>>;
1739 using future_type = typename base_type::future_type;
1740 using value_type = typename base_type::value_type;
1741 using ready_output_type = typename base_type::ready_output_type;
1742 using context_type = typename base_type::context_type;
1743
1744 using base_type::run;
1745};
1746
1747LIBCOPP_COPP_NAMESPACE_END
1748
1749#endif
Definition task.h:38
int start(void *priv_data, EN_TASK_STATUS expected_status=EN_TS_CREATED) override
Definition task.h:523
#define LIBCOPP_UTIL_FORCEINLINE
#define LIBCOPP_UTIL_LIKELY_CONDITION(__C)
#define LIBCOPP_UTIL_UNLIKELY_CONDITION(__C)
#define LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE
Definition coroutine.h:41
锁管理器 Licensed under the MIT licenses.
auto operator==(const not_null< T > &lhs, const not_null< U > &rhs) noexcept(noexcept(lhs.get()==rhs.get())) -> decltype(lhs.get()==rhs.get())
Definition not_null.h:116
auto operator!=(const not_null< T > &lhs, const not_null< U > &rhs) noexcept(noexcept(lhs.get() !=rhs.get())) -> decltype(lhs.get() !=rhs.get())
Definition not_null.h:122
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
Definition span.h:54
LIBCOPP_UTIL_FORCEINLINE default_strong_rc_ptr< T > default_make_strong(ArgsT &&... args)
STL namespace.
assign_t< T > assign(T &t)
std::shared_ptr< cli::cmd_option_value > value_type
Definition cmd_option.h:50
自旋锁 Licensed under the MIT licenses.
class LIBCOPP_COTASK_API_HEAD_ONLY task_manager