9#include "QXmppGlobal.h"
18#if QXMPP_DEPRECATED_SINCE(1, 11)
22namespace QXmpp::Private {
26 std::conditional_t<std::is_void_v<T>, std::monostate, std::optional<T>> result;
27 std::coroutine_handle<> handle;
28 QPointer<const QObject> context;
29 bool finished =
false;
30 bool cancelled =
false;
31 bool hasContext =
false;
32 uint8_t promiseCount = 1;
36 Q_ASSERT(promiseCount == 0);
41struct ConstRefOrVoidHelper {
42 using Type =
const T &;
45struct ConstRefOrVoidHelper<void> {
50using ConstRefOrVoid = ConstRefOrVoidHelper<T>::Type;
52template<
typename Continuation,
typename T>
53struct InvokeContinuationResultHelper {
54 using Type = std::invoke_result_t<Continuation, T &&>;
56template<
typename Continuation>
57struct InvokeContinuationResultHelper<Continuation, void> {
58 using Type = std::invoke_result_t<Continuation>;
61template<
typename Continuation,
typename T>
62using InvokeContinuationResult = InvokeContinuationResultHelper<Continuation, T>::Type;
83 using SharedData = QXmpp::Private::TaskData<T>;
84 using SharedDataPtr = std::shared_ptr<SharedData>;
88 QPointer<const QObject> context;
89 std::coroutine_handle<> handle;
91 bool hasContext =
false;
95 QXmppPromise() : data(InlineData()) { }
102 sharedData().promiseCount += 1;
107 std::swap(data, p.data);
109 if (
auto *
task = inlineData().
task) {
110 task->setPromise(
this);
117 sharedData().promiseCount -= 1;
120 if (sharedData().promiseCount == 0) {
121 if (
auto handle = sharedData().handle) {
122 sharedData().handle =
nullptr;
127 if (
auto *
task = inlineData().
task) {
128 task->setPromise(
nullptr);
131 if (inlineData().handle) {
132 inlineData().handle.destroy();
142 sharedData().promiseCount -= 1;
147 sharedData().promiseCount += 1;
154 std::swap(data, p.data);
156 if (
auto *
task = inlineData().
task) {
157 task->setPromise(
this);
170 if (inlineData().
task ==
nullptr) {
171 return Task {
this };
176 return Task { std::get<SharedDataPtr>(data) };
185 requires(std::is_void_v<T>)
188 sharedData().finished =
true;
190 if (
auto *
task = inlineData().
task) {
191 task->inlineData().finished =
true;
195 sharedData().finished =
true;
208 requires(!std::is_void_v<T>)
211 sharedData().finished =
true;
212 sharedData().result = std::forward<U>(value);
214 if (
auto *
task = inlineData().
task) {
215 inlineData().task->inlineData().finished =
true;
216 inlineData().task->inlineData().result = std::forward<U>(value);
220 sharedData().finished =
true;
221 sharedData().result = std::forward<U>(value);
236 return shared() ? sharedData().cancelled : inlineData().cancelled;
242 bool shared()
const {
return std::holds_alternative<SharedDataPtr>(data); }
243 InlineData &inlineData()
246 return std::get<InlineData>(data);
248 const InlineData &inlineData()
const
251 return std::get<InlineData>(data);
253 SharedData &sharedData()
256 return *std::get<SharedDataPtr>(data);
258 const SharedData &sharedData()
const
261 return *std::get<SharedDataPtr>(data);
264 bool contextAlive()
const
267 return sharedData().context !=
nullptr || !sharedData().hasContext;
269 return inlineData().context !=
nullptr || !inlineData().hasContext;
275 auto &handleRef = shared() ? sharedData().handle : inlineData().handle;
276 if (
auto handle = handleRef) {
278 if (contextAlive()) {
289 void detachData()
const
295 if (inlineData().
task !=
nullptr) {
296 auto &taskData = inlineData().task->inlineData();
298 auto sharedData = std::make_shared<SharedData>(
299 std::move(taskData.result),
301 inlineData().context,
304 inlineData().hasContext,
306 inlineData().task->data = sharedData;
307 data = std::move(sharedData);
309 data = std::make_shared<SharedData>();
313 mutable std::variant<InlineData, SharedDataPtr> data;
332 using SharedData = QXmpp::Private::TaskData<T>;
333 using SharedDataPtr = std::shared_ptr<SharedData>;
337 std::conditional_t<std::is_void_v<T>, std::monostate, std::optional<T>>
result;
338 bool finished =
false;
345 std::swap(data, t.data);
347 if (
auto *p = inlineData().promise) {
348 p->inlineData().task =
this;
356 if (
auto *p = inlineData().promise) {
357 p->inlineData().task =
nullptr;
367 if (
auto *p = inlineData().promise) {
368 p->inlineData().task =
nullptr;
370 inlineData().promise =
nullptr;
373 std::swap(data, t.data);
376 if (
auto *p = inlineData().promise) {
377 p->inlineData().task =
this;
385 bool await_ready() const noexcept {
return isFinished(); }
386 void await_suspend(std::coroutine_handle<> handle)
388 auto replace = [](
auto &var,
auto newValue) {
396 if (sharedData().promiseCount > 0 && !sharedData().cancelled) {
397 replace(sharedData().handle, handle);
402 if (
auto *p = inlineData().promise; p && !p->cancelled()) {
403 replace(p->inlineData().handle, handle);
411 if constexpr (!std::is_void_v<T>) {
448 template<
typename Continuation>
449 auto then(
const QObject *context, Continuation continuation)
453 if constexpr (std::is_void_v<T>) {
475 if (!sharedData().finished) {
476 sharedData().context = c;
477 sharedData().hasContext =
true;
480 if (
auto *p = inlineData().promise) {
481 p->inlineData().context = c;
482 p->inlineData().hasContext =
true;
499 sharedData().cancelled =
true;
500 if (
auto handle = sharedData().handle) {
501 sharedData().handle =
nullptr;
505 if (
auto *p = inlineData().promise) {
506 p->inlineData().cancelled =
true;
507 if (
auto handle = p->inlineData().handle) {
508 p->inlineData().handle =
nullptr;
524 return shared() ? sharedData().finished : inlineData().finished;
532 requires(!std::is_void_v<T>)
534 return shared() ? sharedData().result.has_value() : inlineData().result.has_value();
543 QXmpp::Private::ConstRefOrVoid<T>
result() const
544 requires(!std::is_void_v<T>)
548 return shared() ? sharedData().result.value() : inlineData().result.value();
558 requires(!std::is_void_v<T>)
562 auto &
result = shared() ? sharedData().result : inlineData().result;
564 auto value = std::move(*
result);
575 QFutureInterface<T> interface;
577 if constexpr (std::is_same_v<T, void>) {
578 then(context, [interface]()
mutable {
579 interface.reportFinished();
582 then(context, [interface](T &&val)
mutable {
583 interface.reportResult(val);
584 interface.reportFinished();
588 return interface.future();
596 inlineData().promise = p;
598 Q_ASSERT(p->inlineData().task ==
nullptr);
599 p->inlineData().task =
this;
601 explicit QXmppTask(SharedDataPtr data) : data(std::move(data)) { }
603 bool shared()
const {
return std::holds_alternative<SharedDataPtr>(data); }
604 InlineData &inlineData()
607 return std::get<InlineData>(data);
609 const InlineData &inlineData()
const
612 return std::get<InlineData>(data);
614 SharedData &sharedData()
617 return *std::get<SharedDataPtr>(data);
619 const SharedData &sharedData()
const
622 return *std::get<SharedDataPtr>(data);
625 void setPromise(QXmppPromise<T> *p)
627 inlineData().promise = p;
630 std::variant<InlineData, SharedDataPtr> data;
635template<
typename T,
typename... Args>
636struct coroutine_traits<QXmppTask<T>, Args...> {
637 struct promise_type {
640 QXmppTask<T> get_return_object() {
return p.
task(); }
641 std::suspend_never initial_suspend() noexcept {
return {}; }
642 std::suspend_never final_suspend() noexcept {
return {}; }
644 void unhandled_exception()
647 throw std::current_exception();
650 void return_value(T value) { p.finish(std::move(value)); }
654template<
typename... Args>
655struct coroutine_traits<QXmppTask<void>, Args...> {
656 struct promise_type {
657 QXmppPromise<void> p;
659 QXmppTask<void> get_return_object() {
return p.task(); }
660 std::suspend_never initial_suspend() noexcept {
return {}; }
661 std::suspend_never final_suspend() noexcept {
return {}; }
663 void unhandled_exception()
666 throw std::current_exception();
669 void return_void() { p.finish(); }
681 constexpr static bool Value =
false;
684struct IsTaskHelper<QXmppTask<T>> {
686 constexpr static bool Value =
true;
697concept IsTask = Private::IsTaskHelper<T>::Value;
Create and update QXmppTask objects to communicate results of asynchronous operations.
Definition QXmppTask.h:81
QXmppTask< T > task()
Definition QXmppTask.h:167
QXmppPromise< T > & operator=(const QXmppPromise< T > &p)
Definition QXmppTask.h:139
bool cancelled() const
Definition QXmppTask.h:234
QXmppPromise< T > & operator=(QXmppPromise< T > &&p)
Move assignment operator.
Definition QXmppTask.h:152
void finish(U &&value)
Definition QXmppTask.h:207
void finish()
Definition QXmppTask.h:184
QXmppPromise(const QXmppPromise< T > &p)
Definition QXmppTask.h:98
QXmppPromise(QXmppPromise< T > &&p)
Move constructor.
Definition QXmppTask.h:105
Definition QXmppTask.h:330
auto then(const QObject *context, Continuation continuation) -> QXmppTask< QXmpp::Private::InvokeContinuationResult< Continuation, T > >
Definition QXmppTask.h:449
QXmppTask(QXmppTask &&t)
Move constructor.
Definition QXmppTask.h:343
QXmppTask & operator=(QXmppTask &&t) noexcept
Move assignment operator.
Definition QXmppTask.h:363
T takeResult()
Definition QXmppTask.h:557
bool hasResult() const
Definition QXmppTask.h:531
QXmppTask< T > & withContext(const QObject *c)
Definition QXmppTask.h:472
QFuture< T > toFuture(const QObject *context)
Definition QXmppTask.h:573
QXmpp::Private::ConstRefOrVoid< T > result() const
Definition QXmppTask.h:543
void cancel()
Definition QXmppTask.h:496
bool isFinished() const
Definition QXmppTask.h:522
Definition QXmppTask.h:697
Definition Algorithms.h:14
typename Private::IsTaskHelper< T >::Type TaskValueType
Definition QXmppTask.h:705