5#include <libcopp/utils/config/libcopp_build_features.h>
16#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
26#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
28LIBCOPP_COPP_NAMESPACE_BEGIN
30template <
class TFUTURE>
31class LIBCOPP_COPP_API_HEAD_ONLY some_delegate;
33template <
class TVALUE,
class TERROR_TRANSFORM>
34class LIBCOPP_COPP_API_HEAD_ONLY callable_future;
36template <
class TVALUE,
bool RETURN_VOID>
37class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_base;
39template <
class TPROMISE,
class TERROR_TRANSFORM,
bool RETURN_VOID>
40class LIBCOPP_COPP_API_HEAD_ONLY callable_awaitable;
42template <
class TVALUE>
43class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_base<TVALUE, true> :
public promise_base_type {
47 template <
class... TARGS>
48 callable_promise_base(TARGS&&...) {}
50 callable_promise_base() =
default;
52 void return_void() noexcept {
53 set_flag(promise_flag::kHasReturned,
true);
54 if (get_status() < promise_status::kDone) {
55 set_status(promise_status::kDone);
60template <
class TVALUE,
bool IS_DEFAULT_CONSTRUCTIBLE>
61class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_value_constructor;
63template <
class TVALUE>
64class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_value_constructor<TVALUE, true> {
66 template <
class... TARGS>
67 inline static TVALUE construct(TARGS&&...) {
72template <
class TVALUE>
73class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_value_constructor<TVALUE, false> {
75 template <
class... TARGS>
76 inline static TVALUE construct(TARGS&&... args) {
77 return TVALUE{std::forward<TARGS>(args)...};
81template <
class TVALUE>
82class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_base<TVALUE, false> :
public promise_base_type {
86 template <
class... TARGS>
87 callable_promise_base(TARGS&&... args)
89 construct(
std::forward<TARGS>(args)...)) {}
91 void return_value(value_type value) {
92 set_flag(promise_flag::kHasReturned,
true);
93 if (get_status() < promise_status::kDone) {
94 set_status(promise_status::kDone);
96 data_ = std::move(value);
106# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
107template <DerivedPromiseBaseType TPROMISE>
109template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
111class LIBCOPP_COPP_API_HEAD_ONLY callable_awaitable_base :
public awaitable_base_type {
113 using promise_type = TPROMISE;
114 using value_type =
typename promise_type::value_type;
118 callable_awaitable_base(handle_type handle) : callee_{handle} {}
126 if (callee_.done()) {
130 if (callee_.promise().get_status() >= promise_status::kDone) {
134 if (callee_.promise().check_flag(promise_flag::kHasReturned)) {
138 return callee_.done();
141# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
142 template <DerivedPromiseBaseType TCPROMISE>
144 template <class TCPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TCPROMISE>::value>>
147 if (caller.promise().get_status() < promise_status::kDone) {
149 caller.promise().set_waiting_handle(callee_);
150 callee_.promise().add_caller(caller);
152 caller.promise().set_flag(promise_flag::kInternalWaitting,
true);
156 auto& callee_promise = get_callee().promise();
158 if (callee_promise.get_status() < promise_status::kDone &&
159 callee_promise.check_flag(promise_flag::kInternalWaitting)) {
160 callee_promise.set_status(caller.promise().get_status());
172 void detach() noexcept {
174 auto caller = get_caller();
175 auto& callee_promise = get_callee().promise();
178 if (
nullptr != caller.promise) {
179 caller.promise->set_flag(promise_flag::kInternalWaitting,
false);
180 caller.promise->set_waiting_handle(
nullptr);
182 callee_promise.remove_caller(caller,
true);
186 if (callee_promise.get_status() < promise_status::kDone) {
188 callee_promise.set_status(promise_status::kKilled);
190 callee_promise.set_status(caller.promise->get_status());
199template <
class TPROMISE,
class TERROR_TRANSFORM>
200class LIBCOPP_COPP_API_HEAD_ONLY callable_awaitable<TPROMISE, TERROR_TRANSFORM, true>
201 :
public callable_awaitable_base<TPROMISE> {
203 using base_type = callable_awaitable_base<TPROMISE>;
204 using promise_type =
typename base_type::promise_type;
205 using value_type =
typename base_type::value_type;
206 using handle_type =
typename base_type::handle_type;
209 using base_type::await_ready;
210 using base_type::await_suspend;
211 using base_type::detach;
212 using base_type::get_callee;
213 using base_type::get_caller;
214 using base_type::set_caller;
215 callable_awaitable(handle_type handle) : base_type(handle) {}
219 get_callee().promise().resume_waiting(get_callee(),
true);
223template <
class TPROMISE,
class TERROR_TRANSFORM>
224class LIBCOPP_COPP_API_HEAD_ONLY callable_awaitable<TPROMISE, TERROR_TRANSFORM, false>
225 :
public callable_awaitable_base<TPROMISE> {
227 using base_type = callable_awaitable_base<TPROMISE>;
228 using promise_type =
typename base_type::promise_type;
229 using value_type =
typename base_type::value_type;
230 using handle_type =
typename base_type::handle_type;
233 using base_type::await_ready;
234 using base_type::await_suspend;
235 using base_type::detach;
236 using base_type::get_callee;
237 using base_type::get_caller;
238 using base_type::set_caller;
239 callable_awaitable(handle_type handle) : base_type(handle) {}
243 auto& callee_promise = get_callee().promise();
244 callee_promise.resume_waiting(get_callee(),
true);
246 if (!callee_promise.check_flag(promise_flag::kHasReturned)) {
247 return TERROR_TRANSFORM()(callee_promise.get_status());
250 return std::move(callee_promise.data());
254template <
class TVALUE,
class TERROR_TRANSFORM = promise_error_transform<TVALUE>>
255class LIBCOPP_COPP_API_HEAD_ONLY callable_future {
258 using error_transform = TERROR_TRANSFORM;
259 using self_type = callable_future<value_type, error_transform>;
261 :
public callable_promise_base<value_type, std::is_void<typename std::decay<value_type>::type>::value> {
263# if defined(__GNUC__) && !defined(__clang__)
264 template <
class... TARGS>
265 promise_type(TARGS&&... args)
268 template <
class... TARGS>
269 promise_type(TARGS&&... args)
271 std::forward<TARGS>(args)...) {}
274 auto get_return_object() noexcept {
278 struct initial_awaitable {
279 inline bool await_ready() const noexcept {
return false; }
281 inline void await_resume() const noexcept {
282 if (handle.promise().get_status() == promise_status::kCreated) {
283 promise_status excepted = promise_status::kCreated;
284 handle.promise().set_status(promise_status::kRunning, &excepted);
297 initial_awaitable initial_suspend() noexcept {
return {}; }
298# if defined(LIBCOPP_MACRO_ENABLE_EXCEPTION) && LIBCOPP_MACRO_ENABLE_EXCEPTION
299 void unhandled_exception() {
throw; }
301 void unhandled_exception() { std::abort(); }
305 using awaitable_type =
306 callable_awaitable<promise_type, error_transform, std::is_void<typename std::decay<value_type>::type>::value>;
309 callable_future(handle_type handle) noexcept : current_handle_{handle} {}
311 callable_future(
const callable_future&) =
delete;
312 callable_future(callable_future&& other)
noexcept {
313 current_handle_ = other.current_handle_;
314 other.current_handle_ =
nullptr;
317 callable_future& operator=(
const callable_future&) =
delete;
318 callable_future& operator=(callable_future&& other)
noexcept {
319 current_handle_ = other.current_handle_;
320 other.current_handle_ =
nullptr;
326 handle_type current_handle = current_handle_;
327 current_handle_ =
nullptr;
329 while (current_handle && !current_handle.done() &&
330 !current_handle.promise().check_flag(promise_flag::kHasReturned)) {
331 if (current_handle.promise().get_status() < promise_status::kDone) {
332 current_handle.promise().set_status(promise_status::kKilled);
334 current_handle.resume();
337 if (current_handle) {
338 current_handle.promise().set_flag(promise_flag::kDestroying,
true);
339 current_handle.destroy();
343 awaitable_type
operator co_await() {
return awaitable_type{current_handle_}; }
345 inline bool is_ready() const noexcept {
346 if (!current_handle_) {
350 return current_handle_.done() || current_handle_.promise().check_flag(promise_flag::kHasReturned);
353 LIBCOPP_UTIL_FORCEINLINE promise_status get_status() const noexcept {
return current_handle_.promise().get_status(); }
355 static auto yield_status() noexcept {
return promise_base_type::pick_current_status(); }
365 bool kill(promise_status target_status = promise_status::kKilled,
bool force_resume =
false) noexcept {
366 if (target_status < promise_status::kDone) {
372 if (!current_handle_) {
377 if (current_handle_.done()) {
382 promise_status current_status = get_status();
383 if (current_status >= promise_status::kDone) {
388 if (!current_handle_.promise().set_status(target_status, ¤t_status)) {
392 if ((force_resume || current_handle_.promise().is_waiting()) &&
393 !current_handle_.promise().check_flag(promise_flag::kDestroying) &&
394 !current_handle_.promise().check_flag(promise_flag::kHasReturned)) {
397# if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
398 std::exception_ptr unhandled_exception;
401 current_handle_.resume();
405# if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
407 unhandled_exception = std::current_exception();
409 if (unhandled_exception) {
410 std::rethrow_exception(unhandled_exception);
443 return current_handle_.promise();
455 handle_type current_handle_;
459template <
class TFUTURE>
460struct LIBCOPP_COPP_API_HEAD_ONLY some_delegate_context {
461 using future_type = TFUTURE;
462 using ready_output_type =
typename some_ready<future_type>::type;
464 std::list<future_type*> pending;
465 ready_output_type ready;
466 size_t ready_bound = 0;
467 size_t scan_bound = 0;
468 promise_status status = promise_status::kCreated;
469 promise_caller_manager::handle_delegate caller_handle = promise_caller_manager::handle_delegate(
nullptr);
472template <
class TFUTURE,
class TDELEGATE_ACTION>
473class LIBCOPP_COPP_API_HEAD_ONLY some_delegate_base {
475 using future_type = TFUTURE;
476 using value_type =
typename future_type::value_type;
477 using context_type = some_delegate_context<future_type>;
478 using ready_output_type =
typename context_type::ready_output_type;
479 using delegate_action_type = TDELEGATE_ACTION;
482 static void force_resume_all(context_type& context) {
483 for (
auto& pending_future : context.pending) {
484 delegate_action_type::resume_future(context.caller_handle, *pending_future);
487 if (context.status < promise_status::kDone &&
nullptr != context.caller_handle.promise) {
488 context.status = context.caller_handle.promise->get_status();
491 context.caller_handle =
nullptr;
492 if (context.status < promise_status::kDone) {
493 context.status = promise_status::kKilled;
497 static void scan_ready(context_type& context) {
498 auto iter = context.pending.begin();
500 while (iter != context.pending.end()) {
501 if (delegate_action_type::is_pending(**iter)) {
505 future_type&
future = **iter;
507 iter = context.pending.erase(iter);
509 delegate_action_type::resume_future(context.caller_handle,
future);
514 class awaitable_type :
public awaitable_base_type {
516 awaitable_type(context_type* context) : context_(context) {}
518 inline bool await_ready() noexcept {
519 if (
nullptr == context_) {
523 if (context_->status >= promise_status::kDone) {
527 return context_->pending.empty();
530# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
531 template <DerivedPromiseBaseType TCPROMISE>
533 template <class TCPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TCPROMISE>::value>>
536 if (
nullptr == context_ || caller.promise().get_status() >= promise_status::kDone) {
545 caller.promise().set_flag(promise_flag::kInternalWaitting,
true);
548 if (!context_->caller_handle) {
549 context_->caller_handle = caller;
551 std::list<future_type*> copy_pending = context_->pending;
552 for (
auto& pending_future : copy_pending) {
553 delegate_action_type::suspend_future(context_->caller_handle, *pending_future);
560 void await_resume() {
562 auto caller = get_caller();
564 if (
nullptr != caller.promise) {
565 caller.promise->set_flag(promise_flag::kInternalWaitting,
false);
570 if (
nullptr == context_) {
574 ++context_->scan_bound;
575 if (context_->scan_bound >= context_->ready_bound) {
576 scan_ready(*context_);
577 context_->scan_bound = context_->ready.size();
579 if (context_->scan_bound >= context_->ready_bound && context_->status < promise_status::kDone) {
580 context_->status = promise_status::kDone;
586 context_type* context_;
590 struct promise_type {
591 context_type* context_;
593 promise_type(context_type* context) : context_(context) {}
594 promise_type(
const promise_type&) =
delete;
595 promise_type(promise_type&&) =
delete;
596 promise_type& operator=(
const promise_type&) =
delete;
597 promise_type& operator=(promise_type&&) =
delete;
600 force_resume_all(*context_);
604 inline awaitable_type
operator co_await() & {
return awaitable_type{context_}; }
607 template <
class TCONTAINER>
608 static callable_future<promise_status> run(ready_output_type& ready_futures,
size_t ready_count,
609 TCONTAINER* futures) {
610 using container_type =
typename std::decay<typename std::remove_pointer<TCONTAINER>::type>::type;
611 context_type context;
612 context.ready.reserve(
gsl::size(*futures));
614 for (
auto& future_object : *futures) {
616 pick_some_reference<
typename std::remove_reference<
decltype(future_object)>::type>::unwrap(future_object);
617 if (delegate_action_type::is_pending(future_ref)) {
618 context.pending.push_back(&future_ref);
624 if (context.ready.size() >= ready_count) {
625 context.ready.swap(ready_futures);
626 co_return promise_status::kDone;
629 if (ready_count >= context.pending.size() + ready_futures.size()) {
630 ready_count = context.pending.size() + ready_futures.size();
632 context.ready_bound = ready_count;
633 context.scan_bound = context.ready.size();
634 context.status = promise_status::kRunning;
637 promise_type some_promise{&context};
638 while (context.status < promise_status::kDone) {
640 auto current_status =
co_yield callable_future<promise_status>::yield_status();
641 if (current_status >= promise_status::kDone) {
642 context.status = current_status;
646 co_await some_promise;
652 context.ready.swap(ready_futures);
653 co_return context.status;
657 LIBCOPP_COPP_NAMESPACE_ID::memory::default_strong_rc_ptr<context_type> context_;
661template <
class TVALUE,
class TERROR_TRANSFORM>
662struct LIBCOPP_COPP_API_HEAD_ONLY some_delegate_callable_action {
663 using future_type = callable_future<TVALUE, TERROR_TRANSFORM>;
664 using context_type = some_delegate_context<future_type>;
666 inline static void suspend_future(
const promise_caller_manager::handle_delegate& caller, future_type& callee) {
667 callee.get_internal_promise().add_caller(caller);
670 inline static void resume_future(
const promise_caller_manager::handle_delegate& caller, future_type& callee) {
671 callee.get_internal_promise().remove_caller(caller,
false);
675 inline static bool is_pending(future_type& future_object)
noexcept {
676 auto future_status = future_object.get_status();
677 return future_status >= promise_status::kCreated && future_status < promise_status::kDone;
681template <
class TVALUE,
class TERROR_TRANSFORM>
682class LIBCOPP_COPP_API_HEAD_ONLY some_delegate<callable_future<TVALUE, TERROR_TRANSFORM>>
683 :
public some_delegate_base<callable_future<TVALUE, TERROR_TRANSFORM>,
684 some_delegate_callable_action<TVALUE, TERROR_TRANSFORM>> {
686 using base_type = some_delegate_base<callable_future<TVALUE, TERROR_TRANSFORM>,
687 some_delegate_callable_action<TVALUE, TERROR_TRANSFORM>>;
688 using future_type =
typename base_type::future_type;
689 using value_type =
typename base_type::value_type;
690 using ready_output_type =
typename base_type::ready_output_type;
691 using context_type =
typename base_type::context_type;
693 using base_type::run;
696LIBCOPP_COPP_NAMESPACE_END
#define LIBCOPP_UTIL_FORCEINLINE
#define LIBCOPP_UTIL_LIKELY_CONDITION(__C)
#define LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE
auto make_not_null(T &&t) noexcept
constexpr auto size(TCONTAINER &&container) -> decltype(container.size())
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
std::shared_ptr< cli::cmd_option_value > value_type