1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
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 Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #ifndef QFUTUREINTERFACE_H |
43 | #define QFUTUREINTERFACE_H |
44 | |
45 | #include <QtCore/qglobal.h> |
46 | #include <QtCore/qrunnable.h> |
47 | |
48 | #ifndef QT_NO_QFUTURE |
49 | |
50 | #include <QtCore/qmutex.h> |
51 | #include <QtCore/qtconcurrentexception.h> |
52 | #include <QtCore/qtconcurrentresultstore.h> |
53 | |
54 | QT_BEGIN_HEADER |
55 | QT_BEGIN_NAMESPACE |
56 | |
57 | QT_MODULE(Core) |
58 | |
59 | template <typename T> class QFuture; |
60 | class QFutureInterfaceBasePrivate; |
61 | class QFutureWatcherBase; |
62 | class QFutureWatcherBasePrivate; |
63 | |
64 | class Q_CORE_EXPORT QFutureInterfaceBase |
65 | { |
66 | public: |
67 | enum State { |
68 | NoState = 0x00, |
69 | Running = 0x01, |
70 | Started = 0x02, |
71 | Finished = 0x04, |
72 | Canceled = 0x08, |
73 | Paused = 0x10, |
74 | Throttled = 0x20 |
75 | }; |
76 | |
77 | QFutureInterfaceBase(State initialState = NoState); |
78 | QFutureInterfaceBase(const QFutureInterfaceBase &other); |
79 | virtual ~QFutureInterfaceBase(); |
80 | |
81 | // reporting functions available to the engine author: |
82 | void reportStarted(); |
83 | void reportFinished(); |
84 | void reportCanceled(); |
85 | #ifndef QT_NO_EXCEPTIONS |
86 | void reportException(const QtConcurrent::Exception &e); |
87 | #endif |
88 | void reportResultsReady(int beginIndex, int endIndex); |
89 | |
90 | void setRunnable(QRunnable *runnable); |
91 | void setFilterMode(bool enable); |
92 | void setProgressRange(int minimum, int maximum); |
93 | int progressMinimum() const; |
94 | int progressMaximum() const; |
95 | bool isProgressUpdateNeeded() const; |
96 | void setProgressValue(int progressValue); |
97 | int progressValue() const; |
98 | void setProgressValueAndText(int progressValue, const QString &progressText); |
99 | QString progressText() const; |
100 | |
101 | void setExpectedResultCount(int resultCount); |
102 | int expectedResultCount(); |
103 | int resultCount() const; |
104 | |
105 | bool queryState(State state) const; |
106 | bool isRunning() const; |
107 | bool isStarted() const; |
108 | bool isCanceled() const; |
109 | bool isFinished() const; |
110 | bool isPaused() const; |
111 | bool isThrottled() const; |
112 | bool isResultReadyAt(int index) const; |
113 | |
114 | void cancel(); |
115 | void setPaused(bool paused); |
116 | void togglePaused(); |
117 | void setThrottled(bool enable); |
118 | |
119 | void waitForFinished(); |
120 | bool waitForNextResult(); |
121 | void waitForResult(int resultIndex); |
122 | void waitForResume(); |
123 | |
124 | QMutex *mutex() const; |
125 | QtConcurrent::internal::ExceptionStore &exceptionStore(); |
126 | QtConcurrent::ResultStoreBase &resultStoreBase(); |
127 | const QtConcurrent::ResultStoreBase &resultStoreBase() const; |
128 | |
129 | inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; } |
130 | inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; } |
131 | QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other); |
132 | |
133 | protected: |
134 | bool referenceCountIsOne() const; |
135 | public: |
136 | |
137 | #ifndef QFUTURE_TEST |
138 | private: |
139 | #endif |
140 | QFutureInterfaceBasePrivate *d; |
141 | |
142 | private: |
143 | friend class QFutureWatcherBase; |
144 | friend class QFutureWatcherBasePrivate; |
145 | }; |
146 | |
147 | template <typename T> |
148 | class QFutureInterface : public QFutureInterfaceBase |
149 | { |
150 | public: |
151 | QFutureInterface(State initialState = NoState) |
152 | : QFutureInterfaceBase(initialState) |
153 | { } |
154 | QFutureInterface(const QFutureInterface &other) |
155 | : QFutureInterfaceBase(other) |
156 | { } |
157 | ~QFutureInterface() |
158 | { |
159 | if (referenceCountIsOne()) |
160 | resultStore().clear(); |
161 | } |
162 | |
163 | static QFutureInterface canceledResult() |
164 | { return QFutureInterface(State(Started | Finished | Canceled)); } |
165 | |
166 | QFutureInterface &operator=(const QFutureInterface &other) |
167 | { |
168 | if (referenceCountIsOne()) |
169 | resultStore().clear(); |
170 | QFutureInterfaceBase::operator=(other); |
171 | return *this; |
172 | } |
173 | |
174 | inline QFuture<T> future(); // implemented in qfuture.h |
175 | |
176 | inline void reportResult(const T *result, int index = -1); |
177 | inline void reportResult(const T &result, int index = -1); |
178 | inline void reportResults(const QVector<T> &results, int beginIndex = -1, int count = -1); |
179 | inline void reportFinished(const T *result = 0); |
180 | |
181 | inline const T &resultReference(int index) const; |
182 | inline const T *resultPointer(int index) const; |
183 | inline QList<T> results(); |
184 | private: |
185 | QtConcurrent::ResultStore<T> &resultStore() |
186 | { return static_cast<QtConcurrent::ResultStore<T> &>(resultStoreBase()); } |
187 | const QtConcurrent::ResultStore<T> &resultStore() const |
188 | { return static_cast<const QtConcurrent::ResultStore<T> &>(resultStoreBase()); } |
189 | }; |
190 | |
191 | template <typename T> |
192 | inline void QFutureInterface<T>::reportResult(const T *result, int index) |
193 | { |
194 | QMutexLocker locker(mutex()); |
195 | if (this->queryState(Canceled) || this->queryState(Finished)) { |
196 | return; |
197 | } |
198 | |
199 | QtConcurrent::ResultStore<T> &store = resultStore(); |
200 | |
201 | |
202 | if (store.filterMode()) { |
203 | const int resultCountBefore = store.count(); |
204 | store.addResult(index, result); |
205 | this->reportResultsReady(resultCountBefore, resultCountBefore + store.count()); |
206 | } else { |
207 | const int insertIndex = store.addResult(index, result); |
208 | this->reportResultsReady(insertIndex, insertIndex + 1); |
209 | } |
210 | } |
211 | |
212 | template <typename T> |
213 | inline void QFutureInterface<T>::reportResult(const T &result, int index) |
214 | { |
215 | reportResult(&result, index); |
216 | } |
217 | |
218 | template <typename T> |
219 | inline void QFutureInterface<T>::reportResults(const QVector<T> &_results, int beginIndex, int count) |
220 | { |
221 | QMutexLocker locker(mutex()); |
222 | if (this->queryState(Canceled) || this->queryState(Finished)) { |
223 | return; |
224 | } |
225 | |
226 | QtConcurrent::ResultStore<T> &store = resultStore(); |
227 | |
228 | if (store.filterMode()) { |
229 | const int resultCountBefore = store.count(); |
230 | store.addResults(beginIndex, &_results, count); |
231 | this->reportResultsReady(resultCountBefore, store.count()); |
232 | } else { |
233 | const int insertIndex = store.addResults(beginIndex, &_results, count); |
234 | this->reportResultsReady(insertIndex, insertIndex + _results.count()); |
235 | } |
236 | } |
237 | |
238 | template <typename T> |
239 | inline void QFutureInterface<T>::reportFinished(const T *result) |
240 | { |
241 | if (result) |
242 | reportResult(result); |
243 | QFutureInterfaceBase::reportFinished(); |
244 | } |
245 | |
246 | template <typename T> |
247 | inline const T &QFutureInterface<T>::resultReference(int index) const |
248 | { |
249 | QMutexLocker lock(mutex()); |
250 | return resultStore().resultAt(index).value(); |
251 | } |
252 | |
253 | template <typename T> |
254 | inline const T *QFutureInterface<T>::resultPointer(int index) const |
255 | { |
256 | QMutexLocker lock(mutex()); |
257 | return resultStore().resultAt(index).pointer(); |
258 | } |
259 | |
260 | template <typename T> |
261 | inline QList<T> QFutureInterface<T>::results() |
262 | { |
263 | if (this->isCanceled()) { |
264 | exceptionStore().throwPossibleException(); |
265 | return QList<T>(); |
266 | } |
267 | QFutureInterfaceBase::waitForResult(-1); |
268 | |
269 | QList<T> res; |
270 | QMutexLocker lock(mutex()); |
271 | |
272 | QtConcurrent::ResultIterator<T> it = resultStore().begin(); |
273 | while (it != resultStore().end()) { |
274 | res.append(it.value()); |
275 | ++it; |
276 | } |
277 | |
278 | return res; |
279 | } |
280 | |
281 | template <> |
282 | class QFutureInterface<void> : public QFutureInterfaceBase |
283 | { |
284 | public: |
285 | QFutureInterface<void>(State initialState = NoState) |
286 | : QFutureInterfaceBase(initialState) |
287 | { } |
288 | QFutureInterface<void>(const QFutureInterface<void> &other) |
289 | : QFutureInterfaceBase(other) |
290 | { } |
291 | |
292 | static QFutureInterface<void> canceledResult() |
293 | { return QFutureInterface(State(Started | Finished | Canceled)); } |
294 | |
295 | QFutureInterface<void> &operator=(const QFutureInterface<void> &other) |
296 | { |
297 | QFutureInterfaceBase::operator=(other); |
298 | return *this; |
299 | } |
300 | |
301 | inline QFuture<void> future(); // implemented in qfuture.h |
302 | |
303 | void reportResult(const void *, int) { } |
304 | void reportResults(const QVector<void> &, int) { } |
305 | void reportFinished(void * = 0) { QFutureInterfaceBase::reportFinished(); } |
306 | }; |
307 | |
308 | QT_END_NAMESPACE |
309 | QT_END_HEADER |
310 | |
311 | #endif // QT_NO_CONCURRENT |
312 | |
313 | #endif // QFUTUREINTERFACE_H |
314 | |