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;
90 bool cancelled =
false;
91 bool hasContext =
false;
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.emplace(std::forward<U>(value));
214 if (
auto *
task = inlineData().
task) {
215 inlineData().task->inlineData().finished =
true;
216 inlineData().task->inlineData().result.emplace(std::forward<U>(value));
220 sharedData().finished =
true;
221 sharedData().result.emplace(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>) {
452 template<
typename Continuation>
453 auto then(
const QObject *context, Continuation continuation)
456 using Result = QXmpp::Private::InvokeContinuationResult<Continuation, T>;
458 if constexpr (std::is_void_v<T>) {
460 if constexpr (std::is_void_v<Result>) {
463 co_return continuation();
466 if constexpr (std::is_void_v<Result>) {
469 co_return continuation(
co_await task.
withContext(context));
488 if (!sharedData().finished) {
489 sharedData().context = c;
490 sharedData().hasContext =
true;
493 if (
auto *p = inlineData().promise) {
494 p->inlineData().context = c;
495 p->inlineData().hasContext =
true;
512 sharedData().cancelled =
true;
513 if (
auto handle = sharedData().handle) {
514 sharedData().handle =
nullptr;
518 if (
auto *p = inlineData().promise) {
519 p->inlineData().cancelled =
true;
520 if (
auto handle = p->inlineData().handle) {
521 p->inlineData().handle =
nullptr;
537 return shared() ? sharedData().finished : inlineData().finished;
545 requires(!std::is_void_v<T>)
547 return shared() ? sharedData().result.has_value() : inlineData().result.has_value();
556 QXmpp::Private::ConstRefOrVoid<T>
result() const
557 requires(!std::is_void_v<T>)
561 return shared() ? sharedData().result.value() : inlineData().result.value();
571 requires(!std::is_void_v<T>)
575 auto &
result = shared() ? sharedData().result : inlineData().result;
577 auto value = std::move(*
result);
588 QFutureInterface<T> interface;
590 if constexpr (std::is_same_v<T, void>) {
591 then(context, [interface]()
mutable {
592 interface.reportFinished();
595 then(context, [interface](T &&val)
mutable {
596 interface.reportResult(val);
597 interface.reportFinished();
601 return interface.future();
609 inlineData().promise = p;
611 Q_ASSERT(p->inlineData().task ==
nullptr);
612 p->inlineData().task =
this;
614 explicit QXmppTask(SharedDataPtr data) : data(std::move(data)) { }
616 bool shared()
const {
return std::holds_alternative<SharedDataPtr>(data); }
617 InlineData &inlineData()
620 return std::get<InlineData>(data);
622 const InlineData &inlineData()
const
625 return std::get<InlineData>(data);
627 SharedData &sharedData()
630 return *std::get<SharedDataPtr>(data);
632 const SharedData &sharedData()
const
635 return *std::get<SharedDataPtr>(data);
640 inlineData().promise = p;
643 std::variant<InlineData, SharedDataPtr> data;
648template<
typename T,
typename... Args>
649struct coroutine_traits<
QXmppTask<T>, Args...> {
650 struct promise_type {
654 std::suspend_never initial_suspend() noexcept {
return {}; }
655 std::suspend_never final_suspend() noexcept {
return {}; }
657 void unhandled_exception()
660 throw std::current_exception();
663 void return_value(T value) { p.finish(std::move(value)); }
667template<
typename... Args>
668struct coroutine_traits<
QXmppTask<void>, Args...> {
669 struct promise_type {
673 std::suspend_never initial_suspend() noexcept {
return {}; }
674 std::suspend_never final_suspend() noexcept {
return {}; }
676 void unhandled_exception()
679 throw std::current_exception();
682 void return_void() { p.finish(); }
694 constexpr static bool Value =
false;
699 constexpr static bool Value =
true;
710concept 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:453
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:570
bool hasResult() const
Definition QXmppTask.h:544
QXmppTask< T > & withContext(const QObject *c)
Definition QXmppTask.h:485
QFuture< T > toFuture(const QObject *context)
Definition QXmppTask.h:586
QXmpp::Private::ConstRefOrVoid< T > result() const
Definition QXmppTask.h:556
void cancel()
Definition QXmppTask.h:509
bool isFinished() const
Definition QXmppTask.h:535
Definition QXmppTask.h:710
Definition Algorithms.h:14
typename Private::IsTaskHelper< T >::Type TaskValueType
Definition QXmppTask.h:718