Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qfutureinterface.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// Qt-Security score:significant reason:default
4
5#ifndef QFUTUREINTERFACE_H
6#define QFUTUREINTERFACE_H
7
8#include <QtCore/qmutex.h>
9#include <QtCore/qresultstore.h>
10#include <QtCore/qtcoreexports.h>
11#ifndef QT_NO_EXCEPTIONS
12#include <exception>
13#endif
14
15#include <utility>
16
18
20QT_FORWARD_DECLARE_CLASS(QException)
21QT_BEGIN_NAMESPACE
22
23
24template <typename T> class QFuture;
25class QThreadPool;
26class QFutureInterfaceBase;
28class QFutureWatcherBase;
29class QFutureWatcherBasePrivate;
30
31namespace QtPrivate {
32template<typename Function, typename ResultType, typename ParentResultType>
34
35class ExceptionStore;
36
37template<class Function, class ResultType>
38class CanceledHandler;
39
40#ifndef QT_NO_EXCEPTIONS
41template<class Function, class ResultType>
42class FailureHandler;
43#endif
44
45#if QT_CORE_REMOVED_SINCE(6, 10)
49#endif // QT_CORE_REMOVED_SINCE(6, 10)
50}
51
52class Q_CORE_EXPORT QFutureInterfaceBase
53{
54public:
55 enum State {
56 NoState = 0x00,
57 Running = 0x01,
58 Started = 0x02,
59 Finished = 0x04,
60 Canceled = 0x08,
61 Suspending = 0x10,
62 Suspended = 0x20,
63 Throttled = 0x40,
64 // Pending means that the future depends on another one, which is not finished yet
65 Pending = 0x80,
66 };
67
68 QFutureInterfaceBase(State initialState = NoState);
69 QFutureInterfaceBase(const QFutureInterfaceBase &other);
70 QFutureInterfaceBase(QFutureInterfaceBase &&other) noexcept
71 : d(std::exchange(other.d, nullptr)) {}
72 QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other);
73 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QFutureInterfaceBase)
74 virtual ~QFutureInterfaceBase();
75
76 // reporting functions available to the engine author:
77 void reportStarted();
78 void reportFinished();
79 void reportCanceled();
80#ifndef QT_NO_EXCEPTIONS
81 void reportException(const QException &e);
82#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
83 void reportException(std::exception_ptr e);
84#else
85 void reportException(const std::exception_ptr &e);
86#endif
87#endif
88 void reportResultsReady(int beginIndex, int endIndex);
89
90 void setRunnable(QRunnable *runnable);
91 void setThreadPool(QThreadPool *pool);
92 QThreadPool *threadPool() const;
93 void setFilterMode(bool enable);
94 void setProgressRange(int minimum, int maximum);
95 int progressMinimum() const;
96 int progressMaximum() const;
97 bool isProgressUpdateNeeded() const;
98 void setProgressValue(int progressValue);
99 int progressValue() const;
100 void setProgressValueAndText(int progressValue, const QString &progressText);
101 QString progressText() const;
102
103 void setExpectedResultCount(int resultCount);
104 int expectedResultCount();
105 int resultCount() const;
106
107 bool queryState(State state) const;
108 bool isRunning() const;
109 bool isStarted() const;
110 bool isCanceled() const;
111 bool isFinished() const;
112#if QT_DEPRECATED_SINCE(6, 0)
113 QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.")
114 bool isPaused() const;
115
116 QT_DEPRECATED_VERSION_X_6_0("Use setSuspended() instead.")
117 void setPaused(bool paused) { setSuspended(paused); }
118
119 QT_DEPRECATED_VERSION_X_6_0("Use toggleSuspended() instead.")
120 void togglePaused() { toggleSuspended(); }
121#endif
122 bool isSuspending() const;
123 bool isSuspended() const;
124 bool isThrottled() const;
125 bool isResultReadyAt(int index) const;
126 bool isValid() const;
127 int loadState() const;
128
129 void cancel();
130 void cancelAndFinish() { cancel(CancelMode::CancelAndFinish); }
131 void cancelChain();
132
133 void setSuspended(bool suspend);
134 void toggleSuspended();
135 void reportSuspended() const;
136 void setThrottled(bool enable);
137
138 void waitForFinished();
139 bool waitForNextResult();
140 void waitForResult(int resultIndex);
141 void waitForResume();
142 void suspendIfRequested();
143
144 QMutex &mutex() const;
145 bool hasException() const;
146 QtPrivate::ExceptionStore &exceptionStore();
147 QtPrivate::ResultStoreBase &resultStoreBase();
148 const QtPrivate::ResultStoreBase &resultStoreBase() const;
149
150 inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; }
151 inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; }
152
153 // ### Qt 7: inline
154 void swap(QFutureInterfaceBase &other) noexcept;
155
156 template<typename T>
157 static QFutureInterfaceBase get(const QFuture<T> &future); // implemented in qfuture.h
158
159 bool isChainCanceled() const;
160
161protected:
162 // ### Qt 7: remove const from refT/derefT
163 bool refT() const noexcept;
164 bool derefT() const noexcept;
165 void reset();
166 void rethrowPossibleException();
167public:
168
169#ifndef QFUTURE_TEST
170private:
171#endif
172 friend class QFutureInterfaceBasePrivate;
173 QFutureInterfaceBasePrivate *d;
174
175private:
176 friend class QFutureWatcherBase;
177 friend class QFutureWatcherBasePrivate;
178
179 template<typename Function, typename ResultType, typename ParentResultType>
180 friend class QtPrivate::CompactContinuation;
181
182 template<class Function, class ResultType>
183 friend class QtPrivate::CanceledHandler;
184
185#ifndef QT_NO_EXCEPTIONS
186 template<class Function, class ResultType>
187 friend class QtPrivate::FailureHandler;
188#endif
189
190#if QT_CORE_REMOVED_SINCE(6, 10)
191 friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl(
192 const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi);
193#endif // QT_CORE_REMOVED_SINCE(6, 10)
194
195 template<class T>
196 friend class QPromise;
197
198protected:
199 enum class ContinuationType : quint8
200 {
201 Unknown,
202 Then,
203 OnFailed,
204 OnCanceled,
205 };
206
207#if QT_CORE_REMOVED_SINCE(6, 10)
208 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func);
209 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
210 QFutureInterfaceBasePrivate *continuationFutureData);
211#endif // QT_CORE_REMOVED_SINCE(6, 10)
212 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
213 void *continuationFutureData, ContinuationType type);
214 void setContinuation(const QObject *context, std::function<void()> func,
215 const QVariant &continuationFuture, ContinuationType type);
216 void cleanContinuation();
217 void runContinuation() const;
218
219 void setLaunchAsync(bool value);
220 bool launchAsync() const;
221
222 bool isRunningOrPending() const;
223
224 enum class CancelMode { CancelOnly, CancelAndFinish };
225 void cancel(CancelMode mode);
226 void cancelChain(CancelMode mode);
227};
228
229inline void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept
230{
231 lhs.swap(rhs);
232}
233
234template <typename T>
236{
237public:
238 QFutureInterface(State initialState = NoState)
239 : QFutureInterfaceBase(initialState)
240 {
241 refT();
242 }
244 : QFutureInterfaceBase(other)
245 {
246 refT();
247 }
248 QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { refT(); }
249 QFutureInterface(QFutureInterfaceBase &&dd) noexcept : QFutureInterfaceBase(std::move(dd)) { refT(); }
251 {
252 QFutureInterface copy(other);
253 swap(copy);
254 return *this;
255 }
258
260 {
261 if (!derefT() && !hasException())
262 resultStoreBase().template clear<T>();
263 }
264
267
268 inline QFuture<T> future(); // implemented in qfuture.h
269
270 template <typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true>
271 inline bool reportAndEmplaceResult(int index, Args&&...args);
272 inline bool reportResult(const T *result, int index = -1);
273 inline bool reportAndMoveResult(T &&result, int index = -1);
274 inline bool reportResult(T &&result, int index = -1);
275 inline bool reportResult(const T &result, int index = -1);
276 inline bool reportResults(const QList<T> &results, int beginIndex = -1, int count = -1);
277 inline bool reportFinished(const T *result);
279 {
280 QFutureInterfaceBase::reportFinished();
281 QFutureInterfaceBase::runContinuation();
282 }
283
284 inline const T &resultReference(int index) const;
285 inline const T *resultPointer(int index) const;
286 inline QList<T> results();
287
289#if 0
290 // TODO: Enable and make it return a QList, when QList is fixed to support move-only types
292#endif
293
294#ifndef QT_NO_EXCEPTIONS
295 void reportException(const std::exception_ptr &e)
296 {
297 if (hasException())
298 return;
299
300 resultStoreBase().template clear<T>();
301 QFutureInterfaceBase::reportException(e);
302 }
303 void reportException(const QException &e)
304 {
305 if (hasException())
306 return;
307
308 resultStoreBase().template clear<T>();
309 QFutureInterfaceBase::reportException(e);
310 }
311#endif
312};
313
314template <typename T>
315inline bool QFutureInterface<T>::reportResult(const T *result, int index)
316{
317 QMutexLocker<QMutex> locker{&mutex()};
318 if (this->queryState(Canceled) || this->queryState(Finished))
319 return false;
320
321 Q_ASSERT(!hasException());
322 QtPrivate::ResultStoreBase &store = resultStoreBase();
323
324 const int resultCountBefore = store.count();
325 const int insertIndex = store.addResult<T>(index, result);
326 if (insertIndex == -1)
327 return false;
328 if (store.filterMode()) {
329 this->reportResultsReady(resultCountBefore, store.count());
330 } else {
331 this->reportResultsReady(insertIndex, insertIndex + 1);
332 }
333 return true;
334}
335
336template<typename T>
337template<typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool>>
338bool QFutureInterface<T>::reportAndEmplaceResult(int index, Args&&...args)
339{
340 QMutexLocker<QMutex> locker{&mutex()};
341 if (queryState(Canceled) || queryState(Finished))
342 return false;
343
344 Q_ASSERT(!hasException());
345 QtPrivate::ResultStoreBase &store = resultStoreBase();
346
347 const int oldResultCount = store.count();
348 const int insertIndex = store.emplaceResult<T>(index, std::forward<Args>(args)...);
349 // Let's make sure it's not in pending results.
350 if (insertIndex != -1 && (!store.filterMode() || oldResultCount < store.count()))
351 reportResultsReady(insertIndex, store.count());
352 return insertIndex != -1;
353}
354
355template<typename T>
356bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
357{
358 return reportAndEmplaceResult(index, std::move(result));
359}
360
361template<typename T>
362bool QFutureInterface<T>::reportResult(T &&result, int index)
363{
364 return reportAndMoveResult(std::move(result), index);
365}
366
367template <typename T>
368inline bool QFutureInterface<T>::reportResult(const T &result, int index)
369{
370 return reportResult(&result, index);
371}
372
373template<typename T>
374inline bool QFutureInterface<T>::reportResults(const QList<T> &_results, int beginIndex, int count)
375{
376 QMutexLocker<QMutex> locker{&mutex()};
377 if (this->queryState(Canceled) || this->queryState(Finished))
378 return false;
379
380 Q_ASSERT(!hasException());
381 auto &store = resultStoreBase();
382
383 const int resultCountBefore = store.count();
384 const int insertIndex = store.addResults(beginIndex, &_results, count);
385 if (insertIndex == -1)
386 return false;
387 if (store.filterMode()) {
388 this->reportResultsReady(resultCountBefore, store.count());
389 } else {
390 this->reportResultsReady(insertIndex, insertIndex + _results.size());
391 }
392 return true;
393}
394
395template <typename T>
396inline bool QFutureInterface<T>::reportFinished(const T *result)
397{
398 bool resultReported = false;
399 if (result)
400 resultReported = reportResult(result);
401 reportFinished();
402 return resultReported;
403}
404
405template <typename T>
406inline const T &QFutureInterface<T>::resultReference(int index) const
407{
408 Q_ASSERT(!hasException());
409
410 QMutexLocker<QMutex> locker{&mutex()};
411 return resultStoreBase().resultAt(index).template value<T>();
412}
413
414template <typename T>
415inline const T *QFutureInterface<T>::resultPointer(int index) const
416{
417 Q_ASSERT(!hasException());
418
419 QMutexLocker<QMutex> locker{&mutex()};
420 return resultStoreBase().resultAt(index).template pointer<T>();
421}
422
423template <typename T>
425{
426 if (this->isCanceled()) {
427 rethrowPossibleException();
428 return QList<T>();
429 }
430
431 QFutureInterfaceBase::waitForResult(-1);
432
433 QList<T> res;
434 QMutexLocker<QMutex> locker{&mutex()};
435
436 QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
437 while (it != resultStoreBase().end()) {
438 res.append(it.value<T>());
439 ++it;
440 }
441
442 return res;
443}
444
445template<typename T>
447{
448 // Note: we wait for all, this is intentional,
449 // not to mess with other unready results.
450 waitForResult(-1);
451
452 Q_ASSERT(isValid());
453 Q_ASSERT(!hasException());
454
455 const QMutexLocker<QMutex> locker{&mutex()};
456 QtPrivate::ResultIteratorBase position = resultStoreBase().resultAt(0);
457 T ret(std::move_if_noexcept(position.value<T>()));
458 reset();
459 resultStoreBase().template clear<T>();
460
461 return ret;
462}
463
464#if 0
465template<typename T>
466std::vector<T> QFutureInterface<T>::takeResults()
467{
468 waitForResult(-1);
469
470 Q_ASSERT(isValid());
471 Q_ASSERT(!hasException());
472
473 std::vector<T> res;
474 res.reserve(resultCount());
475
476 const QMutexLocker<QMutex> locker{&mutex()};
477
478 QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
479 for (auto endIt = resultStoreBase().end(); it != endIt; ++it)
480 res.push_back(std::move_if_noexcept(it.value<T>()));
481
482 reset();
483 resultStoreBase().template clear<T>();
484
485 return res;
486}
487#endif
488
489QT_WARNING_PUSH
490QT_WARNING_DISABLE_CLANG("-Wweak-vtables") // QTBUG-125115
491
492template <>
493class QFutureInterface<void> : public QFutureInterfaceBase
494{
495public:
496 explicit QFutureInterface(State initialState = NoState)
497 : QFutureInterfaceBase(initialState)
498 { }
499
500 QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { }
501
502 static QFutureInterface<void> canceledResult()
503 { return QFutureInterface(State(Started | Finished | Canceled)); }
504
505
506 inline QFuture<void> future(); // implemented in qfuture.h
507
508 bool reportResult(const void *, int) { return false; }
509 bool reportResults(const QList<void> &, int) { return false; }
510 bool reportFinished(const void *)
511 {
512 reportFinished();
513 return false;
514 }
515 void reportFinished()
516 {
517 QFutureInterfaceBase::reportFinished();
518 QFutureInterfaceBase::runContinuation();
519 }
520};
521
522QT_WARNING_POP // Clang -Wweak-vtables
523
524template<typename T>
525inline void swap(QFutureInterface<T> &a, QFutureInterface<T> &b) noexcept
526{
527 a.swap(b);
528}
529
530QT_END_NAMESPACE
531
532#endif // QFUTUREINTERFACE_H
QFutureInterface(QFutureInterface &&other)=default
bool reportAndEmplaceResult(int index, Args &&...args)
QFutureInterface(const QFutureInterfaceBase &dd)
bool reportResult(T &&result, int index=-1)
QFutureInterface & operator=(const QFutureInterface &other)
bool reportResults(const QList< T > &results, int beginIndex=-1, int count=-1)
const T * resultPointer(int index) const
QFutureInterface(State initialState=NoState)
bool reportResult(const T &result, int index=-1)
void reportException(const std::exception_ptr &e)
QFutureInterface(const QFutureInterface &other)
bool reportFinished(const T *result)
void reportException(const QException &e)
bool reportResult(const T *result, int index=-1)
bool reportAndMoveResult(T &&result, int index=-1)
QFutureInterface(QFutureInterfaceBase &&dd) noexcept
const T & resultReference(int index) const
\inmodule QtCore
Definition qrunnable.h:19
void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept
QFuture< void > future
[5]