5 #include <libcopp/utils/config/libcopp_build_features.h>
13 #include <type_traits>
15 #if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
27 #if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
29 LIBCOPP_COPP_NAMESPACE_BEGIN
31 template <
class TVALUE>
32 class LIBCOPP_COPP_API_HEAD_ONLY generator_context_base;
34 template <
class TVALUE,
class TERROR_TRANSFORM,
bool RETURN_VOID>
35 class LIBCOPP_COPP_API_HEAD_ONLY generator_context_delegate;
37 template <
class TVALUE,
class TERROR_TRANSFORM>
38 class LIBCOPP_COPP_API_HEAD_ONLY generator_context;
40 template <
class TVALUE,
class TERROR_TRANSFORM>
41 class LIBCOPP_COPP_API_HEAD_ONLY generator_future;
43 template <
class TPROMISE,
bool RETURN_VOID>
44 class LIBCOPP_COPP_API_HEAD_ONLY generator_awaitable;
46 template <
class TVALUE>
47 class LIBCOPP_COPP_API_HEAD_ONLY generator_context_base {
50 using handle_delegate = promise_caller_manager::handle_delegate;
53 generator_context_base(
const generator_context_base&) =
delete;
54 generator_context_base(generator_context_base&&) =
delete;
55 generator_context_base& operator=(
const generator_context_base&) =
delete;
56 generator_context_base& operator=(generator_context_base&&) =
delete;
59 generator_context_base() =
default;
60 ~generator_context_base() { wake(); }
69 UTIL_FORCEINLINE void add_caller(handle_delegate handle) noexcept { caller_manager_.add_caller(handle); }
71 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
72 template <DerivedPromiseBaseType TPROMISE>
74 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
78 add_caller(handle_delegate{handle});
81 UTIL_FORCEINLINE void remove_caller(handle_delegate handle) noexcept { caller_manager_.remove_caller(handle); }
83 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
84 template <DerivedPromiseBaseType TPROMISE>
86 template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
90 remove_caller(handle_delegate{handle}, inherit_status);
93 UTIL_FORCEINLINE bool has_multiple_callers()
const noexcept {
return caller_manager_.has_multiple_callers(); }
101 promise_caller_manager caller_manager_;
104 template <
class TVALUE,
class TERROR_TRANSFORM>
105 class LIBCOPP_COPP_API_HEAD_ONLY generator_context_delegate<TVALUE, TERROR_TRANSFORM, true>
106 :
public generator_context_base<TVALUE> {
108 using base_type = generator_context_base<TVALUE>;
112 template <
class... TARGS>
113 generator_context_delegate(TARGS&&... args) : base_type(std::forward<TARGS>(args)...) {}
115 ~generator_context_delegate() { wake(); }
117 using base_type::add_caller;
118 using base_type::is_pending;
119 using base_type::is_ready;
120 using base_type::remove_caller;
121 using base_type::reset_value;
126 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
127 std::exception_ptr unhandled_exception;
130 data_.reset_data(
true);
134 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
136 unhandled_exception = std::current_exception();
138 if (unhandled_exception) {
139 std::rethrow_exception(unhandled_exception);
145 using base_type::data_;
146 using base_type::wake;
149 template <
class TVALUE,
class TERROR_TRANSFORM>
150 class LIBCOPP_COPP_API_HEAD_ONLY generator_context_delegate<TVALUE, TERROR_TRANSFORM, false>
151 :
public generator_context_base<TVALUE> {
153 using base_type = generator_context_base<TVALUE>;
157 template <
class... TARGS>
158 generator_context_delegate(TARGS&&... args) : base_type(std::forward<TARGS>(args)...) {}
160 using base_type::add_caller;
161 using base_type::is_pending;
162 using base_type::is_ready;
163 using base_type::remove_caller;
164 using base_type::reset_value;
166 ~generator_context_delegate() {
168 set_value(TERROR_TRANSFORM()(promise_status::kKilled));
194 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
195 std::exception_ptr unhandled_exception;
198 data_.reset_data(std::forward<U>(in));
202 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
204 unhandled_exception = std::current_exception();
206 if (unhandled_exception) {
207 std::rethrow_exception(unhandled_exception);
213 using base_type::data_;
214 using base_type::wake;
217 template <
class TVALUE,
class TERROR_TRANSFORM>
218 class LIBCOPP_COPP_API_HEAD_ONLY generator_context
219 :
public generator_context_delegate<TVALUE, TERROR_TRANSFORM,
220 std::is_void<typename std::decay<TVALUE>::type>::value>,
221 public std::enable_shared_from_this<generator_context<TVALUE, TERROR_TRANSFORM>> {
224 generator_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value>;
226 using error_transform = TERROR_TRANSFORM;
229 template <
class... TARGS>
230 generator_context(TARGS&&... args) : base_type(std::forward<TARGS>(args)...) {}
232 using base_type::is_pending;
233 using base_type::is_ready;
234 using base_type::reset_value;
235 using base_type::set_value;
238 template <
class TCONTEXT>
239 class LIBCOPP_COPP_API_HEAD_ONLY generator_vtable {
241 using context_type = TCONTEXT;
242 using context_pointer_type = std::shared_ptr<context_type>;
244 using await_suspend_callback_type = std::function<void(context_pointer_type)>;
245 using await_resume_callback_type = std::function<void(
const context_type&)>;
248 template <
class TSUSPEND,
class TRESUME>
249 generator_vtable(TSUSPEND&& await_suspend_callback, TRESUME&& await_resume_callback)
250 : intrusive_ref_counter_(0),
251 await_suspend_callback_(std::forward<TSUSPEND>(await_suspend_callback)),
252 await_resume_callback_(std::forward<TRESUME>(await_resume_callback)) {}
254 template <
class TSUSPEND>
255 generator_vtable(TSUSPEND&& await_suspend_callback)
256 : intrusive_ref_counter_(0), await_suspend_callback_(std::forward<TSUSPEND>(await_suspend_callback)) {}
258 generator_vtable(
const generator_vtable&) =
delete;
259 generator_vtable(generator_vtable&&) =
delete;
260 generator_vtable& operator=(
const generator_vtable&) =
delete;
261 generator_vtable& operator=(generator_vtable&&) =
delete;
264 return await_suspend_callback_;
266 UTIL_FORCEINLINE await_suspend_callback_type& get_await_suspend_callback() noexcept {
267 return await_suspend_callback_;
270 return await_resume_callback_;
272 UTIL_FORCEINLINE await_resume_callback_type& get_await_resume_callback() noexcept {
return await_resume_callback_; }
275 friend void intrusive_ptr_add_ref(generator_vtable* p) {
277 ++p->intrusive_ref_counter_;
281 friend void intrusive_ptr_release(generator_vtable* p) {
285 assert(p->intrusive_ref_counter_ > 0);
286 size_t ref = --p->intrusive_ref_counter_;
292 size_t intrusive_ref_counter_;
293 await_suspend_callback_type await_suspend_callback_;
294 await_resume_callback_type await_resume_callback_;
297 template <
class TCONTEXT>
298 class LIBCOPP_COPP_API_HEAD_ONLY generator_awaitable_base :
public awaitable_base_type {
300 using context_type = TCONTEXT;
301 using context_pointer_type = std::shared_ptr<context_type>;
303 using vtable_type = generator_vtable<context_type>;
304 using await_suspend_callback_type =
typename vtable_type::await_suspend_callback_type;
305 using await_resume_callback_type =
typename vtable_type::await_resume_callback_type;
308 generator_awaitable_base(context_type* context,
const copp::util::intrusive_ptr<vtable_type>& vtable)
309 : context_{context}, vtable_(vtable) {}
311 inline bool await_ready() noexcept {
312 if (
nullptr == context_) {
316 return context_->is_ready();
319 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
320 template <DerivedPromiseBaseType TCPROMISE>
322 template <class TCPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TCPROMISE>::value>>
325 if (
nullptr != context_ && caller.promise().get_status() < promise_status::kDone) {
327 context_->add_caller(caller);
330 caller.promise().set_flag(promise_flag::kInternalWaitting,
true);
333 if (vtable_ && vtable_->get_await_suspend_callback()) {
334 vtable_->get_await_suspend_callback()(context_->shared_from_this());
346 promise_status detach() noexcept {
347 promise_status result_status;
349 result_status = promise_status::kInvalid;
350 }
else if (context_->is_ready()) {
351 result_status = promise_status::kDone;
353 result_status = promise_status::kKilled;
357 auto caller = get_caller();
360 if (
nullptr != caller.promise) {
361 caller.promise->set_flag(promise_flag::kInternalWaitting,
false);
363 if (
nullptr != context_) {
364 if (!context_->is_ready() &&
nullptr != caller.promise) {
365 result_status = caller.promise->get_status();
368 context_->remove_caller(caller);
372 if (vtable_ && vtable_->get_await_resume_callback()) {
373 vtable_->get_await_resume_callback()(*context_);
380 return result_status;
389 inline context_type* get_context() noexcept {
return context_; }
392 context_type* context_;
393 copp::util::intrusive_ptr<vtable_type> vtable_;
396 template <
class TCONTEXT>
397 class LIBCOPP_COPP_API_HEAD_ONLY generator_awaitable<TCONTEXT, true> :
public generator_awaitable_base<TCONTEXT> {
399 using base_type = generator_awaitable_base<TCONTEXT>;
401 using context_type =
typename base_type::context_type;
402 using context_pointer_type =
typename base_type::context_pointer_type;
403 using vtable_type =
typename base_type::vtable_type;
404 using await_suspend_callback_type =
typename base_type::await_suspend_callback_type;
405 using await_resume_callback_type =
typename base_type::await_resume_callback_type;
406 using error_transform =
typename context_type::error_transform;
409 using base_type::await_ready;
410 using base_type::await_suspend;
411 using base_type::get_caller;
412 using base_type::set_caller;
413 generator_awaitable(context_type* context,
const copp::util::intrusive_ptr<vtable_type>& vtable)
414 : base_type(context, vtable) {}
416 inline void await_resume() { detach(); }
419 using base_type::detach;
420 using base_type::get_context;
423 template <
class TCONTEXT>
424 class LIBCOPP_COPP_API_HEAD_ONLY generator_awaitable<TCONTEXT, false> :
public generator_awaitable_base<TCONTEXT> {
426 using base_type = generator_awaitable_base<TCONTEXT>;
428 using context_type =
typename base_type::context_type;
429 using context_pointer_type =
typename base_type::context_pointer_type;
430 using vtable_type =
typename base_type::vtable_type;
431 using await_suspend_callback_type =
typename base_type::await_suspend_callback_type;
432 using await_resume_callback_type =
typename base_type::await_resume_callback_type;
433 using error_transform =
typename context_type::error_transform;
436 using base_type::await_ready;
437 using base_type::await_suspend;
438 using base_type::get_caller;
439 using base_type::set_caller;
440 generator_awaitable(context_type* context,
const copp::util::intrusive_ptr<vtable_type>& vtable)
441 : base_type(context, vtable) {}
444 bool has_multiple_callers;
446 has_multiple_callers = get_context()->has_multiple_callers();
448 has_multiple_callers =
false;
450 promise_status result_status = detach();
452 if (promise_status::kDone != result_status) {
453 return error_transform()(result_status);
457 if (has_multiple_callers) {
458 return *get_context()->data();
460 return multiple_callers_constructor<value_type>::return_value(*get_context()->
data());
463 return error_transform()(promise_status::kInvalid);
468 using base_type::detach;
469 using base_type::get_context;
472 template <
class TVALUE,
class TERROR_TRANSFORM = promise_error_transform<TVALUE>>
473 class LIBCOPP_COPP_API_HEAD_ONLY generator_future {
476 using error_transform = TERROR_TRANSFORM;
477 using self_type = generator_future<value_type, error_transform>;
478 using context_type = generator_context<value_type, error_transform>;
479 using context_pointer_type = std::shared_ptr<context_type>;
480 using awaitable_type = generator_awaitable<context_type, std::is_void<typename std::decay<value_type>::type>::value>;
481 using vtable_type =
typename awaitable_type::vtable_type;
482 using await_suspend_callback_type =
typename awaitable_type::await_suspend_callback_type;
483 using await_resume_callback_type =
typename awaitable_type::await_resume_callback_type;
486 template <
class TSUSPEND,
class TRESUME>
487 generator_future(TSUSPEND&& await_suspend_callback, TRESUME&& await_resume_callback)
488 : context_(std::make_shared<context_type>()),
489 vtable_(new vtable_type(std::forward<TSUSPEND>(await_suspend_callback),
490 std::forward<TRESUME>(await_resume_callback))) {}
492 template <
class TSUSPEND>
493 generator_future(TSUSPEND&& await_suspend_callback)
494 : context_(std::make_shared<context_type>()),
495 vtable_(new vtable_type(std::forward<TSUSPEND>(await_suspend_callback))) {}
497 generator_future(generator_future&&) =
default;
498 generator_future(
const generator_future&) =
default;
499 generator_future& operator=(generator_future&&) =
default;
500 generator_future& operator=(
const generator_future&) =
default;
502 ~generator_future() {
508 awaitable_type
operator co_await() {
510 return awaitable_type{context_.get(), vtable_};
513 inline bool is_ready()
const noexcept {
518 return context_->is_ready();
521 inline bool is_pending()
const noexcept {
526 return context_->is_pending();
529 inline promise_status get_status()
const noexcept {
531 return promise_status::kInvalid;
534 if (context_->is_ready()) {
535 return promise_status::kDone;
538 return promise_status::kRunning;
541 UTIL_FORCEINLINE const std::shared_ptr<context_type>& get_context()
const noexcept {
return context_; }
543 UTIL_FORCEINLINE std::shared_ptr<context_type>& get_context() noexcept {
return context_; }
546 template <
class TFUTURE>
547 friend class LIBCOPP_COPP_API_HEAD_ONLY some_delegate;
549 template <
class TFUTURE,
class>
550 friend struct LIBCOPP_COPP_API_HEAD_ONLY some_delegate_generator_action;
552 std::shared_ptr<context_type> context_;
553 copp::util::intrusive_ptr<vtable_type> vtable_;
557 template <
class TVALUE,
class TERROR_TRANSFORM>
558 struct LIBCOPP_COPP_API_HEAD_ONLY some_delegate_generator_action {
559 using future_type = generator_future<TVALUE, TERROR_TRANSFORM>;
560 using context_type = some_delegate_context<future_type>;
562 inline static void suspend_future(
const promise_caller_manager::handle_delegate& caller, future_type& generator) {
563 generator.get_context()->add_caller(caller);
566 if (generator.vtable_ && generator.vtable_->get_await_suspend_callback()) {
567 generator.vtable_->get_await_suspend_callback()(generator.get_context());
571 inline static void resume_future(
const promise_caller_manager::handle_delegate& caller, future_type& generator) {
572 generator.get_context()->remove_caller(caller);
575 if (generator.vtable_ && generator.vtable_->get_await_resume_callback()) {
576 generator.vtable_->get_await_resume_callback()(*generator.get_context());
580 inline static bool is_pending(future_type& future_object) noexcept {
return future_object.is_pending(); }
583 template <
class TVALUE,
class TERROR_TRANSFORM>
584 class LIBCOPP_COPP_API_HEAD_ONLY some_delegate<generator_future<TVALUE, TERROR_TRANSFORM>>
585 :
public some_delegate_base<generator_future<TVALUE, TERROR_TRANSFORM>,
586 some_delegate_generator_action<TVALUE, TERROR_TRANSFORM>> {
588 using base_type = some_delegate_base<generator_future<TVALUE, TERROR_TRANSFORM>,
589 some_delegate_generator_action<TVALUE, TERROR_TRANSFORM>>;
590 using future_type =
typename base_type::future_type;
592 using ready_output_type =
typename base_type::ready_output_type;
593 using context_type =
typename base_type::context_type;
595 using base_type::run;
598 LIBCOPP_COPP_NAMESPACE_END
#define LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE
#define COPP_UNLIKELY_IF(...)
#define COPP_LIKELY_IF(...)
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
std::shared_ptr< cli::cmd_option_value > value_type