Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qfuture_impl.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#ifndef QFUTURE_H
6#error Do not include qfuture_impl.h directly
7#endif
8
9#if 0
10#pragma qt_sync_skip_header_check
11#pragma qt_sync_stop_processing
12#endif
13
14#include <QtCore/qglobal.h>
15#include <QtCore/qfunctionaltools_impl.h>
16#include <QtCore/qfutureinterface.h>
17#include <QtCore/qthreadpool.h>
18#include <QtCore/qexception.h>
19#include <QtCore/qpromise.h>
20#include <QtCore/qvariant.h>
21
22#include <memory>
23
24QT_BEGIN_NAMESPACE
25
26//
27// forward declarations
28//
29template<class T>
30class QFuture;
31template<class T>
33template<class T>
34class QPromise;
35
36namespace QtFuture {
37
38enum class Launch { Sync, Async, Inherit };
39
40template<class T>
46
47// Deduction guide
48template<class T>
49WhenAnyResult(qsizetype, const QFuture<T> &) -> WhenAnyResult<T>;
50}
51
52namespace QtPrivate {
53
54// implemented in qfutureinterface.cpp
55Q_CORE_EXPORT void qfutureWarnIfUnusedResults(qsizetype numResults);
56
57template<class T>
59
60template<class T>
62
63template<typename F, typename Arg, typename Enable = void>
65{
66};
67
68// The callable takes an argument of type Arg
69template<typename F, typename Arg>
75
76// The callable takes an argument of type QFuture<Arg>
77template<class F, class Arg>
83
84// The callable takes an argument of type QFuture<void>
85template<class F>
87 F, void, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
88{
90};
91
92// The callable doesn't take argument
93template<class F>
95 F, void, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
96{
98};
99
100// Helpers to remove QPrivateSignal argument from the list of arguments
101
102template<class T, class Enable = void>
103inline constexpr bool IsPrivateSignalArg = false;
104
105template<class T>
106inline constexpr bool IsPrivateSignalArg<T, typename std::enable_if_t<
107 // finds injected-class-name, the 'class' avoids falling into the rules of [class.qual]/2:
109 >> = true;
110
111template<class Tuple, std::size_t... I>
112auto cutTuple(Tuple &&t, std::index_sequence<I...>)
113{
114 return std::make_tuple(std::get<I>(t)...);
115}
116
117template<class Arg, class... Args>
118auto createTuple(Arg &&arg, Args &&... args)
119{
120 using TupleType = std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>;
121 constexpr auto Size = sizeof...(Args); // One less than the size of all arguments
122 if constexpr (QtPrivate::IsPrivateSignalArg<std::tuple_element_t<Size, TupleType>>) {
123 if constexpr (Size == 1) {
124 return std::forward<Arg>(arg);
125 } else {
126 return cutTuple(std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...),
127 std::make_index_sequence<Size>());
128 }
129 } else {
130 return std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...);
131 }
132}
133
134// Helpers to resolve argument types of callables.
135
136template<class Arg, class... Args>
138 std::conditional_t<(sizeof...(Args) > 0),
139 std::invoke_result_t<decltype(createTuple<Arg, Args...>), Arg, Args...>,
141
142template<typename...>
143struct ArgsType;
144
145template<typename Arg, typename... Args>
146struct ArgsType<Arg, Args...>
147{
148 using First = Arg;
149 using PromiseType = void;
151 static const bool HasExtraArgs = (sizeof...(Args) > 0);
153
154 template<class Class, class Callable>
156};
157
158template<typename Arg, typename... Args>
159struct ArgsType<QPromise<Arg> &, Args...>
160{
161 using First = QPromise<Arg> &;
162 using PromiseType = Arg;
164 static const bool HasExtraArgs = (sizeof...(Args) > 0);
166
167 template<class Class, class Callable>
169};
170
171template<>
172struct ArgsType<>
173{
174 using First = void;
175 using PromiseType = void;
177 static const bool HasExtraArgs = false;
178 using AllArgs = void;
179
180 template<class Class, class Callable>
182};
183
184template<typename F>
185struct ArgResolver : ArgResolver<decltype(&std::decay_t<F>::operator())>
186{
187};
188
189template<typename F>
190struct ArgResolver<std::reference_wrapper<F>> : ArgResolver<decltype(&std::decay_t<F>::operator())>
191{
192};
193
194template<typename R, typename... Args>
195struct ArgResolver<R(Args...)> : public ArgsType<Args...>
196{
197};
198
199template<typename R, typename... Args>
200struct ArgResolver<R (*)(Args...)> : public ArgsType<Args...>
201{
202};
203
204template<typename R, typename... Args>
205struct ArgResolver<R (*&)(Args...)> : public ArgsType<Args...>
206{
207};
208
209template<typename R, typename... Args>
210struct ArgResolver<R (* const)(Args...)> : public ArgsType<Args...>
211{
212};
213
214template<typename R, typename... Args>
215struct ArgResolver<R (&)(Args...)> : public ArgsType<Args...>
216{
217};
218
219template<typename Class, typename R, typename... Args>
220struct ArgResolver<R (Class::*)(Args...)> : public ArgsType<Args...>
221{
222};
223
224template<typename Class, typename R, typename... Args>
225struct ArgResolver<R (Class::*)(Args...) noexcept> : public ArgsType<Args...>
226{
227};
228
229template<typename Class, typename R, typename... Args>
230struct ArgResolver<R (Class::*)(Args...) const> : public ArgsType<Args...>
231{
232};
233
234template<typename Class, typename R, typename... Args>
235struct ArgResolver<R (Class::*)(Args...) const noexcept> : public ArgsType<Args...>
236{
237};
238
239template<typename Class, typename R, typename... Args>
240struct ArgResolver<R (Class::* const)(Args...) const> : public ArgsType<Args...>
241{
242};
243
244template<typename Class, typename R, typename... Args>
245struct ArgResolver<R (Class::* const)(Args...) const noexcept> : public ArgsType<Args...>
246{
247};
248
249template<class Class, class Callable>
252
253template<class T>
254inline constexpr bool isQFutureV = false;
255
256template<class T>
257inline constexpr bool isQFutureV<QFuture<T>> = true;
258
259template<class T>
261
262template<class T>
263struct Future
264{
265};
266
267template<class T>
269{
270 using type = T;
271};
272
273template<class... Args>
274using NotEmpty = std::bool_constant<(sizeof...(Args) > 0)>;
275
276template<class Sequence>
278 std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
281
282template<class Sequence>
284 std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
287
288template<class Iterator>
290 std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category,
291 std::forward_iterator_tag>;
292
293template<typename Function, typename ResultType, typename ParentResultType>
295{
297public:
299
300 template<typename F = Function>
301 CompactContinuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p)
302 : Storage{std::forward<F>(func)}, promise(std::move(p)), parentFuture(f), type(Type::Sync)
303 {
304 }
305
306 template<typename F = Function>
307 CompactContinuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p,
308 QThreadPool *pool)
309 : Storage{std::forward<F>(func)}, promise(std::move(p)), parentFuture(f),
310 threadPool(pool), type(Type::Async)
311 {
312 runObj = QRunnable::create([continuation = this] {
313 continuation->runFunction();
314 delete continuation;
315 });
316 runObj->setAutoDelete(false);
317 }
318
319 ~CompactContinuation() { delete runObj; }
320
321 bool execute();
322
323 QRunnable *runnable() const { return runObj; }
324
325 template<typename F = Function>
326 static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
327 QtFuture::Launch policy);
328
329 template<typename F = Function>
330 static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
331 QThreadPool *pool);
332
333 template<typename F = Function>
334 static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
335 QObject *context);
336
337private:
338 void fulfillPromiseWithResult();
339 void fulfillVoidPromise();
340 void fulfillPromiseWithVoidResult();
341
342 template<class... Args>
343 void fulfillPromise(Args &&... args);
344
345protected:
346 void runImpl()
347 {
348 if (type == Type::Sync) {
350 } else {
351 Q_ASSERT(runObj);
352 QThreadPool *pool = threadPool ? threadPool : QThreadPool::globalInstance();
353 pool->start(runObj);
354 }
355 }
356
357 void runFunction();
358
359protected:
360 enum class Type : quint8 {
363 };
364
365 QPromise<ResultType> promise;
368 QRunnable *runObj = nullptr;
369 const Type type;
370};
371
372#ifndef QT_NO_EXCEPTIONS
373
374template<class Function, class ResultType>
376{
377public:
378 template<typename F = Function>
379 static void create(F &&function, QFuture<ResultType> *future,
380 const QFutureInterface<ResultType> &fi);
381
382 template<typename F = Function>
383 static void create(F &&function, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi,
384 QObject *context);
385
386 template<typename F = Function>
387 FailureHandler(F &&func, const QFuture<ResultType> &f, QPromise<ResultType> &&p)
388 : promise(std::move(p)), parentFuture(f), handler(std::forward<F>(func))
389 {
390 }
391
392public:
393 void run();
394
395private:
396 template<class ArgType>
397 void handleException();
398 void handleAllExceptions();
399
400private:
401 QPromise<ResultType> promise;
402 QFuture<ResultType> parentFuture;
403 Function handler;
404};
405
406#endif
407
408template<typename Function, typename ResultType, typename ParentResultType>
409void CompactContinuation<Function, ResultType, ParentResultType>::runFunction()
410{
411 promise.start();
412
413 Q_ASSERT(parentFuture.isFinished());
414
415#ifndef QT_NO_EXCEPTIONS
416 try {
417#endif
418 if constexpr (!std::is_void_v<ResultType>) {
419 if constexpr (std::is_void_v<ParentResultType>) {
420 fulfillPromiseWithVoidResult();
421 } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
422 fulfillPromiseWithResult();
423 } else {
424 // This assert normally should never fail, this is to make sure
425 // that nothing unexpected happened.
426 static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
427 "The continuation is not invocable with the provided arguments");
428 fulfillPromise(parentFuture);
429 }
430 } else {
431 if constexpr (std::is_void_v<ParentResultType>) {
432 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
433 this->object()(parentFuture);
434 else
435 this->object()();
436 } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
437 fulfillVoidPromise();
438 } else {
439 // This assert normally should never fail, this is to make sure
440 // that nothing unexpected happened.
441 static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
442 "The continuation is not invocable with the provided arguments");
443 this->object()(parentFuture);
444 }
445 }
446#ifndef QT_NO_EXCEPTIONS
447 } catch (...) {
448 promise.setException(std::current_exception());
449 }
450#endif
451 promise.finish();
452}
453
454template<typename Function, typename ResultType, typename ParentResultType>
455bool CompactContinuation<Function, ResultType, ParentResultType>::execute()
456{
457 Q_ASSERT(parentFuture.isFinished());
458
459 if (parentFuture.d.isChainCanceled()) {
460#ifndef QT_NO_EXCEPTIONS
461 if (parentFuture.d.hasException()) {
462 // If the continuation doesn't take a QFuture argument, propagate the exception
463 // to the caller, by reporting it. If the continuation takes a QFuture argument,
464 // the user may want to catch the exception inside the continuation, to not
465 // interrupt the continuation chain, so don't report anything yet.
466 if constexpr (!std::is_invocable_v<std::decay_t<Function>, QFuture<ParentResultType>>) {
467 promise.start();
468 promise.setException(parentFuture.d.exceptionStore().exception());
469 promise.finish();
470 return false;
471 }
472 } else
473#endif
474 {
475 promise.start();
476 promise.future().cancel();
477 promise.finish();
478 return false;
479 }
480 }
481
482 runImpl();
483 return true;
484}
485
486// Workaround for keeping move-only lambdas inside std::function
487template<class Function>
489{
490 ContinuationWrapper(Function &&f) : function(std::move(f)) { }
492 : function(std::move(const_cast<ContinuationWrapper &>(other).function))
493 {
494 Q_ASSERT_X(false, "QFuture", "Continuation shouldn't be copied");
495 }
498
499 template <typename F = Function,
500 std::enable_if_t<std::is_invocable_v<F, const QFutureInterfaceBase &>, bool> = true>
501 void operator()(const QFutureInterfaceBase &parentData) { function(parentData); }
502
503 template <typename F = Function, std::enable_if_t<std::is_invocable_v<F>, bool> = true>
504 void operator()() { function(); }
505
506private:
507 Function function;
508};
509
510template<typename Function, typename ResultType, typename ParentResultType>
511template<typename F>
512void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
513 QFuture<ParentResultType> *f,
514 QFutureInterface<ResultType> &fi,
515 QtFuture::Launch policy)
516{
517 Q_ASSERT(f);
518
519 QThreadPool *pool = nullptr;
520
521 bool launchAsync = (policy == QtFuture::Launch::Async);
522 if (policy == QtFuture::Launch::Inherit) {
523 launchAsync = f->d.launchAsync();
524
525 // If the parent future was using a custom thread pool, inherit it as well.
526 if (launchAsync && f->d.threadPool()) {
527 pool = f->d.threadPool();
528 fi.setThreadPool(pool);
529 }
530 }
531
532 fi.setLaunchAsync(launchAsync);
533
534 auto continuation = [func = std::forward<F>(func), fi, promise_ = QPromise(fi), pool,
535 launchAsync](const QFutureInterfaceBase &parentData) mutable {
536 const auto parent = QFutureInterface<ParentResultType>(parentData).future();
537 CompactContinuation<Function, ResultType, ParentResultType> *continuationJob = nullptr;
538 if (launchAsync) {
539 auto asyncJob = new CompactContinuation<Function, ResultType, ParentResultType>(
540 std::forward<Function>(func), parent, std::move(promise_), pool);
541 fi.setRunnable(asyncJob->runnable());
542 continuationJob = asyncJob;
543 } else {
544 continuationJob = new CompactContinuation<Function, ResultType, ParentResultType>(
545 std::forward<Function>(func), parent, std::move(promise_));
546 }
547
548 bool isLaunched = continuationJob->execute();
549 // If continuation is successfully launched, AsyncContinuation will be deleted
550 // from the QRunnable's lambda. Synchronous continuation will be
551 // executed immediately, so it's safe to always delete it here.
552 if (!(launchAsync && isLaunched)) {
553 delete continuationJob;
554 continuationJob = nullptr;
555 }
556 };
557 f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d,
558 QFutureInterfaceBase::ContinuationType::Then);
559}
560
561template<typename Function, typename ResultType, typename ParentResultType>
562template<typename F>
563void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
564 QFuture<ParentResultType> *f,
565 QFutureInterface<ResultType> &fi,
566 QThreadPool *pool)
567{
568 Q_ASSERT(f);
569
570 fi.setLaunchAsync(true);
571 fi.setThreadPool(pool);
572
573 auto continuation = [func = std::forward<F>(func), promise_ = QPromise(fi),
574 pool](const QFutureInterfaceBase &parentData) mutable {
575 const auto parent = QFutureInterface<ParentResultType>(parentData).future();
576 auto continuationJob = new CompactContinuation<Function, ResultType, ParentResultType>(
577 std::forward<Function>(func), parent, std::move(promise_), pool);
578 bool isLaunched = continuationJob->execute();
579 // If continuation is successfully launched, AsyncContinuation will be deleted
580 // from the QRunnable's lambda.
581 if (!isLaunched) {
582 delete continuationJob;
583 continuationJob = nullptr;
584 }
585 };
586 f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d,
587 QFutureInterfaceBase::ContinuationType::Then);
588}
589
590template<typename Function, typename ResultType, typename ParentResultType>
591template<typename F>
592void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
593 QFuture<ParentResultType> *f,
594 QFutureInterface<ResultType> &fi,
595 QObject *context)
596{
597 Q_ASSERT(f);
598 Q_ASSERT(context);
599
600 // When the context object is destroyed, the signal-slot connection is broken and the
601 // continuation callback is destroyed. The promise that is created in the capture list is
602 // destroyed and, if it is not yet finished, cancelled.
603 auto continuation = [func = std::forward<F>(func), parent = *f,
604 promise_ = QPromise(fi)]() mutable {
605 CompactContinuation<Function, ResultType, ParentResultType> continuationJob(
606 std::forward<Function>(func), parent, std::move(promise_));
607 continuationJob.execute();
608 };
609
610 f->d.setContinuation(context, ContinuationWrapper(std::move(continuation)),
611 QVariant::fromValue(fi),
612 QFutureInterfaceBase::ContinuationType::Then);
613}
614
615template<typename Function, typename ResultType, typename ParentResultType>
616void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromiseWithResult()
617{
618 qfutureWarnIfUnusedResults(parentFuture.resultCount());
619 if constexpr (std::is_copy_constructible_v<ParentResultType>)
620 fulfillPromise(parentFuture.result());
621 else
622 fulfillPromise(parentFuture.takeResult());
623}
624
625template<typename Function, typename ResultType, typename ParentResultType>
626void CompactContinuation<Function, ResultType, ParentResultType>::fulfillVoidPromise()
627{
628 qfutureWarnIfUnusedResults(parentFuture.resultCount());
629 if constexpr (std::is_copy_constructible_v<ParentResultType>)
630 this->object()(parentFuture.result());
631 else
632 this->object()(parentFuture.takeResult());
633}
634
635template<typename Function, typename ResultType, typename ParentResultType>
636void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromiseWithVoidResult()
637{
638 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
639 fulfillPromise(parentFuture);
640 else
641 fulfillPromise();
642}
643
644template<typename Function, typename ResultType, typename ParentResultType>
645template<class... Args>
646void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromise(Args &&... args)
647{
648 promise.addResult(std::invoke(this->object(), std::forward<Args>(args)...));
649}
650
651template<class T>
652void fulfillPromise(QPromise<T> &promise, QFuture<T> &future)
653{
654 if constexpr (!std::is_void_v<T>) {
655 if constexpr (std::is_copy_constructible_v<T>)
656 promise.addResult(future.result());
657 else
658 promise.addResult(future.takeResult());
659 }
660}
661
662template<class T, class Function>
663void fulfillPromise(QPromise<T> &promise, Function &&handler)
664{
665 if constexpr (std::is_void_v<T>)
666 handler();
667 else
668 promise.addResult(handler());
669}
670
671#ifndef QT_NO_EXCEPTIONS
672
673template<class Function, class ResultType>
674template<class F>
675void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultType> *future,
676 const QFutureInterface<ResultType> &fi)
677{
678 Q_ASSERT(future);
679
680 auto failureContinuation = [function = std::forward<F>(function), promise_ = QPromise(fi)](
681 const QFutureInterfaceBase &parentData) mutable {
682 const auto parent = QFutureInterface<ResultType>(parentData).future();
683 FailureHandler<Function, ResultType> failureHandler(std::forward<Function>(function),
684 parent, std::move(promise_));
685 failureHandler.run();
686 };
687
688 future->d.setContinuation(ContinuationWrapper(std::move(failureContinuation)), fi.d,
689 QFutureInterfaceBase::ContinuationType::OnFailed);
690}
691
692template<class Function, class ResultType>
693template<class F>
694void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultType> *future,
695 QFutureInterface<ResultType> &fi,
696 QObject *context)
697{
698 Q_ASSERT(future);
699 Q_ASSERT(context);
700 auto failureContinuation = [function = std::forward<F>(function),
701 parent = *future, promise_ = QPromise(fi)]() mutable {
702 FailureHandler<Function, ResultType> failureHandler(
703 std::forward<Function>(function), parent, std::move(promise_));
704 failureHandler.run();
705 };
706
707 future->d.setContinuation(context, ContinuationWrapper(std::move(failureContinuation)),
708 QVariant::fromValue(fi),
709 QFutureInterfaceBase::ContinuationType::OnFailed);
710}
711
712template<class Function, class ResultType>
713void FailureHandler<Function, ResultType>::run()
714{
715 Q_ASSERT(parentFuture.isFinished());
716
717 promise.start();
718
719 if (parentFuture.d.hasException()) {
720 using ArgType = typename QtPrivate::ArgResolver<Function>::First;
721 if constexpr (std::is_void_v<ArgType>) {
722 handleAllExceptions();
723 } else {
724 handleException<ArgType>();
725 }
726 } else if (parentFuture.d.isChainCanceled()) {
727 promise.future().cancel();
728 } else {
729 QtPrivate::fulfillPromise(promise, parentFuture);
730 }
731 promise.finish();
732}
733
734template<class Function, class ResultType>
735template<class ArgType>
736void FailureHandler<Function, ResultType>::handleException()
737{
738 try {
739 Q_ASSERT(parentFuture.d.hasException());
740 parentFuture.d.exceptionStore().rethrowException();
741 } catch (const ArgType &e) {
742 try {
743 // Handle exceptions matching with the handler's argument type
744 if constexpr (std::is_void_v<ResultType>)
745 handler(e);
746 else
747 promise.addResult(handler(e));
748 } catch (...) {
749 promise.setException(std::current_exception());
750 }
751 } catch (...) {
752 // Exception doesn't match with handler's argument type, propagate
753 // the exception to be handled later.
754 promise.setException(std::current_exception());
755 }
756}
757
758template<class Function, class ResultType>
759void FailureHandler<Function, ResultType>::handleAllExceptions()
760{
761 try {
762 Q_ASSERT(parentFuture.d.hasException());
763 parentFuture.d.exceptionStore().rethrowException();
764 } catch (...) {
765 try {
766 QtPrivate::fulfillPromise(promise, std::forward<Function>(handler));
767 } catch (...) {
768 promise.setException(std::current_exception());
769 }
770 }
771}
772
773#endif // QT_NO_EXCEPTIONS
774
775template<class Function, class ResultType>
777{
778public:
779 template<class F = Function>
780 static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi)
781 {
782 Q_ASSERT(future);
783
784 auto canceledContinuation = [promise = QPromise(fi), handler = std::forward<F>(handler)](
785 const QFutureInterfaceBase &parentData) mutable {
786 auto parentFuture = QFutureInterface<ResultType>(parentData).future();
787 run(std::forward<F>(handler), parentFuture, std::move(promise));
788 };
789 future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation)), fi.d,
790 QFutureInterfaceBase::ContinuationType::OnCanceled);
791 }
792
793 template<class F = Function>
794 static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi,
795 QObject *context)
796 {
797 Q_ASSERT(future);
798 Q_ASSERT(context);
799 auto canceledContinuation = [handler = std::forward<F>(handler),
800 parentFuture = *future, promise = QPromise(fi)]() mutable {
801 run(std::forward<F>(handler), parentFuture, std::move(promise));
802 };
803
804 future->d.setContinuation(context, ContinuationWrapper(std::move(canceledContinuation)),
805 QVariant::fromValue(fi),
806 QFutureInterfaceBase::ContinuationType::OnCanceled);
807 }
808
809 template<class F = Function>
810 static void run(F &&handler, QFuture<ResultType> &parentFuture, QPromise<ResultType> &&promise)
811 {
812 promise.start();
813
814 if (parentFuture.isCanceled()) {
815#ifndef QT_NO_EXCEPTIONS
816 if (parentFuture.d.hasException()) {
817 // Propagate the exception to the result future
818 promise.setException(parentFuture.d.exceptionStore().exception());
819 } else {
820 try {
821#endif
822 QtPrivate::fulfillPromise(promise, std::forward<F>(handler));
823#ifndef QT_NO_EXCEPTIONS
824 } catch (...) {
825 promise.setException(std::current_exception());
826 }
827 }
828#endif
829 } else {
830 QtPrivate::fulfillPromise(promise, parentFuture);
831 }
832
833 promise.finish();
834 }
835};
836
838{
839 template<class T>
840 static auto unwrapImpl(T *outer)
841 {
842 Q_ASSERT(outer);
843
844 using ResultType = typename QtPrivate::Future<std::decay_t<T>>::type;
845 using NestedType = typename QtPrivate::Future<ResultType>::type;
846 QFutureInterface<NestedType> promise(QFutureInterfaceBase::State::Pending);
847
848 outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
849 // We use the .then([](QFuture<ResultType> outerFuture) {...}) version
850 // (where outerFuture == *outer), to propagate the exception if the
851 // outer future has failed.
852 Q_ASSERT(outerFuture.isFinished());
853#ifndef QT_NO_EXCEPTIONS
854 if (outerFuture.d.hasException()) {
855 promise.reportStarted();
856 promise.reportException(outerFuture.d.exceptionStore().exception());
857 promise.reportFinished();
858 return;
859 }
860#endif
861
862 promise.reportStarted();
863 ResultType nestedFuture = outerFuture.result();
864
865 nestedFuture.then([promise] (const QFuture<NestedType> &nested) mutable {
866#ifndef QT_NO_EXCEPTIONS
867 if (nested.d.hasException()) {
868 promise.reportException(nested.d.exceptionStore().exception());
869 } else
870#endif
871 {
872 if constexpr (!std::is_void_v<NestedType>)
873 promise.reportResults(nested.results());
874 }
875 promise.reportFinished();
876 }).onCanceled([promise] () mutable {
877 promise.reportCanceled();
878 promise.reportFinished();
879 });
880 }).onCanceled([promise]() mutable {
881 // propagate the cancellation of the outer future
882 promise.reportStarted();
883 promise.reportCanceled();
884 promise.reportFinished();
885 });
886 return promise.future();
887 }
888};
889
890template<typename ValueType>
891QFuture<ValueType> makeReadyRangeFutureImpl(const QList<ValueType> &values)
892{
893 QFutureInterface<ValueType> promise;
894 promise.reportStarted();
895 promise.reportResults(values);
896 promise.reportFinished();
897 return promise.future();
898}
899
900} // namespace QtPrivate
901
902namespace QtFuture {
903
904template<class Signal>
905using ArgsType = typename QtPrivate::ArgResolver<Signal>::AllArgs;
906
907template<class Sender, class Signal, typename = QtPrivate::EnableIfInvocable<Sender, Signal>>
908static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
909{
910 using ArgsType = ArgsType<Signal>;
911 QFutureInterface<ArgsType> promise;
912 promise.reportStarted();
913 if (!sender) {
914 promise.reportCanceled();
915 promise.reportFinished();
916 return promise.future();
917 }
918
919 using Connections = std::pair<QMetaObject::Connection, QMetaObject::Connection>;
920 auto connections = std::make_shared<Connections>();
921
922 if constexpr (std::is_void_v<ArgsType>) {
923 connections->first =
924 QObject::connect(sender, signal, sender, [promise, connections]() mutable {
925 QObject::disconnect(connections->first);
926 QObject::disconnect(connections->second);
927 promise.reportFinished();
928 });
929 } else if constexpr (QtPrivate::ArgResolver<Signal>::HasExtraArgs) {
930 connections->first = QObject::connect(sender, signal, sender,
931 [promise, connections](auto... values) mutable {
932 QObject::disconnect(connections->first);
933 QObject::disconnect(connections->second);
934 promise.reportResult(QtPrivate::createTuple(
935 std::move(values)...));
936 promise.reportFinished();
937 });
938 } else {
939 connections->first = QObject::connect(sender, signal, sender,
940 [promise, connections](ArgsType value) mutable {
941 QObject::disconnect(connections->first);
942 QObject::disconnect(connections->second);
943 promise.reportResult(value);
944 promise.reportFinished();
945 });
946 }
947
948 if (!connections->first) {
949 promise.reportCanceled();
950 promise.reportFinished();
951 return promise.future();
952 }
953
954 connections->second =
955 QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable {
956 QObject::disconnect(connections->first);
957 QObject::disconnect(connections->second);
958 promise.reportCanceled();
959 promise.reportFinished();
960 });
961
962 return promise.future();
963}
964
965template<typename Container>
968
969template<typename Container>
971 typename std::iterator_traits<decltype(
973
974template<typename Container, if_container_with_input_iterators<Container> = true>
976{
977 // handle QList<T> separately, because reportResults() takes a QList
978 // as an input
979 using ValueType = ContainedType<Container>;
980 if constexpr (std::is_convertible_v<q20::remove_cvref_t<Container>, QList<ValueType>>) {
981 return QtPrivate::makeReadyRangeFutureImpl(container);
982 } else {
983 return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{std::cbegin(container),
984 std::cend(container)});
985 }
986}
987
988template<typename ValueType>
993
994template<typename T>
996{
997 QFutureInterface<std::decay_t<T>> promise;
998 promise.reportStarted();
999 promise.reportResult(std::forward<T>(value));
1000 promise.reportFinished();
1001
1002 return promise.future();
1003}
1004
1005Q_CORE_EXPORT QFuture<void> makeReadyVoidFuture(); // implemented in qfutureinterface.cpp
1006
1007#if QT_DEPRECATED_SINCE(6, 10)
1008template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
1009QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyValueFuture() instead.")
1011{
1013}
1014
1015// the void specialization is moved to the end of qfuture.h, because it now
1016// uses makeReadyVoidFuture() and required QFuture<void> to be defined.
1017
1018template<typename T>
1019QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyRangeFuture() instead.")
1020static QFuture<T> makeReadyFuture(const QList<T> &values)
1021{
1023}
1024#endif // QT_DEPRECATED_SINCE(6, 10)
1025
1026#ifndef QT_NO_EXCEPTIONS
1027
1028template<typename T = void>
1029static QFuture<T> makeExceptionalFuture(std::exception_ptr exception)
1030{
1031 QFutureInterface<T> promise;
1032 promise.reportStarted();
1033 promise.reportException(exception);
1034 promise.reportFinished();
1035
1036 return promise.future();
1037}
1038
1039template<typename T = void>
1040static QFuture<T> makeExceptionalFuture(const QException &exception)
1041{
1042 try {
1043 exception.raise();
1044 } catch (...) {
1045 return makeExceptionalFuture<T>(std::current_exception());
1046 }
1047 Q_UNREACHABLE();
1048}
1049
1050#endif // QT_NO_EXCEPTIONS
1051
1052} // namespace QtFuture
1053
1054namespace QtPrivate {
1055
1056template<typename ResultFutures>
1058{
1059 using ValueType = typename ResultFutures::value_type;
1060
1061 explicit WhenAllContext(qsizetype size) : remaining(size) {}
1062
1063 template<typename T = ValueType>
1064 void checkForCompletion(qsizetype index, T &&future)
1065 {
1066 futures[index] = std::forward<T>(future);
1067 const auto oldRemaining = remaining.fetchAndSubRelaxed(1);
1068 Q_ASSERT(oldRemaining > 0);
1069 if (oldRemaining <= 1) { // that was the last one
1070 promise.addResult(futures);
1071 promise.finish();
1072 }
1073 }
1074
1076 QPromise<ResultFutures> promise;
1077 ResultFutures futures;
1078};
1079
1080template<typename ResultType>
1082{
1083 using ValueType = ResultType;
1084
1085 template<typename T = ResultType, typename = EnableForNonVoid<T>>
1087 {
1088 if (!ready.fetchAndStoreRelaxed(true)) {
1089 promise.addResult(std::forward<T>(result));
1090 promise.finish();
1091 }
1092 }
1093
1095 QPromise<ResultType> promise;
1096};
1097
1098template<qsizetype Index, typename ContextType, typename... Ts>
1099void addCompletionHandlersImpl(const std::shared_ptr<ContextType> &context,
1100 const std::tuple<Ts...> &t)
1101{
1102 auto future = std::get<Index>(t);
1103 using ResultType = typename ContextType::ValueType;
1104 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1105 future.then([context=context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
1106 context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, f });
1107 }).onCanceled([context=context, future]() {
1108 context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, future });
1109 });
1110
1111 if constexpr (Index != 0)
1112 addCompletionHandlersImpl<Index - 1, ContextType, Ts...>(context, t);
1113}
1114
1115template<typename ContextType, typename... Ts>
1116void addCompletionHandlers(const std::shared_ptr<ContextType> &context, const std::tuple<Ts...> &t)
1117{
1118 constexpr qsizetype size = std::tuple_size<std::tuple<Ts...>>::value;
1119 addCompletionHandlersImpl<size - 1, ContextType, Ts...>(context, t);
1120}
1121
1122template<typename OutputSequence, typename InputIt, typename ValueType,
1124 bool> = true>
1126{
1127 const qsizetype size = std::distance(first, last);
1128 if (size == 0)
1130
1134
1135 qsizetype idx = 0;
1136 for (auto it = first; it != last; ++it, ++idx) {
1137 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1138 it->then([context=context, idx](const ValueType &f) {
1140 }).onCanceled([context=context, idx, f = *it] {
1142 });
1143 }
1144 return context->promise.future();
1145}
1146
1147template<typename OutputSequence, typename... Futures>
1148QFuture<OutputSequence> whenAllImpl(Futures &&... futures)
1149{
1150 constexpr qsizetype size = sizeof...(Futures);
1151 const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
1152 context->futures.resize(size);
1153 context->promise.start();
1154
1155 QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));
1156
1157 return context->promise.future();
1158}
1159
1160template<typename InputIt, typename ValueType,
1162 bool> = true>
1164 InputIt last)
1165{
1166 using PackagedType = typename Future<ValueType>::type;
1168
1169 const qsizetype size = std::distance(first, last);
1170 if (size == 0) {
1173 }
1174
1177
1178 qsizetype idx = 0;
1179 for (auto it = first; it != last; ++it, ++idx) {
1180 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1181 it->then([context=context, idx](const ValueType &f) {
1183 }).onCanceled([context=context, idx, f = *it] {
1185 });
1186 }
1187 return context->promise.future();
1188}
1189
1190template<typename... Futures>
1202
1203} // namespace QtPrivate
1204
1205QT_END_NAMESPACE
static void create(F &&handler, QFuture< ResultType > *future, QFutureInterface< ResultType > &fi, QObject *context)
static void create(F &&handler, QFuture< ResultType > *future, QFutureInterface< ResultType > &fi)
static void run(F &&handler, QFuture< ResultType > &parentFuture, QPromise< ResultType > &&promise)
static void create(F &&func, QFuture< ParentResultType > *f, QFutureInterface< ResultType > &fi, QtFuture::Launch policy)
QPromise< ResultType > promise
CompactContinuation(F &&func, const QFuture< ParentResultType > &f, QPromise< ResultType > &&p)
CompactContinuation(F &&func, const QFuture< ParentResultType > &f, QPromise< ResultType > &&p, QThreadPool *pool)
static void create(F &&func, QFuture< ParentResultType > *f, QFutureInterface< ResultType > &fi, QThreadPool *pool)
QFuture< ParentResultType > parentFuture
QRunnable * runnable() const
static void create(F &&function, QFuture< ResultType > *future, QFutureInterface< ResultType > &fi, QObject *context)
static void create(F &&function, QFuture< ResultType > *future, const QFutureInterface< ResultType > &fi)
FailureHandler(F &&func, const QFuture< ResultType > &f, QPromise< ResultType > &&p)
typename QtPrivate::ArgResolver< Signal >::AllArgs ArgsType
static QFuture< T > makeExceptionalFuture(const QException &exception)
static QFuture< std::decay_t< T > > makeReadyValueFuture(T &&value)
static QFuture< T > makeExceptionalFuture(std::exception_ptr exception)
WhenAnyResult(qsizetype, const QFuture< T > &) -> WhenAnyResult< T >
static QFuture< ContainedType< Container > > makeReadyRangeFuture(Container &&container)
static QFuture< ValueType > makeReadyRangeFuture(std::initializer_list< ValueType > values)
static QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
auto createTuple(Arg &&arg, Args &&... args)
void qfutureWarnIfUnusedResults(qsizetype numResults)
void addCompletionHandlersImpl(const std::shared_ptr< ContextType > &context, const std::tuple< Ts... > &t)
void fulfillPromise(QPromise< T > &promise, Function &&handler)
constexpr bool isQFutureV
QFuture< OutputSequence > whenAllImpl(Futures &&... futures)
void fulfillPromise(QPromise< T > &promise, QFuture< T > &future)
QFuture< ValueType > makeReadyRangeFutureImpl(const QList< ValueType > &values)
constexpr bool IsPrivateSignalArg
auto cutTuple(Tuple &&t, std::index_sequence< I... >)
std::is_convertible< typename std::iterator_traits< Iterator >::iterator_category, std::forward_iterator_tag > IsForwardIterable
void addCompletionHandlers(const std::shared_ptr< ContextType > &context, const std::tuple< Ts... > &t)
static const bool HasExtraArgs
static const bool CanInvokeWithArgs
ContinuationWrapper(ContinuationWrapper &&other)=default
ContinuationWrapper & operator=(ContinuationWrapper &&)=default
void operator()(const QFutureInterfaceBase &parentData)
ContinuationWrapper(const ContinuationWrapper &other)
static auto unwrapImpl(T *outer)
QAtomicInteger< qsizetype > remaining
QPromise< ResultFutures > promise
WhenAllContext(qsizetype size)
void checkForCompletion(qsizetype index, T &&future)
typename ResultFutures::value_type ValueType
QPromise< ResultType > promise
void checkForCompletion(qsizetype, T &&result)