1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QFUTURE_H
41#error Do not include qfuture_impl.h directly
42#endif
43
44#if 0
45#pragma qt_sync_skip_header_check
46#pragma qt_sync_stop_processing
47#endif
48
49#include <QtCore/qglobal.h>
50#include <QtCore/qfutureinterface.h>
51#include <QtCore/qthreadpool.h>
52
53QT_BEGIN_NAMESPACE
54
55//
56// forward declarations
57//
58template<class T>
59class QFuture;
60template<class T>
61class QFutureInterface;
62
63namespace QtFuture {
64enum class Launch { Sync, Async, Inherit };
65}
66
67namespace QtPrivate {
68
69template<class T, class U>
70using EnableIfSameOrConvertible = std::enable_if_t<std::is_same_v<T, U>
71 || std::is_convertible_v<T, U>>;
72
73template<class T>
74using EnableForVoid = std::enable_if_t<std::is_same_v<T, void>>;
75
76template<class T>
77using EnableForNonVoid = std::enable_if_t<!std::is_same_v<T, void>>;
78
79template<typename F, typename Arg, typename Enable = void>
80struct ResultTypeHelper
81{
82};
83
84// The callable takes an argument of type Arg
85template<typename F, typename Arg>
86struct ResultTypeHelper<
87 F, Arg, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<Arg>>>>
88{
89 using ResultType = std::invoke_result_t<std::decay_t<F>, std::decay_t<Arg>>;
90};
91
92// The callable takes an argument of type QFuture<Arg>
93template<class F, class Arg>
94struct ResultTypeHelper<
95 F, Arg, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<Arg>>>>
96{
97 using ResultType = std::invoke_result_t<std::decay_t<F>, QFuture<Arg>>;
98};
99
100// The callable takes an argument of type QFuture<void>
101template<class F>
102struct ResultTypeHelper<
103 F, void, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
104{
105 using ResultType = std::invoke_result_t<std::decay_t<F>, QFuture<void>>;
106};
107
108// The callable doesn't take argument
109template<class F>
110struct ResultTypeHelper<
111 F, void, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
112{
113 using ResultType = std::invoke_result_t<std::decay_t<F>>;
114};
115
116// Helpers to resolve argument types of callables.
117template<typename...>
118struct ArgsType;
119
120template<typename Arg, typename... Args>
121struct ArgsType<Arg, Args...>
122{
123 using First = Arg;
124 static const bool HasExtraArgs = (sizeof...(Args) > 0);
125 using AllArgs =
126 std::conditional_t<HasExtraArgs, std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>,
127 std::decay_t<Arg>>;
128
129 template<class Class, class Callable>
130 static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, Arg, Args...>;
131};
132
133template<>
134struct ArgsType<>
135{
136 using First = void;
137 static const bool HasExtraArgs = false;
138 using AllArgs = void;
139
140 template<class Class, class Callable>
141 static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class>;
142};
143
144template<typename F>
145struct ArgResolver : ArgResolver<decltype(&std::decay_t<F>::operator())>
146{
147};
148
149template<typename R, typename... Args>
150struct ArgResolver<R(Args...)> : public ArgsType<Args...>
151{
152};
153
154template<typename R, typename... Args>
155struct ArgResolver<R (*)(Args...)> : public ArgsType<Args...>
156{
157};
158
159template<typename R, typename... Args>
160struct ArgResolver<R (&)(Args...)> : public ArgsType<Args...>
161{
162};
163
164template<typename Class, typename R, typename... Args>
165struct ArgResolver<R (Class::*)(Args...)> : public ArgsType<Args...>
166{
167};
168
169template<typename Class, typename R, typename... Args>
170struct ArgResolver<R (Class::*)(Args...) noexcept> : public ArgsType<Args...>
171{
172};
173
174template<typename Class, typename R, typename... Args>
175struct ArgResolver<R (Class::*)(Args...) const> : public ArgsType<Args...>
176{
177};
178
179template<typename Class, typename R, typename... Args>
180struct ArgResolver<R (Class::*)(Args...) const noexcept> : public ArgsType<Args...>
181{
182};
183
184template<class Class, class Callable>
185using EnableIfInvocable = std::enable_if_t<
186 QtPrivate::ArgResolver<Callable>::template CanInvokeWithArgs<Class, Callable>>;
187
188template<class>
189struct isTuple : std::false_type
190{
191};
192template<class... T>
193struct isTuple<std::tuple<T...>> : std::true_type
194{
195};
196template<class T>
197inline constexpr bool isTupleV = isTuple<T>::value;
198
199template<typename Function, typename ResultType, typename ParentResultType>
200class Continuation
201{
202public:
203 Continuation(Function &&func, const QFuture<ParentResultType> &f,
204 const QFutureInterface<ResultType> &p)
205 : promise(p), parentFuture(f), function(std::forward<Function>(func))
206 {
207 }
208 virtual ~Continuation() = default;
209
210 bool execute();
211
212 static void create(Function &&func, QFuture<ParentResultType> *f,
213 QFutureInterface<ResultType> &p, QtFuture::Launch policy);
214
215 static void create(Function &&func, QFuture<ParentResultType> *f,
216 QFutureInterface<ResultType> &p, QThreadPool *pool);
217
218private:
219 void fulfillPromiseWithResult();
220 void fulfillVoidPromise();
221 void fulfillPromiseWithVoidResult();
222
223 template<class... Args>
224 void fulfillPromise(Args &&... args);
225
226protected:
227 virtual void runImpl() = 0;
228
229 void runFunction();
230
231protected:
232 QFutureInterface<ResultType> promise;
233 QFuture<ParentResultType> parentFuture;
234 Function function;
235};
236
237template<typename Function, typename ResultType, typename ParentResultType>
238class SyncContinuation final : public Continuation<Function, ResultType, ParentResultType>
239{
240public:
241 SyncContinuation(Function &&func, const QFuture<ParentResultType> &f,
242 const QFutureInterface<ResultType> &p)
243 : Continuation<Function, ResultType, ParentResultType>(std::forward<Function>(func), f, p)
244 {
245 }
246
247 ~SyncContinuation() override = default;
248
249private:
250 void runImpl() override { this->runFunction(); }
251};
252
253template<typename Function, typename ResultType, typename ParentResultType>
254class AsyncContinuation final : public QRunnable,
255 public Continuation<Function, ResultType, ParentResultType>
256{
257public:
258 AsyncContinuation(Function &&func, const QFuture<ParentResultType> &f,
259 const QFutureInterface<ResultType> &p, QThreadPool *pool = nullptr)
260 : Continuation<Function, ResultType, ParentResultType>(std::forward<Function>(func), f, p),
261 threadPool(pool)
262 {
263 this->promise.setRunnable(this);
264 }
265
266 ~AsyncContinuation() override = default;
267
268private:
269 void runImpl() override // from Continuation
270 {
271 QThreadPool *pool = threadPool ? threadPool : QThreadPool::globalInstance();
272 pool->start(this);
273 }
274
275 void run() override // from QRunnable
276 {
277 this->runFunction();
278 }
279
280private:
281 QThreadPool *threadPool;
282};
283
284#ifndef QT_NO_EXCEPTIONS
285
286template<class Function, class ResultType>
287class FailureHandler
288{
289public:
290 static void create(Function &&function, QFuture<ResultType> *future,
291 const QFutureInterface<ResultType> &promise);
292
293 FailureHandler(Function &&func, const QFuture<ResultType> &f,
294 const QFutureInterface<ResultType> &p)
295 : promise(p), parentFuture(f), handler(std::forward<Function>(func))
296 {
297 }
298
299public:
300 void run();
301
302private:
303 template<class ArgType>
304 void handleException();
305 void handleAllExceptions();
306
307private:
308 QFutureInterface<ResultType> promise;
309 QFuture<ResultType> parentFuture;
310 Function handler;
311};
312
313#endif
314
315template<typename Function, typename ResultType, typename ParentResultType>
316void Continuation<Function, ResultType, ParentResultType>::runFunction()
317{
318 promise.reportStarted();
319
320 Q_ASSERT(parentFuture.isFinished());
321
322#ifndef QT_NO_EXCEPTIONS
323 try {
324#endif
325 if constexpr (!std::is_void_v<ResultType>) {
326 if constexpr (std::is_void_v<ParentResultType>) {
327 fulfillPromiseWithVoidResult();
328 } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
329 fulfillPromiseWithResult();
330 } else {
331 // This assert normally should never fail, this is to make sure
332 // that nothing unexpected happend.
333 static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
334 "The continuation is not invocable with the provided arguments");
335 fulfillPromise(parentFuture);
336 }
337 } else {
338 if constexpr (std::is_void_v<ParentResultType>) {
339 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
340 function(parentFuture);
341 else
342 function();
343 } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
344 fulfillVoidPromise();
345 } else {
346 // This assert normally should never fail, this is to make sure
347 // that nothing unexpected happend.
348 static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
349 "The continuation is not invocable with the provided arguments");
350 function(parentFuture);
351 }
352 }
353#ifndef QT_NO_EXCEPTIONS
354 } catch (...) {
355 promise.reportException(std::current_exception());
356 }
357#endif
358 promise.reportFinished();
359}
360
361template<typename Function, typename ResultType, typename ParentResultType>
362bool Continuation<Function, ResultType, ParentResultType>::execute()
363{
364 Q_ASSERT(parentFuture.isFinished());
365
366 if (parentFuture.isCanceled()) {
367#ifndef QT_NO_EXCEPTIONS
368 if (parentFuture.d.exceptionStore().hasException()) {
369 // If the continuation doesn't take a QFuture argument, propagate the exception
370 // to the caller, by reporting it. If the continuation takes a QFuture argument,
371 // the user may want to catch the exception inside the continuation, to not
372 // interrupt the continuation chain, so don't report anything yet.
373 if constexpr (!std::is_invocable_v<std::decay_t<Function>, QFuture<ParentResultType>>) {
374 promise.reportStarted();
375 promise.reportException(parentFuture.d.exceptionStore().exception());
376 promise.reportFinished();
377 return false;
378 }
379 } else
380#endif
381 {
382 promise.reportStarted();
383 promise.reportCanceled();
384 promise.reportFinished();
385 return false;
386 }
387 }
388
389 runImpl();
390 return true;
391}
392
393template<typename Function, typename ResultType, typename ParentResultType>
394void Continuation<Function, ResultType, ParentResultType>::create(Function &&func,
395 QFuture<ParentResultType> *f,
396 QFutureInterface<ResultType> &p,
397 QtFuture::Launch policy)
398{
399 Q_ASSERT(f);
400
401 QThreadPool *pool = nullptr;
402
403 bool launchAsync = (policy == QtFuture::Launch::Async);
404 if (policy == QtFuture::Launch::Inherit) {
405 launchAsync = f->d.launchAsync();
406
407 // If the parent future was using a custom thread pool, inherit it as well.
408 if (launchAsync && f->d.threadPool()) {
409 pool = f->d.threadPool();
410 p.setThreadPool(pool);
411 }
412 }
413
414 Continuation<Function, ResultType, ParentResultType> *continuationJob = nullptr;
415 if (launchAsync) {
416 continuationJob = new AsyncContinuation<Function, ResultType, ParentResultType>(
417 std::forward<Function>(func), *f, p, pool);
418 } else {
419 continuationJob = new SyncContinuation<Function, ResultType, ParentResultType>(
420 std::forward<Function>(func), *f, p);
421 }
422
423 p.setLaunchAsync(launchAsync);
424
425 auto continuation = [continuationJob, launchAsync]() mutable {
426 bool isLaunched = continuationJob->execute();
427 // If continuation is successfully launched, AsyncContinuation will be deleted
428 // by the QThreadPool which has started it. Synchronous continuation will be
429 // executed immediately, so it's safe to always delete it here.
430 if (!(launchAsync && isLaunched)) {
431 delete continuationJob;
432 continuationJob = nullptr;
433 }
434 };
435
436 f->d.setContinuation(std::move(continuation));
437}
438
439template<typename Function, typename ResultType, typename ParentResultType>
440void Continuation<Function, ResultType, ParentResultType>::create(Function &&func,
441 QFuture<ParentResultType> *f,
442 QFutureInterface<ResultType> &p,
443 QThreadPool *pool)
444{
445 Q_ASSERT(f);
446
447 auto continuationJob = new AsyncContinuation<Function, ResultType, ParentResultType>(
448 std::forward<Function>(func), *f, p, pool);
449 p.setLaunchAsync(true);
450 p.setThreadPool(pool);
451
452 auto continuation = [continuationJob]() mutable {
453 bool isLaunched = continuationJob->execute();
454 // If continuation is successfully launched, AsyncContinuation will be deleted
455 // by the QThreadPool which has started it.
456 if (!isLaunched) {
457 delete continuationJob;
458 continuationJob = nullptr;
459 }
460 };
461
462 f->d.setContinuation(continuation);
463}
464
465template<typename Function, typename ResultType, typename ParentResultType>
466void Continuation<Function, ResultType, ParentResultType>::fulfillPromiseWithResult()
467{
468 if constexpr (std::is_copy_constructible_v<ParentResultType>)
469 fulfillPromise(parentFuture.result());
470 else
471 fulfillPromise(parentFuture.takeResult());
472}
473
474template<typename Function, typename ResultType, typename ParentResultType>
475void Continuation<Function, ResultType, ParentResultType>::fulfillVoidPromise()
476{
477 if constexpr (std::is_copy_constructible_v<ParentResultType>)
478 function(parentFuture.result());
479 else
480 function(parentFuture.takeResult());
481}
482
483template<typename Function, typename ResultType, typename ParentResultType>
484void Continuation<Function, ResultType, ParentResultType>::fulfillPromiseWithVoidResult()
485{
486 if constexpr (std::is_invocable_v<Function, QFuture<void>>)
487 fulfillPromise(parentFuture);
488 else
489 fulfillPromise();
490}
491
492template<typename Function, typename ResultType, typename ParentResultType>
493template<class... Args>
494void Continuation<Function, ResultType, ParentResultType>::fulfillPromise(Args &&... args)
495{
496 if constexpr (std::is_copy_constructible_v<ResultType>)
497 promise.reportResult(std::invoke(function, std::forward<Args>(args)...));
498 else
499 promise.reportAndMoveResult(std::invoke(function, std::forward<Args>(args)...));
500}
501
502template<class T>
503void fulfillPromise(QFutureInterface<T> &promise, QFuture<T> &future)
504{
505 if constexpr (!std::is_void_v<T>) {
506 if constexpr (std::is_copy_constructible_v<T>)
507 promise.reportResult(future.result());
508 else
509 promise.reportAndMoveResult(future.takeResult());
510 }
511}
512
513template<class T, class Function>
514void fulfillPromise(QFutureInterface<T> &promise, Function &&handler)
515{
516 if constexpr (std::is_void_v<T>)
517 handler();
518 else if constexpr (std::is_copy_constructible_v<T>)
519 promise.reportResult(handler());
520 else
521 promise.reportAndMoveResult(handler());
522}
523
524#ifndef QT_NO_EXCEPTIONS
525
526template<class Function, class ResultType>
527void FailureHandler<Function, ResultType>::create(Function &&function, QFuture<ResultType> *future,
528 const QFutureInterface<ResultType> &promise)
529{
530 Q_ASSERT(future);
531
532 FailureHandler<Function, ResultType> *failureHandler = new FailureHandler<Function, ResultType>(
533 std::forward<Function>(function), *future, promise);
534
535 auto failureContinuation = [failureHandler]() mutable {
536 failureHandler->run();
537 delete failureHandler;
538 };
539
540 future->d.setContinuation(std::move(failureContinuation));
541}
542
543template<class Function, class ResultType>
544void FailureHandler<Function, ResultType>::run()
545{
546 Q_ASSERT(parentFuture.isFinished());
547
548 promise.reportStarted();
549
550 if (parentFuture.d.exceptionStore().hasException()) {
551 using ArgType = typename QtPrivate::ArgResolver<Function>::First;
552 if constexpr (std::is_void_v<ArgType>) {
553 handleAllExceptions();
554 } else {
555 handleException<ArgType>();
556 }
557 } else {
558 QtPrivate::fulfillPromise(promise, parentFuture);
559 }
560 promise.reportFinished();
561}
562
563template<class Function, class ResultType>
564template<class ArgType>
565void FailureHandler<Function, ResultType>::handleException()
566{
567 try {
568 parentFuture.d.exceptionStore().throwPossibleException();
569 } catch (const ArgType &e) {
570 try {
571 // Handle exceptions matching with the handler's argument type
572 if constexpr (std::is_void_v<ResultType>) {
573 handler(e);
574 } else {
575 if constexpr (std::is_copy_constructible_v<ResultType>)
576 promise.reportResult(handler(e));
577 else
578 promise.reportAndMoveResult(handler(e));
579 }
580 } catch (...) {
581 promise.reportException(std::current_exception());
582 }
583 } catch (...) {
584 // Exception doesn't match with handler's argument type, propagate
585 // the exception to be handled later.
586 promise.reportException(std::current_exception());
587 }
588}
589
590template<class Function, class ResultType>
591void FailureHandler<Function, ResultType>::handleAllExceptions()
592{
593 try {
594 parentFuture.d.exceptionStore().throwPossibleException();
595 } catch (...) {
596 try {
597 QtPrivate::fulfillPromise(promise, std::forward<Function>(handler));
598 } catch (...) {
599 promise.reportException(std::current_exception());
600 }
601 }
602}
603
604#endif // QT_NO_EXCEPTIONS
605
606template<class Function, class ResultType>
607class CanceledHandler
608{
609public:
610 static QFuture<ResultType> create(Function &&handler, QFuture<ResultType> *future,
611 QFutureInterface<ResultType> promise)
612 {
613 Q_ASSERT(future);
614
615 auto canceledContinuation = [parentFuture = *future, promise,
616 handler = std::move(handler)]() mutable {
617 promise.reportStarted();
618
619 if (parentFuture.isCanceled()) {
620#ifndef QT_NO_EXCEPTIONS
621 if (parentFuture.d.exceptionStore().hasException()) {
622 // Propagate the exception to the result future
623 promise.reportException(parentFuture.d.exceptionStore().exception());
624 } else {
625 try {
626#endif
627 QtPrivate::fulfillPromise(promise, std::forward<Function>(handler));
628#ifndef QT_NO_EXCEPTIONS
629 } catch (...) {
630 promise.reportException(std::current_exception());
631 }
632 }
633#endif
634 } else {
635 QtPrivate::fulfillPromise(promise, parentFuture);
636 }
637
638 promise.reportFinished();
639 };
640 future->d.setContinuation(std::move(canceledContinuation));
641 return promise.future();
642 }
643};
644
645} // namespace QtPrivate
646
647namespace QtFuture {
648
649template<class Signal>
650using ArgsType = typename QtPrivate::ArgResolver<Signal>::AllArgs;
651
652template<class Sender, class Signal, typename = QtPrivate::EnableIfInvocable<Sender, Signal>>
653static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
654{
655 using ArgsType = ArgsType<Signal>;
656 QFutureInterface<ArgsType> promise;
657 promise.reportStarted();
658
659 using Connections = std::pair<QMetaObject::Connection, QMetaObject::Connection>;
660 auto connections = std::make_shared<Connections>();
661
662 if constexpr (std::is_void_v<ArgsType>) {
663 connections->first =
664 QObject::connect(sender, signal, sender, [promise, connections]() mutable {
665 promise.reportFinished();
666 QObject::disconnect(connections->first);
667 QObject::disconnect(connections->second);
668 });
669 } else if constexpr (QtPrivate::isTupleV<ArgsType>) {
670 connections->first = QObject::connect(sender, signal, sender,
671 [promise, connections](auto... values) mutable {
672 promise.reportResult(std::make_tuple(values...));
673 promise.reportFinished();
674 QObject::disconnect(connections->first);
675 QObject::disconnect(connections->second);
676 });
677 } else {
678 connections->first = QObject::connect(sender, signal, sender,
679 [promise, connections](ArgsType value) mutable {
680 promise.reportResult(value);
681 promise.reportFinished();
682 QObject::disconnect(connections->first);
683 QObject::disconnect(connections->second);
684 });
685 }
686
687 connections->second =
688 QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable {
689 promise.reportCanceled();
690 promise.reportFinished();
691 QObject::disconnect(connections->first);
692 QObject::disconnect(connections->second);
693 });
694
695 return promise.future();
696}
697
698} // namespace QtFuture
699
700QT_END_NAMESPACE
701