Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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/qfutureinterface.h>
15#include <QtCore/qthreadpool.h>
16#include <QtCore/qexception.h>
17#include <QtCore/qpromise.h>
18
19#include <memory>
20
22
23//
24// forward declarations
25//
26template<class T>
27class QFuture;
28template<class T>
30template<class T>
31class QPromise;
32
33namespace QtFuture {
34
35enum class Launch { Sync, Async, Inherit };
36
37template<class T>
39{
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>
59{
60};
61
62// The callable takes an argument of type Arg
63template<typename F, typename Arg>
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>
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>
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>
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>
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;
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;
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>
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>
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>
284 std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category,
285 std::forward_iterator_tag>;
286
287template<typename Function, typename ResultType, typename ParentResultType>
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,
304
305 template<typename F = Function>
306 static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
308
309 template<typename F = Function>
310 static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
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;
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>
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,
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>
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>
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>
498{
499 ContinuationWrapper(Function &&f) : function(std::move(f)) { }
501 : function(std::move(const_cast<ContinuationWrapper &>(other).function))
502 {
503 Q_ASSERT_X(false, "QFuture", "Continuation shouldn't be copied");
504 }
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>
517 QFuture<ParentResultType> *f,
518 QFutureInterface<ResultType> &fi,
520{
521 Q_ASSERT(f);
522
523 QThreadPool *pool = nullptr;
524
525 bool launchAsync = (policy == QtFuture::Launch::Async);
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>
567 QFuture<ParentResultType> *f,
568 QFutureInterface<ResultType> &fi,
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>
594{
595 using Prototype = typename QtPrivate::Callable<Continuation>::Function;
597 QtPrivate::makeCallableObject<Prototype>(std::forward<Continuation>(c)),
598 fi);
599}
600
601template<typename Function, typename ResultType, typename ParentResultType>
602template<typename F>
604 QFuture<ParentResultType> *f,
605 QFutureInterface<ResultType> &fi,
607{
608 Q_ASSERT(f);
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>
626{
627 if constexpr (std::is_copy_constructible_v<ParentResultType>)
628 fulfillPromise(parentFuture.result());
629 else
630 fulfillPromise(parentFuture.takeResult());
631}
632
633template<typename Function, typename ResultType, typename ParentResultType>
634void Continuation<Function, ResultType, ParentResultType>::fulfillVoidPromise()
635{
636 if constexpr (std::is_copy_constructible_v<ParentResultType>)
637 function(parentFuture.result());
638 else
639 function(parentFuture.takeResult());
640}
641
642template<typename Function, typename ResultType, typename ParentResultType>
643void Continuation<Function, ResultType, ParentResultType>::fulfillPromiseWithVoidResult()
644{
645 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
646 fulfillPromise(parentFuture);
647 else
649}
650
651template<typename Function, typename ResultType, typename ParentResultType>
652template<class... Args>
653void Continuation<Function, ResultType, ParentResultType>::fulfillPromise(Args &&... args)
654{
655 promise.addResult(std::invoke(function, std::forward<Args>(args)...));
656}
657
658template<class T>
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{
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,
703{
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>
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>
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>
781{
782public:
783 template<class F = Function>
784 static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi)
785 {
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,
799 {
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
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>
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 });
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>
968 std::enable_if_t<QtPrivate::HasInputIterator<Container>::value, bool>;
969
970template<typename Container>
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{
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>
1059{
1060 using ValueType = typename ResultFutures::value_type;
1061
1063
1064 template<typename T = ValueType>
1066 {
1067 futures[index] = std::forward<T>(future);
1068 const auto oldRemaining = remaining.fetchAndSubRelaxed(1);
1069 Q_ASSERT(oldRemaining > 0);
1070 if (oldRemaining <= 1) { // that was the last one
1072 promise.finish();
1073 }
1074 }
1075
1076 QAtomicInteger<qsizetype> remaining;
1077 QPromise<ResultFutures> promise;
1078 ResultFutures futures;
1079};
1080
1081template<typename ResultType>
1083{
1084 using ValueType = ResultType;
1085
1086 template<typename T = ResultType, typename = EnableForNonVoid<T>>
1088 {
1089 if (!ready.fetchAndStoreRelaxed(true)) {
1090 promise.addResult(std::forward<T>(result));
1091 promise.finish();
1092 }
1093 }
1094
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) {
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
\inmodule QtCore
Definition qatomic.h:112
T fetchAndStoreRelaxed(T newValue) noexcept
T fetchAndSubRelaxed(T valueToAdd) noexcept
\inmodule QtCore
Definition qexception.h:22
virtual void raise() const
In your QException subclass, reimplement raise() like this:
QFuture< ResultType< Function > > then(Function &&function)
T result() const
Definition qfuture.h:309
T takeResult()
Definition qfuture.h:117
Definition qlist.h:75
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void finish()
Definition qpromise.h:75
bool addResult(U &&result, int index=-1)
Definition qpromise.h:60
\inmodule QtCore
Definition qrunnable.h:18
\inmodule QtCore
Definition qthreadpool.h:22
void start(QRunnable *runnable, int priority=0)
Reserves a thread and uses it to run runnable, unless this thread will make the current thread count ...
static QThreadPool * globalInstance()
Returns the global QThreadPool instance.
~AsyncContinuation() override=default
AsyncContinuation(F &&func, const QFuture< ParentResultType > &f, QPromise< ResultType > &&p, QThreadPool *pool=nullptr)
void run() override
Implement this pure virtual function in your subclass.
static void create(F &&handler, QFuture< ResultType > *future, QFutureInterface< ResultType > &fi, QObject *context)
static void create(F &&handler, QFuture< ResultType > *future, QFutureInterface< ResultType > &fi)
static void run(F &&handler, QFuture< ResultType > &parentFuture, QPromise< ResultType > &&promise)
QFuture< ParentResultType > parentFuture
virtual void runImpl()=0
Continuation(F &&func, const QFuture< ParentResultType > &f, QPromise< ResultType > &&p)
virtual ~Continuation()=default
static void create(F &&func, QFuture< ParentResultType > *f, QFutureInterface< ResultType > &fi, QtFuture::Launch policy)
QPromise< ResultType > promise
static void create(F &&function, QFuture< ResultType > *future, const QFutureInterface< ResultType > &fi)
FailureHandler(F &&func, const QFuture< ResultType > &f, QPromise< ResultType > &&p)
~SyncContinuation() override=default
SyncContinuation(F &&func, const QFuture< ParentResultType > &f, QPromise< ResultType > &&p)
QSet< QString >::iterator it
auto signal
Combined button and popup list for selecting options.
typename QtPrivate::ArgResolver< Signal >::AllArgs ArgsType
typename std::iterator_traits< decltype( std::cbegin(std::declval< Container & >()))>::value_type ContainedType
Q_CORE_EXPORT QFuture< void > makeReadyVoidFuture()
static QFuture< std::decay_t< T > > makeReadyValueFuture(T &&value)
std::enable_if_t< QtPrivate::HasInputIterator< Container >::value, bool > if_container_with_input_iterators
static QFuture< T > makeExceptionalFuture(std::exception_ptr exception)
WhenAnyResult(qsizetype, const QFuture< T > &) -> WhenAnyResult< T >
static QFuture< ContainedType< Container > > makeReadyRangeFuture(Container &&container)
static QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
\macro QT_NO_KEYWORDS >
QFuture< OutputSequence > whenAllImpl(InputIt first, InputIt last)
std::is_convertible< typename std::iterator_traits< std::decay_t< decltype( std::begin(std::declval< Sequence >()))> >::iterator_category, std::random_access_iterator_tag > IsRandomAccessible
auto createTuple(Arg &&arg, Args &&... args)
std::bool_constant< isQFutureV< T > > isQFuture
std::enable_if_t< std::is_same_v< T, void > > EnableForVoid
void addCompletionHandlersImpl(const std::shared_ptr< ContextType > &context, const std::tuple< Ts... > &t)
constexpr bool isQFutureV
QFuture< QtFuture::WhenAnyResult< typename Future< ValueType >::type > > whenAnyImpl(InputIt first, InputIt last)
void watchContinuation(const QObject *context, Continuation &&c, QFutureInterfaceBase &fi)
void fulfillPromise(QPromise< T > &promise, QFuture< T > &future)
std::enable_if_t<!std::is_same_v< T, void > > EnableForNonVoid
QFuture< ValueType > makeReadyRangeFutureImpl(const QList< ValueType > &values)
constexpr bool IsPrivateSignalArg
auto cutTuple(Tuple &&t, std::index_sequence< I... >)
void Q_CORE_EXPORT watchContinuationImpl(const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi)
std::is_convertible< typename std::iterator_traits< Iterator >::iterator_category, std::forward_iterator_tag > IsForwardIterable
std::is_convertible< typename std::iterator_traits< std::decay_t< decltype( std::begin(std::declval< Sequence >()))> >::iterator_category, std::input_iterator_tag > HasInputIterator
void addCompletionHandlers(const std::shared_ptr< ContextType > &context, const std::tuple< Ts... > &t)
std::enable_if_t< QtPrivate::ArgResolver< Callable >::template CanInvokeWithArgs< Class, Callable > > EnableIfInvocable
std::conditional_t<(sizeof...(Args) > 0), std::invoke_result_t< decltype(createTuple< Arg, Args... >), Arg, Args... >, std::conditional_t< IsPrivateSignalArg< Arg >, void, Arg > > FilterLastPrivateSignalArg
std::bool_constant<(sizeof...(Args) > 0)> NotEmpty
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLsizei GLsizei GLint * values
[15]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLfloat GLfloat f
GLenum type
GLint first
GLenum func
Definition qopenglext.h:663
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
SSL_CTX int void * arg
#define QT_DEPRECATED_VERSION_X(major, minor, text)
ptrdiff_t qsizetype
Definition qtypes.h:165
QFuture< void > future
[5]
QSharedPointer< T > other(t)
[5]
QSizePolicy policy
view create()
QJSValueList args
FilterLastPrivateSignalArg< std::decay_t< Arg >, std::decay_t< Args >... > AllArgs
FilterLastPrivateSignalArg< QPromise< Arg >, std::decay_t< Args >... > AllArgs
std::false_type IsPromise
void operator()(const QFutureInterfaceBase &parentData)
ContinuationWrapper(ContinuationWrapper &&other)=default
ContinuationWrapper & operator=(ContinuationWrapper &&)=default
ContinuationWrapper(const ContinuationWrapper &other)
static auto unwrapImpl(T *outer)
QAtomicInteger< qsizetype > remaining
QPromise< ResultFutures > promise
WhenAllContext(qsizetype size)
void checkForCompletion(qsizetype index, T &&future)
typename ResultFutures::value_type ValueType
QPromise< ResultType > promise
void checkForCompletion(qsizetype, T &&result)