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

source code of qtbase/src/corelib/thread/qfuture_impl.h