5 #include <libcopp/utils/config/libcopp_build_features.h>
11 #include <type_traits>
16 #if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
25 #if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
27 LIBCOPP_COPP_NAMESPACE_BEGIN
29 template <
class TFUTURE>
30 class LIBCOPP_COPP_API_HEAD_ONLY some_delegate;
32 template <
class TVALUE,
class TERROR_TRANSFORM>
33 class LIBCOPP_COPP_API_HEAD_ONLY callable_future;
35 template <
class TVALUE,
bool RETURN_VOID>
36 class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_base;
38 template <
class TPROMISE,
class TERROR_TRANSFORM,
bool RETURN_VOID>
39 class LIBCOPP_COPP_API_HEAD_ONLY callable_awaitable;
41 template <
class TVALUE>
42 class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_base<TVALUE, true> :
public promise_base_type {
46 template <
class... TARGS>
47 callable_promise_base(TARGS&&...) {}
49 callable_promise_base() =
default;
51 void return_void() noexcept {
52 set_flag(promise_flag::kHasReturned,
true);
53 if (get_status() < promise_status::kDone) {
54 set_status(promise_status::kDone);
59 template <
class TVALUE,
bool IS_DEFAULT_CONSTRUCTIBLE>
60 class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_value_constructor;
62 template <
class TVALUE>
63 class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_value_constructor<TVALUE, true> {
65 template <
class... TARGS>
66 inline static TVALUE construct(TARGS&&...) {
71 template <
class TVALUE>
72 class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_value_constructor<TVALUE, false> {
74 template <
class... TARGS>
75 inline static TVALUE construct(TARGS&&... args) {
76 return TVALUE{std::forward<TARGS>(args)...};
80 template <
class TVALUE>
81 class LIBCOPP_COPP_API_HEAD_ONLY callable_promise_base<TVALUE, false> :
public promise_base_type {
85 template <
class... TARGS>
86 callable_promise_base(TARGS&&... args)
87 : data_(callable_promise_value_constructor<
value_type, !std::is_constructible<
value_type, TARGS...>::value>::
88 construct(std::forward<TARGS>(args)...)) {}
91 set_flag(promise_flag::kHasReturned,
true);
92 if (get_status() < promise_status::kDone) {
93 set_status(promise_status::kDone);
95 data_ = std::move(value);
105 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
106 template <DerivedPromiseBaseType TPROMISE>
108 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
110 class LIBCOPP_COPP_API_HEAD_ONLY callable_awaitable_base :
public awaitable_base_type {
112 using promise_type = TPROMISE;
117 callable_awaitable_base(handle_type handle) : callee_{handle} {}
125 if (callee_.done()) {
129 if (callee_.promise().get_status() >= promise_status::kDone) {
133 if (callee_.promise().check_flag(promise_flag::kHasReturned)) {
137 return callee_.done();
140 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
141 template <DerivedPromiseBaseType TCPROMISE>
143 template <class TCPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TCPROMISE>::value>>
146 if (caller.promise().get_status() < promise_status::kDone) {
148 caller.promise().set_waiting_handle(callee_);
149 callee_.promise().add_caller(caller);
151 caller.promise().set_flag(promise_flag::kInternalWaitting,
true);
155 auto& callee_promise = get_callee().promise();
157 if (callee_promise.get_status() < promise_status::kDone &&
158 callee_promise.check_flag(promise_flag::kInternalWaitting)) {
159 callee_promise.set_status(caller.promise().get_status());
171 void detach() noexcept {
173 auto caller = get_caller();
174 auto& callee_promise = get_callee().promise();
177 if (
nullptr != caller.promise) {
178 caller.promise->set_flag(promise_flag::kInternalWaitting,
false);
179 caller.promise->set_waiting_handle(
nullptr);
181 callee_promise.remove_caller(caller,
true);
185 if (callee_promise.get_status() < promise_status::kDone) {
187 callee_promise.set_status(promise_status::kKilled);
189 callee_promise.set_status(caller.promise->get_status());
198 template <
class TPROMISE,
class TERROR_TRANSFORM>
199 class LIBCOPP_COPP_API_HEAD_ONLY callable_awaitable<TPROMISE, TERROR_TRANSFORM, true>
200 :
public callable_awaitable_base<TPROMISE> {
202 using base_type = callable_awaitable_base<TPROMISE>;
203 using promise_type =
typename base_type::promise_type;
205 using handle_type =
typename base_type::handle_type;
208 using base_type::await_ready;
209 using base_type::await_suspend;
210 using base_type::detach;
211 using base_type::get_callee;
212 using base_type::get_caller;
213 using base_type::set_caller;
214 callable_awaitable(handle_type handle) : base_type(handle) {}
218 get_callee().promise().resume_waiting(get_callee(),
true);
222 template <
class TPROMISE,
class TERROR_TRANSFORM>
223 class LIBCOPP_COPP_API_HEAD_ONLY callable_awaitable<TPROMISE, TERROR_TRANSFORM, false>
224 :
public callable_awaitable_base<TPROMISE> {
226 using base_type = callable_awaitable_base<TPROMISE>;
227 using promise_type =
typename base_type::promise_type;
229 using handle_type =
typename base_type::handle_type;
232 using base_type::await_ready;
233 using base_type::await_suspend;
234 using base_type::detach;
235 using base_type::get_callee;
236 using base_type::get_caller;
237 using base_type::set_caller;
238 callable_awaitable(handle_type handle) : base_type(handle) {}
242 auto& callee_promise = get_callee().promise();
243 callee_promise.resume_waiting(get_callee(),
true);
245 if (!callee_promise.check_flag(promise_flag::kHasReturned)) {
246 return TERROR_TRANSFORM()(callee_promise.get_status());
249 return std::move(callee_promise.data());
253 template <
class TVALUE,
class TERROR_TRANSFORM = promise_error_transform<TVALUE>>
254 class LIBCOPP_COPP_API_HEAD_ONLY callable_future {
257 using error_transform = TERROR_TRANSFORM;
258 using self_type = callable_future<value_type, error_transform>;
260 :
public callable_promise_base<value_type, std::is_void<typename std::decay<value_type>::type>::value> {
262 # if defined(__GNUC__) && !defined(__clang__)
263 template <
class... TARGS>
264 promise_type(TARGS&&... args)
265 : callable_promise_base<
value_type, std::is_void<typename std::decay<
value_type>::type>::value>(args...) {}
267 template <
class... TARGS>
268 promise_type(TARGS&&... args)
269 : callable_promise_base<
value_type, std::is_void<typename std::decay<
value_type>::type>::value>(
270 std::forward<TARGS>(args)...) {}
273 auto get_return_object() noexcept {
277 struct initial_awaitable {
278 inline bool await_ready()
const noexcept {
return false; }
280 inline void await_resume()
const noexcept {
281 if (handle.promise().get_status() == promise_status::kCreated) {
282 promise_status excepted = promise_status::kCreated;
283 handle.promise().set_status(promise_status::kRunning, &excepted);
296 initial_awaitable initial_suspend() noexcept {
return {}; }
297 # if defined(LIBCOPP_MACRO_ENABLE_EXCEPTION) && LIBCOPP_MACRO_ENABLE_EXCEPTION
298 void unhandled_exception() {
throw; }
299 # elif defined(LIBCOPP_MACRO_HAS_EXCEPTION) && LIBCOPP_MACRO_HAS_EXCEPTION
300 void unhandled_exception() {
throw; }
302 void unhandled_exception() { std::abort(); }
306 using awaitable_type =
307 callable_awaitable<promise_type, error_transform, std::is_void<typename std::decay<value_type>::type>::value>;
310 callable_future(handle_type handle) noexcept : current_handle_{handle} {}
312 callable_future(
const callable_future&) =
delete;
313 callable_future(callable_future&& other) noexcept {
314 current_handle_ = other.current_handle_;
315 other.current_handle_ =
nullptr;
318 callable_future& operator=(
const callable_future&) =
delete;
319 callable_future& operator=(callable_future&& other) noexcept {
320 current_handle_ = other.current_handle_;
321 other.current_handle_ =
nullptr;
327 handle_type current_handle = current_handle_;
328 current_handle_ =
nullptr;
330 while (current_handle && !current_handle.done() &&
331 !current_handle.promise().check_flag(promise_flag::kHasReturned)) {
332 if (current_handle.promise().get_status() < promise_status::kDone) {
333 current_handle.promise().set_status(promise_status::kKilled);
335 current_handle.resume();
338 if (current_handle) {
339 current_handle.promise().set_flag(promise_flag::kDestroying,
true);
340 current_handle.destroy();
344 awaitable_type
operator co_await() {
return awaitable_type{current_handle_}; }
346 inline bool is_ready()
const noexcept {
347 if (!current_handle_) {
351 return current_handle_.done() || current_handle_.promise().check_flag(promise_flag::kHasReturned);
354 UTIL_FORCEINLINE promise_status get_status()
const noexcept {
return current_handle_.promise().get_status(); }
356 static auto yield_status() noexcept {
return promise_base_type::pick_current_status(); }
366 bool kill(promise_status target_status = promise_status::kKilled,
bool force_resume =
false) noexcept {
367 if (target_status < promise_status::kDone) {
373 if (!current_handle_) {
378 if (current_handle_.done()) {
383 promise_status current_status = get_status();
384 if (current_status >= promise_status::kDone) {
389 if (!current_handle_.promise().set_status(target_status, ¤t_status)) {
393 if ((force_resume || current_handle_.promise().is_waiting()) &&
394 !current_handle_.promise().check_flag(promise_flag::kDestroying) &&
395 !current_handle_.promise().check_flag(promise_flag::kHasReturned)) {
398 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
399 std::exception_ptr unhandled_exception;
402 current_handle_.resume();
406 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
408 unhandled_exception = std::current_exception();
410 if (unhandled_exception) {
411 std::rethrow_exception(unhandled_exception);
435 UTIL_FORCEINLINE handle_type& get_internal_handle() noexcept {
return current_handle_; }
443 UTIL_FORCEINLINE const promise_type& get_internal_promise()
const noexcept {
return current_handle_.promise(); }
451 UTIL_FORCEINLINE promise_type& get_internal_promise() noexcept {
return current_handle_.promise(); }
454 handle_type current_handle_;
458 template <
class TFUTURE>
459 struct LIBCOPP_COPP_API_HEAD_ONLY some_delegate_context {
460 using future_type = TFUTURE;
461 using ready_output_type =
typename some_ready<future_type>::type;
463 std::list<future_type*> pending;
464 ready_output_type ready;
465 size_t ready_bound = 0;
466 size_t scan_bound = 0;
467 promise_status status = promise_status::kCreated;
468 promise_caller_manager::handle_delegate caller_handle = promise_caller_manager::handle_delegate(
nullptr);
471 template <
class TFUTURE,
class TDELEGATE_ACTION>
472 class LIBCOPP_COPP_API_HEAD_ONLY some_delegate_base {
474 using future_type = TFUTURE;
476 using context_type = some_delegate_context<future_type>;
477 using ready_output_type =
typename context_type::ready_output_type;
478 using delegate_action_type = TDELEGATE_ACTION;
481 static void force_resume_all(context_type& context) {
482 for (
auto& pending_future : context.pending) {
483 delegate_action_type::resume_future(context.caller_handle, *pending_future);
486 if (context.status < promise_status::kDone &&
nullptr != context.caller_handle.promise) {
487 context.status = context.caller_handle.promise->get_status();
490 context.caller_handle =
nullptr;
491 if (context.status < promise_status::kDone) {
492 context.status = promise_status::kKilled;
496 static void scan_ready(context_type& context) {
497 auto iter = context.pending.begin();
499 while (iter != context.pending.end()) {
500 if (delegate_action_type::is_pending(**iter)) {
504 future_type&
future = **iter;
506 iter = context.pending.erase(iter);
508 delegate_action_type::resume_future(context.caller_handle,
future);
513 class awaitable_type :
public awaitable_base_type {
515 awaitable_type(context_type* context) : context_(context) {}
517 inline bool await_ready() noexcept {
518 if (
nullptr == context_) {
522 if (context_->status >= promise_status::kDone) {
526 return context_->pending.empty();
529 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
530 template <DerivedPromiseBaseType TCPROMISE>
532 template <class TCPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TCPROMISE>::value>>
535 if (
nullptr == context_ || caller.promise().get_status() >= promise_status::kDone) {
544 caller.promise().set_flag(promise_flag::kInternalWaitting,
true);
547 if (!context_->caller_handle) {
548 context_->caller_handle = caller;
550 std::list<future_type*> copy_pending = context_->pending;
551 for (
auto& pending_future : copy_pending) {
552 delegate_action_type::suspend_future(context_->caller_handle, *pending_future);
559 void await_resume() {
561 auto caller = get_caller();
563 if (
nullptr != caller.promise) {
564 caller.promise->set_flag(promise_flag::kInternalWaitting,
false);
569 if (
nullptr == context_) {
573 ++context_->scan_bound;
574 if (context_->scan_bound >= context_->ready_bound) {
575 scan_ready(*context_);
576 context_->scan_bound = context_->ready.size();
578 if (context_->scan_bound >= context_->ready_bound && context_->status < promise_status::kDone) {
579 context_->status = promise_status::kDone;
585 context_type* context_;
589 struct promise_type {
590 context_type* context_;
592 promise_type(context_type* context) : context_(context) {}
593 promise_type(
const promise_type&) =
delete;
594 promise_type(promise_type&&) =
delete;
595 promise_type& operator=(
const promise_type&) =
delete;
596 promise_type& operator=(promise_type&&) =
delete;
598 COPP_LIKELY_IF (
nullptr != context_ && !!context_->caller_handle) {
599 force_resume_all(*context_);
603 inline awaitable_type
operator co_await() & {
return awaitable_type{context_}; }
606 template <
class TCONTAINER>
607 static callable_future<promise_status> run(ready_output_type& ready_futures,
size_t ready_count,
608 TCONTAINER* futures) {
609 using container_type =
typename std::decay<typename std::remove_pointer<TCONTAINER>::type>::type;
610 context_type context;
611 context.ready.reserve(
gsl::size(*futures));
613 for (
auto& future_object : *futures) {
615 pick_some_reference<
typename std::remove_reference<decltype(future_object)>::type>::unwrap(future_object);
616 if (delegate_action_type::is_pending(future_ref)) {
617 context.pending.push_back(&future_ref);
623 if (context.ready.size() >= ready_count) {
624 context.ready.swap(ready_futures);
625 co_return promise_status::kDone;
628 if (ready_count >= context.pending.size() + ready_futures.size()) {
629 ready_count = context.pending.size() + ready_futures.size();
631 context.ready_bound = ready_count;
632 context.scan_bound = context.ready.size();
633 context.status = promise_status::kRunning;
636 promise_type some_promise{&context};
637 while (context.status < promise_status::kDone) {
639 auto current_status = co_yield callable_future<promise_status>::yield_status();
640 if (current_status >= promise_status::kDone) {
641 context.status = current_status;
645 co_await some_promise;
651 context.ready.swap(ready_futures);
652 co_return context.status;
656 std::shared_ptr<context_type> context_;
660 template <
class TVALUE,
class TERROR_TRANSFORM>
661 struct LIBCOPP_COPP_API_HEAD_ONLY some_delegate_callable_action {
662 using future_type = callable_future<TVALUE, TERROR_TRANSFORM>;
663 using context_type = some_delegate_context<future_type>;
665 inline static void suspend_future(
const promise_caller_manager::handle_delegate& caller, future_type& callee) {
666 callee.get_internal_promise().add_caller(caller);
669 inline static void resume_future(
const promise_caller_manager::handle_delegate& caller, future_type& callee) {
670 callee.get_internal_promise().remove_caller(caller,
false);
674 inline static bool is_pending(future_type& future_object) noexcept {
675 auto future_status = future_object.get_status();
676 return future_status >= promise_status::kCreated && future_status < promise_status::kDone;
680 template <
class TVALUE,
class TERROR_TRANSFORM>
681 class LIBCOPP_COPP_API_HEAD_ONLY some_delegate<callable_future<TVALUE, TERROR_TRANSFORM>>
682 :
public some_delegate_base<callable_future<TVALUE, TERROR_TRANSFORM>,
683 some_delegate_callable_action<TVALUE, TERROR_TRANSFORM>> {
685 using base_type = some_delegate_base<callable_future<TVALUE, TERROR_TRANSFORM>,
686 some_delegate_callable_action<TVALUE, TERROR_TRANSFORM>>;
687 using future_type =
typename base_type::future_type;
689 using ready_output_type =
typename base_type::ready_output_type;
690 using context_type =
typename base_type::context_type;
692 using base_type::run;
695 LIBCOPP_COPP_NAMESPACE_END
#define LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE
#define COPP_LIKELY_IF(...)
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