QtConcurrent: Fix for leak in QFuture
[qt:qt.git] / src / corelib / concurrent / qfutureinterface.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 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     bool refT() const;
136     bool derefT() const;
137 public:
138
139 #ifndef QFUTURE_TEST
140 private:
141 #endif
142     QFutureInterfaceBasePrivate *d;
143
144 private:
145     friend class QFutureWatcherBase;
146     friend class QFutureWatcherBasePrivate;
147 };
148
149 template <typename T>
150 class QFutureInterface : public QFutureInterfaceBase
151 {
152 public:
153     QFutureInterface(State initialState = NoState)
154         : QFutureInterfaceBase(initialState)
155     {
156         refT();
157     }
158     QFutureInterface(const QFutureInterface &other)
159         : QFutureInterfaceBase(other)
160     {
161         refT();
162     }
163     ~QFutureInterface()
164     {
165         if (!derefT())
166             resultStore().clear();
167     }
168
169     static QFutureInterface canceledResult()
170     { return QFutureInterface(State(Started | Finished | Canceled)); }
171
172     QFutureInterface &operator=(const QFutureInterface &other)
173     {
174         other.refT();
175         if (!derefT())
176             resultStore().clear();
177         QFutureInterfaceBase::operator=(other);
178         return *this;
179     }
180
181     inline QFuture<T> future(); // implemented in qfuture.h
182
183     inline void reportResult(const T *result, int index = -1);
184     inline void reportResult(const T &result, int index = -1);
185     inline void reportResults(const QVector<T> &results, int beginIndex = -1, int count = -1);
186     inline void reportFinished(const T *result = 0);
187
188     inline const T &resultReference(int index) const;
189     inline const T *resultPointer(int index) const;
190     inline QList<T> results();
191 private:
192     QtConcurrent::ResultStore<T> &resultStore()
193     { return static_cast<QtConcurrent::ResultStore<T> &>(resultStoreBase()); }
194     const QtConcurrent::ResultStore<T> &resultStore() const
195     { return static_cast<const QtConcurrent::ResultStore<T> &>(resultStoreBase()); }
196 };
197
198 template <typename T>
199 inline void QFutureInterface<T>::reportResult(const T *result, int index)
200 {
201     QMutexLocker locker(mutex());
202     if (this->queryState(Canceled) || this->queryState(Finished)) {
203         return;
204     }
205
206     QtConcurrent::ResultStore<T> &store = resultStore();
207
208
209     if (store.filterMode()) {
210         const int resultCountBefore = store.count();
211         store.addResult(index, result);
212         this->reportResultsReady(resultCountBefore, resultCountBefore + store.count());
213     } else {
214         const int insertIndex = store.addResult(index, result);
215         this->reportResultsReady(insertIndex, insertIndex + 1);
216     }
217 }
218
219 template <typename T>
220 inline void QFutureInterface<T>::reportResult(const T &result, int index)
221 {
222     reportResult(&result, index);
223 }
224
225 template <typename T>
226 inline void QFutureInterface<T>::reportResults(const QVector<T> &_results, int beginIndex, int count)
227 {
228     QMutexLocker locker(mutex());
229     if (this->queryState(Canceled) || this->queryState(Finished)) {
230         return;
231     }
232
233     QtConcurrent::ResultStore<T> &store = resultStore();
234
235     if (store.filterMode()) {
236         const int resultCountBefore = store.count();
237         store.addResults(beginIndex, &_results, count);
238         this->reportResultsReady(resultCountBefore, store.count());
239     } else {
240         const int insertIndex = store.addResults(beginIndex, &_results, count);
241         this->reportResultsReady(insertIndex, insertIndex + _results.count());    
242     }
243 }
244
245 template <typename T>
246 inline void QFutureInterface<T>::reportFinished(const T *result)
247 {
248     if (result)
249         reportResult(result);
250     QFutureInterfaceBase::reportFinished();
251 }
252
253 template <typename T>
254 inline const T &QFutureInterface<T>::resultReference(int index) const
255 {
256     QMutexLocker lock(mutex());
257     return resultStore().resultAt(index).value();
258 }
259
260 template <typename T>
261 inline const T *QFutureInterface<T>::resultPointer(int index) const
262 {
263     QMutexLocker lock(mutex());
264     return resultStore().resultAt(index).pointer();
265 }
266
267 template <typename T>
268 inline QList<T> QFutureInterface<T>::results()
269 {
270     if (this->isCanceled()) {
271         exceptionStore().throwPossibleException();
272         return QList<T>();
273     }
274     QFutureInterfaceBase::waitForResult(-1);
275
276     QList<T> res;
277     QMutexLocker lock(mutex());
278
279     QtConcurrent::ResultIterator<T> it = resultStore().begin();
280     while (it != resultStore().end()) {
281         res.append(it.value());
282         ++it;
283     }
284
285     return res;
286 }
287
288 template <>
289 class QFutureInterface<void> : public QFutureInterfaceBase
290 {
291 public:
292     QFutureInterface<void>(State initialState = NoState)
293         : QFutureInterfaceBase(initialState)
294     { }
295     QFutureInterface<void>(const QFutureInterface<void> &other)
296         : QFutureInterfaceBase(other)
297     { }
298
299     static QFutureInterface<void> canceledResult()
300     { return QFutureInterface(State(Started | Finished | Canceled)); }
301
302     QFutureInterface<void> &operator=(const QFutureInterface<void> &other)
303     {
304         QFutureInterfaceBase::operator=(other);
305         return *this;
306     }
307
308     inline QFuture<void> future(); // implemented in qfuture.h
309
310     void reportResult(const void *, int) { }
311     void reportResults(const QVector<void> &, int) { }
312     void reportFinished(void * = 0) { QFutureInterfaceBase::reportFinished(); }
313 };
314
315 QT_END_NAMESPACE
316 QT_END_HEADER
317
318 #endif // QT_NO_CONCURRENT
319
320 #endif // QFUTUREINTERFACE_H