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/qpromise.h>
18
19#include <memory>
20
21QT_BEGIN_NAMESPACE
22
23//
24// forward declarations
25//
26template<class T>
27class QFuture;
28template<class T>
29class QFutureInterface;
30template<class T>
31class QPromise;
32
33namespace QtFuture {
34
35enum class Launch { Sync, Async, Inherit };
36
37template<class T>
38struct WhenAnyResult
39{
40 qsizetype index = -1;
41 QFuture<T> future;
42};
43
44// Deduction guide
45template<class T>
46WhenAnyResult(qsizetype, const QFuture<T> &) -> WhenAnyResult<T>;
47}
48
49namespace QtPrivate {
50
51template<class T>
52using EnableForVoid = std::enable_if_t<std::is_same_v<T, void>>;
53
54template<class T>
55using EnableForNonVoid = std::enable_if_t<!std::is_same_v<T, void>>;
56
57template<typename F, typename Arg, typename Enable = void>
58struct ResultTypeHelper
59{
60};
61
62// The callable takes an argument of type Arg
63template<typename F, typename Arg>
64struct ResultTypeHelper<
65 F, Arg, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<Arg>>>>
66{
67 using ResultType = std::invoke_result_t<std::decay_t<F>, std::decay_t<Arg>>;
68};
69
70// The callable takes an argument of type QFuture<Arg>
71template<class F, class Arg>
72struct ResultTypeHelper<
73 F, Arg, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<Arg>>>>
74{
75 using ResultType = std::invoke_result_t<std::decay_t<F>, QFuture<Arg>>;
76};
77
78// The callable takes an argument of type QFuture<void>
79template<class F>
80struct ResultTypeHelper<
81 F, void, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
82{
83 using ResultType = std::invoke_result_t<std::decay_t<F>, QFuture<void>>;
84};
85
86// The callable doesn't take argument
87template<class F>
88struct ResultTypeHelper<
89 F, void, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
90{
91 using ResultType = std::invoke_result_t<std::decay_t<F>>;
92};
93
94// Helpers to remove QPrivateSignal argument from the list of arguments
95
96template<class T, class Enable = void>
97inline constexpr bool IsPrivateSignalArg = false;
98
99template<class T>
100inline constexpr bool IsPrivateSignalArg<T, typename std::enable_if_t<
101 // finds injected-class-name, the 'class' avoids falling into the rules of [class.qual]/2:
102 std::is_class_v<class T::QPrivateSignal>
103 >> = true;
104
105template<class Tuple, std::size_t... I>
106auto cutTuple(Tuple &&t, std::index_sequence<I...>)
107{
108 return std::make_tuple(std::get<I>(t)...);
109}
110
111template<class Arg, class... Args>
112auto createTuple(Arg &&arg, Args &&... args)
113{
114 using TupleType = std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>;
115 constexpr auto Size = sizeof...(Args); // One less than the size of all arguments
116 if constexpr (QtPrivate::IsPrivateSignalArg<std::tuple_element_t<Size, TupleType>>) {
117 if constexpr (Size == 1) {
118 return std::forward<Arg>(arg);
119 } else {
120 return cutTuple(std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...),
121 std::make_index_sequence<Size>());
122 }
123 } else {
124 return std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...);
125 }
126}
127
128// Helpers to resolve argument types of callables.
129
130template<class Arg, class... Args>
131using FilterLastPrivateSignalArg =
132 std::conditional_t<(sizeof...(Args) > 0),
133 std::invoke_result_t<decltype(createTuple<Arg, Args...>), Arg, Args...>,
134 std::conditional_t<IsPrivateSignalArg<Arg>, void, Arg>>;
135
136template<typename...>
137struct ArgsType;
138
139template<typename Arg, typename... Args>
140struct ArgsType<Arg, Args...>
141{
142 using First = Arg;
143 using PromiseType = void;
144 using IsPromise = std::false_type;
145 static const bool HasExtraArgs = (sizeof...(Args) > 0);
146 using AllArgs = FilterLastPrivateSignalArg<std::decay_t<Arg>, std::decay_t<Args>...>;
147
148 template<class Class, class Callable>
149 static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, Arg, Args...>;
150};
151
152template<typename Arg, typename... Args>
153struct ArgsType<QPromise<Arg> &, Args...>
154{
155 using First = QPromise<Arg> &;
156 using PromiseType = Arg;
157 using IsPromise = std::true_type;
158 static const bool HasExtraArgs = (sizeof...(Args) > 0);
159 using AllArgs = FilterLastPrivateSignalArg<QPromise<Arg>, std::decay_t<Args>...>;
160
161 template<class Class, class Callable>
162 static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, QPromise<Arg> &, Args...>;
163};
164
165template<>
166struct ArgsType<>
167{
168 using First = void;
169 using PromiseType = void;
170 using IsPromise = std::false_type;
171 static const bool HasExtraArgs = false;
172 using AllArgs = void;
173
174 template<class Class, class Callable>
175 static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class>;
176};
177
178template<typename F>
179struct ArgResolver : ArgResolver<decltype(&std::decay_t<F>::operator())>
180{
181};
182
183template<typename F>
184struct ArgResolver<std::reference_wrapper<F>> : ArgResolver<decltype(&std::decay_t<F>::operator())>
185{
186};
187
188template<typename R, typename... Args>
189struct ArgResolver<R(Args...)> : public ArgsType<Args...>
190{
191};
192
193template<typename R, typename... Args>
194struct ArgResolver<R (*)(Args...)> : public ArgsType<Args...>
195{
196};
197
198template<typename R, typename... Args>
199struct ArgResolver<R (*&)(Args...)> : public ArgsType<Args...>
200{
201};
202
203template<typename R, typename... Args>
204struct ArgResolver<R (* const)(Args...)> : public ArgsType<Args...>
205{
206};
207
208template<typename R, typename... Args>
209struct ArgResolver<R (&)(Args...)> : public ArgsType<Args...>
210{
211};
212
213template<typename Class, typename R, typename... Args>
214struct ArgResolver<R (Class::*)(Args...)> : public ArgsType<Args...>
215{
216};
217
218template<typename Class, typename R, typename... Args>
219struct ArgResolver<R (Class::*)(Args...) noexcept> : public ArgsType<Args...>
220{
221};
222
223template<typename Class, typename R, typename... Args>
224struct ArgResolver<R (Class::*)(Args...) const> : public ArgsType<Args...>
225{
226};
227
228template<typename Class, typename R, typename... Args>
229struct ArgResolver<R (Class::*)(Args...) const noexcept> : public ArgsType<Args...>
230{
231};
232
233template<typename Class, typename R, typename... Args>
234struct ArgResolver<R (Class::* const)(Args...) const> : public ArgsType<Args...>
235{
236};
237
238template<typename Class, typename R, typename... Args>
239struct ArgResolver<R (Class::* const)(Args...) const noexcept> : public ArgsType<Args...>
240{
241};
242
243template<class Class, class Callable>
244using EnableIfInvocable = std::enable_if_t<
245 QtPrivate::ArgResolver<Callable>::template CanInvokeWithArgs<Class, Callable>>;
246
247template<class T>
248inline constexpr bool isQFutureV = false;
249
250template<class T>
251inline constexpr bool isQFutureV<QFuture<T>> = true;
252
253template<class T>
254using isQFuture = std::bool_constant<isQFutureV<T>>;
255
256template<class T>
257struct Future
258{
259};
260
261template<class T>
262struct Future<QFuture<T>>
263{
264 using type = T;
265};
266
267template<class... Args>
268using NotEmpty = std::bool_constant<(sizeof...(Args) > 0)>;
269
270template<class Sequence>
271using IsRandomAccessible =
272 std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
273 std::begin(std::declval<Sequence>()))>>::iterator_category,
274 std::random_access_iterator_tag>;
275
276template<class Sequence>
277using HasInputIterator =
278 std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
279 std::begin(std::declval<Sequence>()))>>::iterator_category,
280 std::input_iterator_tag>;
281
282template<class Iterator>
283using IsForwardIterable =
284 std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category,
285 std::forward_iterator_tag>;
286
287template<typename Function, typename ResultType, typename ParentResultType>
288class Continuation
289{
290 Q_DISABLE_COPY_MOVE(Continuation)
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
592template <typename Continuation>
593void watchContinuation(const QObject *context, Continuation &&c, QFutureInterfaceBase &fi)
594{
595 using Prototype = typename QtPrivate::Callable<Continuation>::Function;
596 watchContinuationImpl(context,
597 QtPrivate::makeCallableObject<Prototype>(std::forward<Continuation>(c)),
598 fi);
599}
600
601template<typename Function, typename ResultType, typename ParentResultType>
602template<typename F>
603void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
604 QFuture<ParentResultType> *f,
605 QFutureInterface<ResultType> &fi,
606 QObject *context)
607{
608 Q_ASSERT(f);
609 Q_ASSERT(context);
610
611 // When the context object is destroyed, the signal-slot connection is broken and the
612 // continuation callback is destroyed. The promise that is created in the capture list is
613 // destroyed and, if it is not yet finished, cancelled.
614 auto continuation = [func = std::forward<F>(func), parent = *f,
615 promise_ = QPromise(fi)]() mutable {
616 SyncContinuation<Function, ResultType, ParentResultType> continuationJob(
617 std::forward<Function>(func), parent, std::move(promise_));
618 continuationJob.execute();
619 };
620
621 QtPrivate::watchContinuation(context, std::move(continuation), f->d);
622}
623
624template<typename Function, typename ResultType, typename ParentResultType>
625void Continuation<Function, ResultType, ParentResultType>::fulfillPromiseWithResult()
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
648 fulfillPromise();
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>
659void fulfillPromise(QPromise<T> &promise, QFuture<T> &future)
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>
682void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultType> *future,
683 const QFutureInterface<ResultType> &fi)
684{
685 Q_ASSERT(future);
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>
700void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultType> *future,
701 QFutureInterface<ResultType> &fi,
702 QObject *context)
703{
704 Q_ASSERT(future);
705 Q_ASSERT(context);
706 auto failureContinuation = [function = std::forward<F>(function),
707 parent = *future, promise_ = QPromise(fi)]() mutable {
708 FailureHandler<Function, ResultType> failureHandler(
709 std::forward<Function>(function), parent, std::move(promise_));
710 failureHandler.run();
711 };
712
713 QtPrivate::watchContinuation(context, std::move(failureContinuation), future->d);
714}
715
716template<class Function, class ResultType>
717void FailureHandler<Function, ResultType>::run()
718{
719 Q_ASSERT(parentFuture.isFinished());
720
721 promise.start();
722
723 if (parentFuture.d.hasException()) {
724 using ArgType = typename QtPrivate::ArgResolver<Function>::First;
725 if constexpr (std::is_void_v<ArgType>) {
726 handleAllExceptions();
727 } else {
728 handleException<ArgType>();
729 }
730 } else if (parentFuture.d.isChainCanceled()) {
731 promise.future().cancel();
732 } else {
733 QtPrivate::fulfillPromise(promise, parentFuture);
734 }
735 promise.finish();
736}
737
738template<class Function, class ResultType>
739template<class ArgType>
740void FailureHandler<Function, ResultType>::handleException()
741{
742 try {
743 Q_ASSERT(parentFuture.d.hasException());
744 parentFuture.d.exceptionStore().rethrowException();
745 } catch (const ArgType &e) {
746 try {
747 // Handle exceptions matching with the handler's argument type
748 if constexpr (std::is_void_v<ResultType>)
749 handler(e);
750 else
751 promise.addResult(handler(e));
752 } catch (...) {
753 promise.setException(std::current_exception());
754 }
755 } catch (...) {
756 // Exception doesn't match with handler's argument type, propagate
757 // the exception to be handled later.
758 promise.setException(std::current_exception());
759 }
760}
761
762template<class Function, class ResultType>
763void FailureHandler<Function, ResultType>::handleAllExceptions()
764{
765 try {
766 Q_ASSERT(parentFuture.d.hasException());
767 parentFuture.d.exceptionStore().rethrowException();
768 } catch (...) {
769 try {
770 QtPrivate::fulfillPromise(promise, std::forward<Function>(handler));
771 } catch (...) {
772 promise.setException(std::current_exception());
773 }
774 }
775}
776
777#endif // QT_NO_EXCEPTIONS
778
779template<class Function, class ResultType>
780class CanceledHandler
781{
782public:
783 template<class F = Function>
784 static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi)
785 {
786 Q_ASSERT(future);
787
788 auto canceledContinuation = [promise = QPromise(fi), handler = std::forward<F>(handler)](
789 const QFutureInterfaceBase &parentData) mutable {
790 auto parentFuture = QFutureInterface<ResultType>(parentData).future();
791 run(std::forward<F>(handler), parentFuture, std::move(promise));
792 };
793 future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation)));
794 }
795
796 template<class F = Function>
797 static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi,
798 QObject *context)
799 {
800 Q_ASSERT(future);
801 Q_ASSERT(context);
802 auto canceledContinuation = [handler = std::forward<F>(handler),
803 parentFuture = *future, promise = QPromise(fi)]() mutable {
804 run(std::forward<F>(handler), parentFuture, std::move(promise));
805 };
806
807 QtPrivate::watchContinuation(context, std::move(canceledContinuation), future->d);
808 }
809
810 template<class F = Function>
811 static void run(F &&handler, QFuture<ResultType> &parentFuture, QPromise<ResultType> &&promise)
812 {
813 promise.start();
814
815 if (parentFuture.isCanceled()) {
816#ifndef QT_NO_EXCEPTIONS
817 if (parentFuture.d.hasException()) {
818 // Propagate the exception to the result future
819 promise.setException(parentFuture.d.exceptionStore().exception());
820 } else {
821 try {
822#endif
823 QtPrivate::fulfillPromise(promise, std::forward<F>(handler));
824#ifndef QT_NO_EXCEPTIONS
825 } catch (...) {
826 promise.setException(std::current_exception());
827 }
828 }
829#endif
830 } else {
831 QtPrivate::fulfillPromise(promise, parentFuture);
832 }
833
834 promise.finish();
835 }
836};
837
838struct UnwrapHandler
839{
840 template<class T>
841 static auto unwrapImpl(T *outer)
842 {
843 Q_ASSERT(outer);
844
845 using ResultType = typename QtPrivate::Future<std::decay_t<T>>::type;
846 using NestedType = typename QtPrivate::Future<ResultType>::type;
847 QFutureInterface<NestedType> promise(QFutureInterfaceBase::State::Pending);
848
849 outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
850 // We use the .then([](QFuture<ResultType> outerFuture) {...}) version
851 // (where outerFuture == *outer), to propagate the exception if the
852 // outer future has failed.
853 Q_ASSERT(outerFuture.isFinished());
854#ifndef QT_NO_EXCEPTIONS
855 if (outerFuture.d.hasException()) {
856 promise.reportStarted();
857 promise.reportException(outerFuture.d.exceptionStore().exception());
858 promise.reportFinished();
859 return;
860 }
861#endif
862
863 promise.reportStarted();
864 ResultType nestedFuture = outerFuture.result();
865
866 nestedFuture.then([promise] (const QFuture<NestedType> &nested) mutable {
867#ifndef QT_NO_EXCEPTIONS
868 if (nested.d.hasException()) {
869 promise.reportException(nested.d.exceptionStore().exception());
870 } else
871#endif
872 {
873 if constexpr (!std::is_void_v<NestedType>)
874 promise.reportResults(nested.results());
875 }
876 promise.reportFinished();
877 }).onCanceled([promise] () mutable {
878 promise.reportCanceled();
879 promise.reportFinished();
880 });
881 }).onCanceled([promise]() mutable {
882 // propagate the cancellation of the outer future
883 promise.reportStarted();
884 promise.reportCanceled();
885 promise.reportFinished();
886 });
887 return promise.future();
888 }
889};
890
891template<typename ValueType>
892QFuture<ValueType> makeReadyRangeFutureImpl(const QList<ValueType> &values)
893{
894 QFutureInterface<ValueType> promise;
895 promise.reportStarted();
896 promise.reportResults(values);
897 promise.reportFinished();
898 return promise.future();
899}
900
901} // namespace QtPrivate
902
903namespace QtFuture {
904
905template<class Signal>
906using ArgsType = typename QtPrivate::ArgResolver<Signal>::AllArgs;
907
908template<class Sender, class Signal, typename = QtPrivate::EnableIfInvocable<Sender, Signal>>
909static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
910{
911 using ArgsType = ArgsType<Signal>;
912 QFutureInterface<ArgsType> promise;
913 promise.reportStarted();
914 if (!sender) {
915 promise.reportCanceled();
916 promise.reportFinished();
917 return promise.future();
918 }
919
920 using Connections = std::pair<QMetaObject::Connection, QMetaObject::Connection>;
921 auto connections = std::make_shared<Connections>();
922
923 if constexpr (std::is_void_v<ArgsType>) {
924 connections->first =
925 QObject::connect(sender, signal, sender, [promise, connections]() mutable {
926 QObject::disconnect(connections->first);
927 QObject::disconnect(connections->second);
928 promise.reportFinished();
929 });
930 } else if constexpr (QtPrivate::ArgResolver<Signal>::HasExtraArgs) {
931 connections->first = QObject::connect(sender, signal, sender,
932 [promise, connections](auto... values) mutable {
933 QObject::disconnect(connections->first);
934 QObject::disconnect(connections->second);
935 promise.reportResult(QtPrivate::createTuple(
936 std::move(values)...));
937 promise.reportFinished();
938 });
939 } else {
940 connections->first = QObject::connect(sender, signal, sender,
941 [promise, connections](ArgsType value) mutable {
942 QObject::disconnect(connections->first);
943 QObject::disconnect(connections->second);
944 promise.reportResult(value);
945 promise.reportFinished();
946 });
947 }
948
949 if (!connections->first) {
950 promise.reportCanceled();
951 promise.reportFinished();
952 return promise.future();
953 }
954
955 connections->second =
956 QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable {
957 QObject::disconnect(connections->first);
958 QObject::disconnect(connections->second);
959 promise.reportCanceled();
960 promise.reportFinished();
961 });
962
963 return promise.future();
964}
965
966template<typename Container>
967using if_container_with_input_iterators =
968 std::enable_if_t<QtPrivate::HasInputIterator<Container>::value, bool>;
969
970template<typename Container>
971using ContainedType =
972 typename std::iterator_traits<decltype(
973 std::cbegin(std::declval<Container&>()))>::value_type;
974
975template<typename Container, if_container_with_input_iterators<Container> = true>
976static QFuture<ContainedType<Container>> makeReadyRangeFuture(Container &&container)
977{
978 // handle QList<T> separately, because reportResults() takes a QList
979 // as an input
980 using ValueType = ContainedType<Container>;
981 if constexpr (std::is_convertible_v<q20::remove_cvref_t<Container>, QList<ValueType>>) {
982 return QtPrivate::makeReadyRangeFutureImpl(container);
983 } else {
984 return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{std::cbegin(container),
985 std::cend(container)});
986 }
987}
988
989template<typename ValueType>
990static QFuture<ValueType> makeReadyRangeFuture(std::initializer_list<ValueType> values)
991{
992 return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{values});
993}
994
995template<typename T>
996static QFuture<std::decay_t<T>> makeReadyValueFuture(T &&value)
997{
998 QFutureInterface<std::decay_t<T>> promise;
999 promise.reportStarted();
1000 promise.reportResult(std::forward<T>(value));
1001 promise.reportFinished();
1002
1003 return promise.future();
1004}
1005
1006Q_CORE_EXPORT QFuture<void> makeReadyVoidFuture(); // implemented in qfutureinterface.cpp
1007
1008#if QT_DEPRECATED_SINCE(6, 10)
1009template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
1010QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyValueFuture() instead.")
1011static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
1012{
1013 return makeReadyValueFuture(std::forward<T>(value));
1014}
1015
1016// the void specialization is moved to the end of qfuture.h, because it now
1017// uses makeReadyVoidFuture() and required QFuture<void> to be defined.
1018
1019template<typename T>
1020QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyRangeFuture() instead.")
1021static QFuture<T> makeReadyFuture(const QList<T> &values)
1022{
1023 return makeReadyRangeFuture(values);
1024}
1025#endif // QT_DEPRECATED_SINCE(6, 10)
1026
1027#ifndef QT_NO_EXCEPTIONS
1028
1029template<typename T = void>
1030static QFuture<T> makeExceptionalFuture(std::exception_ptr exception)
1031{
1032 QFutureInterface<T> promise;
1033 promise.reportStarted();
1034 promise.reportException(exception);
1035 promise.reportFinished();
1036
1037 return promise.future();
1038}
1039
1040template<typename T = void>
1041static QFuture<T> makeExceptionalFuture(const QException &exception)
1042{
1043 try {
1044 exception.raise();
1045 } catch (...) {
1046 return makeExceptionalFuture<T>(std::current_exception());
1047 }
1048 Q_UNREACHABLE();
1049}
1050
1051#endif // QT_NO_EXCEPTIONS
1052
1053} // namespace QtFuture
1054
1055namespace QtPrivate {
1056
1057template<typename ResultFutures>
1058struct WhenAllContext
1059{
1060 using ValueType = typename ResultFutures::value_type;
1061
1062 explicit WhenAllContext(qsizetype size) : remaining(size) {}
1063
1064 template<typename T = ValueType>
1065 void checkForCompletion(qsizetype index, T &&future)
1066 {
1067 futures[index] = std::forward<T>(future);
1068 const auto oldRemaining = remaining.fetchAndSubRelaxed(valueToAdd: 1);
1069 Q_ASSERT(oldRemaining > 0);
1070 if (oldRemaining <= 1) { // that was the last one
1071 promise.addResult(futures);
1072 promise.finish();
1073 }
1074 }
1075
1076 QAtomicInteger<qsizetype> remaining;
1077 QPromise<ResultFutures> promise;
1078 ResultFutures futures;
1079};
1080
1081template<typename ResultType>
1082struct WhenAnyContext
1083{
1084 using ValueType = ResultType;
1085
1086 template<typename T = ResultType, typename = EnableForNonVoid<T>>
1087 void checkForCompletion(qsizetype, T &&result)
1088 {
1089 if (!ready.fetchAndStoreRelaxed(newValue: true)) {
1090 promise.addResult(std::forward<T>(result));
1091 promise.finish();
1092 }
1093 }
1094
1095 QAtomicInt ready = false;
1096 QPromise<ResultType> promise;
1097};
1098
1099template<qsizetype Index, typename ContextType, typename... Ts>
1100void addCompletionHandlersImpl(const std::shared_ptr<ContextType> &context,
1101 const std::tuple<Ts...> &t)
1102{
1103 auto future = std::get<Index>(t);
1104 using ResultType = typename ContextType::ValueType;
1105 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1106 future.then([context=context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
1107 context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, f });
1108 }).onCanceled([context=context, future]() {
1109 context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, future });
1110 });
1111
1112 if constexpr (Index != 0)
1113 addCompletionHandlersImpl<Index - 1, ContextType, Ts...>(context, t);
1114}
1115
1116template<typename ContextType, typename... Ts>
1117void addCompletionHandlers(const std::shared_ptr<ContextType> &context, const std::tuple<Ts...> &t)
1118{
1119 constexpr qsizetype size = std::tuple_size<std::tuple<Ts...>>::value;
1120 addCompletionHandlersImpl<size - 1, ContextType, Ts...>(context, t);
1121}
1122
1123template<typename OutputSequence, typename InputIt, typename ValueType>
1124QFuture<OutputSequence> whenAllImpl(InputIt first, InputIt last)
1125{
1126 const qsizetype size = std::distance(first, last);
1127 if (size == 0)
1128 return QtFuture::makeReadyValueFuture(OutputSequence());
1129
1130 const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
1131 context->futures.resize(size);
1132 context->promise.start();
1133
1134 qsizetype idx = 0;
1135 for (auto it = first; it != last; ++it, ++idx) {
1136 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1137 it->then([context=context, idx](const ValueType &f) {
1138 context->checkForCompletion(idx, f);
1139 }).onCanceled([context=context, idx, f = *it] {
1140 context->checkForCompletion(idx, f);
1141 });
1142 }
1143 return context->promise.future();
1144}
1145
1146template<typename OutputSequence, typename... Futures>
1147QFuture<OutputSequence> whenAllImpl(Futures &&... futures)
1148{
1149 constexpr qsizetype size = sizeof...(Futures);
1150 const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
1151 context->futures.resize(size);
1152 context->promise.start();
1153
1154 QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));
1155
1156 return context->promise.future();
1157}
1158
1159template<typename InputIt, typename ValueType>
1160QFuture<QtFuture::WhenAnyResult<typename Future<ValueType>::type>> whenAnyImpl(InputIt first,
1161 InputIt last)
1162{
1163 using PackagedType = typename Future<ValueType>::type;
1164 using ResultType = QtFuture::WhenAnyResult<PackagedType>;
1165
1166 const qsizetype size = std::distance(first, last);
1167 if (size == 0) {
1168 return QtFuture::makeReadyValueFuture(
1169 QtFuture::WhenAnyResult { qsizetype(-1), QFuture<PackagedType>() });
1170 }
1171
1172 const auto context = std::make_shared<QtPrivate::WhenAnyContext<ResultType>>();
1173 context->promise.start();
1174
1175 qsizetype idx = 0;
1176 for (auto it = first; it != last; ++it, ++idx) {
1177 // Need context=context so that the compiler does not infer the captured variable's type as 'const'
1178 it->then([context=context, idx](const ValueType &f) {
1179 context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
1180 }).onCanceled([context=context, idx, f = *it] {
1181 context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
1182 });
1183 }
1184 return context->promise.future();
1185}
1186
1187template<typename... Futures>
1188QFuture<std::variant<std::decay_t<Futures>...>> whenAnyImpl(Futures &&... futures)
1189{
1190 using ResultType = std::variant<std::decay_t<Futures>...>;
1191
1192 const auto context = std::make_shared<QtPrivate::WhenAnyContext<ResultType>>();
1193 context->promise.start();
1194
1195 QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));
1196
1197 return context->promise.future();
1198}
1199
1200} // namespace QtPrivate
1201
1202QT_END_NAMESPACE
1203

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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