From 727f25214e870bc5d947a2f89ada9a4a4bd07365 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 27 Aug 2012 18:33:55 +0200 Subject: Move QFuture from QtConcurrent to QtCore This class belongs to QThreadPool/QRunnable more than to QtConcurrent, so move to QtCore, where QThreadPool awaits it. Change-Id: Ibf20288a986593bf779453427c2dae8db1e1423a Reviewed-by: Qt Doc Bot Reviewed-by: Thiago Macieira --- src/concurrent/concurrent.pro | 5 - .../doc/snippets/code/src_concurrent_qfuture.cpp | 64 -- src/concurrent/qfuture.cpp | 697 --------------------- src/concurrent/qfuture.h | 276 -------- src/concurrent/qfutureinterface.cpp | 565 ----------------- src/concurrent/qfutureinterface.h | 313 --------- src/concurrent/qfutureinterface_p.h | 169 ----- src/concurrent/qfuturesynchronizer.h | 2 +- src/concurrent/qfuturewatcher.h | 2 +- src/concurrent/qfuturewatcher_p.h | 2 +- src/concurrent/qtconcurrent_global.h | 4 - src/concurrent/qtconcurrentrunbase.h | 2 +- src/concurrent/qtconcurrentthreadengine.h | 2 +- .../snippets/code/src_corelib_thread_qfuture.cpp | 64 ++ src/corelib/thread/qfuture.h | 276 ++++++++ src/corelib/thread/qfuture.qdoc | 697 +++++++++++++++++++++ src/corelib/thread/qfutureinterface.cpp | 565 +++++++++++++++++ src/corelib/thread/qfutureinterface.h | 311 +++++++++ src/corelib/thread/qfutureinterface_p.h | 167 +++++ src/corelib/thread/thread.pri | 4 + 20 files changed, 2089 insertions(+), 2098 deletions(-) delete mode 100644 src/concurrent/doc/snippets/code/src_concurrent_qfuture.cpp delete mode 100644 src/concurrent/qfuture.cpp delete mode 100644 src/concurrent/qfuture.h delete mode 100644 src/concurrent/qfutureinterface.cpp delete mode 100644 src/concurrent/qfutureinterface.h delete mode 100644 src/concurrent/qfutureinterface_p.h create mode 100644 src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp create mode 100644 src/corelib/thread/qfuture.h create mode 100644 src/corelib/thread/qfuture.qdoc create mode 100644 src/corelib/thread/qfutureinterface.cpp create mode 100644 src/corelib/thread/qfutureinterface.h create mode 100644 src/corelib/thread/qfutureinterface_p.h (limited to 'src') diff --git a/src/concurrent/concurrent.pro b/src/concurrent/concurrent.pro index d21dff91dd..8fdd6d8cd2 100644 --- a/src/concurrent/concurrent.pro +++ b/src/concurrent/concurrent.pro @@ -12,8 +12,6 @@ load(qt_module) PRECOMPILED_HEADER = ../corelib/global/qt_pch.h SOURCES += \ - qfuture.cpp \ - qfutureinterface.cpp \ qfuturesynchronizer.cpp \ qfuturewatcher.cpp \ qtconcurrentfilter.cpp \ @@ -23,8 +21,6 @@ SOURCES += \ HEADERS += \ qtconcurrent_global.h \ - qfuture.h \ - qfutureinterface.h \ qfuturesynchronizer.h \ qfuturewatcher.h \ qtconcurrentcompilertest.h \ @@ -44,7 +40,6 @@ HEADERS += \ # private headers HEADERS += \ - qfutureinterface_p.h \ qfuturewatcher_p.h QMAKE_DOCS = $$PWD/doc/qtconcurrent.qdocconf diff --git a/src/concurrent/doc/snippets/code/src_concurrent_qfuture.cpp b/src/concurrent/doc/snippets/code/src_concurrent_qfuture.cpp deleted file mode 100644 index 16c9d0b162..0000000000 --- a/src/concurrent/doc/snippets/code/src_concurrent_qfuture.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -//! [0] -QFuture future = ...; - -QFuture::const_iterator i; -for (i = future.constBegin(); i != future.constEnd(); ++i) - cout << *i << endl; -//! [0] - - -//! [1] -QFuture future; -... -QFutureIterator i(future); -while (i.hasNext()) - qDebug() << i.next(); -//! [1] - - -//! [2] -QFutureIterator i(future); -i.toBack(); -while (i.hasPrevious()) - qDebug() << i.previous(); -//! [2] diff --git a/src/concurrent/qfuture.cpp b/src/concurrent/qfuture.cpp deleted file mode 100644 index 0316366e6e..0000000000 --- a/src/concurrent/qfuture.cpp +++ /dev/null @@ -1,697 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! \class QFuture - \threadsafe - \brief The QFuture class represents the result of an asynchronous computation. - \since 4.4 - - \ingroup thread - - To start a computation, use one of the APIs in the - \l {Concurrent Programming}{Qt Concurrent} framework. - - QFuture allows threads to be synchronized against one or more results - which will be ready at a later point in time. The result can be of any type - that has a default constructor and a copy constructor. If a result is not - available at the time of calling the result(), resultAt(), or results() - functions, QFuture will wait until the result becomes available. You can - use the isResultReadyAt() function to determine if a result is ready or - not. For QFuture objects that report more than one result, the - resultCount() function returns the number of continuous results. This - means that it is always safe to iterate through the results from 0 to - resultCount(). - - QFuture provides a \l{Java-style iterators}{Java-style iterator} - (QFutureIterator) and an \l{STL-style iterators}{STL-style iterator} - (QFuture::const_iterator). Using these iterators is another way to access - results in the future. - - QFuture also offers ways to interact with a runnning computation. For - instance, the computation can be canceled with the cancel() function. To - pause the computation, use the setPaused() function or one of the pause(), - resume(), or togglePaused() convenience functions. Be aware that not all - asynchronous computations can be canceled or paused. For example, the - future returned by QtConcurrent::run() cannot be canceled; but the - future returned by QtConcurrent::mappedReduced() can. - - Progress information is provided by the progressValue(), - progressMinimum(), progressMaximum(), and progressText() functions. The - waitForFinished() function causes the calling thread to block and wait for - the computation to finish, ensuring that all results are available. - - The state of the computation represented by a QFuture can be queried using - the isCanceled(), isStarted(), isFinished(), isRunning(), or isPaused() - functions. - - QFuture is a lightweight reference counted class that can be passed by - value. - - QFuture is specialized to not contain any of the result fetching - functions. Any QFuture can be assigned or copied into a QFuture - as well. This is useful if only status or progress information is needed - - not the actual result data. - - To interact with running tasks using signals and slots, use QFutureWatcher. - - \sa QFutureWatcher, {Concurrent Programming}{Qt Concurrent} -*/ - -/*! \fn QFuture::QFuture() - - Constructs an empty future. -*/ - -/*! \fn QFuture::QFuture(const QFuture &other) - - Constructs a copy of \a other. - - \sa operator=() -*/ - -/*! \fn QFuture::QFuture(QFutureInterface *resultHolder) - \internal -*/ - -/*! \fn QFuture::~QFuture() - - Destroys the future. - - Note that this neither waits nor cancels the asynchronous computation. Use - waitForFinished() or QFutureSynchronizer when you need to ensure that the - computation is completed before the future is destroyed. -*/ - -/*! \fn QFuture &QFuture::operator=(const QFuture &other) - - Assigns \a other to this future and returns a reference to this future. -*/ - -/*! \fn bool QFuture::operator==(const QFuture &other) const - - Returns true if \a other is a copy of this future; otherwise returns false. -*/ - -/*! \fn bool QFuture::operator!=(const QFuture &other) const - - Returns true if \a other is \e not a copy of this future; otherwise returns - false. -*/ - -/*! \fn void QFuture::cancel() - - Cancels the asynchronous computation represented by this future. Note that - the cancelation is asynchronous. Use waitForFinished() after calling - cancel() when you need synchronous cancelation. - - Results currently available may still be accessed on a canceled future, - but new results will \e not become available after calling this function. - Any QFutureWatcher object that is watching this future will not deliver - progress and result ready signals on a canceled future. - - Be aware that not all asynchronous computations can be canceled. For - example, the future returned by QtConcurrent::run() cannot be canceled; - but the future returned by QtConcurrent::mappedReduced() can. -*/ - -/*! \fn bool QFuture::isCanceled() const - - Returns true if the asynchronous computation has been canceled with the - cancel() function; otherwise returns false. - - Be aware that the computation may still be running even though this - function returns true. See cancel() for more details. -*/ - -/*! \fn void QFuture::setPaused(bool paused) - - If \a paused is true, this function pauses the asynchronous computation - represented by the future. If the computation is already paused, this - function does nothing. Any QFutureWatcher object that is watching this - future will stop delivering progress and result ready signals while the - future is paused. Signal delivery will continue once the future is - resumed. - - If \a paused is false, this function resumes the asynchronous computation. - If the computation was not previously paused, this function does nothing. - - Be aware that not all computations can be paused. For example, the future - returned by QtConcurrent::run() cannot be paused; but the future returned - by QtConcurrent::mappedReduced() can. - - \sa pause(), resume(), togglePaused() -*/ - -/*! \fn bool QFuture::isPaused() const - - Returns true if the asynchronous computation has been paused with the - pause() function; otherwise returns false. - - Be aware that the computation may still be running even though this - function returns true. See setPaused() for more details. - - \sa setPaused(), togglePaused() -*/ - -/*! \fn void QFuture::pause() - - Pauses the asynchronous computation represented by this future. This is a - convenience method that simply calls setPaused(true). - - \sa resume() -*/ - -/*! \fn void QFuture::resume() - - Resumes the asynchronous computation represented by this future. This is a - convenience method that simply calls setPaused(false). - - \sa pause() -*/ - -/*! \fn void QFuture::togglePaused() - - Toggles the paused state of the asynchronous computation. In other words, - if the computation is currently paused, calling this function resumes it; - if the computation is running, it is paused. This is a convenience method - for calling setPaused(!isPaused()). - - \sa setPaused(), pause(), resume() -*/ - -/*! \fn bool QFuture::isStarted() const - - Returns true if the asynchronous computation represented by this future - has been started; otherwise returns false. -*/ - -/*! \fn bool QFuture::isFinished() const - - Returns true if the asynchronous computation represented by this future - has finished; otherwise returns false. -*/ - -/*! \fn bool QFuture::isRunning() const - - Returns true if the asynchronous computation represented by this future is - currently running; otherwise returns false. -*/ - -/*! \fn int QFuture::resultCount() const - - Returns the number of continuous results available in this future. The real - number of results stored might be different from this value, due to gaps - in the result set. It is always safe to iterate through the results from 0 - to resultCount(). - \sa result(), resultAt(), results() -*/ - -/*! \fn int QFuture::progressValue() const - - Returns the current progress value, which is between the progressMinimum() - and progressMaximum(). - - \sa progressMinimum(), progressMaximum() -*/ - -/*! \fn int QFuture::progressMinimum() const - - Returns the minimum progressValue(). - - \sa progressValue(), progressMaximum() -*/ - -/*! \fn int QFuture::progressMaximum() const - - Returns the maximum progressValue(). - - \sa progressValue(), progressMinimum() -*/ - -/*! \fn QString QFuture::progressText() const - - Returns the (optional) textual representation of the progress as reported - by the asynchronous computation. - - Be aware that not all computations provide a textual representation of the - progress, and as such, this function may return an empty string. -*/ - -/*! \fn void QFuture::waitForFinished() - - Waits for the asynchronous computation to finish (including cancel()ed - computations). -*/ - -/*! \fn T QFuture::result() const - - Returns the first result in the future. If the result is not immediately - available, this function will block and wait for the result to become - available. This is a convenience method for calling resultAt(0). - - \sa resultAt(), results() -*/ - -/*! \fn T QFuture::resultAt(int index) const - - Returns the result at \a index in the future. If the result is not - immediately available, this function will block and wait for the result to - become available. - - \sa result(), results(), resultCount() -*/ - -/*! \fn bool QFuture::isResultReadyAt(int index) const - - Returns true if the result at \a index is immediately available; otherwise - returns false. - - \sa resultAt(), resultCount() -*/ - -/*! \fn QFuture::operator T() const - - Returns the first result in the future. If the result is not immediately - available, this function will block and wait for the result to become - available. This is a convenience method for calling result() or - resultAt(0). - - \sa result(), resultAt(), results() -*/ - -/*! \fn QList QFuture::results() const - - Returns all results from the future. If the results are not immediately - available, this function will block and wait for them to become available. - - \sa result(), resultAt(), resultCount() -*/ - -/*! \fn QFuture::const_iterator QFuture::begin() const - - Returns a const \l{STL-style iterator} pointing to the first result in the - future. - - \sa constBegin(), end() -*/ - -/*! \fn QFuture::const_iterator QFuture::end() const - - Returns a const \l{STL-style iterator} pointing to the imaginary result - after the last result in the future. - - \sa begin(), constEnd() -*/ - -/*! \fn QFuture::const_iterator QFuture::constBegin() const - - Returns a const \l{STL-style iterator} pointing to the first result in the - future. - - \sa begin(), constEnd() -*/ - -/*! \fn QFuture::const_iterator QFuture::constEnd() const - - Returns a const \l{STL-style iterator} pointing to the imaginary result - after the last result in the future. - - \sa constBegin(), end() -*/ - -/*! \class QFuture::const_iterator - \reentrant - \since 4.4 - - \brief The QFuture::const_iterator class provides an STL-style const - iterator for QFuture. - - QFuture provides both \l{STL-style iterators} and \l{Java-style iterators}. - The STL-style iterators are more low-level and more cumbersome to use; on - the other hand, they are slightly faster and, for developers who already - know STL, have the advantage of familiarity. - - The default QFuture::const_iterator constructor creates an uninitialized - iterator. You must initialize it using a QFuture function like - QFuture::constBegin() or QFuture::constEnd() before you start iterating. - Here's a typical loop that prints all the results available in a future: - - \snippet code/src_concurrent_qfuture.cpp 0 - - \sa QFutureIterator, QFuture -*/ - -/*! \typedef QFuture::const_iterator::iterator_category - - Typedef for std::bidirectional_iterator_tag. Provided for STL compatibility. -*/ - -/*! \typedef QFuture::const_iterator::difference_type - - Typedef for ptrdiff_t. Provided for STL compatibility. -*/ - -/*! \typedef QFuture::const_iterator::value_type - - Typedef for T. Provided for STL compatibility. -*/ - -/*! \typedef QFuture::const_iterator::pointer - - Typedef for const T *. Provided for STL compatibility. -*/ - -/*! \typedef QFuture::const_iterator::reference - - Typedef for const T &. Provided for STL compatibility. -*/ - -/*! \fn QFuture::const_iterator::const_iterator() - - Constructs an uninitialized iterator. - - Functions like operator*() and operator++() should not be called on an - uninitialized iterartor. Use operator=() to assign a value to it before - using it. - - \sa QFuture::constBegin(), QFuture::constEnd() -*/ - -/*! \fn QFuture::const_iterator::const_iterator(QFuture const * const future, int index) - \internal -*/ - -/*! \fn QFuture::const_iterator::const_iterator(const const_iterator &other) - - Constructs a copy of \a other. -*/ - -/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator=(const const_iterator &other) - - Assigns \a other to this iterator. -*/ - -/*! \fn const T &QFuture::const_iterator::operator*() const - - Returns the current result. -*/ - -/*! \fn const T *QFuture::const_iterator::operator->() const - - Returns a pointer to the current result. -*/ - -/*! \fn bool QFuture::const_iterator::operator!=(const const_iterator &other) const - - Returns true if \a other points to a different result than this iterator; - otherwise returns false. - - \sa operator==() -*/ - -/*! \fn bool QFuture::const_iterator::operator==(const const_iterator &other) const - - Returns true if \a other points to the same result as this iterator; - otherwise returns false. - - \sa operator!=() -*/ - -/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator++() - - The prefix ++ operator (\c{++it}) advances the iterator to the next result - in the future and returns an iterator to the new current result. - - Calling this function on QFuture::constEnd() leads to undefined results. - - \sa operator--() -*/ - -/*! \fn QFuture::const_iterator QFuture::const_iterator::operator++(int) - - \overload - - The postfix ++ operator (\c{it++}) advances the iterator to the next - result in the future and returns an iterator to the previously current - result. -*/ - -/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator--() - - The prefix -- operator (\c{--it}) makes the preceding result current and - returns an iterator to the new current result. - - Calling this function on QFuture::constBegin() leads to undefined results. - - \sa operator++() -*/ - -/*! \fn QFuture::const_iterator QFuture::const_iterator::operator--(int) - - \overload - - The postfix -- operator (\c{it--}) makes the preceding result current and - returns an iterator to the previously current result. -*/ - -/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator+=(int j) - - Advances the iterator by \a j results. (If \a j is negative, the iterator - goes backward.) - - \sa operator-=(), operator+() -*/ - -/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator-=(int j) - - Makes the iterator go back by \a j results. (If \a j is negative, the - iterator goes forward.) - - \sa operator+=(), operator-() -*/ - -/*! \fn QFuture::const_iterator QFuture::const_iterator::operator+(int j) const - - Returns an iterator to the results at \a j positions forward from this - iterator. (If \a j is negative, the iterator goes backward.) - - \sa operator-(), operator+=() -*/ - -/*! \fn QFuture::const_iterator QFuture::const_iterator::operator-(int j) const - - Returns an iterator to the result at \a j positions backward from this - iterator. (If \a j is negative, the iterator goes forward.) - - \sa operator+(), operator-=() -*/ - -/*! \typedef QFuture::ConstIterator - - Qt-style synonym for QFuture::const_iterator. -*/ - -/*! - \class QFutureIterator - \reentrant - \since 4.4 - \inmodule QtCore - - \brief The QFutureIterator class provides a Java-style const iterator for - QFuture. - - QFuture has both \l{Java-style iterators} and \l{STL-style iterators}. The - Java-style iterators are more high-level and easier to use than the - STL-style iterators; on the other hand, they are slightly less efficient. - - An alternative to using iterators is to use index positions. Some QFuture - member functions take an index as their first parameter, making it - possible to access results without using iterators. - - QFutureIterator\ allows you to iterate over a QFuture\. Note that - there is no mutable iterator for QFuture (unlike the other Java-style - iterators). - - The QFutureIterator constructor takes a QFuture as its argument. After - construction, the iterator is located at the very beginning of the result - list (i.e. before the first result). Here's how to iterate over all the - results sequentially: - - \snippet code/src_concurrent_qfuture.cpp 1 - - The next() function returns the next result (waiting for it to become - available, if necessary) from the future and advances the iterator. Unlike - STL-style iterators, Java-style iterators point \e between results rather - than directly \e at results. The first call to next() advances the iterator - to the position between the first and second result, and returns the first - result; the second call to next() advances the iterator to the position - between the second and third result, and returns the second result; and - so on. - - \image javaiterators1.png - - Here's how to iterate over the elements in reverse order: - - \snippet code/src_concurrent_qfuture.cpp 2 - - If you want to find all occurrences of a particular value, use findNext() - or findPrevious() in a loop. - - Multiple iterators can be used on the same future. If the future is - modified while a QFutureIterator is active, the QFutureIterator will - continue iterating over the original future, ignoring the modified copy. - - \sa QFuture::const_iterator, QFuture -*/ - -/*! - \fn QFutureIterator::QFutureIterator(const QFuture &future) - - Constructs an iterator for traversing \a future. The iterator is set to be - at the front of the result list (before the first result). - - \sa operator=() -*/ - -/*! \fn QFutureIterator &QFutureIterator::operator=(const QFuture &future) - - Makes the iterator operate on \a future. The iterator is set to be at the - front of the result list (before the first result). - - \sa toFront(), toBack() -*/ - -/*! \fn void QFutureIterator::toFront() - - Moves the iterator to the front of the result list (before the first - result). - - \sa toBack(), next() -*/ - -/*! \fn void QFutureIterator::toBack() - - Moves the iterator to the back of the result list (after the last result). - - \sa toFront(), previous() -*/ - -/*! \fn bool QFutureIterator::hasNext() const - - Returns true if there is at least one result ahead of the iterator, e.g., - the iterator is \e not at the back of the result list; otherwise returns - false. - - \sa hasPrevious(), next() -*/ - -/*! \fn const T &QFutureIterator::next() - - Returns the next result and advances the iterator by one position. - - Calling this function on an iterator located at the back of the result - list leads to undefined results. - - \sa hasNext(), peekNext(), previous() -*/ - -/*! \fn const T &QFutureIterator::peekNext() const - - Returns the next result without moving the iterator. - - Calling this function on an iterator located at the back of the result - list leads to undefined results. - - \sa hasNext(), next(), peekPrevious() -*/ - -/*! \fn bool QFutureIterator::hasPrevious() const - - Returns true if there is at least one result ahead of the iterator, e.g., - the iterator is \e not at the front of the result list; otherwise returns - false. - - \sa hasNext(), previous() -*/ - -/*! \fn const T &QFutureIterator::previous() - - Returns the previous result and moves the iterator back by one position. - - Calling this function on an iterator located at the front of the result - list leads to undefined results. - - \sa hasPrevious(), peekPrevious(), next() -*/ - -/*! \fn const T &QFutureIterator::peekPrevious() const - - Returns the previous result without moving the iterator. - - Calling this function on an iterator located at the front of the result - list leads to undefined results. - - \sa hasPrevious(), previous(), peekNext() -*/ - -/*! \fn bool QFutureIterator::findNext(const T &value) - - Searches for \a value starting from the current iterator position forward. - Returns true if \a value is found; otherwise returns false. - - After the call, if \a value was found, the iterator is positioned just - after the matching result; otherwise, the iterator is positioned at the - back of the result list. - - \sa findPrevious() -*/ - -/*! \fn bool QFutureIterator::findPrevious(const T &value) - - Searches for \a value starting from the current iterator position - backward. Returns true if \a value is found; otherwise returns false. - - After the call, if \a value was found, the iterator is positioned just - before the matching result; otherwise, the iterator is positioned at the - front of the result list. - - \sa findNext() -*/ diff --git a/src/concurrent/qfuture.h b/src/concurrent/qfuture.h deleted file mode 100644 index 3a9fd64bb8..0000000000 --- a/src/concurrent/qfuture.h +++ /dev/null @@ -1,276 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QFUTURE_H -#define QFUTURE_H - -#include - -#ifndef QT_NO_QFUTURE - -#include -#include - -QT_BEGIN_HEADER -QT_BEGIN_NAMESPACE - - -template -class QFutureWatcher; -template <> -class QFutureWatcher; - -template -class QFuture -{ -public: - QFuture() - : d(QFutureInterface::canceledResult()) - { } - explicit QFuture(QFutureInterface *p) // internal - : d(*p) - { } - QFuture(const QFuture &other) - : d(other.d) - { } - ~QFuture() - { } - - inline QFuture &operator=(const QFuture &other); - bool operator==(const QFuture &other) const { return (d == other.d); } - bool operator!=(const QFuture &other) const { return (d != other.d); } - - void cancel() { d.cancel(); } - bool isCanceled() const { return d.isCanceled(); } - - void setPaused(bool paused) { d.setPaused(paused); } - bool isPaused() const { return d.isPaused(); } - void pause() { setPaused(true); } - void resume() { setPaused(false); } - void togglePaused() { d.togglePaused(); } - - bool isStarted() const { return d.isStarted(); } - bool isFinished() const { return d.isFinished(); } - bool isRunning() const { return d.isRunning(); } - - int resultCount() const { return d.resultCount(); } - int progressValue() const { return d.progressValue(); } - int progressMinimum() const { return d.progressMinimum(); } - int progressMaximum() const { return d.progressMaximum(); } - QString progressText() const { return d.progressText(); } - void waitForFinished() { d.waitForFinished(); } - - inline T result() const; - inline T resultAt(int index) const; - bool isResultReadyAt(int resultIndex) const { return d.isResultReadyAt(resultIndex); } - - operator T() const { return result(); } - QList results() const { return d.results(); } - - class const_iterator - { - public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef qptrdiff difference_type; - typedef T value_type; - typedef const T *pointer; - typedef const T &reference; - - inline const_iterator() {} - inline const_iterator(QFuture const * const _future, int _index) : future(_future), index(_index) {} - inline const_iterator(const const_iterator &o) : future(o.future), index(o.index) {} - inline const_iterator &operator=(const const_iterator &o) - { future = o.future; index = o.index; return *this; } - inline const T &operator*() const { return future->d.resultReference(index); } - inline const T *operator->() const { return future->d.resultPointer(index); } - - inline bool operator!=(const const_iterator &other) const - { - if (index == -1 && other.index == -1) // comparing end != end? - return false; - if (other.index == -1) - return (future->isRunning() || (index < future->resultCount())); - return (index != other.index); - } - - inline bool operator==(const const_iterator &o) const { return !operator!=(o); } - inline const_iterator &operator++() { ++index; return *this; } - inline const_iterator operator++(int) { const_iterator r = *this; ++index; return r; } - inline const_iterator &operator--() { --index; return *this; } - inline const_iterator operator--(int) { const_iterator r = *this; --index; return r; } - inline const_iterator operator+(int j) const { return const_iterator(future, index + j); } - inline const_iterator operator-(int j) const { return const_iterator(future, index - j); } - inline const_iterator &operator+=(int j) { index += j; return *this; } - inline const_iterator &operator-=(int j) { index -= j; return *this; } - private: - QFuture const * future; - int index; - }; - friend class const_iterator; - typedef const_iterator ConstIterator; - - const_iterator begin() const { return const_iterator(this, 0); } - const_iterator constBegin() const { return const_iterator(this, 0); } - const_iterator end() const { return const_iterator(this, -1); } - const_iterator constEnd() const { return const_iterator(this, -1); } - -private: - friend class QFutureWatcher; - -public: // Warning: the d pointer is not documented and is considered private. - mutable QFutureInterface d; -}; - -template -inline QFuture &QFuture::operator=(const QFuture &other) -{ - d = other.d; - return *this; -} - -template -inline T QFuture::result() const -{ - d.waitForResult(0); - return d.resultReference(0); -} - -template -inline T QFuture::resultAt(int index) const -{ - d.waitForResult(index); - return d.resultReference(index); -} - -template -inline QFuture QFutureInterface::future() -{ - return QFuture(this); -} - -Q_DECLARE_SEQUENTIAL_ITERATOR(Future) - -template <> -class QFuture -{ -public: - QFuture() - : d(QFutureInterface::canceledResult()) - { } - explicit QFuture(QFutureInterfaceBase *p) // internal - : d(*p) - { } - QFuture(const QFuture &other) - : d(other.d) - { } - ~QFuture() - { } - - QFuture &operator=(const QFuture &other); - bool operator==(const QFuture &other) const { return (d == other.d); } - bool operator!=(const QFuture &other) const { return (d != other.d); } - -#if !defined(Q_CC_XLC) - template - QFuture(const QFuture &other) - : d(other.d) - { } - - template - QFuture &operator=(const QFuture &other) - { - d = other.d; - return *this; - } -#endif - - void cancel() { d.cancel(); } - bool isCanceled() const { return d.isCanceled(); } - - void setPaused(bool paused) { d.setPaused(paused); } - bool isPaused() const { return d.isPaused(); } - void pause() { setPaused(true); } - void resume() { setPaused(false); } - void togglePaused() { d.togglePaused(); } - - bool isStarted() const { return d.isStarted(); } - bool isFinished() const { return d.isFinished(); } - bool isRunning() const { return d.isRunning(); } - - int resultCount() const { return d.resultCount(); } - int progressValue() const { return d.progressValue(); } - int progressMinimum() const { return d.progressMinimum(); } - int progressMaximum() const { return d.progressMaximum(); } - QString progressText() const { return d.progressText(); } - void waitForFinished() { d.waitForFinished(); } - -private: - friend class QFutureWatcher; - -#ifdef QFUTURE_TEST -public: -#endif - mutable QFutureInterfaceBase d; -}; - -inline QFuture &QFuture::operator=(const QFuture &other) -{ - d = other.d; - return *this; -} - -inline QFuture QFutureInterface::future() -{ - return QFuture(this); -} - -template -QFuture qToVoidFuture(const QFuture &future) -{ - return QFuture(future.d); -} - -QT_END_NAMESPACE -QT_END_HEADER - -#endif // QT_NO_QFUTURE - -#endif // QFUTURE_H diff --git a/src/concurrent/qfutureinterface.cpp b/src/concurrent/qfutureinterface.cpp deleted file mode 100644 index 2c33418ee9..0000000000 --- a/src/concurrent/qfutureinterface.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// qfutureinterface.h included from qfuture.h -#include "qfuture.h" - -#ifndef QT_NO_QFUTURE - -#include "qfutureinterface_p.h" - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -enum { - MaxProgressEmitsPerSecond = 25 -}; - -QFutureInterfaceBase::QFutureInterfaceBase(State initialState) - : d(new QFutureInterfaceBasePrivate(initialState)) -{ } - -QFutureInterfaceBase::QFutureInterfaceBase(const QFutureInterfaceBase &other) - : d(other.d) -{ - d->refCount.ref(); -} - -QFutureInterfaceBase::~QFutureInterfaceBase() -{ - if (!d->refCount.deref()) - delete d; -} - -void QFutureInterfaceBase::cancel() -{ - QMutexLocker locker(&d->m_mutex); - if (d->state & Canceled) - return; - - d->state = State((d->state & ~Paused) | Canceled); - d->waitCondition.wakeAll(); - d->pausedWaitCondition.wakeAll(); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); -} - -void QFutureInterfaceBase::setPaused(bool paused) -{ - QMutexLocker locker(&d->m_mutex); - if (paused) { - d->state = State(d->state | Paused); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); - } else { - d->state = State(d->state & ~Paused); - d->pausedWaitCondition.wakeAll(); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); - } -} - -void QFutureInterfaceBase::togglePaused() -{ - QMutexLocker locker(&d->m_mutex); - if (d->state & Paused) { - d->state = State(d->state & ~Paused); - d->pausedWaitCondition.wakeAll(); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); - } else { - d->state = State(d->state | Paused); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); - } -} - -void QFutureInterfaceBase::setThrottled(bool enable) -{ - // bail out if we are not changing the state - if ((enable && (d->state & Throttled)) || (!enable && !(d->state & Throttled))) - return; - - // lock and change the state - QMutexLocker lock(&d->m_mutex); - if (enable) { - d->state = State(d->state | Throttled); - } else { - d->state = State(d->state & ~Throttled); - if (!(d->state & Paused)) - d->pausedWaitCondition.wakeAll(); - } -} - - -bool QFutureInterfaceBase::isRunning() const -{ - return queryState(Running); -} - -bool QFutureInterfaceBase::isStarted() const -{ - return queryState(Started); -} - -bool QFutureInterfaceBase::isCanceled() const -{ - return queryState(Canceled); -} - -bool QFutureInterfaceBase::isFinished() const -{ - return queryState(Finished); -} - -bool QFutureInterfaceBase::isPaused() const -{ - return queryState(Paused); -} - -bool QFutureInterfaceBase::isThrottled() const -{ - return queryState(Throttled); -} - -bool QFutureInterfaceBase::isResultReadyAt(int index) const -{ - QMutexLocker lock(&d->m_mutex); - return d->internal_isResultReadyAt(index); -} - -bool QFutureInterfaceBase::waitForNextResult() -{ - QMutexLocker lock(&d->m_mutex); - return d->internal_waitForNextResult(); -} - -void QFutureInterfaceBase::waitForResume() -{ - // return early if possible to avoid taking the mutex lock. - if ((d->state & Paused) == false || (d->state & Canceled)) - return; - - QMutexLocker lock(&d->m_mutex); - if ((d->state & Paused) == false || (d->state & Canceled)) - return; - - // decrease active thread count since this thread will wait. - QThreadPool::globalInstance()->releaseThread(); - - d->pausedWaitCondition.wait(&d->m_mutex); - - QThreadPool::globalInstance()->reserveThread(); -} - -int QFutureInterfaceBase::progressValue() const -{ - return d->m_progressValue; -} - -int QFutureInterfaceBase::progressMinimum() const -{ - return d->m_progressMinimum; -} - -int QFutureInterfaceBase::progressMaximum() const -{ - return d->m_progressMaximum; -} - -int QFutureInterfaceBase::resultCount() const -{ - QMutexLocker lock(&d->m_mutex); - return d->internal_resultCount(); -} - -QString QFutureInterfaceBase::progressText() const -{ - QMutexLocker locker(&d->m_mutex); - return d->m_progressText; -} - -bool QFutureInterfaceBase::isProgressUpdateNeeded() const -{ - QMutexLocker locker(&d->m_mutex); - return !d->progressTime.isValid() || (d->progressTime.elapsed() > (1000 / MaxProgressEmitsPerSecond)); -} - -void QFutureInterfaceBase::reportStarted() -{ - QMutexLocker locker(&d->m_mutex); - if ((d->state & Started) || (d->state & Canceled) || (d->state & Finished)) - return; - - d->setState(State(Started | Running)); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Started)); -} - -void QFutureInterfaceBase::reportCanceled() -{ - cancel(); -} - -#ifndef QT_NO_EXCEPTIONS -void QFutureInterfaceBase::reportException(const QException &exception) -{ - QMutexLocker locker(&d->m_mutex); - if ((d->state & Canceled) || (d->state & Finished)) - return; - - d->m_exceptionStore.setException(exception); - d->state = State(d->state | Canceled); - d->waitCondition.wakeAll(); - d->pausedWaitCondition.wakeAll(); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); -} -#endif - -void QFutureInterfaceBase::reportFinished() -{ - QMutexLocker locker(&d->m_mutex); - if (!(d->state & Finished)) { - d->state = State((d->state & ~Running) | Finished); - d->waitCondition.wakeAll(); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Finished)); - } -} - -void QFutureInterfaceBase::setExpectedResultCount(int resultCount) -{ - if (d->manualProgress == false) - setProgressRange(0, resultCount); - d->m_expectedResultCount = resultCount; -} - -int QFutureInterfaceBase::expectedResultCount() -{ - return d->m_expectedResultCount; -} - -bool QFutureInterfaceBase::queryState(State state) const -{ - return (d->state & state); -} - -void QFutureInterfaceBase::waitForResult(int resultIndex) -{ - d->m_exceptionStore.throwPossibleException(); - - if (!(d->state & Running)) - return; - - // To avoid deadlocks and reduce the number of threads used, try to - // run the runnable in the current thread. - QThreadPool::globalInstance()->d_func()->stealRunnable(d->runnable); - - QMutexLocker lock(&d->m_mutex); - - if (!(d->state & Running)) - return; - - const int waitIndex = (resultIndex == -1) ? INT_MAX : resultIndex; - while ((d->state & Running) && d->internal_isResultReadyAt(waitIndex) == false) - d->waitCondition.wait(&d->m_mutex); - - d->m_exceptionStore.throwPossibleException(); -} - -void QFutureInterfaceBase::waitForFinished() -{ - if (d->state & Running) { - QThreadPool::globalInstance()->d_func()->stealRunnable(d->runnable); - - QMutexLocker lock(&d->m_mutex); - - while (d->state & Running) - d->waitCondition.wait(&d->m_mutex); - } - - d->m_exceptionStore.throwPossibleException(); -} - -void QFutureInterfaceBase::reportResultsReady(int beginIndex, int endIndex) -{ - if ((d->state & Canceled) || (d->state & Finished) || beginIndex == endIndex) - return; - - d->waitCondition.wakeAll(); - - if (d->manualProgress == false) { - if (d->internal_updateProgress(d->m_progressValue + endIndex - beginIndex) == false) { - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, - beginIndex, - endIndex)); - return; - } - - d->sendCallOuts(QFutureCallOutEvent(QFutureCallOutEvent::Progress, - d->m_progressValue, - d->m_progressText), - QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, - beginIndex, - endIndex)); - return; - } - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, beginIndex, endIndex)); -} - -void QFutureInterfaceBase::setRunnable(QRunnable *runnable) -{ - d->runnable = runnable; -} - -void QFutureInterfaceBase::setFilterMode(bool enable) -{ - QMutexLocker locker(&d->m_mutex); - resultStoreBase().setFilterMode(enable); -} - -void QFutureInterfaceBase::setProgressRange(int minimum, int maximum) -{ - QMutexLocker locker(&d->m_mutex); - d->m_progressMinimum = minimum; - d->m_progressMaximum = maximum; - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, minimum, maximum)); -} - -void QFutureInterfaceBase::setProgressValue(int progressValue) -{ - setProgressValueAndText(progressValue, QString()); -} - -void QFutureInterfaceBase::setProgressValueAndText(int progressValue, - const QString &progressText) -{ - QMutexLocker locker(&d->m_mutex); - if (d->manualProgress == false) - d->manualProgress = true; - if (d->m_progressValue >= progressValue) - return; - - if ((d->state & Canceled) || (d->state & Finished)) - return; - - if (d->internal_updateProgress(progressValue, progressText)) { - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Progress, - d->m_progressValue, - d->m_progressText)); - } -} - -QMutex *QFutureInterfaceBase::mutex() const -{ - return &d->m_mutex; -} - -QtPrivate::ExceptionStore &QFutureInterfaceBase::exceptionStore() -{ - return d->m_exceptionStore; -} - -QtPrivate::ResultStoreBase &QFutureInterfaceBase::resultStoreBase() -{ - return d->m_results; -} - -const QtPrivate::ResultStoreBase &QFutureInterfaceBase::resultStoreBase() const -{ - return d->m_results; -} - -QFutureInterfaceBase &QFutureInterfaceBase::operator=(const QFutureInterfaceBase &other) -{ - other.d->refCount.ref(); - if (!d->refCount.deref()) - delete d; - d = other.d; - return *this; -} - -bool QFutureInterfaceBase::referenceCountIsOne() const -{ - return d->refCount.load() == 1; -} - -QFutureInterfaceBasePrivate::QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState) - : refCount(1), m_progressValue(0), m_progressMinimum(0), m_progressMaximum(0), - state(initialState), pendingResults(0), - manualProgress(false), m_expectedResultCount(0), runnable(0) -{ - progressTime.invalidate(); -} - -int QFutureInterfaceBasePrivate::internal_resultCount() const -{ - return m_results.count(); // ### subtract canceled results. -} - -bool QFutureInterfaceBasePrivate::internal_isResultReadyAt(int index) const -{ - return (m_results.contains(index)); -} - -bool QFutureInterfaceBasePrivate::internal_waitForNextResult() -{ - if (m_results.hasNextResult()) - return true; - - while ((state & QFutureInterfaceBase::Running) && m_results.hasNextResult() == false) - waitCondition.wait(&m_mutex); - - return (!(state & QFutureInterfaceBase::Canceled) && m_results.hasNextResult()); -} - -bool QFutureInterfaceBasePrivate::internal_updateProgress(int progress, - const QString &progressText) -{ - if (m_progressValue >= progress) - return false; - - m_progressValue = progress; - m_progressText = progressText; - - if (progressTime.isValid() && m_progressValue != m_progressMaximum) // make sure the first and last steps are emitted. - if (progressTime.elapsed() < (1000 / MaxProgressEmitsPerSecond)) - return false; - - progressTime.start(); - return true; -} - -void QFutureInterfaceBasePrivate::internal_setThrottled(bool enable) -{ - // bail out if we are not changing the state - if ((enable && (state & QFutureInterfaceBase::Throttled)) - || (!enable && !(state & QFutureInterfaceBase::Throttled))) - return; - - // change the state - if (enable) { - state = QFutureInterfaceBase::State(state | QFutureInterfaceBase::Throttled); - } else { - state = QFutureInterfaceBase::State(state & ~QFutureInterfaceBase::Throttled); - if (!(state & QFutureInterfaceBase::Paused)) - pausedWaitCondition.wakeAll(); - } -} - -void QFutureInterfaceBasePrivate::sendCallOut(const QFutureCallOutEvent &callOutEvent) -{ - if (outputConnections.isEmpty()) - return; - - for (int i = 0; i < outputConnections.count(); ++i) - outputConnections.at(i)->postCallOutEvent(callOutEvent); -} - -void QFutureInterfaceBasePrivate::sendCallOuts(const QFutureCallOutEvent &callOutEvent1, - const QFutureCallOutEvent &callOutEvent2) -{ - if (outputConnections.isEmpty()) - return; - - for (int i = 0; i < outputConnections.count(); ++i) { - QFutureCallOutInterface *interface = outputConnections.at(i); - interface->postCallOutEvent(callOutEvent1); - interface->postCallOutEvent(callOutEvent2); - } -} - -// This function connects an output interface (for example a QFutureWatcher) -// to this future. While holding the lock we check the state and ready results -// and add the appropriate callouts to the queue. In order to avoid deadlocks, -// the actual callouts are made at the end while not holding the lock. -void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface *interface) -{ - QMutexLocker locker(&m_mutex); - - if (state & QFutureInterfaceBase::Started) { - interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Started)); - interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, - m_progressMinimum, - m_progressMaximum)); - interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress, - m_progressValue, - m_progressText)); - } - - QtPrivate::ResultIteratorBase it = m_results.begin(); - while (it != m_results.end()) { - const int begin = it.resultIndex(); - const int end = begin + it.batchSize(); - interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, - begin, - end)); - it.batchedAdvance(); - } - - if (state & QFutureInterfaceBase::Paused) - interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); - - if (state & QFutureInterfaceBase::Canceled) - interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); - - if (state & QFutureInterfaceBase::Finished) - interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Finished)); - - outputConnections.append(interface); -} - -void QFutureInterfaceBasePrivate::disconnectOutputInterface(QFutureCallOutInterface *interface) -{ - QMutexLocker lock(&m_mutex); - const int index = outputConnections.indexOf(interface); - if (index == -1) - return; - outputConnections.removeAt(index); - - interface->callOutInterfaceDisconnected(); -} - -void QFutureInterfaceBasePrivate::setState(QFutureInterfaceBase::State newState) -{ - state = newState; -} - -QT_END_NAMESPACE - -#endif // QT_NO_CONCURRENT diff --git a/src/concurrent/qfutureinterface.h b/src/concurrent/qfutureinterface.h deleted file mode 100644 index e9d8d37b67..0000000000 --- a/src/concurrent/qfutureinterface.h +++ /dev/null @@ -1,313 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QFUTUREINTERFACE_H -#define QFUTUREINTERFACE_H - -#include - -#include - -#ifndef QT_NO_QFUTURE - -#include -#include -#include - -QT_BEGIN_HEADER -QT_BEGIN_NAMESPACE - - -template class QFuture; -class QFutureInterfaceBasePrivate; -class QFutureWatcherBase; -class QFutureWatcherBasePrivate; - -class Q_CONCURRENT_EXPORT QFutureInterfaceBase -{ -public: - enum State { - NoState = 0x00, - Running = 0x01, - Started = 0x02, - Finished = 0x04, - Canceled = 0x08, - Paused = 0x10, - Throttled = 0x20 - }; - - QFutureInterfaceBase(State initialState = NoState); - QFutureInterfaceBase(const QFutureInterfaceBase &other); - virtual ~QFutureInterfaceBase(); - - // reporting functions available to the engine author: - void reportStarted(); - void reportFinished(); - void reportCanceled(); -#ifndef QT_NO_EXCEPTIONS - void reportException(const QException &e); -#endif - void reportResultsReady(int beginIndex, int endIndex); - - void setRunnable(QRunnable *runnable); - void setFilterMode(bool enable); - void setProgressRange(int minimum, int maximum); - int progressMinimum() const; - int progressMaximum() const; - bool isProgressUpdateNeeded() const; - void setProgressValue(int progressValue); - int progressValue() const; - void setProgressValueAndText(int progressValue, const QString &progressText); - QString progressText() const; - - void setExpectedResultCount(int resultCount); - int expectedResultCount(); - int resultCount() const; - - bool queryState(State state) const; - bool isRunning() const; - bool isStarted() const; - bool isCanceled() const; - bool isFinished() const; - bool isPaused() const; - bool isThrottled() const; - bool isResultReadyAt(int index) const; - - void cancel(); - void setPaused(bool paused); - void togglePaused(); - void setThrottled(bool enable); - - void waitForFinished(); - bool waitForNextResult(); - void waitForResult(int resultIndex); - void waitForResume(); - - QMutex *mutex() const; - QtPrivate::ExceptionStore &exceptionStore(); - QtPrivate::ResultStoreBase &resultStoreBase(); - const QtPrivate::ResultStoreBase &resultStoreBase() const; - - inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; } - inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; } - QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other); - -protected: - bool referenceCountIsOne() const; -public: - -#ifndef QFUTURE_TEST -private: -#endif - QFutureInterfaceBasePrivate *d; - -private: - friend class QFutureWatcherBase; - friend class QFutureWatcherBasePrivate; -}; - -template -class QFutureInterface : public QFutureInterfaceBase -{ -public: - QFutureInterface(State initialState = NoState) - : QFutureInterfaceBase(initialState) - { } - QFutureInterface(const QFutureInterface &other) - : QFutureInterfaceBase(other) - { } - ~QFutureInterface() - { - if (referenceCountIsOne()) - resultStore().clear(); - } - - static QFutureInterface canceledResult() - { return QFutureInterface(State(Started | Finished | Canceled)); } - - QFutureInterface &operator=(const QFutureInterface &other) - { - if (referenceCountIsOne()) - resultStore().clear(); - QFutureInterfaceBase::operator=(other); - return *this; - } - - inline QFuture future(); // implemented in qfuture.h - - inline void reportResult(const T *result, int index = -1); - inline void reportResult(const T &result, int index = -1); - inline void reportResults(const QVector &results, int beginIndex = -1, int count = -1); - inline void reportFinished(const T *result = 0); - - inline const T &resultReference(int index) const; - inline const T *resultPointer(int index) const; - inline QList results(); -private: - QtPrivate::ResultStore &resultStore() - { return static_cast &>(resultStoreBase()); } - const QtPrivate::ResultStore &resultStore() const - { return static_cast &>(resultStoreBase()); } -}; - -template -inline void QFutureInterface::reportResult(const T *result, int index) -{ - QMutexLocker locker(mutex()); - if (this->queryState(Canceled) || this->queryState(Finished)) { - return; - } - - QtPrivate::ResultStore &store = resultStore(); - - - if (store.filterMode()) { - const int resultCountBefore = store.count(); - store.addResult(index, result); - this->reportResultsReady(resultCountBefore, resultCountBefore + store.count()); - } else { - const int insertIndex = store.addResult(index, result); - this->reportResultsReady(insertIndex, insertIndex + 1); - } -} - -template -inline void QFutureInterface::reportResult(const T &result, int index) -{ - reportResult(&result, index); -} - -template -inline void QFutureInterface::reportResults(const QVector &_results, int beginIndex, int count) -{ - QMutexLocker locker(mutex()); - if (this->queryState(Canceled) || this->queryState(Finished)) { - return; - } - - QtPrivate::ResultStore &store = resultStore(); - - if (store.filterMode()) { - const int resultCountBefore = store.count(); - store.addResults(beginIndex, &_results, count); - this->reportResultsReady(resultCountBefore, store.count()); - } else { - const int insertIndex = store.addResults(beginIndex, &_results, count); - this->reportResultsReady(insertIndex, insertIndex + _results.count()); - } -} - -template -inline void QFutureInterface::reportFinished(const T *result) -{ - if (result) - reportResult(result); - QFutureInterfaceBase::reportFinished(); -} - -template -inline const T &QFutureInterface::resultReference(int index) const -{ - QMutexLocker lock(mutex()); - return resultStore().resultAt(index).value(); -} - -template -inline const T *QFutureInterface::resultPointer(int index) const -{ - QMutexLocker lock(mutex()); - return resultStore().resultAt(index).pointer(); -} - -template -inline QList QFutureInterface::results() -{ - if (this->isCanceled()) { - exceptionStore().throwPossibleException(); - return QList(); - } - QFutureInterfaceBase::waitForResult(-1); - - QList res; - QMutexLocker lock(mutex()); - - QtPrivate::ResultIterator it = resultStore().begin(); - while (it != resultStore().end()) { - res.append(it.value()); - ++it; - } - - return res; -} - -template <> -class QFutureInterface : public QFutureInterfaceBase -{ -public: - QFutureInterface(State initialState = NoState) - : QFutureInterfaceBase(initialState) - { } - QFutureInterface(const QFutureInterface &other) - : QFutureInterfaceBase(other) - { } - - static QFutureInterface canceledResult() - { return QFutureInterface(State(Started | Finished | Canceled)); } - - QFutureInterface &operator=(const QFutureInterface &other) - { - QFutureInterfaceBase::operator=(other); - return *this; - } - - inline QFuture future(); // implemented in qfuture.h - - void reportResult(const void *, int) { } - void reportResults(const QVector &, int) { } - void reportFinished(const void * = 0) { QFutureInterfaceBase::reportFinished(); } -}; - -QT_END_NAMESPACE -QT_END_HEADER - -#endif // QT_NO_CONCURRENT - -#endif // QFUTUREINTERFACE_H diff --git a/src/concurrent/qfutureinterface_p.h b/src/concurrent/qfutureinterface_p.h deleted file mode 100644 index 7fd2ea4d99..0000000000 --- a/src/concurrent/qfutureinterface_p.h +++ /dev/null @@ -1,169 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QFUTUREINTERFACE_P_H -#define QFUTUREINTERFACE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QFutureCallOutEvent : public QEvent -{ -public: - enum CallOutType { - Started, - Finished, - Canceled, - Paused, - Resumed, - Progress, - ProgressRange, - ResultsReady - }; - - QFutureCallOutEvent() - : QEvent(QEvent::FutureCallOut), callOutType(CallOutType(0)), index1(-1), index2(-1) - { } - explicit QFutureCallOutEvent(CallOutType callOutType, int index1 = -1) - : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(-1) - { } - QFutureCallOutEvent(CallOutType callOutType, int index1, int index2) - : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(index2) - { } - - QFutureCallOutEvent(CallOutType callOutType, int index1, const QString &text) - : QEvent(QEvent::FutureCallOut), - callOutType(callOutType), - index1(index1), - index2(-1), - text(text) - { } - - CallOutType callOutType; - int index1; - int index2; - QString text; - - QFutureCallOutEvent *clone() const - { - return new QFutureCallOutEvent(callOutType, index1, index2, text); - } - -private: - QFutureCallOutEvent(CallOutType callOutType, - int index1, - int index2, - const QString &text) - : QEvent(QEvent::FutureCallOut), - callOutType(callOutType), - index1(index1), - index2(index2), - text(text) - { } -}; - -class QFutureCallOutInterface -{ -public: - virtual ~QFutureCallOutInterface() {} - virtual void postCallOutEvent(const QFutureCallOutEvent &) = 0; - virtual void callOutInterfaceDisconnected() = 0; -}; - -class QFutureInterfaceBasePrivate -{ -public: - QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState); - - QAtomicInt refCount; - mutable QMutex m_mutex; - QWaitCondition waitCondition; - QList outputConnections; - int m_progressValue; - int m_progressMinimum; - int m_progressMaximum; - QFutureInterfaceBase::State state; - QElapsedTimer progressTime; - QWaitCondition pausedWaitCondition; - int pendingResults; - QtPrivate::ResultStoreBase m_results; - bool manualProgress; - int m_expectedResultCount; - QtPrivate::ExceptionStore m_exceptionStore; - QString m_progressText; - QRunnable *runnable; - - // Internal functions that does not change the mutex state. - // The mutex must be locked when calling these. - int internal_resultCount() const; - bool internal_isResultReadyAt(int index) const; - bool internal_waitForNextResult(); - bool internal_updateProgress(int progress, const QString &progressText = QString()); - void internal_setThrottled(bool enable); - void sendCallOut(const QFutureCallOutEvent &callOut); - void sendCallOuts(const QFutureCallOutEvent &callOut1, const QFutureCallOutEvent &callOut2); - void connectOutputInterface(QFutureCallOutInterface *iface); - void disconnectOutputInterface(QFutureCallOutInterface *iface); - - void setState(QFutureInterfaceBase::State state); -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/concurrent/qfuturesynchronizer.h b/src/concurrent/qfuturesynchronizer.h index 9e003c0fa9..b82e968d8f 100644 --- a/src/concurrent/qfuturesynchronizer.h +++ b/src/concurrent/qfuturesynchronizer.h @@ -44,7 +44,7 @@ #include -#include +#include #ifndef QT_NO_CONCURRENT diff --git a/src/concurrent/qfuturewatcher.h b/src/concurrent/qfuturewatcher.h index 4cee31b5ef..a08f418d01 100644 --- a/src/concurrent/qfuturewatcher.h +++ b/src/concurrent/qfuturewatcher.h @@ -44,7 +44,7 @@ #include -#include +#include #ifndef QT_NO_QFUTURE diff --git a/src/concurrent/qfuturewatcher_p.h b/src/concurrent/qfuturewatcher_p.h index 2092084b86..23d9472cd7 100644 --- a/src/concurrent/qfuturewatcher_p.h +++ b/src/concurrent/qfuturewatcher_p.h @@ -55,7 +55,7 @@ #include -#include "qfutureinterface_p.h" +#include #include #ifndef QT_NO_QFUTURE diff --git a/src/concurrent/qtconcurrent_global.h b/src/concurrent/qtconcurrent_global.h index 54e70b67f8..464aa88d49 100644 --- a/src/concurrent/qtconcurrent_global.h +++ b/src/concurrent/qtconcurrent_global.h @@ -47,10 +47,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -#ifdef QT_NO_CONCURRENT -# define QT_NO_QFUTURE -#endif - #ifndef QT_STATIC # if defined(QT_BUILD_CONCURRENT_LIB) # define Q_CONCURRENT_EXPORT Q_DECL_EXPORT diff --git a/src/concurrent/qtconcurrentrunbase.h b/src/concurrent/qtconcurrentrunbase.h index 897345f239..6c67338d25 100644 --- a/src/concurrent/qtconcurrentrunbase.h +++ b/src/concurrent/qtconcurrentrunbase.h @@ -46,7 +46,7 @@ #ifndef QT_NO_CONCURRENT -#include +#include #include #include diff --git a/src/concurrent/qtconcurrentthreadengine.h b/src/concurrent/qtconcurrentthreadengine.h index 2a5187502f..ee3f7e6bd6 100644 --- a/src/concurrent/qtconcurrentthreadengine.h +++ b/src/concurrent/qtconcurrentthreadengine.h @@ -47,7 +47,7 @@ #ifndef QT_NO_CONCURRENT #include -#include +#include #include #include #include diff --git a/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp b/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp new file mode 100644 index 0000000000..16c9d0b162 --- /dev/null +++ b/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +QFuture future = ...; + +QFuture::const_iterator i; +for (i = future.constBegin(); i != future.constEnd(); ++i) + cout << *i << endl; +//! [0] + + +//! [1] +QFuture future; +... +QFutureIterator i(future); +while (i.hasNext()) + qDebug() << i.next(); +//! [1] + + +//! [2] +QFutureIterator i(future); +i.toBack(); +while (i.hasPrevious()) + qDebug() << i.previous(); +//! [2] diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h new file mode 100644 index 0000000000..8b16f308f2 --- /dev/null +++ b/src/corelib/thread/qfuture.h @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTURE_H +#define QFUTURE_H + +#include + +#ifndef QT_NO_QFUTURE + +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + + +template +class QFutureWatcher; +template <> +class QFutureWatcher; + +template +class QFuture +{ +public: + QFuture() + : d(QFutureInterface::canceledResult()) + { } + explicit QFuture(QFutureInterface *p) // internal + : d(*p) + { } + QFuture(const QFuture &other) + : d(other.d) + { } + ~QFuture() + { } + + inline QFuture &operator=(const QFuture &other); + bool operator==(const QFuture &other) const { return (d == other.d); } + bool operator!=(const QFuture &other) const { return (d != other.d); } + + void cancel() { d.cancel(); } + bool isCanceled() const { return d.isCanceled(); } + + void setPaused(bool paused) { d.setPaused(paused); } + bool isPaused() const { return d.isPaused(); } + void pause() { setPaused(true); } + void resume() { setPaused(false); } + void togglePaused() { d.togglePaused(); } + + bool isStarted() const { return d.isStarted(); } + bool isFinished() const { return d.isFinished(); } + bool isRunning() const { return d.isRunning(); } + + int resultCount() const { return d.resultCount(); } + int progressValue() const { return d.progressValue(); } + int progressMinimum() const { return d.progressMinimum(); } + int progressMaximum() const { return d.progressMaximum(); } + QString progressText() const { return d.progressText(); } + void waitForFinished() { d.waitForFinished(); } + + inline T result() const; + inline T resultAt(int index) const; + bool isResultReadyAt(int resultIndex) const { return d.isResultReadyAt(resultIndex); } + + operator T() const { return result(); } + QList results() const { return d.results(); } + + class const_iterator + { + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef qptrdiff difference_type; + typedef T value_type; + typedef const T *pointer; + typedef const T &reference; + + inline const_iterator() {} + inline const_iterator(QFuture const * const _future, int _index) : future(_future), index(_index) {} + inline const_iterator(const const_iterator &o) : future(o.future), index(o.index) {} + inline const_iterator &operator=(const const_iterator &o) + { future = o.future; index = o.index; return *this; } + inline const T &operator*() const { return future->d.resultReference(index); } + inline const T *operator->() const { return future->d.resultPointer(index); } + + inline bool operator!=(const const_iterator &other) const + { + if (index == -1 && other.index == -1) // comparing end != end? + return false; + if (other.index == -1) + return (future->isRunning() || (index < future->resultCount())); + return (index != other.index); + } + + inline bool operator==(const const_iterator &o) const { return !operator!=(o); } + inline const_iterator &operator++() { ++index; return *this; } + inline const_iterator operator++(int) { const_iterator r = *this; ++index; return r; } + inline const_iterator &operator--() { --index; return *this; } + inline const_iterator operator--(int) { const_iterator r = *this; --index; return r; } + inline const_iterator operator+(int j) const { return const_iterator(future, index + j); } + inline const_iterator operator-(int j) const { return const_iterator(future, index - j); } + inline const_iterator &operator+=(int j) { index += j; return *this; } + inline const_iterator &operator-=(int j) { index -= j; return *this; } + private: + QFuture const * future; + int index; + }; + friend class const_iterator; + typedef const_iterator ConstIterator; + + const_iterator begin() const { return const_iterator(this, 0); } + const_iterator constBegin() const { return const_iterator(this, 0); } + const_iterator end() const { return const_iterator(this, -1); } + const_iterator constEnd() const { return const_iterator(this, -1); } + +private: + friend class QFutureWatcher; + +public: // Warning: the d pointer is not documented and is considered private. + mutable QFutureInterface d; +}; + +template +inline QFuture &QFuture::operator=(const QFuture &other) +{ + d = other.d; + return *this; +} + +template +inline T QFuture::result() const +{ + d.waitForResult(0); + return d.resultReference(0); +} + +template +inline T QFuture::resultAt(int index) const +{ + d.waitForResult(index); + return d.resultReference(index); +} + +template +inline QFuture QFutureInterface::future() +{ + return QFuture(this); +} + +Q_DECLARE_SEQUENTIAL_ITERATOR(Future) + +template <> +class QFuture +{ +public: + QFuture() + : d(QFutureInterface::canceledResult()) + { } + explicit QFuture(QFutureInterfaceBase *p) // internal + : d(*p) + { } + QFuture(const QFuture &other) + : d(other.d) + { } + ~QFuture() + { } + + QFuture &operator=(const QFuture &other); + bool operator==(const QFuture &other) const { return (d == other.d); } + bool operator!=(const QFuture &other) const { return (d != other.d); } + +#if !defined(Q_CC_XLC) + template + QFuture(const QFuture &other) + : d(other.d) + { } + + template + QFuture &operator=(const QFuture &other) + { + d = other.d; + return *this; + } +#endif + + void cancel() { d.cancel(); } + bool isCanceled() const { return d.isCanceled(); } + + void setPaused(bool paused) { d.setPaused(paused); } + bool isPaused() const { return d.isPaused(); } + void pause() { setPaused(true); } + void resume() { setPaused(false); } + void togglePaused() { d.togglePaused(); } + + bool isStarted() const { return d.isStarted(); } + bool isFinished() const { return d.isFinished(); } + bool isRunning() const { return d.isRunning(); } + + int resultCount() const { return d.resultCount(); } + int progressValue() const { return d.progressValue(); } + int progressMinimum() const { return d.progressMinimum(); } + int progressMaximum() const { return d.progressMaximum(); } + QString progressText() const { return d.progressText(); } + void waitForFinished() { d.waitForFinished(); } + +private: + friend class QFutureWatcher; + +#ifdef QFUTURE_TEST +public: +#endif + mutable QFutureInterfaceBase d; +}; + +inline QFuture &QFuture::operator=(const QFuture &other) +{ + d = other.d; + return *this; +} + +inline QFuture QFutureInterface::future() +{ + return QFuture(this); +} + +template +QFuture qToVoidFuture(const QFuture &future) +{ + return QFuture(future.d); +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_QFUTURE + +#endif // QFUTURE_H diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc new file mode 100644 index 0000000000..91414a092a --- /dev/null +++ b/src/corelib/thread/qfuture.qdoc @@ -0,0 +1,697 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! \class QFuture + \threadsafe + \brief The QFuture class represents the result of an asynchronous computation. + \since 4.4 + + \ingroup thread + + To start a computation, use one of the APIs in the + \l {Concurrent Programming}{Qt Concurrent} framework. + + QFuture allows threads to be synchronized against one or more results + which will be ready at a later point in time. The result can be of any type + that has a default constructor and a copy constructor. If a result is not + available at the time of calling the result(), resultAt(), or results() + functions, QFuture will wait until the result becomes available. You can + use the isResultReadyAt() function to determine if a result is ready or + not. For QFuture objects that report more than one result, the + resultCount() function returns the number of continuous results. This + means that it is always safe to iterate through the results from 0 to + resultCount(). + + QFuture provides a \l{Java-style iterators}{Java-style iterator} + (QFutureIterator) and an \l{STL-style iterators}{STL-style iterator} + (QFuture::const_iterator). Using these iterators is another way to access + results in the future. + + QFuture also offers ways to interact with a runnning computation. For + instance, the computation can be canceled with the cancel() function. To + pause the computation, use the setPaused() function or one of the pause(), + resume(), or togglePaused() convenience functions. Be aware that not all + asynchronous computations can be canceled or paused. For example, the + future returned by QtConcurrent::run() cannot be canceled; but the + future returned by QtConcurrent::mappedReduced() can. + + Progress information is provided by the progressValue(), + progressMinimum(), progressMaximum(), and progressText() functions. The + waitForFinished() function causes the calling thread to block and wait for + the computation to finish, ensuring that all results are available. + + The state of the computation represented by a QFuture can be queried using + the isCanceled(), isStarted(), isFinished(), isRunning(), or isPaused() + functions. + + QFuture is a lightweight reference counted class that can be passed by + value. + + QFuture is specialized to not contain any of the result fetching + functions. Any QFuture can be assigned or copied into a QFuture + as well. This is useful if only status or progress information is needed + - not the actual result data. + + To interact with running tasks using signals and slots, use QFutureWatcher. + + \sa QFutureWatcher, {Concurrent Programming}{Qt Concurrent} +*/ + +/*! \fn QFuture::QFuture() + + Constructs an empty future. +*/ + +/*! \fn QFuture::QFuture(const QFuture &other) + + Constructs a copy of \a other. + + \sa operator=() +*/ + +/*! \fn QFuture::QFuture(QFutureInterface *resultHolder) + \internal +*/ + +/*! \fn QFuture::~QFuture() + + Destroys the future. + + Note that this neither waits nor cancels the asynchronous computation. Use + waitForFinished() or QFutureSynchronizer when you need to ensure that the + computation is completed before the future is destroyed. +*/ + +/*! \fn QFuture &QFuture::operator=(const QFuture &other) + + Assigns \a other to this future and returns a reference to this future. +*/ + +/*! \fn bool QFuture::operator==(const QFuture &other) const + + Returns true if \a other is a copy of this future; otherwise returns false. +*/ + +/*! \fn bool QFuture::operator!=(const QFuture &other) const + + Returns true if \a other is \e not a copy of this future; otherwise returns + false. +*/ + +/*! \fn void QFuture::cancel() + + Cancels the asynchronous computation represented by this future. Note that + the cancelation is asynchronous. Use waitForFinished() after calling + cancel() when you need synchronous cancelation. + + Results currently available may still be accessed on a canceled future, + but new results will \e not become available after calling this function. + Any QFutureWatcher object that is watching this future will not deliver + progress and result ready signals on a canceled future. + + Be aware that not all asynchronous computations can be canceled. For + example, the future returned by QtConcurrent::run() cannot be canceled; + but the future returned by QtConcurrent::mappedReduced() can. +*/ + +/*! \fn bool QFuture::isCanceled() const + + Returns true if the asynchronous computation has been canceled with the + cancel() function; otherwise returns false. + + Be aware that the computation may still be running even though this + function returns true. See cancel() for more details. +*/ + +/*! \fn void QFuture::setPaused(bool paused) + + If \a paused is true, this function pauses the asynchronous computation + represented by the future. If the computation is already paused, this + function does nothing. Any QFutureWatcher object that is watching this + future will stop delivering progress and result ready signals while the + future is paused. Signal delivery will continue once the future is + resumed. + + If \a paused is false, this function resumes the asynchronous computation. + If the computation was not previously paused, this function does nothing. + + Be aware that not all computations can be paused. For example, the future + returned by QtConcurrent::run() cannot be paused; but the future returned + by QtConcurrent::mappedReduced() can. + + \sa pause(), resume(), togglePaused() +*/ + +/*! \fn bool QFuture::isPaused() const + + Returns true if the asynchronous computation has been paused with the + pause() function; otherwise returns false. + + Be aware that the computation may still be running even though this + function returns true. See setPaused() for more details. + + \sa setPaused(), togglePaused() +*/ + +/*! \fn void QFuture::pause() + + Pauses the asynchronous computation represented by this future. This is a + convenience method that simply calls setPaused(true). + + \sa resume() +*/ + +/*! \fn void QFuture::resume() + + Resumes the asynchronous computation represented by this future. This is a + convenience method that simply calls setPaused(false). + + \sa pause() +*/ + +/*! \fn void QFuture::togglePaused() + + Toggles the paused state of the asynchronous computation. In other words, + if the computation is currently paused, calling this function resumes it; + if the computation is running, it is paused. This is a convenience method + for calling setPaused(!isPaused()). + + \sa setPaused(), pause(), resume() +*/ + +/*! \fn bool QFuture::isStarted() const + + Returns true if the asynchronous computation represented by this future + has been started; otherwise returns false. +*/ + +/*! \fn bool QFuture::isFinished() const + + Returns true if the asynchronous computation represented by this future + has finished; otherwise returns false. +*/ + +/*! \fn bool QFuture::isRunning() const + + Returns true if the asynchronous computation represented by this future is + currently running; otherwise returns false. +*/ + +/*! \fn int QFuture::resultCount() const + + Returns the number of continuous results available in this future. The real + number of results stored might be different from this value, due to gaps + in the result set. It is always safe to iterate through the results from 0 + to resultCount(). + \sa result(), resultAt(), results() +*/ + +/*! \fn int QFuture::progressValue() const + + Returns the current progress value, which is between the progressMinimum() + and progressMaximum(). + + \sa progressMinimum(), progressMaximum() +*/ + +/*! \fn int QFuture::progressMinimum() const + + Returns the minimum progressValue(). + + \sa progressValue(), progressMaximum() +*/ + +/*! \fn int QFuture::progressMaximum() const + + Returns the maximum progressValue(). + + \sa progressValue(), progressMinimum() +*/ + +/*! \fn QString QFuture::progressText() const + + Returns the (optional) textual representation of the progress as reported + by the asynchronous computation. + + Be aware that not all computations provide a textual representation of the + progress, and as such, this function may return an empty string. +*/ + +/*! \fn void QFuture::waitForFinished() + + Waits for the asynchronous computation to finish (including cancel()ed + computations). +*/ + +/*! \fn T QFuture::result() const + + Returns the first result in the future. If the result is not immediately + available, this function will block and wait for the result to become + available. This is a convenience method for calling resultAt(0). + + \sa resultAt(), results() +*/ + +/*! \fn T QFuture::resultAt(int index) const + + Returns the result at \a index in the future. If the result is not + immediately available, this function will block and wait for the result to + become available. + + \sa result(), results(), resultCount() +*/ + +/*! \fn bool QFuture::isResultReadyAt(int index) const + + Returns true if the result at \a index is immediately available; otherwise + returns false. + + \sa resultAt(), resultCount() +*/ + +/*! \fn QFuture::operator T() const + + Returns the first result in the future. If the result is not immediately + available, this function will block and wait for the result to become + available. This is a convenience method for calling result() or + resultAt(0). + + \sa result(), resultAt(), results() +*/ + +/*! \fn QList QFuture::results() const + + Returns all results from the future. If the results are not immediately + available, this function will block and wait for them to become available. + + \sa result(), resultAt(), resultCount() +*/ + +/*! \fn QFuture::const_iterator QFuture::begin() const + + Returns a const \l{STL-style iterator} pointing to the first result in the + future. + + \sa constBegin(), end() +*/ + +/*! \fn QFuture::const_iterator QFuture::end() const + + Returns a const \l{STL-style iterator} pointing to the imaginary result + after the last result in the future. + + \sa begin(), constEnd() +*/ + +/*! \fn QFuture::const_iterator QFuture::constBegin() const + + Returns a const \l{STL-style iterator} pointing to the first result in the + future. + + \sa begin(), constEnd() +*/ + +/*! \fn QFuture::const_iterator QFuture::constEnd() const + + Returns a const \l{STL-style iterator} pointing to the imaginary result + after the last result in the future. + + \sa constBegin(), end() +*/ + +/*! \class QFuture::const_iterator + \reentrant + \since 4.4 + + \brief The QFuture::const_iterator class provides an STL-style const + iterator for QFuture. + + QFuture provides both \l{STL-style iterators} and \l{Java-style iterators}. + The STL-style iterators are more low-level and more cumbersome to use; on + the other hand, they are slightly faster and, for developers who already + know STL, have the advantage of familiarity. + + The default QFuture::const_iterator constructor creates an uninitialized + iterator. You must initialize it using a QFuture function like + QFuture::constBegin() or QFuture::constEnd() before you start iterating. + Here's a typical loop that prints all the results available in a future: + + \snippet code/src_corelib_thread_qfuture.cpp 0 + + \sa QFutureIterator, QFuture +*/ + +/*! \typedef QFuture::const_iterator::iterator_category + + Typedef for std::bidirectional_iterator_tag. Provided for STL compatibility. +*/ + +/*! \typedef QFuture::const_iterator::difference_type + + Typedef for ptrdiff_t. Provided for STL compatibility. +*/ + +/*! \typedef QFuture::const_iterator::value_type + + Typedef for T. Provided for STL compatibility. +*/ + +/*! \typedef QFuture::const_iterator::pointer + + Typedef for const T *. Provided for STL compatibility. +*/ + +/*! \typedef QFuture::const_iterator::reference + + Typedef for const T &. Provided for STL compatibility. +*/ + +/*! \fn QFuture::const_iterator::const_iterator() + + Constructs an uninitialized iterator. + + Functions like operator*() and operator++() should not be called on an + uninitialized iterartor. Use operator=() to assign a value to it before + using it. + + \sa QFuture::constBegin(), QFuture::constEnd() +*/ + +/*! \fn QFuture::const_iterator::const_iterator(QFuture const * const future, int index) + \internal +*/ + +/*! \fn QFuture::const_iterator::const_iterator(const const_iterator &other) + + Constructs a copy of \a other. +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator=(const const_iterator &other) + + Assigns \a other to this iterator. +*/ + +/*! \fn const T &QFuture::const_iterator::operator*() const + + Returns the current result. +*/ + +/*! \fn const T *QFuture::const_iterator::operator->() const + + Returns a pointer to the current result. +*/ + +/*! \fn bool QFuture::const_iterator::operator!=(const const_iterator &other) const + + Returns true if \a other points to a different result than this iterator; + otherwise returns false. + + \sa operator==() +*/ + +/*! \fn bool QFuture::const_iterator::operator==(const const_iterator &other) const + + Returns true if \a other points to the same result as this iterator; + otherwise returns false. + + \sa operator!=() +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator++() + + The prefix ++ operator (\c{++it}) advances the iterator to the next result + in the future and returns an iterator to the new current result. + + Calling this function on QFuture::constEnd() leads to undefined results. + + \sa operator--() +*/ + +/*! \fn QFuture::const_iterator QFuture::const_iterator::operator++(int) + + \overload + + The postfix ++ operator (\c{it++}) advances the iterator to the next + result in the future and returns an iterator to the previously current + result. +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator--() + + The prefix -- operator (\c{--it}) makes the preceding result current and + returns an iterator to the new current result. + + Calling this function on QFuture::constBegin() leads to undefined results. + + \sa operator++() +*/ + +/*! \fn QFuture::const_iterator QFuture::const_iterator::operator--(int) + + \overload + + The postfix -- operator (\c{it--}) makes the preceding result current and + returns an iterator to the previously current result. +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator+=(int j) + + Advances the iterator by \a j results. (If \a j is negative, the iterator + goes backward.) + + \sa operator-=(), operator+() +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator-=(int j) + + Makes the iterator go back by \a j results. (If \a j is negative, the + iterator goes forward.) + + \sa operator+=(), operator-() +*/ + +/*! \fn QFuture::const_iterator QFuture::const_iterator::operator+(int j) const + + Returns an iterator to the results at \a j positions forward from this + iterator. (If \a j is negative, the iterator goes backward.) + + \sa operator-(), operator+=() +*/ + +/*! \fn QFuture::const_iterator QFuture::const_iterator::operator-(int j) const + + Returns an iterator to the result at \a j positions backward from this + iterator. (If \a j is negative, the iterator goes forward.) + + \sa operator+(), operator-=() +*/ + +/*! \typedef QFuture::ConstIterator + + Qt-style synonym for QFuture::const_iterator. +*/ + +/*! + \class QFutureIterator + \reentrant + \since 4.4 + \inmodule QtCore + + \brief The QFutureIterator class provides a Java-style const iterator for + QFuture. + + QFuture has both \l{Java-style iterators} and \l{STL-style iterators}. The + Java-style iterators are more high-level and easier to use than the + STL-style iterators; on the other hand, they are slightly less efficient. + + An alternative to using iterators is to use index positions. Some QFuture + member functions take an index as their first parameter, making it + possible to access results without using iterators. + + QFutureIterator\ allows you to iterate over a QFuture\. Note that + there is no mutable iterator for QFuture (unlike the other Java-style + iterators). + + The QFutureIterator constructor takes a QFuture as its argument. After + construction, the iterator is located at the very beginning of the result + list (i.e. before the first result). Here's how to iterate over all the + results sequentially: + + \snippet code/src_corelib_thread_qfuture.cpp 1 + + The next() function returns the next result (waiting for it to become + available, if necessary) from the future and advances the iterator. Unlike + STL-style iterators, Java-style iterators point \e between results rather + than directly \e at results. The first call to next() advances the iterator + to the position between the first and second result, and returns the first + result; the second call to next() advances the iterator to the position + between the second and third result, and returns the second result; and + so on. + + \image javaiterators1.png + + Here's how to iterate over the elements in reverse order: + + \snippet code/src_corelib_thread_qfuture.cpp 2 + + If you want to find all occurrences of a particular value, use findNext() + or findPrevious() in a loop. + + Multiple iterators can be used on the same future. If the future is + modified while a QFutureIterator is active, the QFutureIterator will + continue iterating over the original future, ignoring the modified copy. + + \sa QFuture::const_iterator, QFuture +*/ + +/*! + \fn QFutureIterator::QFutureIterator(const QFuture &future) + + Constructs an iterator for traversing \a future. The iterator is set to be + at the front of the result list (before the first result). + + \sa operator=() +*/ + +/*! \fn QFutureIterator &QFutureIterator::operator=(const QFuture &future) + + Makes the iterator operate on \a future. The iterator is set to be at the + front of the result list (before the first result). + + \sa toFront(), toBack() +*/ + +/*! \fn void QFutureIterator::toFront() + + Moves the iterator to the front of the result list (before the first + result). + + \sa toBack(), next() +*/ + +/*! \fn void QFutureIterator::toBack() + + Moves the iterator to the back of the result list (after the last result). + + \sa toFront(), previous() +*/ + +/*! \fn bool QFutureIterator::hasNext() const + + Returns true if there is at least one result ahead of the iterator, e.g., + the iterator is \e not at the back of the result list; otherwise returns + false. + + \sa hasPrevious(), next() +*/ + +/*! \fn const T &QFutureIterator::next() + + Returns the next result and advances the iterator by one position. + + Calling this function on an iterator located at the back of the result + list leads to undefined results. + + \sa hasNext(), peekNext(), previous() +*/ + +/*! \fn const T &QFutureIterator::peekNext() const + + Returns the next result without moving the iterator. + + Calling this function on an iterator located at the back of the result + list leads to undefined results. + + \sa hasNext(), next(), peekPrevious() +*/ + +/*! \fn bool QFutureIterator::hasPrevious() const + + Returns true if there is at least one result ahead of the iterator, e.g., + the iterator is \e not at the front of the result list; otherwise returns + false. + + \sa hasNext(), previous() +*/ + +/*! \fn const T &QFutureIterator::previous() + + Returns the previous result and moves the iterator back by one position. + + Calling this function on an iterator located at the front of the result + list leads to undefined results. + + \sa hasPrevious(), peekPrevious(), next() +*/ + +/*! \fn const T &QFutureIterator::peekPrevious() const + + Returns the previous result without moving the iterator. + + Calling this function on an iterator located at the front of the result + list leads to undefined results. + + \sa hasPrevious(), previous(), peekNext() +*/ + +/*! \fn bool QFutureIterator::findNext(const T &value) + + Searches for \a value starting from the current iterator position forward. + Returns true if \a value is found; otherwise returns false. + + After the call, if \a value was found, the iterator is positioned just + after the matching result; otherwise, the iterator is positioned at the + back of the result list. + + \sa findPrevious() +*/ + +/*! \fn bool QFutureIterator::findPrevious(const T &value) + + Searches for \a value starting from the current iterator position + backward. Returns true if \a value is found; otherwise returns false. + + After the call, if \a value was found, the iterator is positioned just + before the matching result; otherwise, the iterator is positioned at the + front of the result list. + + \sa findNext() +*/ diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp new file mode 100644 index 0000000000..ce9eb143d7 --- /dev/null +++ b/src/corelib/thread/qfutureinterface.cpp @@ -0,0 +1,565 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// qfutureinterface.h included from qfuture.h +#include "qfuture.h" + +#ifndef QT_NO_QFUTURE + +#include "qfutureinterface_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum { + MaxProgressEmitsPerSecond = 25 +}; + +QFutureInterfaceBase::QFutureInterfaceBase(State initialState) + : d(new QFutureInterfaceBasePrivate(initialState)) +{ } + +QFutureInterfaceBase::QFutureInterfaceBase(const QFutureInterfaceBase &other) + : d(other.d) +{ + d->refCount.ref(); +} + +QFutureInterfaceBase::~QFutureInterfaceBase() +{ + if (!d->refCount.deref()) + delete d; +} + +void QFutureInterfaceBase::cancel() +{ + QMutexLocker locker(&d->m_mutex); + if (d->state & Canceled) + return; + + d->state = State((d->state & ~Paused) | Canceled); + d->waitCondition.wakeAll(); + d->pausedWaitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); +} + +void QFutureInterfaceBase::setPaused(bool paused) +{ + QMutexLocker locker(&d->m_mutex); + if (paused) { + d->state = State(d->state | Paused); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + } else { + d->state = State(d->state & ~Paused); + d->pausedWaitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); + } +} + +void QFutureInterfaceBase::togglePaused() +{ + QMutexLocker locker(&d->m_mutex); + if (d->state & Paused) { + d->state = State(d->state & ~Paused); + d->pausedWaitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); + } else { + d->state = State(d->state | Paused); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + } +} + +void QFutureInterfaceBase::setThrottled(bool enable) +{ + // bail out if we are not changing the state + if ((enable && (d->state & Throttled)) || (!enable && !(d->state & Throttled))) + return; + + // lock and change the state + QMutexLocker lock(&d->m_mutex); + if (enable) { + d->state = State(d->state | Throttled); + } else { + d->state = State(d->state & ~Throttled); + if (!(d->state & Paused)) + d->pausedWaitCondition.wakeAll(); + } +} + + +bool QFutureInterfaceBase::isRunning() const +{ + return queryState(Running); +} + +bool QFutureInterfaceBase::isStarted() const +{ + return queryState(Started); +} + +bool QFutureInterfaceBase::isCanceled() const +{ + return queryState(Canceled); +} + +bool QFutureInterfaceBase::isFinished() const +{ + return queryState(Finished); +} + +bool QFutureInterfaceBase::isPaused() const +{ + return queryState(Paused); +} + +bool QFutureInterfaceBase::isThrottled() const +{ + return queryState(Throttled); +} + +bool QFutureInterfaceBase::isResultReadyAt(int index) const +{ + QMutexLocker lock(&d->m_mutex); + return d->internal_isResultReadyAt(index); +} + +bool QFutureInterfaceBase::waitForNextResult() +{ + QMutexLocker lock(&d->m_mutex); + return d->internal_waitForNextResult(); +} + +void QFutureInterfaceBase::waitForResume() +{ + // return early if possible to avoid taking the mutex lock. + if ((d->state & Paused) == false || (d->state & Canceled)) + return; + + QMutexLocker lock(&d->m_mutex); + if ((d->state & Paused) == false || (d->state & Canceled)) + return; + + // decrease active thread count since this thread will wait. + QThreadPool::globalInstance()->releaseThread(); + + d->pausedWaitCondition.wait(&d->m_mutex); + + QThreadPool::globalInstance()->reserveThread(); +} + +int QFutureInterfaceBase::progressValue() const +{ + return d->m_progressValue; +} + +int QFutureInterfaceBase::progressMinimum() const +{ + return d->m_progressMinimum; +} + +int QFutureInterfaceBase::progressMaximum() const +{ + return d->m_progressMaximum; +} + +int QFutureInterfaceBase::resultCount() const +{ + QMutexLocker lock(&d->m_mutex); + return d->internal_resultCount(); +} + +QString QFutureInterfaceBase::progressText() const +{ + QMutexLocker locker(&d->m_mutex); + return d->m_progressText; +} + +bool QFutureInterfaceBase::isProgressUpdateNeeded() const +{ + QMutexLocker locker(&d->m_mutex); + return !d->progressTime.isValid() || (d->progressTime.elapsed() > (1000 / MaxProgressEmitsPerSecond)); +} + +void QFutureInterfaceBase::reportStarted() +{ + QMutexLocker locker(&d->m_mutex); + if ((d->state & Started) || (d->state & Canceled) || (d->state & Finished)) + return; + + d->setState(State(Started | Running)); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Started)); +} + +void QFutureInterfaceBase::reportCanceled() +{ + cancel(); +} + +#ifndef QT_NO_EXCEPTIONS +void QFutureInterfaceBase::reportException(const QException &exception) +{ + QMutexLocker locker(&d->m_mutex); + if ((d->state & Canceled) || (d->state & Finished)) + return; + + d->m_exceptionStore.setException(exception); + d->state = State(d->state | Canceled); + d->waitCondition.wakeAll(); + d->pausedWaitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); +} +#endif + +void QFutureInterfaceBase::reportFinished() +{ + QMutexLocker locker(&d->m_mutex); + if (!(d->state & Finished)) { + d->state = State((d->state & ~Running) | Finished); + d->waitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Finished)); + } +} + +void QFutureInterfaceBase::setExpectedResultCount(int resultCount) +{ + if (d->manualProgress == false) + setProgressRange(0, resultCount); + d->m_expectedResultCount = resultCount; +} + +int QFutureInterfaceBase::expectedResultCount() +{ + return d->m_expectedResultCount; +} + +bool QFutureInterfaceBase::queryState(State state) const +{ + return (d->state & state); +} + +void QFutureInterfaceBase::waitForResult(int resultIndex) +{ + d->m_exceptionStore.throwPossibleException(); + + if (!(d->state & Running)) + return; + + // To avoid deadlocks and reduce the number of threads used, try to + // run the runnable in the current thread. + QThreadPool::globalInstance()->d_func()->stealRunnable(d->runnable); + + QMutexLocker lock(&d->m_mutex); + + if (!(d->state & Running)) + return; + + const int waitIndex = (resultIndex == -1) ? INT_MAX : resultIndex; + while ((d->state & Running) && d->internal_isResultReadyAt(waitIndex) == false) + d->waitCondition.wait(&d->m_mutex); + + d->m_exceptionStore.throwPossibleException(); +} + +void QFutureInterfaceBase::waitForFinished() +{ + if (d->state & Running) { + QThreadPool::globalInstance()->d_func()->stealRunnable(d->runnable); + + QMutexLocker lock(&d->m_mutex); + + while (d->state & Running) + d->waitCondition.wait(&d->m_mutex); + } + + d->m_exceptionStore.throwPossibleException(); +} + +void QFutureInterfaceBase::reportResultsReady(int beginIndex, int endIndex) +{ + if ((d->state & Canceled) || (d->state & Finished) || beginIndex == endIndex) + return; + + d->waitCondition.wakeAll(); + + if (d->manualProgress == false) { + if (d->internal_updateProgress(d->m_progressValue + endIndex - beginIndex) == false) { + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, + beginIndex, + endIndex)); + return; + } + + d->sendCallOuts(QFutureCallOutEvent(QFutureCallOutEvent::Progress, + d->m_progressValue, + d->m_progressText), + QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, + beginIndex, + endIndex)); + return; + } + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, beginIndex, endIndex)); +} + +void QFutureInterfaceBase::setRunnable(QRunnable *runnable) +{ + d->runnable = runnable; +} + +void QFutureInterfaceBase::setFilterMode(bool enable) +{ + QMutexLocker locker(&d->m_mutex); + resultStoreBase().setFilterMode(enable); +} + +void QFutureInterfaceBase::setProgressRange(int minimum, int maximum) +{ + QMutexLocker locker(&d->m_mutex); + d->m_progressMinimum = minimum; + d->m_progressMaximum = maximum; + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, minimum, maximum)); +} + +void QFutureInterfaceBase::setProgressValue(int progressValue) +{ + setProgressValueAndText(progressValue, QString()); +} + +void QFutureInterfaceBase::setProgressValueAndText(int progressValue, + const QString &progressText) +{ + QMutexLocker locker(&d->m_mutex); + if (d->manualProgress == false) + d->manualProgress = true; + if (d->m_progressValue >= progressValue) + return; + + if ((d->state & Canceled) || (d->state & Finished)) + return; + + if (d->internal_updateProgress(progressValue, progressText)) { + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Progress, + d->m_progressValue, + d->m_progressText)); + } +} + +QMutex *QFutureInterfaceBase::mutex() const +{ + return &d->m_mutex; +} + +QtPrivate::ExceptionStore &QFutureInterfaceBase::exceptionStore() +{ + return d->m_exceptionStore; +} + +QtPrivate::ResultStoreBase &QFutureInterfaceBase::resultStoreBase() +{ + return d->m_results; +} + +const QtPrivate::ResultStoreBase &QFutureInterfaceBase::resultStoreBase() const +{ + return d->m_results; +} + +QFutureInterfaceBase &QFutureInterfaceBase::operator=(const QFutureInterfaceBase &other) +{ + other.d->refCount.ref(); + if (!d->refCount.deref()) + delete d; + d = other.d; + return *this; +} + +bool QFutureInterfaceBase::referenceCountIsOne() const +{ + return d->refCount.load() == 1; +} + +QFutureInterfaceBasePrivate::QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState) + : refCount(1), m_progressValue(0), m_progressMinimum(0), m_progressMaximum(0), + state(initialState), pendingResults(0), + manualProgress(false), m_expectedResultCount(0), runnable(0) +{ + progressTime.invalidate(); +} + +int QFutureInterfaceBasePrivate::internal_resultCount() const +{ + return m_results.count(); // ### subtract canceled results. +} + +bool QFutureInterfaceBasePrivate::internal_isResultReadyAt(int index) const +{ + return (m_results.contains(index)); +} + +bool QFutureInterfaceBasePrivate::internal_waitForNextResult() +{ + if (m_results.hasNextResult()) + return true; + + while ((state & QFutureInterfaceBase::Running) && m_results.hasNextResult() == false) + waitCondition.wait(&m_mutex); + + return (!(state & QFutureInterfaceBase::Canceled) && m_results.hasNextResult()); +} + +bool QFutureInterfaceBasePrivate::internal_updateProgress(int progress, + const QString &progressText) +{ + if (m_progressValue >= progress) + return false; + + m_progressValue = progress; + m_progressText = progressText; + + if (progressTime.isValid() && m_progressValue != m_progressMaximum) // make sure the first and last steps are emitted. + if (progressTime.elapsed() < (1000 / MaxProgressEmitsPerSecond)) + return false; + + progressTime.start(); + return true; +} + +void QFutureInterfaceBasePrivate::internal_setThrottled(bool enable) +{ + // bail out if we are not changing the state + if ((enable && (state & QFutureInterfaceBase::Throttled)) + || (!enable && !(state & QFutureInterfaceBase::Throttled))) + return; + + // change the state + if (enable) { + state = QFutureInterfaceBase::State(state | QFutureInterfaceBase::Throttled); + } else { + state = QFutureInterfaceBase::State(state & ~QFutureInterfaceBase::Throttled); + if (!(state & QFutureInterfaceBase::Paused)) + pausedWaitCondition.wakeAll(); + } +} + +void QFutureInterfaceBasePrivate::sendCallOut(const QFutureCallOutEvent &callOutEvent) +{ + if (outputConnections.isEmpty()) + return; + + for (int i = 0; i < outputConnections.count(); ++i) + outputConnections.at(i)->postCallOutEvent(callOutEvent); +} + +void QFutureInterfaceBasePrivate::sendCallOuts(const QFutureCallOutEvent &callOutEvent1, + const QFutureCallOutEvent &callOutEvent2) +{ + if (outputConnections.isEmpty()) + return; + + for (int i = 0; i < outputConnections.count(); ++i) { + QFutureCallOutInterface *interface = outputConnections.at(i); + interface->postCallOutEvent(callOutEvent1); + interface->postCallOutEvent(callOutEvent2); + } +} + +// This function connects an output interface (for example a QFutureWatcher) +// to this future. While holding the lock we check the state and ready results +// and add the appropriate callouts to the queue. In order to avoid deadlocks, +// the actual callouts are made at the end while not holding the lock. +void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface *interface) +{ + QMutexLocker locker(&m_mutex); + + if (state & QFutureInterfaceBase::Started) { + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Started)); + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, + m_progressMinimum, + m_progressMaximum)); + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress, + m_progressValue, + m_progressText)); + } + + QtPrivate::ResultIteratorBase it = m_results.begin(); + while (it != m_results.end()) { + const int begin = it.resultIndex(); + const int end = begin + it.batchSize(); + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, + begin, + end)); + it.batchedAdvance(); + } + + if (state & QFutureInterfaceBase::Paused) + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + + if (state & QFutureInterfaceBase::Canceled) + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); + + if (state & QFutureInterfaceBase::Finished) + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Finished)); + + outputConnections.append(interface); +} + +void QFutureInterfaceBasePrivate::disconnectOutputInterface(QFutureCallOutInterface *interface) +{ + QMutexLocker lock(&m_mutex); + const int index = outputConnections.indexOf(interface); + if (index == -1) + return; + outputConnections.removeAt(index); + + interface->callOutInterfaceDisconnected(); +} + +void QFutureInterfaceBasePrivate::setState(QFutureInterfaceBase::State newState) +{ + state = newState; +} + +QT_END_NAMESPACE + +#endif // QT_NO_QFUTURE diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h new file mode 100644 index 0000000000..b7bf779412 --- /dev/null +++ b/src/corelib/thread/qfutureinterface.h @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREINTERFACE_H +#define QFUTUREINTERFACE_H + +#include + +#ifndef QT_NO_QFUTURE + +#include +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + + +template class QFuture; +class QFutureInterfaceBasePrivate; +class QFutureWatcherBase; +class QFutureWatcherBasePrivate; + +class Q_CORE_EXPORT QFutureInterfaceBase +{ +public: + enum State { + NoState = 0x00, + Running = 0x01, + Started = 0x02, + Finished = 0x04, + Canceled = 0x08, + Paused = 0x10, + Throttled = 0x20 + }; + + QFutureInterfaceBase(State initialState = NoState); + QFutureInterfaceBase(const QFutureInterfaceBase &other); + virtual ~QFutureInterfaceBase(); + + // reporting functions available to the engine author: + void reportStarted(); + void reportFinished(); + void reportCanceled(); +#ifndef QT_NO_EXCEPTIONS + void reportException(const QException &e); +#endif + void reportResultsReady(int beginIndex, int endIndex); + + void setRunnable(QRunnable *runnable); + void setFilterMode(bool enable); + void setProgressRange(int minimum, int maximum); + int progressMinimum() const; + int progressMaximum() const; + bool isProgressUpdateNeeded() const; + void setProgressValue(int progressValue); + int progressValue() const; + void setProgressValueAndText(int progressValue, const QString &progressText); + QString progressText() const; + + void setExpectedResultCount(int resultCount); + int expectedResultCount(); + int resultCount() const; + + bool queryState(State state) const; + bool isRunning() const; + bool isStarted() const; + bool isCanceled() const; + bool isFinished() const; + bool isPaused() const; + bool isThrottled() const; + bool isResultReadyAt(int index) const; + + void cancel(); + void setPaused(bool paused); + void togglePaused(); + void setThrottled(bool enable); + + void waitForFinished(); + bool waitForNextResult(); + void waitForResult(int resultIndex); + void waitForResume(); + + QMutex *mutex() const; + QtPrivate::ExceptionStore &exceptionStore(); + QtPrivate::ResultStoreBase &resultStoreBase(); + const QtPrivate::ResultStoreBase &resultStoreBase() const; + + inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; } + inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; } + QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other); + +protected: + bool referenceCountIsOne() const; +public: + +#ifndef QFUTURE_TEST +private: +#endif + QFutureInterfaceBasePrivate *d; + +private: + friend class QFutureWatcherBase; + friend class QFutureWatcherBasePrivate; +}; + +template +class QFutureInterface : public QFutureInterfaceBase +{ +public: + QFutureInterface(State initialState = NoState) + : QFutureInterfaceBase(initialState) + { } + QFutureInterface(const QFutureInterface &other) + : QFutureInterfaceBase(other) + { } + ~QFutureInterface() + { + if (referenceCountIsOne()) + resultStore().clear(); + } + + static QFutureInterface canceledResult() + { return QFutureInterface(State(Started | Finished | Canceled)); } + + QFutureInterface &operator=(const QFutureInterface &other) + { + if (referenceCountIsOne()) + resultStore().clear(); + QFutureInterfaceBase::operator=(other); + return *this; + } + + inline QFuture future(); // implemented in qfuture.h + + inline void reportResult(const T *result, int index = -1); + inline void reportResult(const T &result, int index = -1); + inline void reportResults(const QVector &results, int beginIndex = -1, int count = -1); + inline void reportFinished(const T *result = 0); + + inline const T &resultReference(int index) const; + inline const T *resultPointer(int index) const; + inline QList results(); +private: + QtPrivate::ResultStore &resultStore() + { return static_cast &>(resultStoreBase()); } + const QtPrivate::ResultStore &resultStore() const + { return static_cast &>(resultStoreBase()); } +}; + +template +inline void QFutureInterface::reportResult(const T *result, int index) +{ + QMutexLocker locker(mutex()); + if (this->queryState(Canceled) || this->queryState(Finished)) { + return; + } + + QtPrivate::ResultStore &store = resultStore(); + + + if (store.filterMode()) { + const int resultCountBefore = store.count(); + store.addResult(index, result); + this->reportResultsReady(resultCountBefore, resultCountBefore + store.count()); + } else { + const int insertIndex = store.addResult(index, result); + this->reportResultsReady(insertIndex, insertIndex + 1); + } +} + +template +inline void QFutureInterface::reportResult(const T &result, int index) +{ + reportResult(&result, index); +} + +template +inline void QFutureInterface::reportResults(const QVector &_results, int beginIndex, int count) +{ + QMutexLocker locker(mutex()); + if (this->queryState(Canceled) || this->queryState(Finished)) { + return; + } + + QtPrivate::ResultStore &store = resultStore(); + + if (store.filterMode()) { + const int resultCountBefore = store.count(); + store.addResults(beginIndex, &_results, count); + this->reportResultsReady(resultCountBefore, store.count()); + } else { + const int insertIndex = store.addResults(beginIndex, &_results, count); + this->reportResultsReady(insertIndex, insertIndex + _results.count()); + } +} + +template +inline void QFutureInterface::reportFinished(const T *result) +{ + if (result) + reportResult(result); + QFutureInterfaceBase::reportFinished(); +} + +template +inline const T &QFutureInterface::resultReference(int index) const +{ + QMutexLocker lock(mutex()); + return resultStore().resultAt(index).value(); +} + +template +inline const T *QFutureInterface::resultPointer(int index) const +{ + QMutexLocker lock(mutex()); + return resultStore().resultAt(index).pointer(); +} + +template +inline QList QFutureInterface::results() +{ + if (this->isCanceled()) { + exceptionStore().throwPossibleException(); + return QList(); + } + QFutureInterfaceBase::waitForResult(-1); + + QList res; + QMutexLocker lock(mutex()); + + QtPrivate::ResultIterator it = resultStore().begin(); + while (it != resultStore().end()) { + res.append(it.value()); + ++it; + } + + return res; +} + +template <> +class QFutureInterface : public QFutureInterfaceBase +{ +public: + QFutureInterface(State initialState = NoState) + : QFutureInterfaceBase(initialState) + { } + QFutureInterface(const QFutureInterface &other) + : QFutureInterfaceBase(other) + { } + + static QFutureInterface canceledResult() + { return QFutureInterface(State(Started | Finished | Canceled)); } + + QFutureInterface &operator=(const QFutureInterface &other) + { + QFutureInterfaceBase::operator=(other); + return *this; + } + + inline QFuture future(); // implemented in qfuture.h + + void reportResult(const void *, int) { } + void reportResults(const QVector &, int) { } + void reportFinished(const void * = 0) { QFutureInterfaceBase::reportFinished(); } +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_QFUTURE + +#endif // QFUTUREINTERFACE_H diff --git a/src/corelib/thread/qfutureinterface_p.h b/src/corelib/thread/qfutureinterface_p.h new file mode 100644 index 0000000000..4498cdfc4b --- /dev/null +++ b/src/corelib/thread/qfutureinterface_p.h @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREINTERFACE_P_H +#define QFUTUREINTERFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QFutureCallOutEvent : public QEvent +{ +public: + enum CallOutType { + Started, + Finished, + Canceled, + Paused, + Resumed, + Progress, + ProgressRange, + ResultsReady + }; + + QFutureCallOutEvent() + : QEvent(QEvent::FutureCallOut), callOutType(CallOutType(0)), index1(-1), index2(-1) + { } + explicit QFutureCallOutEvent(CallOutType callOutType, int index1 = -1) + : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(-1) + { } + QFutureCallOutEvent(CallOutType callOutType, int index1, int index2) + : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(index2) + { } + + QFutureCallOutEvent(CallOutType callOutType, int index1, const QString &text) + : QEvent(QEvent::FutureCallOut), + callOutType(callOutType), + index1(index1), + index2(-1), + text(text) + { } + + CallOutType callOutType; + int index1; + int index2; + QString text; + + QFutureCallOutEvent *clone() const + { + return new QFutureCallOutEvent(callOutType, index1, index2, text); + } + +private: + QFutureCallOutEvent(CallOutType callOutType, + int index1, + int index2, + const QString &text) + : QEvent(QEvent::FutureCallOut), + callOutType(callOutType), + index1(index1), + index2(index2), + text(text) + { } +}; + +class QFutureCallOutInterface +{ +public: + virtual ~QFutureCallOutInterface() {} + virtual void postCallOutEvent(const QFutureCallOutEvent &) = 0; + virtual void callOutInterfaceDisconnected() = 0; +}; + +class Q_CORE_EXPORT QFutureInterfaceBasePrivate // ### temporary +{ +public: + QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState); + + QAtomicInt refCount; + mutable QMutex m_mutex; + QWaitCondition waitCondition; + QList outputConnections; + int m_progressValue; + int m_progressMinimum; + int m_progressMaximum; + QFutureInterfaceBase::State state; + QElapsedTimer progressTime; + QWaitCondition pausedWaitCondition; + int pendingResults; + QtPrivate::ResultStoreBase m_results; + bool manualProgress; + int m_expectedResultCount; + QtPrivate::ExceptionStore m_exceptionStore; + QString m_progressText; + QRunnable *runnable; + + // Internal functions that does not change the mutex state. + // The mutex must be locked when calling these. + int internal_resultCount() const; + bool internal_isResultReadyAt(int index) const; + bool internal_waitForNextResult(); + bool internal_updateProgress(int progress, const QString &progressText = QString()); + void internal_setThrottled(bool enable); + void sendCallOut(const QFutureCallOutEvent &callOut); + void sendCallOuts(const QFutureCallOutEvent &callOut1, const QFutureCallOutEvent &callOut2); + void connectOutputInterface(QFutureCallOutInterface *iface); + void disconnectOutputInterface(QFutureCallOutInterface *iface); + + void setState(QFutureInterfaceBase::State state); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index d9468cc3a4..1accffcdfe 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -12,6 +12,8 @@ HEADERS += thread/qmutex.h \ thread/qatomic.h \ thread/qexception.h \ thread/qresultstore.h \ + thread/qfuture.h \ + thread/qfutureinterface.h \ thread/qbasicatomic.h \ thread/qgenericatomic.h \ thread/qoldbasicatomic.h @@ -19,6 +21,7 @@ HEADERS += thread/qmutex.h \ # private headers HEADERS += thread/qmutex_p.h \ thread/qmutexpool_p.h \ + thread/qfutureinterface_p.h \ thread/qorderedmutexlocker_p.h \ thread/qreadwritelock_p.h \ thread/qthread_p.h \ @@ -27,6 +30,7 @@ HEADERS += thread/qmutex_p.h \ SOURCES += thread/qatomic.cpp \ thread/qexception.cpp \ thread/qresultstore.cpp \ + thread/qfutureinterface.cpp \ thread/qmutex.cpp \ thread/qreadwritelock.cpp \ thread/qrunnable.cpp \ -- cgit v1.2.3