Qt 6.x
The Qt SDK
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
4#ifndef QFUTURE_H
5#error Do not include qfuture_impl.h directly
6#endif
7
8#if 0
9#pragma qt_sync_skip_header_check
10#pragma qt_sync_stop_processing
11#endif
12
13#include <QtCore/qglobal.h>
14#include <QtCore/qbasicfuturewatcher.h>
15#include <QtCore/qfutureinterface.h>
16#include <QtCore/qthreadpool.h>
17#include <QtCore/qexception.h>
18#include <QtCore/qpointer.h>
19#include <QtCore/qpromise.h>
20
21#include <memory>
22
24
25//
26// forward declarations
27//
28template<class T>
29class QFuture;
30template<class T>
32template<class T>
33class QPromise;
34
35namespace QtFuture {
36
37enum class Launch { Sync, Async, Inherit };
38
39template<class T>
41{
44};
45
46// Deduction guide
47template<class T>
49}
50
51namespace QtPrivate {
52
53template<class T>
54using EnableForVoid = std::enable_if_t<std::is_same_v<T, void>>;
55
56template<class T>
57using EnableForNonVoid = std::enable_if_t<!std::is_same_v<T, void>>;
58
59template<typename F, typename Arg, typename Enable = void>
61{
62};
63
64// The callable takes an argument of type Arg
65template<typename F, typename Arg>
67 F, Arg, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<Arg>>>>
68{
69 using ResultType = std::invoke_result_t<std::decay_t<F>, std::decay_t<Arg>>;
70};
71
72// The callable takes an argument of type QFuture<Arg>
73template<class F, class Arg>
75 F, Arg, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<Arg>>>>
76{
77 using ResultType = std::invoke_result_t<std::decay_t<F>, QFuture<Arg>>;
78};
79
80// The callable takes an argument of type QFuture<void>
81template<class F>
83 F, void, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
84{
85 using ResultType = std::invoke_result_t<std::decay_t<F>, QFuture<void>>;
86};
87
88// The callable doesn't take argument
89template<class F>
91 F, void, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
92{
93 using ResultType = std::invoke_result_t<std::decay_t<F>>;
94};
95
96// Helpers to remove QPrivateSignal argument from the list of arguments
97
98template<class T, class Enable = void>
99inline constexpr bool IsPrivateSignalArg = false;
100
101template<class T>
102inline constexpr bool IsPrivateSignalArg<T, typename std::enable_if_t<
103 // finds injected-class-name, the 'class' avoids falling into the rules of [class.qual]/2:
104 std::is_class_v<class T::QPrivateSignal>
105 >> = true;
106
107template<class Tuple, std::size_t... I>
108auto cutTuple(Tuple &&t, std::index_sequence<I...>)
109{
110 return std::make_tuple(std::get<I>(t)...);
111}
112
113template<class Arg, class... Args>
114auto createTuple(Arg &&arg, Args &&... args)
115{
116 using TupleType = std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>;
117 constexpr auto Size = sizeof...(Args); // One less than the size of all arguments
118 if constexpr (QtPrivate::IsPrivateSignalArg<std::tuple_element_t<Size, TupleType>>) {
119 if constexpr (Size == 1) {
120 return std::forward<Arg>(arg);
121 } else {
122 return cutTuple(std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...),
123 std::make_index_sequence<Size>());
124 }
125 } else {
126 return std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...);
127 }
128}
129
130// Helpers to resolve argument types of callables.
131
132template<class Arg, class... Args>
134 std::conditional_t<(sizeof...(Args) > 0),
135 std::invoke_result_t<decltype(createTuple<Arg, Args...>), Arg, Args...>,
136 std::conditional_t<IsPrivateSignalArg<Arg>, void, Arg>>;
137
138template<typename...>
139struct ArgsType;
140
141template<typename Arg, typename... Args>
142struct ArgsType<Arg, Args...>
143{
144 using First = Arg;
146 using IsPromise = std::false_type;
147 static const bool HasExtraArgs = (sizeof...(Args) > 0);
149
150 template<class Class, class Callable>
151 static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, Arg, Args...>;
152};
153
154template<typename Arg, typename... Args>
155struct ArgsType<QPromise<Arg> &, Args...>
156{
158 using PromiseType = Arg;
159 using IsPromise = std::true_type;
160 static const bool HasExtraArgs = (sizeof...(Args) > 0);
161 using AllArgs = FilterLastPrivateSignalArg<QPromise<Arg>, std::decay_t<Args>...>;
162
163 template<class Class, class Callable>
164 static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, QPromise<Arg> &, Args...>;
165};
166
167template<>
168struct ArgsType<>
169{
170 using First = void;
172 using IsPromise = std::false_type;
173 static const bool HasExtraArgs = false;
174 using AllArgs = void;
175
176 template<class Class, class Callable>
177 static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class>;
178};
179
180template<typename F>
181struct ArgResolver : ArgResolver<decltype(&std::decay_t<F>::operator())>
182{
183};
184
185template<typename F>
186struct ArgResolver<std::reference_wrapper<F>> : ArgResolver<decltype(&std::decay_t<F>::operator())>
187{
188};
189
190template<typename R, typename... Args>
191struct ArgResolver<R(Args...)> : public ArgsType<Args...>
192{
193};
194
195template<typename R, typename... Args>
196struct ArgResolver<R (*)(Args...)> : public ArgsType<Args...>
197{
198};
199
200template<typename R, typename... Args>
201struct ArgResolver<R (*&)(Args...)> : public ArgsType<Args...>
202{
203};
204
205template<typename R, typename... Args>
206struct ArgResolver<R (* const)(Args...)> : public ArgsType<Args...>
207{
208};
209
210template<typename R, typename... Args>
211struct ArgResolver<R (&)(Args...)> : public ArgsType<Args...>
212{
213};
214
215template<typename Class, typename R, typename... Args>
216struct ArgResolver<R (Class::*)(Args...)> : public ArgsType<Args...>
217{
218};
219
220template<typename Class, typename R, typename... Args>
221struct ArgResolver<R (Class::*)(Args...) noexcept> : public ArgsType<Args...>
222{
223};
224
225template<typename Class, typename R, typename... Args>
226struct ArgResolver<R (Class::*)(Args...) const> : public ArgsType<Args...>
227{
228};
229
230template<typename Class, typename R, typename... Args>
231struct ArgResolver<R (Class::*)(Args...) const noexcept> : public ArgsType<Args...>
232{
233};
234
235template<typename Class, typename R, typename... Args>
236struct ArgResolver<R (Class::* const)(Args...) const> : public ArgsType<Args...>
237{
238};
239
240template<typename Class, typename R, typename... Args>
241struct ArgResolver<R (Class::* const)(Args...) const noexcept> : public ArgsType<Args...>
242{
243};
244
245template<class Class, class Callable>
246using EnableIfInvocable = std::enable_if_t<
247 QtPrivate::ArgResolver<Callable>::template CanInvokeWithArgs<Class, Callable>>;
248
249template<class T>
250inline constexpr bool isQFutureV = false;
251
252template<class T>
253inline constexpr bool isQFutureV<QFuture<T>> = true;
254
255template<class T>
256using isQFuture = std::bool_constant<isQFutureV<T>>;
257
258template<class T>
259struct Future
260{
261};
262
263template<class T>
264struct Future<QFuture<T>>
265{
266 using type = T;
267};
268
269template<class... Args>
270using NotEmpty = std::bool_constant<(sizeof...(Args) > 0)>;
271
272template<class Sequence>
274 std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
275 std::begin(std::declval<Sequence>()))>>::iterator_category,
276 std::random_access_iterator_tag>;
277
278template<class Sequence>
280 std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
281 std::begin(std::declval<Sequence>()))>>::iterator_category,
282 std::input_iterator_tag>;
283
284template<class Iterator>
286 std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category,
287 std::forward_iterator_tag>;
288
289template<typename Function, typename ResultType, typename ParentResultType>
291{
292public:
293 template<typename F = Function>
295 : promise(std::move(p)), parentFuture(f), function(std::forward<F>(func))
296 {
297 }
298 virtual ~Continuation() = default;
299
300 bool execute();
301
302 template<typename F = Function>
305
306 template<typename F = Function>
309
310 template<typename F = Function>
313
314private:
315 void fulfillPromiseWithResult();
316 void fulfillVoidPromise();
317 void fulfillPromiseWithVoidResult();
318
319 template<class... Args>
320 void fulfillPromise(Args &&... args);
321
322protected:
323 virtual void runImpl() = 0;
324
325 void runFunction();
326
327protected:
331};
332
333template<typename Function, typename ResultType, typename ParentResultType>
334class SyncContinuation final : public Continuation<Function, ResultType, ParentResultType>
335{
336public:
337 template<typename F = Function>
339 : Continuation<Function, ResultType, ParentResultType>(std::forward<F>(func), f,
340 std::move(p))
341 {
342 }
343
344 ~SyncContinuation() override = default;
345
346private:
347 void runImpl() override { this->runFunction(); }
348};
349
350template<typename Function, typename ResultType, typename ParentResultType>
351class AsyncContinuation final : public QRunnable,
352 public Continuation<Function, ResultType, ParentResultType>
353{
354public:
355 template<typename F = Function>
357 QThreadPool *pool = nullptr)
358 : Continuation<Function, ResultType, ParentResultType>(std::forward<F>(func), f,
359 std::move(p)),
360 threadPool(pool)
361 {
362 }
363
364 ~AsyncContinuation() override = default;
365
366private:
367 void runImpl() override // from Continuation
368 {
369 QThreadPool *pool = threadPool ? threadPool : QThreadPool::globalInstance();
370 pool->start(this);
371 }
372
373 void run() override // from QRunnable
374 {
375 this->runFunction();
376 }
377
378private:
379 QThreadPool *threadPool;
380};
381
382#ifndef QT_NO_EXCEPTIONS
383
384template<class Function, class ResultType>
386{
387public:
388 template<typename F = Function>
389 static void create(F &&function, QFuture<ResultType> *future,
391
392 template<typename F = Function>
395
396 template<typename F = Function>
398 : promise(std::move(p)), parentFuture(f), handler(std::forward<F>(func))
399 {
400 }
401
402public:
403 void run();
404
405private:
406 template<class ArgType>
407 void handleException();
408 void handleAllExceptions();
409
410private:
411 QPromise<ResultType> promise;
412 QFuture<ResultType> parentFuture;
413 Function handler;
414};
415
416#endif
417
418template<typename Function, typename ResultType, typename ParentResultType>
420{
421 promise.start();
422
423 Q_ASSERT(parentFuture.isFinished());
424
425#ifndef QT_NO_EXCEPTIONS
426 try {
427#endif
428 if constexpr (!std::is_void_v<ResultType>) {
429 if constexpr (std::is_void_v<ParentResultType>) {
430 fulfillPromiseWithVoidResult();
431 } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
432 fulfillPromiseWithResult();
433 } else {
434 // This assert normally should never fail, this is to make sure
435 // that nothing unexpected happened.
436 static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
437 "The continuation is not invocable with the provided arguments");
438 fulfillPromise(parentFuture);
439 }
440 } else {
441 if constexpr (std::is_void_v<ParentResultType>) {
442 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
443 function(parentFuture);
444 else
445 function();
446 } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
447 fulfillVoidPromise();
448 } else {
449 // This assert normally should never fail, this is to make sure
450 // that nothing unexpected happened.
451 static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
452 "The continuation is not invocable with the provided arguments");
453 function(parentFuture);
454 }
455 }
456#ifndef QT_NO_EXCEPTIONS
457 } catch (...) {
458 promise.setException(std::current_exception());
459 }
460#endif
461 promise.finish();
462}
463
464template<typename Function, typename ResultType, typename ParentResultType>
466{
467 Q_ASSERT(parentFuture.isFinished());
468
469 if (parentFuture.d.isChainCanceled()) {
470#ifndef QT_NO_EXCEPTIONS
471 if (parentFuture.d.hasException()) {
472 // If the continuation doesn't take a QFuture argument, propagate the exception
473 // to the caller, by reporting it. If the continuation takes a QFuture argument,
474 // the user may want to catch the exception inside the continuation, to not
475 // interrupt the continuation chain, so don't report anything yet.
476 if constexpr (!std::is_invocable_v<std::decay_t<Function>, QFuture<ParentResultType>>) {
477 promise.start();
478 promise.setException(parentFuture.d.exceptionStore().exception());
479 promise.finish();
480 return false;
481 }
482 } else
483#endif
484 {
485 promise.start();
486 promise.future().cancel();
487 promise.finish();
488 return false;
489 }
490 }
491
492 runImpl();
493 return true;
494}
495
496// Workaround for keeping move-only lambdas inside std::function
497template<class Function>
499{
500 ContinuationWrapper(Function &&f) : function(std::move(f)) { }
502 : function(std::move(const_cast<ContinuationWrapper &>(other).function))
503 {
504 Q_ASSERT_X(false, "QFuture", "Continuation shouldn't be copied");
505 }
508
509 void operator()(const QFutureInterfaceBase &parentData) { function(parentData); }
510
511private:
512 Function function;
513};
514
515template<typename Function, typename ResultType, typename ParentResultType>
516template<typename F>
521{
522 Q_ASSERT(f);
523
524 QThreadPool *pool = nullptr;
525
526 bool launchAsync = (policy == QtFuture::Launch::Async);
528 launchAsync = f->d.launchAsync();
529
530 // If the parent future was using a custom thread pool, inherit it as well.
531 if (launchAsync && f->d.threadPool()) {
532 pool = f->d.threadPool();
533 fi.setThreadPool(pool);
534 }
535 }
536
537 fi.setLaunchAsync(launchAsync);
538
539 auto continuation = [func = std::forward<F>(func), fi, promise = QPromise(fi), pool,
540 launchAsync](const QFutureInterfaceBase &parentData) mutable {
541 const auto parent = QFutureInterface<ParentResultType>(parentData).future();
543 if (launchAsync) {
545 std::forward<Function>(func), parent, std::move(promise), pool);
546 fi.setRunnable(asyncJob);
547 continuationJob = asyncJob;
548 } else {
550 std::forward<Function>(func), parent, std::move(promise));
551 }
552
553 bool isLaunched = continuationJob->execute();
554 // If continuation is successfully launched, AsyncContinuation will be deleted
555 // by the QThreadPool which has started it. Synchronous continuation will be
556 // executed immediately, so it's safe to always delete it here.
557 if (!(launchAsync && isLaunched)) {
558 delete continuationJob;
559 continuationJob = nullptr;
560 }
561 };
562 f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d);
563}
564
565template<typename Function, typename ResultType, typename ParentResultType>
566template<typename F>
571{
572 Q_ASSERT(f);
573
574 fi.setLaunchAsync(true);
575 fi.setThreadPool(pool);
576
577 auto continuation = [func = std::forward<F>(func), promise = QPromise(fi),
578 pool](const QFutureInterfaceBase &parentData) mutable {
579 const auto parent = QFutureInterface<ParentResultType>(parentData).future();
581 std::forward<Function>(func), parent, std::move(promise), pool);
582 bool isLaunched = continuationJob->execute();
583 // If continuation is successfully launched, AsyncContinuation will be deleted
584 // by the QThreadPool which has started it.
585 if (!isLaunched) {
586 delete continuationJob;
587 continuationJob = nullptr;
588 }
589 };
590 f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d);
591}
592
593template<typename Function, typename ResultType, typename ParentResultType>
594template<typename F>
599{
600 Q_ASSERT(f);
602
603 // When the context object is destroyed, the signal-slot connection is broken and the
604 // continuation callback is destroyed. The promise that is created in the capture list is
605 // destroyed and, if it is not yet finished, cancelled.
606 auto continuation = [func = std::forward<F>(func), parent = *f,
607 promise = QPromise(fi)]() mutable {
609 std::forward<Function>(func), parent, std::move(promise));
610 continuationJob.execute();
611 };
612
613 auto *watcher = new QBasicFutureWatcher;
614 watcher->moveToThread(context->thread());
616 context, std::move(continuation));
621 watcher->setFuture(f->d);
622}
623
624template<typename Function, typename ResultType, typename ParentResultType>
626{
627 if constexpr (std::is_copy_constructible_v<ParentResultType>)
628 fulfillPromise(parentFuture.result());
629 else
630 fulfillPromise(parentFuture.takeResult());
631}
632
633template<typename Function, typename ResultType, typename ParentResultType>
634void Continuation<Function, ResultType, ParentResultType>::fulfillVoidPromise()
635{
636 if constexpr (std::is_copy_constructible_v<ParentResultType>)
637 function(parentFuture.result());
638 else
639 function(parentFuture.takeResult());
640}
641
642template<typename Function, typename ResultType, typename ParentResultType>
643void Continuation<Function, ResultType, ParentResultType>::fulfillPromiseWithVoidResult()
644{
645 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
646 fulfillPromise(parentFuture);
647 else
649}
650
651template<typename Function, typename ResultType, typename ParentResultType>
652template<class... Args>
653void Continuation<Function, ResultType, ParentResultType>::fulfillPromise(Args &&... args)
654{
655 promise.addResult(std::invoke(function, std::forward<Args>(args)...));
656}
657
658template<class T>
660{
661 if constexpr (!std::is_void_v<T>) {
662 if constexpr (std::is_copy_constructible_v<T>)
663 promise.addResult(future.result());
664 else
665 promise.addResult(future.takeResult());
666 }
667}
668
669template<class T, class Function>
670void fulfillPromise(QPromise<T> &promise, Function &&handler)
671{
672 if constexpr (std::is_void_v<T>)
673 handler();
674 else
675 promise.addResult(handler());
676}
677
678#ifndef QT_NO_EXCEPTIONS
679
680template<class Function, class ResultType>
681template<class F>
684{
686
687 auto failureContinuation = [function = std::forward<F>(function), promise = QPromise(fi)](
688 const QFutureInterfaceBase &parentData) mutable {
689 const auto parent = QFutureInterface<ResultType>(parentData).future();
690 FailureHandler<Function, ResultType> failureHandler(std::forward<Function>(function),
691 parent, std::move(promise));
692 failureHandler.run();
693 };
694
695 future->d.setContinuation(ContinuationWrapper(std::move(failureContinuation)));
696}
697
698template<class Function, class ResultType>
699template<class F>
703{
706 auto failureContinuation = [function = std::forward<F>(function),
707 parent = *future, promise = QPromise(fi)]() mutable {
709 std::forward<Function>(function), parent, std::move(promise));
710 failureHandler.run();
711 };
712
713 auto *watcher = new QBasicFutureWatcher;
714 watcher->moveToThread(context->thread());
715 QObject::connect(watcher, &QBasicFutureWatcher::finished, context, std::move(failureContinuation));
718 watcher->setFuture(future->d);
719}
720
721template<class Function, class ResultType>
723{
724 Q_ASSERT(parentFuture.isFinished());
725
726 promise.start();
727
728 if (parentFuture.d.hasException()) {
729 using ArgType = typename QtPrivate::ArgResolver<Function>::First;
730 if constexpr (std::is_void_v<ArgType>) {
731 handleAllExceptions();
732 } else {
733 handleException<ArgType>();
734 }
735 } else if (parentFuture.d.isChainCanceled()) {
736 promise.future().cancel();
737 } else {
738 QtPrivate::fulfillPromise(promise, parentFuture);
739 }
740 promise.finish();
741}
742
743template<class Function, class ResultType>
744template<class ArgType>
746{
747 try {
748 Q_ASSERT(parentFuture.d.hasException());
749 parentFuture.d.exceptionStore().rethrowException();
750 } catch (const ArgType &e) {
751 try {
752 // Handle exceptions matching with the handler's argument type
753 if constexpr (std::is_void_v<ResultType>)
754 handler(e);
755 else
756 promise.addResult(handler(e));
757 } catch (...) {
758 promise.setException(std::current_exception());
759 }
760 } catch (...) {
761 // Exception doesn't match with handler's argument type, propagate
762 // the exception to be handled later.
763 promise.setException(std::current_exception());
764 }
765}
766
767template<class Function, class ResultType>
768void FailureHandler<Function, ResultType>::handleAllExceptions()
769{
770 try {
771 Q_ASSERT(parentFuture.d.hasException());
772 parentFuture.d.exceptionStore().rethrowException();
773 } catch (...) {
774 try {
775 QtPrivate::fulfillPromise(promise, std::forward<Function>(handler));
776 } catch (...) {
777 promise.setException(std::current_exception());
778 }
779 }
780}
781
782#endif // QT_NO_EXCEPTIONS
783
784template<class Function, class ResultType>
786{
787public:
788 template<class F = Function>
790 {
792
793 auto canceledContinuation = [promise = QPromise(fi), handler = std::forward<F>(handler)](
794 const QFutureInterfaceBase &parentData) mutable {
795 auto parentFuture = QFutureInterface<ResultType>(parentData).future();
796 run(std::forward<F>(handler), parentFuture, std::move(promise));
797 };
798 future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation)));
799 }
800
801 template<class F = Function>
804 {
807 auto canceledContinuation = [handler = std::forward<F>(handler),
808 parentFuture = *future, promise = QPromise(fi)]() mutable {
809 run(std::forward<F>(handler), parentFuture, std::move(promise));
810 };
811
812 auto *watcher = new QBasicFutureWatcher;
813 watcher->moveToThread(context->thread());
815 context, std::move(canceledContinuation));
818 watcher->setFuture(future->d);
819 }
820
821 template<class F = Function>
822 static void run(F &&handler, QFuture<ResultType> &parentFuture, QPromise<ResultType> &&promise)
823 {
824 promise.start();
825
826 if (parentFuture.isCanceled()) {
827#ifndef QT_NO_EXCEPTIONS
828 if (parentFuture.d.hasException()) {
829 // Propagate the exception to the result future
830 promise.setException(parentFuture.d.exceptionStore().exception());
831 } else {
832 try {
833#endif
834 QtPrivate::fulfillPromise(promise, std::forward<F>(handler));
835#ifndef QT_NO_EXCEPTIONS
836 } catch (...) {
837 promise.setException(std::current_exception());
838 }
839 }
840#endif
841 } else {
842 QtPrivate::fulfillPromise(promise, parentFuture);
843 }
844
845 promise.finish();
846 }
847};
848
850{
851 template<class T>
852 static auto unwrapImpl(T *outer)
853 {
854 Q_ASSERT(outer);
855
856 using ResultType = typename QtPrivate::Future<std::decay_t<T>>::type;
857 using NestedType = typename QtPrivate::Future<ResultType>::type;
859
860 outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
861 // We use the .then([](QFuture<ResultType> outerFuture) {...}) version
862 // (where outerFuture == *outer), to propagate the exception if the
863 // outer future has failed.
864 Q_ASSERT(outerFuture.isFinished());
865#ifndef QT_NO_EXCEPTIONS
866 if (outerFuture.d.hasException()) {
867 promise.reportStarted();
868 promise.reportException(outerFuture.d.exceptionStore().exception());
869 promise.reportFinished();
870 return;
871 }
872#endif
873
874 promise.reportStarted();
875 ResultType nestedFuture = outerFuture.result();
876
877 nestedFuture.then([promise] (const QFuture<NestedType> &nested) mutable {
878#ifndef QT_NO_EXCEPTIONS
879 if (nested.d.hasException()) {
880 promise.reportException(nested.d.exceptionStore().exception());
881 } else
882#endif
883 {
884 if constexpr (!std::is_void_v<NestedType>)
885 promise.reportResults(nested.results());
886 }
887 promise.reportFinished();
888 }).onCanceled([promise] () mutable {
889 promise.reportCanceled();
890 promise.reportFinished();
891 });
892 }).onCanceled([promise]() mutable {
893 // propagate the cancellation of the outer future
894 promise.reportStarted();
895 promise.reportCanceled();
896 promise.reportFinished();
897 });
898 return promise.future();
899 }
900};
901
902template<typename ValueType>
904{
906 promise.reportStarted();
907 promise.reportResults(values);
908 promise.reportFinished();
909 return promise.future();
910}
911
912} // namespace QtPrivate
913
914namespace QtFuture {
915
916template<class Signal>
918
919template<class Sender, class Signal, typename = QtPrivate::EnableIfInvocable<Sender, Signal>>
920static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
921{
924 promise.reportStarted();
925 if (!sender) {
926 promise.reportCanceled();
927 promise.reportFinished();
928 return promise.future();
929 }
930
931 using Connections = std::pair<QMetaObject::Connection, QMetaObject::Connection>;
932 auto connections = std::make_shared<Connections>();
933
934 if constexpr (std::is_void_v<ArgsType>) {
935 connections->first =
936 QObject::connect(sender, signal, sender, [promise, connections]() mutable {
937 QObject::disconnect(connections->first);
938 QObject::disconnect(connections->second);
939 promise.reportFinished();
940 });
942 connections->first = QObject::connect(sender, signal, sender,
943 [promise, connections](auto... values) mutable {
944 QObject::disconnect(connections->first);
945 QObject::disconnect(connections->second);
947 std::move(values)...));
948 promise.reportFinished();
949 });
950 } else {
951 connections->first = QObject::connect(sender, signal, sender,
952 [promise, connections](ArgsType value) mutable {
953 QObject::disconnect(connections->first);
954 QObject::disconnect(connections->second);
955 promise.reportResult(value);
956 promise.reportFinished();
957 });
958 }
959
960 if (!connections->first) {
961 promise.reportCanceled();
962 promise.reportFinished();
963 return promise.future();
964 }
965
966 connections->second =
967 QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable {
968 QObject::disconnect(connections->first);
969 QObject::disconnect(connections->second);
970 promise.reportCanceled();
971 promise.reportFinished();
972 });
973
974 return promise.future();
975}
976
977template<typename Container>
979 std::enable_if_t<QtPrivate::HasInputIterator<Container>::value, bool>;
980
981template<typename Container>
983 typename std::iterator_traits<decltype(
984 std::cbegin(std::declval<Container&>()))>::value_type;
985
986template<typename Container, if_container_with_input_iterators<Container> = true>
988{
989 // handle QList<T> separately, because reportResults() takes a QList
990 // as an input
991 using ValueType = ContainedType<Container>;
992 if constexpr (std::is_convertible_v<q20::remove_cvref_t<Container>, QList<ValueType>>) {
993 return QtPrivate::makeReadyRangeFutureImpl(container);
994 } else {
995 return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{std::cbegin(container),
996 std::cend(container)});
997 }
998}
999
1000template<typename ValueType>
1001static QFuture<ValueType> makeReadyRangeFuture(std::initializer_list<ValueType> values)
1002{
1004}
1005
1006template<typename T>
1008{
1010 promise.reportStarted();
1011 promise.reportResult(std::forward<T>(value));
1012 promise.reportFinished();
1013
1014 return promise.future();
1015}
1016
1017Q_CORE_EXPORT QFuture<void> makeReadyVoidFuture(); // implemented in qfutureinterface.cpp
1018
1019#if QT_DEPRECATED_SINCE(6, 10)
1020template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
1021QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyValueFuture() instead")
1022static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
1023{
1024 return makeReadyValueFuture(std::forward<T>(value));
1025}
1026
1027// the void specialization is moved to the end of qfuture.h, because it now
1028// uses makeReadyVoidFuture() and required QFuture<void> to be defined.
1029
1030template<typename T>
1031QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyRangeFuture() instead")
1032static QFuture<T> makeReadyFuture(const QList<T> &values)
1033{
1035}
1036#endif // QT_DEPRECATED_SINCE(6, 10)
1037
1038#ifndef QT_NO_EXCEPTIONS
1039
1040template<typename T = void>
1041static QFuture<T> makeExceptionalFuture(std::exception_ptr exception)
1042{
1043 QFutureInterface<T> promise;
1044 promise.reportStarted();
1045 promise.reportException(exception);
1046 promise.reportFinished();
1047
1048 return promise.future();
1049}
1050
1051template<typename T = void>
1053{
1054 try {
1055 exception.raise();
1056 } catch (...) {
1057 return makeExceptionalFuture<T>(std::current_exception());
1058 }
1059 Q_UNREACHABLE();
1060}
1061
1062#endif // QT_NO_EXCEPTIONS
1063
1064} // namespace QtFuture
1065
1066namespace QtPrivate {
1067
1068template<typename ResultFutures>
1070{
1071 using ValueType = typename ResultFutures::value_type;
1072
1074
1075 template<typename T = ValueType>
1077 {
1078 futures[index] = std::forward<T>(future);
1079 const auto oldRemaining = remaining.fetchAndSubRelaxed(1);
1080 Q_ASSERT(oldRemaining > 0);
1081 if (oldRemaining <= 1) { // that was the last one
1083 promise.finish();
1084 }
1085 }
1086
1089 ResultFutures futures;
1090};
1091
1092template<typename ResultType>
1094{
1095 using ValueType = ResultType;
1096
1097 template<typename T = ResultType, typename = EnableForNonVoid<T>>
1099 {
1100 if (!ready.fetchAndStoreRelaxed(true)) {
1101 promise.addResult(std::forward<T>(result));
1102 promise.finish();
1103 }
1104 }
1105
1108};
1109
1110template<qsizetype Index, typename ContextType, typename... Ts>
1111void addCompletionHandlersImpl(const std::shared_ptr<ContextType> &context,
1112 const std::tuple<Ts...> &t)
1113{
1114 auto future = std::get<Index>(t);
1115 using ResultType = typename ContextType::ValueType;
1116 future.then([context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
1117 context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, f });
1118 }).onCanceled([context, future]() {
1119 context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, future });
1120 });
1121
1122 if constexpr (Index != 0)
1123 addCompletionHandlersImpl<Index - 1, ContextType, Ts...>(context, t);
1124}
1125
1126template<typename ContextType, typename... Ts>
1127void addCompletionHandlers(const std::shared_ptr<ContextType> &context, const std::tuple<Ts...> &t)
1128{
1129 constexpr qsizetype size = std::tuple_size<std::tuple<Ts...>>::value;
1130 addCompletionHandlersImpl<size - 1, ContextType, Ts...>(context, t);
1131}
1132
1133template<typename OutputSequence, typename InputIt, typename ValueType>
1135{
1136 const qsizetype size = std::distance(first, last);
1137 if (size == 0)
1138 return QtFuture::makeReadyValueFuture(OutputSequence());
1139
1140 const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
1141 context->futures.resize(size);
1142 context->promise.start();
1143
1144 qsizetype idx = 0;
1145 for (auto it = first; it != last; ++it, ++idx) {
1146 it->then([context, idx](const ValueType &f) {
1147 context->checkForCompletion(idx, f);
1148 }).onCanceled([context, idx, f = *it] {
1149 context->checkForCompletion(idx, f);
1150 });
1151 }
1152 return context->promise.future();
1153}
1154
1155template<typename OutputSequence, typename... Futures>
1157{
1158 constexpr qsizetype size = sizeof...(Futures);
1159 const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
1160 context->futures.resize(size);
1161 context->promise.start();
1162
1163 QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));
1164
1165 return context->promise.future();
1166}
1167
1168template<typename InputIt, typename ValueType>
1170 InputIt last)
1171{
1172 using PackagedType = typename Future<ValueType>::type;
1173 using ResultType = QtFuture::WhenAnyResult<PackagedType>;
1174
1175 const qsizetype size = std::distance(first, last);
1176 if (size == 0) {
1179 }
1180
1181 const auto context = std::make_shared<QtPrivate::WhenAnyContext<ResultType>>();
1182 context->promise.start();
1183
1184 qsizetype idx = 0;
1185 for (auto it = first; it != last; ++it, ++idx) {
1186 it->then([context, idx](const ValueType &f) {
1187 context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
1188 }).onCanceled([context, idx, f = *it] {
1189 context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
1190 });
1191 }
1192 return context->promise.future();
1193}
1194
1195template<typename... Futures>
1197{
1198 using ResultType = std::variant<std::decay_t<Futures>...>;
1199
1200 const auto context = std::make_shared<QtPrivate::WhenAnyContext<ResultType>>();
1201 context->promise.start();
1202
1203 QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));
1204
1205 return context->promise.future();
1206}
1207
1208} // namespace QtPrivate
1209
\inmodule QtCore
Definition qatomic.h:112
\inmodule QtCore
Definition qatomic.h:18
T fetchAndStoreRelaxed(T newValue) noexcept
T fetchAndSubRelaxed(T valueToAdd) noexcept
\inmodule QtCore
Definition qexception.h:22
virtual void raise() const
In your QException subclass, reimplement raise() like this:
bool reportResults(const QList< T > &results, int beginIndex=-1, int count=-1)
QFuture< T > future()
Definition qfuture.h:320
void reportException(const std::exception_ptr &e)
bool reportFinished(const T *result)
bool reportResult(const T *result, int index=-1)
bool isCanceled() const
Definition qfuture.h:65
T result() const
Definition qfuture.h:305
bool isFinished() const
Definition qfuture.h:94
Definition qlist.h:74
\inmodule QtCore
Definition qobject.h:90
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
void finish()
Definition qpromise.h:75
bool addResult(U &&result, int index=-1)
Definition qpromise.h:60
\inmodule QtCore
Definition qrunnable.h:18
\inmodule QtCore
Definition qthreadpool.h:20
void start(QRunnable *runnable, int priority=0)
Reserves a thread and uses it to run runnable, unless this thread will make the current thread count ...
static QThreadPool * globalInstance()
Returns the global QThreadPool instance.
~AsyncContinuation() override=default
AsyncContinuation(F &&func, const QFuture< ParentResultType > &f, QPromise< ResultType > &&p, QThreadPool *pool=nullptr)
void run() override
Implement this pure virtual function in your subclass.
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)
QFuture< ParentResultType > parentFuture
virtual void runImpl()=0
Continuation(F &&func, const QFuture< ParentResultType > &f, QPromise< ResultType > &&p)
virtual ~Continuation()=default
static void create(F &&func, QFuture< ParentResultType > *f, QFutureInterface< ResultType > &fi, QtFuture::Launch policy)
QPromise< ResultType > promise
static void create(F &&function, QFuture< ResultType > *future, const QFutureInterface< ResultType > &fi)
FailureHandler(F &&func, const QFuture< ResultType > &f, QPromise< ResultType > &&p)
~SyncContinuation() override=default
SyncContinuation(F &&func, const QFuture< ParentResultType > &f, QPromise< ResultType > &&p)
double e
QSet< QString >::iterator it
auto signal
Combined button and popup list for selecting options.
typename std::iterator_traits< decltype(std::cbegin(std::declval< Container & >()))>::value_type ContainedType
Q_CORE_EXPORT QFuture< void > makeReadyVoidFuture()
static QFuture< std::decay_t< T > > makeReadyValueFuture(T &&value)
static QFuture< T > makeExceptionalFuture(std::exception_ptr exception)
static QFuture< ContainedType< Container > > makeReadyRangeFuture(Container &&container)
typename QtPrivate::ArgResolver< Signal >::AllArgs ArgsType
static QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
std::enable_if_t< QtPrivate::HasInputIterator< Container >::value, bool > if_container_with_input_iterators
\macro QT_NAMESPACE
QFuture< OutputSequence > whenAllImpl(InputIt first, InputIt last)
std::enable_if_t< QtPrivate::ArgResolver< Callable >::template CanInvokeWithArgs< Class, Callable > > EnableIfInvocable
auto createTuple(Arg &&arg, Args &&... args)
std::bool_constant<(sizeof...(Args) > 0)> NotEmpty
void addCompletionHandlersImpl(const std::shared_ptr< ContextType > &context, const std::tuple< Ts... > &t)
constexpr bool isQFutureV
QFuture< QtFuture::WhenAnyResult< typename Future< ValueType >::type > > whenAnyImpl(InputIt first, InputIt last)
std::is_convertible< typename std::iterator_traits< Iterator >::iterator_category, std::forward_iterator_tag > IsForwardIterable
std::is_convertible< typename std::iterator_traits< std::decay_t< decltype(std::begin(std::declval< Sequence >()))> >::iterator_category, std::random_access_iterator_tag > IsRandomAccessible
std::is_convertible< typename std::iterator_traits< std::decay_t< decltype(std::begin(std::declval< Sequence >()))> >::iterator_category, std::input_iterator_tag > HasInputIterator
std::bool_constant< isQFutureV< T > > isQFuture
void fulfillPromise(QPromise< T > &promise, QFuture< T > &future)
QFuture< ValueType > makeReadyRangeFutureImpl(const QList< ValueType > &values)
std::enable_if_t<!std::is_same_v< T, void > > EnableForNonVoid
constexpr bool IsPrivateSignalArg
std::enable_if_t< std::is_same_v< T, void > > EnableForVoid
auto cutTuple(Tuple &&t, std::index_sequence< I... >)
std::conditional_t< FunctionPointer< std::decay_t< Func > >::ArgumentCount==-1, ZeroArgFunctor< std::decay_t< Func > >, FunctionPointer< std::decay_t< Func > > > Callable
void addCompletionHandlers(const std::shared_ptr< ContextType > &context, const std::tuple< Ts... > &t)
std::conditional_t<(sizeof...(Args) > 0), std::invoke_result_t< decltype(createTuple< Arg, Args... >), Arg, Args... >, std::conditional_t< IsPrivateSignalArg< Arg >, void, Arg > > FilterLastPrivateSignalArg
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Size(name)
GLenum GLsizei GLsizei GLint * values
[15]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLfloat GLfloat f
GLenum type
GLint first
GLenum func
Definition qopenglext.h:663
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
SSL_CTX int(*) void arg)
#define QT_DEPRECATED_VERSION_X(major, minor, text)
ptrdiff_t qsizetype
Definition qtypes.h:70
QFuture< void > future
[5]
QFutureWatcher< int > watcher
QFileInfo fi("c:/temp/foo")
[newstuff]
QSharedPointer< T > other(t)
[5]
QSizePolicy policy
view create()
QJSValueList args
FilterLastPrivateSignalArg< std::decay_t< Arg >, std::decay_t< Args >... > AllArgs
FilterLastPrivateSignalArg< QPromise< Arg >, std::decay_t< Args >... > AllArgs
std::false_type IsPromise
void operator()(const QFutureInterfaceBase &parentData)
ContinuationWrapper(ContinuationWrapper &&other)=default
ContinuationWrapper & operator=(ContinuationWrapper &&)=default
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)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent