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
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/qfunctionaltools_impl.h>
15#include <QtCore/qfutureinterface.h>
16#include <QtCore/qthreadpool.h>
17#include <QtCore/qexception.h>
18#include <QtCore/qpromise.h>
19#include <QtCore/qvariant.h>
20
21#include <memory>
22
23QT_BEGIN_NAMESPACE
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>
45
46// Deduction guide
47template<class T>
48WhenAnyResult(qsizetype, const QFuture<T> &) -> WhenAnyResult<T>;
49}
50
51namespace QtPrivate {
52
53template<class T>
55
56template<class T>
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>
71
72// The callable takes an argument of type QFuture<Arg>
73template<class F, class Arg>
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{
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{
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:
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...>,
137
138template<typename...>
139struct ArgsType;
140
141template<typename Arg, typename... Args>
142struct ArgsType<Arg, Args...>
143{
144 using First = Arg;
145 using PromiseType = void;
146 using IsPromise = std::false_type;
147 static const bool HasExtraArgs = (sizeof...(Args) > 0);
148 using AllArgs = FilterLastPrivateSignalArg<std::decay_t<Arg>, std::decay_t<Args>...>;
149
150 template<class Class, class Callable>
152};
153
154template<typename Arg, typename... Args>
155struct ArgsType<QPromise<Arg> &, Args...>
156{
157 using First = QPromise<Arg> &;
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>
165};
166
167template<>
168struct ArgsType<>
169{
170 using First = void;
171 using PromiseType = void;
172 using IsPromise = std::false_type;
173 static const bool HasExtraArgs = false;
174 using AllArgs = void;
175
176 template<class Class, class Callable>
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>
248
249template<class T>
250inline constexpr bool isQFutureV = false;
251
252template<class T>
253inline constexpr bool isQFutureV<QFuture<T>> = true;
254
255template<class T>
257
258template<class T>
259struct Future
260{
261};
262
263template<class 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(
277
278template<class Sequence>
280 std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
283
284template<class Iterator>
285using IsForwardIterable =
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{
293public:
295
296 template<typename F = Function>
297 CompactContinuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p)
298 : Storage{std::forward<F>(func)}, promise(std::move(p)), parentFuture(f), type(Type::Sync)
299 {
300 }
301
302 template<typename F = Function>
303 CompactContinuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p,
304 QThreadPool *pool)
305 : Storage{std::forward<F>(func)}, promise(std::move(p)), parentFuture(f),
306 threadPool(pool), type(Type::Async)
307 {
308 runObj = QRunnable::create([continuation = this] {
309 continuation->runFunction();
310 delete continuation;
311 });
312 runObj->setAutoDelete(false);
313 }
314
315 ~CompactContinuation() { delete runObj; }
316
317 bool execute();
318
319 QRunnable *runnable() const { return runObj; }
320
321 template<typename F = Function>
322 static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
323 QtFuture::Launch policy);
324
325 template<typename F = Function>
326 static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
327 QThreadPool *pool);
328
329 template<typename F = Function>
330 static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
331 QObject *context);
332
333private:
334 void fulfillPromiseWithResult();
335 void fulfillVoidPromise();
336 void fulfillPromiseWithVoidResult();
337
338 template<class... Args>
339 void fulfillPromise(Args &&... args);
340
341protected:
342 void runImpl()
343 {
344 if (type == Type::Sync) {
346 } else {
347 Q_ASSERT(runObj);
348 QThreadPool *pool = threadPool ? threadPool : QThreadPool::globalInstance();
349 pool->start(runObj);
350 }
351 }
352
353 void runFunction();
354
355protected:
356 enum class Type : quint8 {
359 };
360
361 QPromise<ResultType> promise;
364 QRunnable *runObj = nullptr;
365 const Type type;
366};
367
368#ifndef QT_NO_EXCEPTIONS
369
370template<class Function, class ResultType>
372{
373public:
374 template<typename F = Function>
375 static void create(F &&function, QFuture<ResultType> *future,
376 const QFutureInterface<ResultType> &fi);
377
378 template<typename F = Function>
379 static void create(F &&function, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi,
380 QObject *context);
381
382 template<typename F = Function>
383 FailureHandler(F &&func, const QFuture<ResultType> &f, QPromise<ResultType> &&p)
384 : promise(std::move(p)), parentFuture(f), handler(std::forward<F>(func))
385 {
386 }
387
388public:
389 void run();
390
391private:
392 template<class ArgType>
393 void handleException();
394 void handleAllExceptions();
395
396private:
397 QPromise<ResultType> promise;
398 QFuture<ResultType> parentFuture;
399 Function handler;
400};
401
402#endif
403
404template<typename Function, typename ResultType, typename ParentResultType>
405void CompactContinuation<Function, ResultType, ParentResultType>::runFunction()
406{
407 promise.start();
408
409 Q_ASSERT(parentFuture.isFinished());
410
411#ifndef QT_NO_EXCEPTIONS
412 try {
413#endif
414 if constexpr (!std::is_void_v<ResultType>) {
415 if constexpr (std::is_void_v<ParentResultType>) {
416 fulfillPromiseWithVoidResult();
417 } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
418 fulfillPromiseWithResult();
419 } else {
420 // This assert normally should never fail, this is to make sure
421 // that nothing unexpected happened.
422 static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
423 "The continuation is not invocable with the provided arguments");
424 fulfillPromise(parentFuture);
425 }
426 } else {
427 if constexpr (std::is_void_v<ParentResultType>) {
428 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
429 this->object()(parentFuture);
430 else
431 this->object()();
432 } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
433 fulfillVoidPromise();
434 } else {
435 // This assert normally should never fail, this is to make sure
436 // that nothing unexpected happened.
437 static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
438 "The continuation is not invocable with the provided arguments");
439 this->object()(parentFuture);
440 }
441 }
442#ifndef QT_NO_EXCEPTIONS
443 } catch (...) {
444 promise.setException(std::current_exception());
445 }
446#endif
447 promise.finish();
448}
449
450template<typename Function, typename ResultType, typename ParentResultType>
451bool CompactContinuation<Function, ResultType, ParentResultType>::execute()
452{
453 Q_ASSERT(parentFuture.isFinished());
454
455 if (parentFuture.d.isChainCanceled()) {
456#ifndef QT_NO_EXCEPTIONS
457 if (parentFuture.d.hasException()) {
458 // If the continuation doesn't take a QFuture argument, propagate the exception
459 // to the caller, by reporting it. If the continuation takes a QFuture argument,
460 // the user may want to catch the exception inside the continuation, to not
461 // interrupt the continuation chain, so don't report anything yet.
462 if constexpr (!std::is_invocable_v<std::decay_t<Function>, QFuture<ParentResultType>>) {
463 promise.start();
464 promise.setException(parentFuture.d.exceptionStore().exception());
465 promise.finish();
466 return false;
467 }
468 } else
469#endif
470 {
471 promise.start();
472 promise.future().cancel();
473 promise.finish();
474 return false;
475 }
476 }
477
478 runImpl();
479 return true;
480}
481
482// Workaround for keeping move-only lambdas inside std::function
483template<class Function>
485{
486 ContinuationWrapper(Function &&f) : function(std::move(f)) { }
488 : function(std::move(const_cast<ContinuationWrapper &>(other).function))
489 {
490 Q_ASSERT_X(false, "QFuture", "Continuation shouldn't be copied");
491 }
494
495 template <typename F = Function,
496 std::enable_if_t<std::is_invocable_v<F, const QFutureInterfaceBase &>, bool> = true>
497 void operator()(const QFutureInterfaceBase &parentData) { function(parentData); }
498
499 template <typename F = Function, std::enable_if_t<std::is_invocable_v<F>, bool> = true>
500 void operator()() { function(); }
501
502private:
503 Function function;
504};
505
506template<typename Function, typename ResultType, typename ParentResultType>
507template<typename F>
508void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
509 QFuture<ParentResultType> *f,
510 QFutureInterface<ResultType> &fi,
511 QtFuture::Launch policy)
512{
513 Q_ASSERT(f);
514
515 QThreadPool *pool = nullptr;
516
517 bool launchAsync = (policy == QtFuture::Launch::Async);
518 if (policy == QtFuture::Launch::Inherit) {
519 launchAsync = f->d.launchAsync();
520
521 // If the parent future was using a custom thread pool, inherit it as well.
522 if (launchAsync && f->d.threadPool()) {
523 pool = f->d.threadPool();
524 fi.setThreadPool(pool);
525 }
526 }
527
528 fi.setLaunchAsync(launchAsync);
529
530 auto continuation = [func = std::forward<F>(func), fi, promise_ = QPromise(fi), pool,
531 launchAsync](const QFutureInterfaceBase &parentData) mutable {
532 const auto parent = QFutureInterface<ParentResultType>(parentData).future();
533 CompactContinuation<Function, ResultType, ParentResultType> *continuationJob = nullptr;
534 if (launchAsync) {
535 auto asyncJob = new CompactContinuation<Function, ResultType, ParentResultType>(
536 std::forward<Function>(func), parent, std::move(promise_), pool);
537 fi.setRunnable(asyncJob->runnable());
538 continuationJob = asyncJob;
539 } else {
540 continuationJob = new CompactContinuation<Function, ResultType, ParentResultType>(
541 std::forward<Function>(func), parent, std::move(promise_));
542 }
543
544 bool isLaunched = continuationJob->execute();
545 // If continuation is successfully launched, AsyncContinuation will be deleted
546 // from the QRunnable's lambda. Synchronous continuation will be
547 // executed immediately, so it's safe to always delete it here.
548 if (!(launchAsync && isLaunched)) {
549 delete continuationJob;
550 continuationJob = nullptr;
551 }
552 };
553 f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d,
554 QFutureInterfaceBase::ContinuationType::Then);
555}
556
557template<typename Function, typename ResultType, typename ParentResultType>
558template<typename F>
559void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
560 QFuture<ParentResultType> *f,
561 QFutureInterface<ResultType> &fi,
562 QThreadPool *pool)
563{
564 Q_ASSERT(f);
565
566 fi.setLaunchAsync(true);
567 fi.setThreadPool(pool);
568
569 auto continuation = [func = std::forward<F>(func), promise_ = QPromise(fi),
570 pool](const QFutureInterfaceBase &parentData) mutable {
571 const auto parent = QFutureInterface<ParentResultType>(parentData).future();
572 auto continuationJob = new CompactContinuation<Function, ResultType, ParentResultType>(
573 std::forward<Function>(func), parent, std::move(promise_), pool);
574 bool isLaunched = continuationJob->execute();
575 // If continuation is successfully launched, AsyncContinuation will be deleted
576 // from the QRunnable's lambda.
577 if (!isLaunched) {
578 delete continuationJob;
579 continuationJob = nullptr;
580 }
581 };
582 f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d,
583 QFutureInterfaceBase::ContinuationType::Then);
584}
585
586template<typename Function, typename ResultType, typename ParentResultType>
587template<typename F>
588void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
589 QFuture<ParentResultType> *f,
590 QFutureInterface<ResultType> &fi,
591 QObject *context)
592{
593 Q_ASSERT(f);
594 Q_ASSERT(context);
595
596 // When the context object is destroyed, the signal-slot connection is broken and the
597 // continuation callback is destroyed. The promise that is created in the capture list is
598 // destroyed and, if it is not yet finished, cancelled.
599 auto continuation = [func = std::forward<F>(func), parent = *f,
600 promise_ = QPromise(fi)]() mutable {
601 CompactContinuation<Function, ResultType, ParentResultType> continuationJob(
602 std::forward<Function>(func), parent, std::move(promise_));
603 continuationJob.execute();
604 };
605
606 f->d.setContinuation(context, ContinuationWrapper(std::move(continuation)),
607 QVariant::fromValue(fi),
608 QFutureInterfaceBase::ContinuationType::Then);
609}
610
611template<typename Function, typename ResultType, typename ParentResultType>
612void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromiseWithResult()
613{
614 if constexpr (std::is_copy_constructible_v<ParentResultType>)
615 fulfillPromise(parentFuture.result());
616 else
617 fulfillPromise(parentFuture.takeResult());
618}
619
620template<typename Function, typename ResultType, typename ParentResultType>
621void CompactContinuation<Function, ResultType, ParentResultType>::fulfillVoidPromise()
622{
623 if constexpr (std::is_copy_constructible_v<ParentResultType>)
624 this->object()(parentFuture.result());
625 else
626 this->object()(parentFuture.takeResult());
627}
628
629template<typename Function, typename ResultType, typename ParentResultType>
630void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromiseWithVoidResult()
631{
632 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
633 fulfillPromise(parentFuture);
634 else
635 fulfillPromise();
636}
637
638template<typename Function, typename ResultType, typename ParentResultType>
639template<class... Args>
640void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromise(Args &&... args)
641{
642 promise.addResult(std::invoke(this->object(), std::forward<Args>(args)...));
643}
644
645template<class T>
646void fulfillPromise(QPromise<T> &promise, QFuture<T> &future)
647{
648 if constexpr (!std::is_void_v<T>) {
649 if constexpr (std::is_copy_constructible_v<T>)
650 promise.addResult(future.result());
651 else
652 promise.addResult(future.takeResult());
653 }
654}
655
656template<class T, class Function>
657void fulfillPromise(QPromise<T> &promise, Function &&handler)
658{
659 if constexpr (std::is_void_v<T>)
660 handler();
661 else
662 promise.addResult(handler());
663}
664
665#ifndef QT_NO_EXCEPTIONS
666
667template<class Function, class ResultType>
668template<class F>
669void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultType> *future,
670 const QFutureInterface<ResultType> &fi)
671{
672 Q_ASSERT(future);
673
674 auto failureContinuation = [function = std::forward<F>(function), promise_ = QPromise(fi)](
675 const QFutureInterfaceBase &parentData) mutable {
676 const auto parent = QFutureInterface<ResultType>(parentData).future();
677 FailureHandler<Function, ResultType> failureHandler(std::forward<Function>(function),
678 parent, std::move(promise_));
679 failureHandler.run();
680 };
681
682 future->d.setContinuation(ContinuationWrapper(std::move(failureContinuation)), fi.d,
683 QFutureInterfaceBase::ContinuationType::OnFailed);
684}
685
686template<class Function, class ResultType>
687template<class F>
688void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultType> *future,
689 QFutureInterface<ResultType> &fi,
690 QObject *context)
691{
692 Q_ASSERT(future);
693 Q_ASSERT(context);
694 auto failureContinuation = [function = std::forward<F>(function),
695 parent = *future, promise_ = QPromise(fi)]() mutable {
696 FailureHandler<Function, ResultType> failureHandler(
697 std::forward<Function>(function), parent, std::move(promise_));
698 failureHandler.run();
699 };
700
701 future->d.setContinuation(context, ContinuationWrapper(std::move(failureContinuation)),
702 QVariant::fromValue(fi),
703 QFutureInterfaceBase::ContinuationType::OnFailed);
704}
705
706template<class Function, class ResultType>
707void FailureHandler<Function, ResultType>::run()
708{
709 Q_ASSERT(parentFuture.isFinished());
710
711 promise.start();
712
713 if (parentFuture.d.hasException()) {
714 using ArgType = typename QtPrivate::ArgResolver<Function>::First;
715 if constexpr (std::is_void_v<ArgType>) {
716 handleAllExceptions();
717 } else {
718 handleException<ArgType>();
719 }
720 } else if (parentFuture.d.isChainCanceled()) {
721 promise.future().cancel();
722 } else {
723 QtPrivate::fulfillPromise(promise, parentFuture);
724 }
725 promise.finish();
726}
727
728template<class Function, class ResultType>
729template<class ArgType>
730void FailureHandler<Function, ResultType>::handleException()
731{
732 try {
733 Q_ASSERT(parentFuture.d.hasException());
734 parentFuture.d.exceptionStore().rethrowException();
735 } catch (const ArgType &e) {
736 try {
737 // Handle exceptions matching with the handler's argument type
738 if constexpr (std::is_void_v<ResultType>)
739 handler(e);
740 else
741 promise.addResult(handler(e));
742 } catch (...) {
743 promise.setException(std::current_exception());
744 }
745 } catch (...) {
746 // Exception doesn't match with handler's argument type, propagate
747 // the exception to be handled later.
748 promise.setException(std::current_exception());
749 }
750}
751
752template<class Function, class ResultType>
753void FailureHandler<Function, ResultType>::handleAllExceptions()
754{
755 try {
756 Q_ASSERT(parentFuture.d.hasException());
757 parentFuture.d.exceptionStore().rethrowException();
758 } catch (...) {
759 try {
760 QtPrivate::fulfillPromise(promise, std::forward<Function>(handler));
761 } catch (...) {
762 promise.setException(std::current_exception());
763 }
764 }
765}
766
767#endif // QT_NO_EXCEPTIONS
768
769template<class Function, class ResultType>
771{
772public:
773 template<class F = Function>
774 static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi)
775 {
776 Q_ASSERT(future);
777
778 auto canceledContinuation = [promise = QPromise(fi), handler = std::forward<F>(handler)](
779 const QFutureInterfaceBase &parentData) mutable {
780 auto parentFuture = QFutureInterface<ResultType>(parentData).future();
781 run(std::forward<F>(handler), parentFuture, std::move(promise));
782 };
783 future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation)), fi.d,
784 QFutureInterfaceBase::ContinuationType::OnCanceled);
785 }
786
787 template<class F = Function>
788 static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi,
789 QObject *context)
790 {
791 Q_ASSERT(future);
792 Q_ASSERT(context);
793 auto canceledContinuation = [handler = std::forward<F>(handler),
794 parentFuture = *future, promise = QPromise(fi)]() mutable {
795 run(std::forward<F>(handler), parentFuture, std::move(promise));
796 };
797
798 future->d.setContinuation(context, ContinuationWrapper(std::move(canceledContinuation)),
799 QVariant::fromValue(fi),
800 QFutureInterfaceBase::ContinuationType::OnCanceled);
801 }
802
803 template<class F = Function>
804 static void run(F &&handler, QFuture<ResultType> &parentFuture, QPromise<ResultType> &&promise)
805 {
806 promise.start();
807
808 if (parentFuture.isCanceled()) {
809#ifndef QT_NO_EXCEPTIONS
810 if (parentFuture.d.hasException()) {
811 // Propagate the exception to the result future
812 promise.setException(parentFuture.d.exceptionStore().exception());
813 } else {
814 try {
815#endif
816 QtPrivate::fulfillPromise(promise, std::forward<F>(handler));
817#ifndef QT_NO_EXCEPTIONS
818 } catch (...) {
819 promise.setException(std::current_exception());
820 }
821 }
822#endif
823 } else {
824 QtPrivate::fulfillPromise(promise, parentFuture);
825 }
826
827 promise.finish();
828 }
829};
830
832{
833 template<class T>
834 static auto unwrapImpl(T *outer)
835 {
836 Q_ASSERT(outer);
837
838 using ResultType = typename QtPrivate::Future<std::decay_t<T>>::type;
839 using NestedType = typename QtPrivate::Future<ResultType>::type;
840 QFutureInterface<NestedType> promise(QFutureInterfaceBase::State::Pending);
841
842 outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
843 // We use the .then([](QFuture<ResultType> outerFuture) {...}) version
844 // (where outerFuture == *outer), to propagate the exception if the
845 // outer future has failed.
846 Q_ASSERT(outerFuture.isFinished());
847#ifndef QT_NO_EXCEPTIONS
848 if (outerFuture.d.hasException()) {
849 promise.reportStarted();
850 promise.reportException(outerFuture.d.exceptionStore().exception());
851 promise.reportFinished();
852 return;
853 }
854#endif
855
856 promise.reportStarted();
857 ResultType nestedFuture = outerFuture.result();
858
859 nestedFuture.then([promise] (const QFuture<NestedType> &nested) mutable {
860#ifndef QT_NO_EXCEPTIONS
861 if (nested.d.hasException()) {
862 promise.reportException(nested.d.exceptionStore().exception());
863 } else
864#endif
865 {
866 if constexpr (!std::is_void_v<NestedType>)
867 promise.reportResults(nested.results());
868 }
869 promise.reportFinished();
870 }).onCanceled([promise] () mutable {
871 promise.reportCanceled();
872 promise.reportFinished();
873 });
874 }).onCanceled([promise]() mutable {
875 // propagate the cancellation of the outer future
876 promise.reportStarted();
877 promise.reportCanceled();
878 promise.reportFinished();
879 });
880 return promise.future();
881 }
882};
883
884template<typename ValueType>
885QFuture<ValueType> makeReadyRangeFutureImpl(const QList<ValueType> &values)
886{
887 QFutureInterface<ValueType> promise;
888 promise.reportStarted();
889 promise.reportResults(values);
890 promise.reportFinished();
891 return promise.future();
892}
893
894} // namespace QtPrivate
895
896namespace QtFuture {
897
898template<class Signal>
899using ArgsType = typename QtPrivate::ArgResolver<Signal>::AllArgs;
900
901template<class Sender, class Signal, typename = QtPrivate::EnableIfInvocable<Sender, Signal>>
902static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
903{
904 using ArgsType = ArgsType<Signal>;
905 QFutureInterface<ArgsType> promise;
906 promise.reportStarted();
907 if (!sender) {
908 promise.reportCanceled();
909 promise.reportFinished();
910 return promise.future();
911 }
912
913 using Connections = std::pair<QMetaObject::Connection, QMetaObject::Connection>;
914 auto connections = std::make_shared<Connections>();
915
916 if constexpr (std::is_void_v<ArgsType>) {
917 connections->first =
918 QObject::connect(sender, signal, sender, [promise, connections]() mutable {
919 QObject::disconnect(connections->first);
920 QObject::disconnect(connections->second);
921 promise.reportFinished();
922 });
923 } else if constexpr (QtPrivate::ArgResolver<Signal>::HasExtraArgs) {
924 connections->first = QObject::connect(sender, signal, sender,
925 [promise, connections](auto... values) mutable {
926 QObject::disconnect(connections->first);
927 QObject::disconnect(connections->second);
928 promise.reportResult(QtPrivate::createTuple(
929 std::move(values)...));
930 promise.reportFinished();
931 });
932 } else {
933 connections->first = QObject::connect(sender, signal, sender,
934 [promise, connections](ArgsType value) mutable {
935 QObject::disconnect(connections->first);
936 QObject::disconnect(connections->second);
937 promise.reportResult(value);
938 promise.reportFinished();
939 });
940 }
941
942 if (!connections->first) {
943 promise.reportCanceled();
944 promise.reportFinished();
945 return promise.future();
946 }
947
948 connections->second =
949 QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable {
950 QObject::disconnect(connections->first);
951 QObject::disconnect(connections->second);
952 promise.reportCanceled();
953 promise.reportFinished();
954 });
955
956 return promise.future();
957}
958
959template<typename Container>
962
963template<typename Container>
965 typename std::iterator_traits<decltype(
967
968template<typename Container, if_container_with_input_iterators<Container> = true>
970{
971 // handle QList<T> separately, because reportResults() takes a QList
972 // as an input
973 using ValueType = ContainedType<Container>;
974 if constexpr (std::is_convertible_v<q20::remove_cvref_t<Container>, QList<ValueType>>) {
975 return QtPrivate::makeReadyRangeFutureImpl(container);
976 } else {
977 return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{std::cbegin(container),
978 std::cend(container)});
979 }
980}
981
982template<typename ValueType>
987
988template<typename T>
990{
991 QFutureInterface<std::decay_t<T>> promise;
992 promise.reportStarted();
993 promise.reportResult(std::forward<T>(value));
994 promise.reportFinished();
995
996 return promise.future();
997}
998
999Q_CORE_EXPORT QFuture<void> makeReadyVoidFuture(); // implemented in qfutureinterface.cpp
1000
1001#if QT_DEPRECATED_SINCE(6, 10)
1002template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
1003QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyValueFuture() instead.")
1005{
1007}
1008
1009// the void specialization is moved to the end of qfuture.h, because it now
1010// uses makeReadyVoidFuture() and required QFuture<void> to be defined.
1011
1012template<typename T>
1013QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyRangeFuture() instead.")
1014static QFuture<T> makeReadyFuture(const QList<T> &values)
1015{
1017}
1018#endif // QT_DEPRECATED_SINCE(6, 10)
1019
1020#ifndef QT_NO_EXCEPTIONS
1021
1022template<typename T = void>
1023static QFuture<T> makeExceptionalFuture(std::exception_ptr exception)
1024{
1025 QFutureInterface<T> promise;
1026 promise.reportStarted();
1027 promise.reportException(exception);
1028 promise.reportFinished();
1029
1030 return promise.future();
1031}
1032
1033template<typename T = void>
1034static QFuture<T> makeExceptionalFuture(const QException &exception)
1035{
1036 try {
1037 exception.raise();
1038 } catch (...) {
1039 return makeExceptionalFuture<T>(std::current_exception());
1040 }
1041 Q_UNREACHABLE();
1042}
1043
1044#endif // QT_NO_EXCEPTIONS
1045
1046} // namespace QtFuture
1047
1048namespace QtPrivate {
1049
1050template<typename ResultFutures>
1052{
1053 using ValueType = typename ResultFutures::value_type;
1054
1055 explicit WhenAllContext(qsizetype size) : remaining(size) {}
1056
1057 template<typename T = ValueType>
1058 void checkForCompletion(qsizetype index, T &&future)
1059 {
1060 futures[index] = std::forward<T>(future);
1061 const auto oldRemaining = remaining.fetchAndSubRelaxed(1);
1062 Q_ASSERT(oldRemaining > 0);
1063 if (oldRemaining <= 1) { // that was the last one
1064 promise.addResult(futures);
1065 promise.finish();
1066 }
1067 }
1068
1070 QPromise<ResultFutures> promise;
1071 ResultFutures futures;
1072};
1073
1074template<typename ResultType>
1076{
1077 using ValueType = ResultType;
1078
1079 template<typename T = ResultType, typename = EnableForNonVoid<T>>
1081 {
1082 if (!ready.fetchAndStoreRelaxed(true)) {
1083 promise.addResult(std::forward<T>(result));
1084 promise.finish();
1085 }
1086 }
1087
1089 QPromise<ResultType> promise;
1090};
1091
1092template<qsizetype Index, typename ContextType, typename... Ts>
1093void addCompletionHandlersImpl(const std::shared_ptr<ContextType> &context,
1094 const std::tuple<Ts...> &t)
1095{
1096 auto future = std::get<Index>(t);
1097 using ResultType = typename ContextType::ValueType;
1098 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1099 future.then([context=context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
1100 context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, f });
1101 }).onCanceled([context=context, future]() {
1102 context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, future });
1103 });
1104
1105 if constexpr (Index != 0)
1106 addCompletionHandlersImpl<Index - 1, ContextType, Ts...>(context, t);
1107}
1108
1109template<typename ContextType, typename... Ts>
1110void addCompletionHandlers(const std::shared_ptr<ContextType> &context, const std::tuple<Ts...> &t)
1111{
1112 constexpr qsizetype size = std::tuple_size<std::tuple<Ts...>>::value;
1113 addCompletionHandlersImpl<size - 1, ContextType, Ts...>(context, t);
1114}
1115
1116template<typename OutputSequence, typename InputIt, typename ValueType,
1118 bool> = true>
1120{
1121 const qsizetype size = std::distance(first, last);
1122 if (size == 0)
1124
1128
1129 qsizetype idx = 0;
1130 for (auto it = first; it != last; ++it, ++idx) {
1131 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1132 it->then([context=context, idx](const ValueType &f) {
1134 }).onCanceled([context=context, idx, f = *it] {
1136 });
1137 }
1138 return context->promise.future();
1139}
1140
1141template<typename OutputSequence, typename... Futures>
1142QFuture<OutputSequence> whenAllImpl(Futures &&... futures)
1143{
1144 constexpr qsizetype size = sizeof...(Futures);
1145 const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
1146 context->futures.resize(size);
1147 context->promise.start();
1148
1149 QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));
1150
1151 return context->promise.future();
1152}
1153
1154template<typename InputIt, typename ValueType,
1156 bool> = true>
1158 InputIt last)
1159{
1160 using PackagedType = typename Future<ValueType>::type;
1162
1163 const qsizetype size = std::distance(first, last);
1164 if (size == 0) {
1167 }
1168
1171
1172 qsizetype idx = 0;
1173 for (auto it = first; it != last; ++it, ++idx) {
1174 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1175 it->then([context=context, idx](const ValueType &f) {
1177 }).onCanceled([context=context, idx, f = *it] {
1179 });
1180 }
1181 return context->promise.future();
1182}
1183
1184template<typename... Futures>
1196
1197} // namespace QtPrivate
1198
1199QT_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)
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 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... >)
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)
QPromise< ResultType > promise
void checkForCompletion(qsizetype, T &&result)