diff options
author | axis <qt-info@nokia.com> | 2009-04-24 11:34:15 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2009-04-24 11:34:15 (GMT) |
commit | 8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76 (patch) | |
tree | a17e1a767a89542ab59907462206d7dcf2e504b2 /src/corelib/concurrent | |
download | Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.zip Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.gz Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.bz2 |
Long live Qt for S60!
Diffstat (limited to 'src/corelib/concurrent')
38 files changed, 11525 insertions, 0 deletions
diff --git a/src/corelib/concurrent/concurrent.pri b/src/corelib/concurrent/concurrent.pri new file mode 100644 index 0000000..9402971 --- /dev/null +++ b/src/corelib/concurrent/concurrent.pri @@ -0,0 +1,42 @@ +SOURCES += \ + concurrent/qfuture.cpp \ + concurrent/qfutureinterface.cpp \ + concurrent/qfuturesynchronizer.cpp \ + concurrent/qfuturewatcher.cpp \ + concurrent/qrunnable.cpp \ + concurrent/qtconcurrentfilter.cpp \ + concurrent/qtconcurrentmap.cpp \ + concurrent/qtconcurrentresultstore.cpp \ + concurrent/qtconcurrentthreadengine.cpp \ + concurrent/qtconcurrentiteratekernel.cpp \ + concurrent/qtconcurrentexception.cpp \ + concurrent/qthreadpool.cpp + +HEADERS += \ + concurrent/qfuture.h \ + concurrent/qfutureinterface.h \ + concurrent/qfuturesynchronizer.h \ + concurrent/qfuturewatcher.h \ + concurrent/qrunnable.h \ + concurrent/qtconcurrentcompilertest.h \ + concurrent/qtconcurrentexception.h \ + concurrent/qtconcurrentfilter.h \ + concurrent/qtconcurrentfilterkernel.h \ + concurrent/qtconcurrentfunctionwrappers.h \ + concurrent/qtconcurrentiteratekernel.h \ + concurrent/qtconcurrentmap.h \ + concurrent/qtconcurrentmapkernel.h \ + concurrent/qtconcurrentmedian.h \ + concurrent/qtconcurrentreducekernel.h \ + concurrent/qtconcurrentresultstore.h \ + concurrent/qtconcurrentrun.h \ + concurrent/qtconcurrentrunbase.h \ + concurrent/qtconcurrentstoredfunctioncall.h \ + concurrent/qtconcurrentthreadengine.h \ + concurrent/qthreadpool.h + +# private headers +HEADERS += \ + concurrent/qfutureinterface_p.h \ + concurrent/qfuturewatcher_p.h \ + concurrent/qthreadpool_p.h diff --git a/src/corelib/concurrent/qfuture.cpp b/src/corelib/concurrent/qfuture.cpp new file mode 100644 index 0000000..1840fab --- /dev/null +++ b/src/corelib/concurrent/qfuture.cpp @@ -0,0 +1,695 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! \class QFuture + \threadsafe + \brief The QFuture class represents the result of an asynchronous computation. + \since 4.4 + + To start a computation, use one of the APIs in the + \l {threads.html#qtconcurrent-intro}{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<void> is specialized to not contain any of the result fetching + functions. Any QFuture<T> can be assigned or copied into a QFuture<void> + 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, {threads.html#qtconcurrent-intro}{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<T> *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<T> 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 doc/src/snippets/code/src_corelib_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\<T\> allows you to iterate over a QFuture\<T\>. 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 doc/src/snippets/code/src_corelib_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. + + \img javaiterators1.png + + Here's how to iterate over the elements in reverse order: + + \snippet doc/src/snippets/code/src_corelib_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<T> &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<T> &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/concurrent/qfuture.h b/src/corelib/concurrent/qfuture.h new file mode 100644 index 0000000..da24db7 --- /dev/null +++ b/src/corelib/concurrent/qfuture.h @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTURE_H +#define QFUTURE_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_QFUTURE + +#include <QtCore/qfutureinterface.h> +#include <QtCore/qstring.h> +#include <QtCore/qtconcurrentcompilertest.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template <typename T> +class QFutureWatcher; +template <> +class QFutureWatcher<void>; + +template <typename T> +class QFuture +{ +public: + QFuture() + : d(QFutureInterface<T>::canceledResult()) + { } + explicit QFuture(QFutureInterface<T> *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<T> results() const { return d.results(); } + + class const_iterator + { + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef ptrdiff_t 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<T>; + +public: // Warning: the d pointer is not documented and is considered private. + mutable QFutureInterface<T> d; +}; + +template <typename T> +inline QFuture<T> &QFuture<T>::operator=(const QFuture<T> &other) +{ + d = other.d; + return *this; +} + +template <typename T> +inline T QFuture<T>::result() const +{ + d.waitForResult(0); + return d.resultReference(0); +} + +template <typename T> +inline T QFuture<T>::resultAt(int index) const +{ + d.waitForResult(index); + return d.resultReference(index); +} + +template <typename T> +inline QFuture<T> QFutureInterface<T>::future() +{ + return QFuture<T>(this); +} + +Q_DECLARE_SEQUENTIAL_ITERATOR(Future) + +template <> +class QFuture<void> +{ +public: + QFuture() + : d(QFutureInterface<void>::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); } + +#ifndef QT_NO_MEMBER_TEMPLATES + template <typename T> + QFuture(const QFuture<T> &other) + : d(other.d) + { } + + template <typename T> + QFuture<void> &operator=(const QFuture<T> &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<void>; + +#ifdef QFUTURE_TEST +public: +#endif + mutable QFutureInterfaceBase d; +}; + +inline QFuture<void> &QFuture<void>::operator=(const QFuture<void> &other) +{ + d = other.d; + return *this; +} + +inline QFuture<void> QFutureInterface<void>::future() +{ + return QFuture<void>(this); +} + +template <typename T> +QFuture<void> qToVoidFuture(const QFuture<T> &future) +{ + return QFuture<void>(future.d); +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif // QFUTURE_H diff --git a/src/corelib/concurrent/qfutureinterface.cpp b/src/corelib/concurrent/qfutureinterface.cpp new file mode 100644 index 0000000..b7589b7 --- /dev/null +++ b/src/corelib/concurrent/qfutureinterface.cpp @@ -0,0 +1,564 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// qfutureinterface.h included from qfuture.h +#include "qfuture.h" + +#ifndef QT_NO_QFUTURE + +#include <QtCore/qatomic.h> +#include <QtCore/qthread.h> +#include <QtCore/qthreadpool.h> +#include <private/qthreadpool_p.h> + +#include "qfutureinterface_p.h" + +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.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 QtConcurrent::Exception &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; +} + +QtConcurrent::internal::ExceptionStore &QFutureInterfaceBase::exceptionStore() +{ + return d->m_exceptionStore; +} + +QtConcurrent::ResultStoreBase &QFutureInterfaceBase::resultStoreBase() +{ + return d->m_results; +} + +const QtConcurrent::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 == 1; +} + +QFutureInterfaceBasePrivate::QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState) + : refCount(1), m_progressValue(0), m_progressMinimum(0), m_progressMaximum(0), + state(initialState), progressTimeStarted(false), pendingResults(0), + manualProgress(false), m_expectedResultCount(0), runnable(0) +{ } + +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 (progressTimeStarted == true && m_progressValue != m_progressMaximum) // make sure the first and last steps are emitted. + if (progressTime.elapsed() < (1000 / MaxProgressEmitsPerSecond)) + return false; + + progressTime.start(); + progressTimeStarted = true; + 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)); + } + + QtConcurrent::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/corelib/concurrent/qfutureinterface.h b/src/corelib/concurrent/qfutureinterface.h new file mode 100644 index 0000000..85d03c9 --- /dev/null +++ b/src/corelib/concurrent/qfutureinterface.h @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREINTERFACE_H +#define QFUTUREINTERFACE_H + +#include <QtCore/qglobal.h> +#include <QtCore/qrunnable.h> + +#ifndef QT_NO_QFUTURE + +#include <QtCore/qmutex.h> +#include <QtCore/qtconcurrentexception.h> +#include <QtCore/qtconcurrentresultstore.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template <typename T> 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 QtConcurrent::Exception &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; + QtConcurrent::internal::ExceptionStore &exceptionStore(); + QtConcurrent::ResultStoreBase &resultStoreBase(); + const QtConcurrent::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 <typename T> +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) + { + QFutureInterfaceBase::operator=(other); + return *this; + } + + inline QFuture<T> 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<T> &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<T> results(); +private: + QtConcurrent::ResultStore<T> &resultStore() + { return static_cast<QtConcurrent::ResultStore<T> &>(resultStoreBase()); } + const QtConcurrent::ResultStore<T> &resultStore() const + { return static_cast<const QtConcurrent::ResultStore<T> &>(resultStoreBase()); } +}; + +template <typename T> +inline void QFutureInterface<T>::reportResult(const T *result, int index) +{ + QMutexLocker locker(mutex()); + if (this->queryState(Canceled) || this->queryState(Finished)) { + return; + } + + QtConcurrent::ResultStore<T> &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 <typename T> +inline void QFutureInterface<T>::reportResult(const T &result, int index) +{ + reportResult(&result, index); +} + +template <typename T> +inline void QFutureInterface<T>::reportResults(const QVector<T> &_results, int beginIndex, int count) +{ + QMutexLocker locker(mutex()); + if (this->queryState(Canceled) || this->queryState(Finished)) { + return; + } + + QtConcurrent::ResultStore<T> &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 <typename T> +inline void QFutureInterface<T>::reportFinished(const T *result) +{ + if (result) + reportResult(result); + QFutureInterfaceBase::reportFinished(); +} + +template <typename T> +inline const T &QFutureInterface<T>::resultReference(int index) const +{ + QMutexLocker lock(mutex()); + return resultStore().resultAt(index).value(); +} + +template <typename T> +inline const T *QFutureInterface<T>::resultPointer(int index) const +{ + QMutexLocker lock(mutex()); + return resultStore().resultAt(index).pointer(); +} + +template <typename T> +inline QList<T> QFutureInterface<T>::results() +{ + if (this->isCanceled()) { + exceptionStore().throwPossibleException(); + return QList<T>(); + } + QFutureInterfaceBase::waitForResult(-1); + + QList<T> res; + QMutexLocker lock(mutex()); + + QtConcurrent::ResultIterator<T> it = resultStore().begin(); + while (it != resultStore().end()) { + res.append(it.value()); + ++it; + } + + return res; +} + +template <> +class QFutureInterface<void> : public QFutureInterfaceBase +{ +public: + QFutureInterface<void>(State initialState = NoState) + : QFutureInterfaceBase(initialState) + { } + QFutureInterface<void>(const QFutureInterface<void> &other) + : QFutureInterfaceBase(other) + { } + + static QFutureInterface<void> canceledResult() + { return QFutureInterface(State(Started | Finished | Canceled)); } + + QFutureInterface<void> &operator=(const QFutureInterface<void> &other) + { + QFutureInterfaceBase::operator=(other); + return *this; + } + + inline QFuture<void> future(); // implemented in qfuture.h + + void reportResult(const void *, int) { } + void reportResults(const QVector<void> &, int) { } + void reportFinished(void * = 0) { QFutureInterfaceBase::reportFinished(); } +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif // QFUTUREINTERFACE_H diff --git a/src/corelib/concurrent/qfutureinterface_p.h b/src/corelib/concurrent/qfutureinterface_p.h new file mode 100644 index 0000000..719d7a1 --- /dev/null +++ b/src/corelib/concurrent/qfutureinterface_p.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $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 <QtCore/qdatetime.h> +#include <QtCore/qcoreevent.h> +#include <QtCore/qlist.h> +#include <QtCore/qwaitcondition.h> +#include <QtCore/qrunnable.h> + +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) + { } + 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<QFutureCallOutInterface *> outputConnections; + int m_progressValue; + int m_progressMinimum; + int m_progressMaximum; + QFutureInterfaceBase::State state; + QTime progressTime; + bool progressTimeStarted; + QWaitCondition pausedWaitCondition; + int pendingResults; + QtConcurrent::ResultStoreBase m_results; + bool manualProgress; + int m_expectedResultCount; + QtConcurrent::internal::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/concurrent/qfuturesynchronizer.cpp b/src/corelib/concurrent/qfuturesynchronizer.cpp new file mode 100644 index 0000000..a0e88f3 --- /dev/null +++ b/src/corelib/concurrent/qfuturesynchronizer.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! \class QFutureSynchronizer + \since 4.4 + + \brief The QFutureSynchronizer class is a convenience class that simplifies + QFuture synchronization. + + QFutureSynchronizer is a template class that simplifies synchronization of + one or more QFuture objects. Futures are added using the addFuture() or + setFuture() functions. The futures() function returns a list of futures. + Use clearFutures() to remove all futures from the QFutureSynchronizer. + + The waitForFinished() function waits for all futures to finish. + The destructor of QFutureSynchronizer calls waitForFinished(), providing + an easy way to ensure that all futures have finished before returning from + a function: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qfuturesynchronizer.cpp 0 + + The behavior of waitForFinished() can be changed using the + setCancelOnWait() function. Calling setCancelOnWait(true) will cause + waitForFinished() to cancel all futures before waiting for them to finish. + You can query the status of the cancel-on-wait feature using the + cancelOnWait() function. + + \sa QFuture, QFutureWatcher, {threads.html#qtconcurrent-intro}{Qt Concurrent} +*/ + +/*! + \fn QFutureSynchronizer::QFutureSynchronizer() + + Constructs a QFutureSynchronizer. +*/ + +/*! + \fn QFutureSynchronizer::QFutureSynchronizer(const QFuture<T> &future) + + Constructs a QFutureSynchronizer and begins watching \a future by calling + addFuture(). + + \sa addFuture() +*/ + +/*! + \fn QFutureSynchronizer::~QFutureSynchronizer() + + Calls waitForFinished() function to ensure that all futures have finished + before destroying this QFutureSynchronizer. + + \sa waitForFinished() +*/ + +/*! + \fn void QFutureSynchronizer::setFuture(const QFuture<T> &future) + + Sets \a future to be the only future managed by this QFutureSynchronizer. + This is a convenience function that calls waitForFinished(), + then clearFutures(), and finally passes \a future to addFuture(). + + \sa addFuture(), waitForFinished(), clearFutures() +*/ + +/*! + \fn void QFutureSynchronizer::addFuture(const QFuture<T> &future) + + Adds \a future to the list of managed futures. + + \sa futures() +*/ + +/*! + \fn void QFutureSynchronizer::waitForFinished() + + Waits for all futures to finish. If cancelOnWait() returns true, each + future is canceled before waiting for them to finish. + + \sa cancelOnWait(), setCancelOnWait() +*/ + +/*! + \fn void QFutureSynchronizer::clearFutures() + + Removes all managed futures from this QFutureSynchronizer. + + \sa addFuture(), setFuture() +*/ + +/*! + \fn QList<QFuture<T> > QFutureSynchronizer::futures() const + + Returns a list of all managed futures. + + \sa addFuture(), setFuture() +*/ + +/*! + \fn void QFutureSynchronizer::setCancelOnWait(bool enabled) + + Enables or disables the cancel-on-wait feature based on the \a enabled + argument. If \a enabled is true, the waitForFinished() function will cancel + all futures before waiting for them to finish. + + \sa waitForFinished() +*/ + +/*! + \fn bool QFutureSynchronizer::cancelOnWait() const + + Returns true if the cancel-on-wait feature is enabled; otherwise returns + false. If cancel-on-wait is enabled, the waitForFinished() function will + cancel all futures before waiting for them to finish. + + \sa waitForFinished() +*/ diff --git a/src/corelib/concurrent/qfuturesynchronizer.h b/src/corelib/concurrent/qfuturesynchronizer.h new file mode 100644 index 0000000..daf65b9 --- /dev/null +++ b/src/corelib/concurrent/qfuturesynchronizer.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTRUESYNCHRONIZER_H +#define QFUTRUESYNCHRONIZER_H + +#include <QtCore/qfuture.h> + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template <typename T> +class QFutureSynchronizer +{ + Q_DISABLE_COPY(QFutureSynchronizer) + +public: + QFutureSynchronizer() : m_cancelOnWait(false) { } + explicit QFutureSynchronizer(const QFuture<T> &future) + : m_cancelOnWait(false) + { addFuture(future); } + ~QFutureSynchronizer() { waitForFinished(); } + + void setFuture(const QFuture<T> &future) + { + waitForFinished(); + m_futures.clear(); + addFuture(future); + } + + void addFuture(const QFuture<T> &future) + { + m_futures.append(future); + } + + void waitForFinished() + { + if (m_cancelOnWait) { + for (int i = 0; i < m_futures.count(); ++i) { + m_futures[i].cancel(); + } + } + + for (int i = 0; i < m_futures.count(); ++i) { + m_futures[i].waitForFinished(); + } + } + + void clearFutures() + { + m_futures.clear(); + } + + QList<QFuture<T> > futures() const + { + return m_futures; + } + + void setCancelOnWait(bool enabled) + { + m_cancelOnWait = enabled; + } + + bool cancelOnWait() const + { + return m_cancelOnWait; + } + +protected: + QList<QFuture<T> > m_futures; + bool m_cancelOnWait; +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif // QFUTRUESYNCHRONIZER_H diff --git a/src/corelib/concurrent/qfuturewatcher.cpp b/src/corelib/concurrent/qfuturewatcher.cpp new file mode 100644 index 0000000..ea35e9e --- /dev/null +++ b/src/corelib/concurrent/qfuturewatcher.cpp @@ -0,0 +1,574 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfuturewatcher.h" + +#ifndef QT_NO_QFUTURE + +#include <QEvent> +#include <QCoreApplication> +#include <QThread> + +#include "qfuturewatcher_p.h" + +QT_BEGIN_NAMESPACE + +/*! \class QFutureWatcher + \reentrant + \since 4.4 + + \brief The QFutureWatcher class allows monitoring a QFuture using signals + and slots. + + QFutureWatcher provides information and notifications about a QFuture. Use + the setFuture() function to start watching a particular QFuture. The + future() function returns the future set with setFuture(). + + For convenience, several of QFuture's functions are also available in + QFutureWatcher: progressValue(), progressMinimum(), progressMaximum(), + progressText(), isStarted(), isFinished(), isRunning(), isCanceled(), + isPaused(), waitForFinished(), result(), and resultAt(). The cancel(), + setPaused(), pause(), resume(), and togglePaused() functions are slots in + QFutureWatcher. + + Status changes are reported via the started(), finished(), canceled(), + paused(), resumed(), resultReadyAt(), and resultsReadyAt() signals. + Progress information is provided from the progressRangeChanged(), + void progressValueChanged(), and progressTextChanged() signals. + + Throttling control is provided by the setPendingResultsLimit() function. + When the number of pending resultReadyAt() or resultsReadyAt() signals + exceeds the limit, the computation represented by the future will be + throttled automatically. The computation will resume once the number of + pending signals drops below the limit. + + Example: Starting a computation and getting a slot callback when it's + finished: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qfuturewatcher.cpp 0 + + 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. + + QFutureWatcher<void> is specialized to not contain any of the result + fetching functions. Any QFuture<T> can be watched by a + QFutureWatcher<void> as well. This is useful if only status or progress + information is needed; not the actual result data. + + \sa QFuture, {threads.html#qtconcurrent-intro}{Qt Concurrent} +*/ + +/*! \fn QFutureWatcher::QFutureWatcher(QObject *parent) + + Constructs a new QFutureWatcher with the given \a parent. +*/ +QFutureWatcherBase::QFutureWatcherBase(QObject *parent) + :QObject(*new QFutureWatcherBasePrivate, parent) +{ } + +/*! \fn QFutureWatcher::~QFutureWatcher() + + Destroys the QFutureWatcher. +*/ + +/*! \fn void QFutureWatcher::cancel() + + Cancels the asynchronous computation represented by the future(). Note that + the cancelation is asynchronous. Use waitForFinished() after calling + cancel() when you need synchronous cancelation. + + Currently available results may still be accessed on a canceled QFuture, + but new results will \e not become available after calling this function. + Also, this QFutureWatcher will not deliver progress and result ready + signals once canceled. This includes the progressValueChanged(), + progressRangeChanged(), progressTextChanged(), resultReadyAt(), and + resultsReadyAt() signals. + + Be aware that not all asynchronous computations can be canceled. For + example, the QFuture returned by QtConcurrent::run() cannot be canceled; + but the QFuture returned by QtConcurrent::mappedReduced() can. +*/ +void QFutureWatcherBase::cancel() +{ + futureInterface().cancel(); +} + +/*! \fn void QFutureWatcher::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. This QFutureWatcher will stop delivering progress + and result ready signals while the future is paused. Signal delivery will + continue once the computation 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 + QFuture returned by QtConcurrent::run() cannot be paused; but the QFuture + returned by QtConcurrent::mappedReduced() can. + + \sa pause(), resume(), togglePaused() +*/ +void QFutureWatcherBase::setPaused(bool paused) +{ + futureInterface().setPaused(paused); +} + +/*! \fn void QFutureWatcher::pause() + + Pauses the asynchronous computation represented by the future(). This is a + convenience method that simply calls setPaused(true). + + \sa resume() +*/ +void QFutureWatcherBase::pause() +{ + futureInterface().setPaused(true); +} + +/*! \fn void QFutureWatcher::resume() + + Resumes the asynchronous computation represented by the future(). This is + a convenience method that simply calls setPaused(false). + + \sa pause() +*/ +void QFutureWatcherBase::resume() +{ + futureInterface().setPaused(false); +} + +/*! \fn void QFutureWatcher::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 becomes paused. This is a convenience + method for calling setPaused(!isPaused()). + + \sa setPaused(), pause(), resume() +*/ +void QFutureWatcherBase::togglePaused() +{ + futureInterface().togglePaused(); +} + +/*! \fn int QFutureWatcher::progressValue() const + + Returns the current progress value, which is between the progressMinimum() + and progressMaximum(). + + \sa progressMinimum(), progressMaximum() +*/ +int QFutureWatcherBase::progressValue() const +{ + return futureInterface().progressValue(); +} + +/*! \fn int QFutureWatcher::progressMinimum() const + + Returns the minimum progressValue(). + + \sa progressValue(), progressMaximum() +*/ +int QFutureWatcherBase::progressMinimum() const +{ + return futureInterface().progressMinimum(); +} + +/*! \fn int QFutureWatcher::progressMaximum() const + + Returns the maximum progressValue(). + + \sa progressValue(), progressMinimum() +*/ +int QFutureWatcherBase::progressMaximum() const +{ + return futureInterface().progressMaximum(); +} + +/*! \fn QString QFutureWatcher::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. +*/ +QString QFutureWatcherBase::progressText() const +{ + return futureInterface().progressText(); +} + +/*! \fn bool QFutureWatcher::isStarted() const + + Returns true if the asynchronous computation represented by the future() + has been started; otherwise returns false. +*/ +bool QFutureWatcherBase::isStarted() const +{ + return futureInterface().queryState(QFutureInterfaceBase::Started); +} + +/*! \fn bool QFutureWatcher::isFinished() const + + Returns true if the asynchronous computation represented by the future() + has finished; otherwise returns false. +*/ +bool QFutureWatcherBase::isFinished() const +{ + Q_D(const QFutureWatcherBase); + return d->finished; +} + +/*! \fn bool QFutureWatcher::isRunning() const + + Returns true if the asynchronous computation represented by the future() + is currently running; otherwise returns false. +*/ +bool QFutureWatcherBase::isRunning() const +{ + return futureInterface().queryState(QFutureInterfaceBase::Running); +} + +/*! \fn bool QFutureWatcher::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. +*/ +bool QFutureWatcherBase::isCanceled() const +{ + return futureInterface().queryState(QFutureInterfaceBase::Canceled); +} + +/*! \fn bool QFutureWatcher::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() +*/ +bool QFutureWatcherBase::isPaused() const +{ + return futureInterface().queryState(QFutureInterfaceBase::Paused); +} + +/*! \fn void QFutureWatcher::waitForFinished() + + Waits for the asynchronous computation to finish (including cancel()ed + computations). +*/ +void QFutureWatcherBase::waitForFinished() +{ + futureInterface().waitForFinished(); +} + +/*! \fn void QFutureWatcher::setPendingResultsLimit(int limit) + + The setPendingResultsLimit() provides throttling control. When the number + of pending resultReadyAt() or resultsReadyAt() signals exceeds the + \a limit, the computation represented by the future will be throttled + automatically. The computation will resume once the number of pending + signals drops below the \a limit. +*/ + +bool QFutureWatcherBase::event(QEvent *event) +{ + Q_D(QFutureWatcherBase); + if (event->type() == QEvent::FutureCallOut) { + QFutureCallOutEvent *callOutEvent = static_cast<QFutureCallOutEvent *>(event); + + if (futureInterface().isPaused()) { + d->pendingCallOutEvents.append(callOutEvent->clone()); + return true; + } + + if (callOutEvent->callOutType == QFutureCallOutEvent::Resumed + && !d->pendingCallOutEvents.isEmpty()) { + // send the resume + d->sendCallOutEvent(callOutEvent); + + // next send all pending call outs + for (int i = 0; i < d->pendingCallOutEvents.count(); ++i) + d->sendCallOutEvent(d->pendingCallOutEvents.at(i)); + qDeleteAll(d->pendingCallOutEvents); + d->pendingCallOutEvents.clear(); + } else { + d->sendCallOutEvent(callOutEvent); + } + return true; + } + return QObject::event(event); +} + +void QFutureWatcherBase::setPendingResultsLimit(int limit) +{ + Q_D(QFutureWatcherBase); + d->maximumPendingResultsReady = limit; +} + +void QFutureWatcherBase::connectNotify(const char * signal) +{ + Q_D(QFutureWatcherBase); + if (qstrcmp(signal, SIGNAL(resultReadyAt(int))) == 0) + d->resultAtConnected.ref(); +} + +void QFutureWatcherBase::disconnectNotify(const char * signal) +{ + Q_D(QFutureWatcherBase); + if (qstrcmp(signal, SIGNAL(resultReadyAt(int))) == 0) + d->resultAtConnected.deref(); +} + +/*! + \internal +*/ +QFutureWatcherBasePrivate::QFutureWatcherBasePrivate() + : maximumPendingResultsReady(QThread::idealThreadCount() * 2), + resultAtConnected(0) +{ } + +/*! + \internal +*/ +void QFutureWatcherBase::connectOutputInterface() +{ + futureInterface().d->connectOutputInterface(d_func()); +} + +/*! + \internal +*/ +void QFutureWatcherBase::disconnectOutputInterface(bool pendingAssignment) +{ + if (pendingAssignment) { + Q_D(QFutureWatcherBase); + d->pendingResultsReady = 0; + qDeleteAll(d->pendingCallOutEvents); + d->pendingCallOutEvents.clear(); + d->finished = false; + } + + futureInterface().d->disconnectOutputInterface(d_func()); +} + +void QFutureWatcherBasePrivate::postCallOutEvent(const QFutureCallOutEvent &callOutEvent) +{ + Q_Q(QFutureWatcherBase); + + if (callOutEvent.callOutType == QFutureCallOutEvent::ResultsReady) { + if (pendingResultsReady.fetchAndAddRelaxed(1) >= maximumPendingResultsReady) + q->futureInterface().d->internal_setThrottled(true); + } + + QCoreApplication::postEvent(q, callOutEvent.clone()); +} + +void QFutureWatcherBasePrivate::callOutInterfaceDisconnected() +{ + QCoreApplication::removePostedEvents(q_func(), QEvent::FutureCallOut); +} + +void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event) +{ + Q_Q(QFutureWatcherBase); + + switch (event->callOutType) { + case QFutureCallOutEvent::Started: + emit q->started(); + break; + case QFutureCallOutEvent::Finished: + finished = true; + emit q->finished(); + break; + case QFutureCallOutEvent::Canceled: + pendingResultsReady = 0; + emit q->canceled(); + break; + case QFutureCallOutEvent::Paused: + if (q->futureInterface().isCanceled()) + break; + emit q->paused(); + break; + case QFutureCallOutEvent::Resumed: + if (q->futureInterface().isCanceled()) + break; + emit q->resumed(); + break; + case QFutureCallOutEvent::ResultsReady: { + if (q->futureInterface().isCanceled()) + break; + + if (pendingResultsReady.fetchAndAddRelaxed(-1) <= maximumPendingResultsReady) + q->futureInterface().setThrottled(false); + + const int beginIndex = event->index1; + const int endIndex = event->index2; + + emit q->resultsReadyAt(beginIndex, endIndex); + + if (int(resultAtConnected) <= 0) + break; + + for (int i = beginIndex; i < endIndex; ++i) + emit q->resultReadyAt(i); + + } break; + case QFutureCallOutEvent::Progress: + if (q->futureInterface().isCanceled()) + break; + + emit q->progressValueChanged(event->index1); + if (event->text != QString()) // ### + q->progressTextChanged(event->text); + break; + case QFutureCallOutEvent::ProgressRange: + emit q->progressRangeChanged(event->index1, event->index2); + break; + default: break; + } +} + + +/*! \fn const T &QFutureWatcher::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() +*/ + +/*! \fn const T &QFutureWatcher::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() +*/ + +/*! \fn void QFutureWatcher::setFuture(const QFuture<T> &future) + + Starts watching the given \a future. +*/ + +/*! \fn QFuture<T> QFutureWatcher::future() const + + Returns the watched future. +*/ + +/*! \fn void QFutureWatcher::started() + + This signal is emitted when this QFutureWatcher starts watching the future + set with setFuture(). +*/ + +/*! + \fn void QFutureWatcher::finished() + This signal is emitted when the watched future finishes. +*/ + +/*! + \fn void QFutureWatcher::canceled() + This signal is emitted if the watched future is canceled. +*/ + +/*! \fn void QFutureWatcher::paused() + This signal is emitted when the watched future is paused. +*/ + +/*! \fn void QFutureWatcher::resumed() + This signal is emitted when the watched future is resumed. +*/ + +/*! + \fn void QFutureWatcher::progressRangeChanged(int minimum, int maximum) + + The progress range for the watched future has changed to \a minimum and + \a maximum +*/ + +/*! + \fn void QFutureWatcher::progressValueChanged(int progressValue) + + This signal is emitted when the watched future reports progress, + \a progressValue gives the current progress. In order to avoid overloading + the GUI event loop, QFutureWatcher limits the progress signal emission + rate. This means that listeners connected to this slot might not get all + progress reports the future makes. The last progress update (where + \a progressValue equals the maximum value) will always be delivered. +*/ + +/*! \fn void QFutureWatcher::progressTextChanged(const QString &progressText) + + This signal is emitted when the watched future reports textual progress + information, \a progressText. +*/ + +/*! + \fn void QFutureWatcher::resultReadyAt(int index) + + This signal is emitted when the watched future reports a ready result at + \a index. If the future reports multiple results, the index will indicate + which one it is. Results can be reported out-of-order. To get the result, + call future().result(index); +*/ + +/*! + \fn void QFutureWatcher::resultsReadyAt(int beginIndex, int endIndex); + + This signal is emitted when the watched future reports ready results. + The results are indexed from \a beginIndex to \a endIndex. + +*/ + +QT_END_NAMESPACE + +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qfuturewatcher.h b/src/corelib/concurrent/qfuturewatcher.h new file mode 100644 index 0000000..75dfd3d --- /dev/null +++ b/src/corelib/concurrent/qfuturewatcher.h @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREWATCHER_H +#define QFUTUREWATCHER_H + +#include <QtCore/qfuture.h> + +#ifndef QT_NO_QFUTURE + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEvent; + +class QFutureWatcherBasePrivate; +class Q_CORE_EXPORT QFutureWatcherBase : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QFutureWatcherBase) + +public: + QFutureWatcherBase(QObject *parent = 0); + + int progressValue() const; + int progressMinimum() const; + int progressMaximum() const; + QString progressText() const; + + bool isStarted() const; + bool isFinished() const; + bool isRunning() const; + bool isCanceled() const; + bool isPaused() const; + + void waitForFinished(); + + void setPendingResultsLimit(int limit); + + bool event(QEvent *event); + +Q_SIGNALS: + void started(); + void finished(); + void canceled(); + void paused(); + void resumed(); + void resultReadyAt(int resultIndex); + void resultsReadyAt(int beginIndex, int endIndex); + void progressRangeChanged(int minimum, int maximum); + void progressValueChanged(int progressValue); + void progressTextChanged(const QString &progressText); + +public Q_SLOTS: + void cancel(); + void setPaused(bool paused); + void pause(); + void resume(); + void togglePaused(); + +protected: + void connectNotify (const char * signal); + void disconnectNotify (const char * signal); + + // called from setFuture() implemented in template sub-classes + void connectOutputInterface(); + void disconnectOutputInterface(bool pendingAssignment = false); + +private: + // implemented in the template sub-classes + virtual const QFutureInterfaceBase &futureInterface() const = 0; + virtual QFutureInterfaceBase &futureInterface() = 0; +}; + +template <typename T> +class QFutureWatcher : public QFutureWatcherBase +{ +public: + QFutureWatcher(QObject *_parent = 0) + : QFutureWatcherBase(_parent) + { } + ~QFutureWatcher() + { disconnectOutputInterface(); } + + void setFuture(const QFuture<T> &future); + QFuture<T> future() const + { return m_future; } + + T result() const { return m_future.result(); } + T resultAt(int index) const { return m_future.resultAt(index); } + +#ifdef qdoc + int progressValue() const; + int progressMinimum() const; + int progressMaximum() const; + QString progressText() const; + + bool isStarted() const; + bool isFinished() const; + bool isRunning() const; + bool isCanceled() const; + bool isPaused() const; + + void waitForFinished(); + + void setPendingResultsLimit(int limit); + +Q_SIGNALS: + void started(); + void finished(); + void canceled(); + void paused(); + void resumed(); + void resultReadyAt(int resultIndex); + void resultsReadyAt(int beginIndex, int endIndex); + void progressRangeChanged(int minimum, int maximum); + void progressValueChanged(int progressValue); + void progressTextChanged(const QString &progressText); + +public Q_SLOTS: + void cancel(); + void setPaused(bool paused); + void pause(); + void resume(); + void togglePaused(); +#endif + +private: + QFuture<T> m_future; + const QFutureInterfaceBase &futureInterface() const { return m_future.d; } + QFutureInterfaceBase &futureInterface() { return m_future.d; } +}; + +template <typename T> +Q_INLINE_TEMPLATE void QFutureWatcher<T>::setFuture(const QFuture<T> &_future) +{ + if (_future == m_future) + return; + + disconnectOutputInterface(true); + m_future = _future; + connectOutputInterface(); +} + +template <> +class QFutureWatcher<void> : public QFutureWatcherBase +{ +public: + QFutureWatcher(QObject *_parent = 0) + : QFutureWatcherBase(_parent) + { } + ~QFutureWatcher() + { disconnectOutputInterface(); } + + void setFuture(const QFuture<void> &future); + QFuture<void> future() const + { return m_future; } + +private: + QFuture<void> m_future; + const QFutureInterfaceBase &futureInterface() const { return m_future.d; } + QFutureInterfaceBase &futureInterface() { return m_future.d; } +}; + +Q_INLINE_TEMPLATE void QFutureWatcher<void>::setFuture(const QFuture<void> &_future) +{ + if (_future == m_future) + return; + + disconnectOutputInterface(true); + m_future = _future; + connectOutputInterface(); +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif // QFUTUREWATCHER_H diff --git a/src/corelib/concurrent/qfuturewatcher_p.h b/src/corelib/concurrent/qfuturewatcher_p.h new file mode 100644 index 0000000..324839d --- /dev/null +++ b/src/corelib/concurrent/qfuturewatcher_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREWATCHER_P_H +#define QFUTUREWATCHER_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 "qfutureinterface_p.h" +#include <QList> + +#ifndef QT_NO_QFUTURE + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QFutureWatcherBase; +class Q_CORE_EXPORT QFutureWatcherBasePrivate : public QObjectPrivate, + public QFutureCallOutInterface +{ + Q_DECLARE_PUBLIC(QFutureWatcherBase) + +public: + QFutureWatcherBasePrivate(); + + void postCallOutEvent(const QFutureCallOutEvent &callOutEvent); + void callOutInterfaceDisconnected(); + + void sendCallOutEvent(QFutureCallOutEvent *event); + + QList<QFutureCallOutEvent *> pendingCallOutEvents; + QAtomicInt pendingResultsReady; + int maximumPendingResultsReady; + + QAtomicInt resultAtConnected; + bool finished; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_QFUTURE +#endif diff --git a/src/corelib/concurrent/qrunnable.cpp b/src/corelib/concurrent/qrunnable.cpp new file mode 100644 index 0000000..a581a21 --- /dev/null +++ b/src/corelib/concurrent/qrunnable.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QRunnable + \since 4.4 + \brief The QRunnable class is the base class for all runnable objects. + + The QRunnable class is an interface for representing a task or + piece of code that needs to be executed, represented by your + reimplementation of the run() function. + + You can use QThreadPool to execute your code in a separate + thread. QThreadPool deletes the QRunnable automatically if + autoDelete() returns true (the default). Use setAutoDelete() to + change the auto-deletion flag. + + QThreadPool supports executing the same QRunnable more than once + by calling QThreadPool::tryStart(this) from within the run() function. + If autoDelete is enabled the QRunnable will be deleted when + the last thread exits the run function. Calling QThreadPool::start() + multiple times with the same QRunnable when autoDelete is enabled + creates a race condition and is not recommended. + + \sa QThreadPool +*/ + +/*! \fn QRunnable::run() + Implement this pure virtual function in your subclass. +*/ + +/*! \fn QRunnable::QRunnable() + Constructs a QRunnable. Auto-deletion is enabled by default. + + \sa autoDelete(), setAutoDelete() +*/ + +/*! \fn QRunnable::~QRunnable() + QRunnable virtual destructor. +*/ + +/*! \fn bool QRunnable::autoDelete() const + + Returns true is auto-deletion is enabled; false otherwise. + + If auto-deletion is enabled, QThreadPool will automatically delete + this runnable after calling run(); otherwise, ownership remains + with the application programmer. + + \sa setAutoDelete(), QThreadPool +*/ + +/*! \fn bool QRunnable::setAutoDelete(bool autoDelete) + + Enables auto-deletion if \a autoDelete is true; otherwise + auto-deletion is disabled. + + If auto-deletion is enabled, QThreadPool will automatically delete + this runnable after calling run(); otherwise, ownership remains + with the application programmer. + + Note that this flag must be set before calling + QThreadPool::start(). Calling this function after + QThreadPool::start() results in undefined behavior. + + \sa autoDelete(), QThreadPool +*/ diff --git a/src/corelib/concurrent/qrunnable.h b/src/corelib/concurrent/qrunnable.h new file mode 100644 index 0000000..1f480f4 --- /dev/null +++ b/src/corelib/concurrent/qrunnable.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRUNNABLE_H +#define QRUNNABLE_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QRunnable +{ + int ref; + + friend class QThreadPool; + friend class QThreadPoolPrivate; + friend class QThreadPoolThread; + +public: + virtual void run() = 0; + + QRunnable() : ref(0) { } + virtual ~QRunnable() { } + + bool autoDelete() const { return ref != -1; } + void setAutoDelete(bool _autoDelete) { ref = _autoDelete ? 0 : -1; } +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/corelib/concurrent/qtconcurrentcompilertest.h b/src/corelib/concurrent/qtconcurrentcompilertest.h new file mode 100644 index 0000000..763750a --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentcompilertest.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_COMPILERTEST_H +#define QTCONCURRENT_COMPILERTEST_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifdef Q_CC_MSVC +# if _MSC_VER < 1300 +# define QT_CONURRENT_NONSTANDARD_COMPILER +# endif +#endif + +#if defined (Q_CC_MSVC) && (_MSC_VER < 1300) +# define QT_TYPENAME +#else +# define QT_TYPENAME typename +#endif + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentexception.cpp b/src/corelib/concurrent/qtconcurrentexception.cpp new file mode 100644 index 0000000..cce1c31 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentexception.cpp @@ -0,0 +1,228 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtconcurrentexception.h" + +#ifndef QT_NO_QFUTURE +#ifndef QT_NO_EXCEPTIONS + +QT_BEGIN_NAMESPACE + +/*! + \class QtConcurrent::Exception + \brief The Exception class provides a base class for exceptions that can transferred across threads. + \since 4.4 + + Qt Concurrent supports throwing and catching exceptions across thread + boundaries, provided that the exception inherit from QtConcurrent::Exception + and implement two helper functions: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentexception.cpp 0 + + QtConcurrent::Exception subclasses must be thrown by value and + caught by reference: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentexception.cpp 1 + + If you throw an exception that is not a subclass of QtConcurrent::Exception, + the Qt Concurrent functions will throw a QtConcurrent::UnhandledException + in the receiver thread. + + When using QFuture, transferred exceptions willl be thrown when calling the following functions: + \list + \o QFuture::waitForFinished() + \o QFuture::result() + \o QFuture::resultAt() + \o QFuture::results() + \endlist +*/ + +/*! + \fn QtConcurrent::Exception::raise() const + In your QtConcurrent::Exception subclass, reimplement raise() like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentexception.cpp 2 +*/ + +/*! + \fn QtConcurrent::Exception::clone() const + In your QtConcurrent::Exception subclass, reimplement clone() like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentexception.cpp 3 +*/ + +/*! + \class QtConcurrent::UnhandledException + + \brief The UnhandledException class represents an unhandled exception in a worker thread. + \since 4.4 + + If a worker thread throws an exception that is not a subclass of QtConcurrent::Exception, + the Qt Concurrent functions will throw a QtConcurrent::UnhandledException + on the receiver thread side. + + Inheriting from this class is not supported. +*/ + +/*! + \fn QtConcurrent::UnhandledException::raise() const + \internal +*/ + +/*! + \fn QtConcurrent::UnhandledException::clone() const + \internal +*/ + +namespace QtConcurrent +{ + +void Exception::raise() const +{ + Exception e = *this; + throw e; +} + +Exception *Exception::clone() const +{ + return new Exception(*this); +} + +void UnhandledException::raise() const +{ + UnhandledException e = *this; + throw e; +} + +Exception *UnhandledException::clone() const +{ + return new UnhandledException(*this); +} + +#ifndef qdoc + +namespace internal { + +class Base +{ +public: + Base(Exception *exception) + : exception(exception), refCount(1), hasThrown(false) { } + ~Base() { delete exception; } + + Exception *exception; + QAtomicInt refCount; + bool hasThrown; +}; + +ExceptionHolder::ExceptionHolder(Exception *exception) +: base(new Base(exception)) {} + +ExceptionHolder::ExceptionHolder(const ExceptionHolder &other) +: base(other.base) +{ + base->refCount.ref(); +} + +void ExceptionHolder::operator=(const ExceptionHolder &other) +{ + if (base == other.base) + return; + + if (base->refCount.deref() == false) + delete base; + + base = other.base; + base->refCount.ref(); +} + +ExceptionHolder::~ExceptionHolder() +{ + if (base->refCount.deref() == 0) + delete base; +} + +Exception *ExceptionHolder::exception() const +{ + return base->exception; +} + +void ExceptionStore::setException(const Exception &e) +{ + if (hasException() == false) + exceptionHolder = ExceptionHolder(e.clone()); +} + +bool ExceptionStore::hasException() const +{ + return (exceptionHolder.exception() != 0); +} + +ExceptionHolder ExceptionStore::exception() +{ + return exceptionHolder; +} + +void ExceptionStore::throwPossibleException() +{ + /* On win32-g++, with GCC 3.4.2 std::uncaught_exception() isn't reliable. */ + if (hasException() +#ifndef Q_CC_MINGW + && std::uncaught_exception() == false +#endif + ) { + exceptionHolder.base->hasThrown = true; + exceptionHolder.exception()->raise(); + } +} + +bool ExceptionStore::hasThrown() const { return exceptionHolder.base->hasThrown; } + +} // namespace internal + +#endif //qdoc + +} // namespace QtConcurrent + +QT_END_NAMESPACE + +#endif // QT_NO_EXCEPTIONS +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qtconcurrentexception.h b/src/corelib/concurrent/qtconcurrentexception.h new file mode 100644 index 0000000..eaa63d8 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentexception.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_EXCEPTION_H +#define QTCONCURRENT_EXCEPTION_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_QFUTURE + +#include <QtCore/qatomic.h> + +#ifndef QT_NO_EXCEPTIONS +# include <exception> +#endif + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +namespace QtConcurrent +{ + +#ifndef QT_NO_EXCEPTIONS + +class Q_CORE_EXPORT Exception : public std::exception +{ +public: + virtual void raise() const; + virtual Exception *clone() const; +}; + +class Q_CORE_EXPORT UnhandledException : public Exception +{ +public: + void raise() const; + Exception *clone() const; +}; + +namespace internal { + +class Base; +class ExceptionHolder +{ +public: + ExceptionHolder(Exception *exception = 0); + ExceptionHolder(const ExceptionHolder &other); + void operator=(const ExceptionHolder &other); + ~ExceptionHolder(); + Exception *exception() const; + Base *base; +}; + +class Q_CORE_EXPORT ExceptionStore +{ +public: + void setException(const Exception &e); + bool hasException() const; + ExceptionHolder exception(); + void throwPossibleException(); + bool hasThrown() const; + ExceptionHolder exceptionHolder; +}; + +} // namespace internal + +#else // QT_NO_EXCEPTIONS + +namespace internal { + +class Q_CORE_EXPORT ExceptionStore +{ +public: + ExceptionStore() { } + inline void throwPossibleException() const {} +}; + +} // namespace internal + +#endif + +} // namespace QtConcurrent + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentfilter.cpp b/src/corelib/concurrent/qtconcurrentfilter.cpp new file mode 100644 index 0000000..4fbda82 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentfilter.cpp @@ -0,0 +1,330 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \headerfile <QtConcurrentFilter> + \title Concurrent Filter and Filter-Reduce + \ingroup threading + + \brief The <QtConcurrentFilter> header provides concurrent Filter and + Filter-Reduce. + + These functions are a part of the \l {threads.html#qtconcurrent-intro}{Qt Concurrent} framework. + + The QtConcurrent::filter(), QtConcurrent::filtered() and + QtConcurrent::filteredReduced() functions filter items in a sequence such + as a QList or a QVector in parallel. QtConcurrent::filter() modifies a + sequence in-place, QtConcurrent::filtered() returns a new sequence + containing the filtered content, and QtConcurrent::filteredReduced() + returns a single result. + + Each of the above functions have a blocking variant that returns the final + result instead of a QFuture. You use them in the same way as the + asynchronous variants. + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 6 + + Note that the result types above are not QFuture objects, but real result + types (in this case, QStringList and QSet<QString>). + + \section1 Concurrent Filter + + QtConcurrent::filtered() takes an input sequence and a filter function. + This filter function is then called for each item in the sequence, and a + new sequence containing the filtered values is returned. + + The filter function must be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 0 + + T must match the type stored in the sequence. The function returns true if + the item should be kept, false if it should be discarded. + + This example shows how to keep strings that are all lower-case from a + QStringList: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 1 + + The results of the filter are made available through QFuture. See the + QFuture and QFutureWatcher documentation for more information on how to + use QFuture in your applications. + + If you want to modify a sequence in-place, use QtConcurrent::filter(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 2 + + Since the sequence is modified in place, QtConcurrent::filter() does not + return any results via QFuture. However, you can still use QFuture and + QFutureWatcher to monitor the status of the filter. + + \section1 Concurrent Filter-Reduce + + QtConcurrent::filteredReduced() is similar to QtConcurrent::filtered(), + but instead of returing a sequence with the filtered results, the results + are combined into a single value using a reduce function. + + The reduce function must be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 3 + + T is the type of the final result, U is the type of items being filtered. + Note that the return value and return type of the reduce function are not + used. + + Call QtConcurrent::filteredReduced() like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 4 + + The reduce function will be called once for each result kept by the filter + function, and should merge the \e{intermediate} into the \e{result} + variable. QtConcurrent::filteredReduced() guarantees that only one thread + will call reduce at a time, so using a mutex to lock the result variable + is not neccesary. The QtConcurrent::ReduceOptions enum provides a way to + control the order in which the reduction is done. + + \section1 Additional API Features + + \section2 Using Iterators instead of Sequence + + Each of the above functions has a variant that takes an iterator range + instead of a sequence. You use them in the same way as the sequence + variants: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 5 + + + \section2 Using Member Functions + + QtConcurrent::filter(), QtConcurrent::filtered(), and + QtConcurrent::filteredReduced() accept pointers to member functions. + The member function class type must match the type stored in the sequence: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 7 + + Note that when using QtConcurrent::filteredReduced(), you can mix the use of + normal and member functions freely: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 8 + + \section2 Using Function Objects + + QtConcurrent::filter(), QtConcurrent::filtered(), and + QtConcurrent::filteredReduced() accept function objects, which can be used to + add state to a function call. The result_type typedef must define the + result type of the function call operator: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 13 + + \section2 Using Bound Function Arguments + + Note that Qt does not provide support for bound functions. This is + provided by 3rd party libraries like + \l{http://www.boost.org/libs/bind/bind.html}{Boost} or + \l{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf} + {C++ TR1 Library Extensions}. + + If you want to use a filter function takes more than one argument, you can + use boost::bind() or std::tr1::bind() to transform it onto a function that + takes one argument. + + As an example, we use QString::contains(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 9 + + QString::contains() takes 2 arguments (including the "this" pointer) and + can't be used with QtConcurrent::filtered() directly, because + QtConcurrent::filtered() expects a function that takes one argument. To + use QString::contains() with QtConcurrent::filtered() we have to provide a + value for the \e regexp argument: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 10 + + The return value from boost::bind() is a function object (functor) with + the following signature: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 11 + + This matches what QtConcurrent::filtered() expects, and the complete + example becomes: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 12 +*/ + +/*! + \fn QFuture<void> QtConcurrent::filter(Sequence &sequence, FilterFunction filterFunction) + \relates <QtConcurrentFilter> + + Calls \a filterFunction once for each item in \a sequence. If + \a filterFunction returns true, the item is kept in \a sequence; + otherwise, the item is removed from \a sequence. +*/ + +/*! + \fn QFuture<T> QtConcurrent::filtered(const Sequence &sequence, FilterFunction filterFunction) + \relates <QtConcurrentFilter> + + Calls \a filterFunction once for each item in \a sequence and returns a + new Sequence of kept items. If \a filterFunction returns true, a copy of + the item is put in the new Sequence. Otherwise, the item will \e not + appear in the new Sequence. +*/ + +/*! + \fn QFuture<T> QtConcurrent::filtered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction) + \relates <QtConcurrentFilter> + + Calls \a filterFunction once for each item from \a begin to \a end and + returns a new Sequence of kept items. If \a filterFunction returns true, a + copy of the item is put in the new Sequence. Otherwise, the item will + \e not appear in the new Sequence. +*/ + +/*! + \fn QFuture<T> QtConcurrent::filteredReduced(const Sequence &sequence, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + \relates <QtConcurrentFilter> + + Calls \a filterFunction once for each item in \a sequence. If + \a filterFunction returns true for an item, that item is then passed to + \a reduceFunction. In other words, the return value is the result of + \a reduceFunction for each item where \a filterFunction returns true. + + Note that while \a filterFunction is called concurrently, only one thread + at a time will call \a reduceFunction. The order in which \a reduceFunction + is called is undefined if \a reduceOptions is + QtConcurrent::UnorderedReduce. If \a reduceOptions is + QtConcurrent::OrderedReduce, \a reduceFunction is called in the order of + the original sequence. +*/ + +/*! + \fn QFuture<T> QtConcurrent::filteredReduced(ConstIterator begin, ConstIterator end, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + \relates <QtConcurrentFilter> + + Calls \a filterFunction once for each item from \a begin to \a end. If + \a filterFunction returns true for an item, that item is then passed to + \a reduceFunction. In other words, the return value is the result of + \a reduceFunction for each item where \a filterFunction returns true. + + Note that while \a filterFunction is called concurrently, only one thread + at a time will call \a reduceFunction. The order in which + \a reduceFunction is called is undefined if \a reduceOptions is + QtConcurrent::UnorderedReduce. If \a reduceOptions is + QtConcurrent::OrderedReduce, the \a reduceFunction is called in the order + of the original sequence. +*/ + +/*! + \fn void QtConcurrent::blockingFilter(Sequence &sequence, FilterFunction filterFunction) + + Calls \a filterFunction once for each item in \a sequence. If + \a filterFunction returns true, the item is kept in \a sequence; + otherwise, the item is removed from \a sequence. + + \note This function will block until all items in the sequence have been processed. +*/ + +/*! + \fn Sequence QtConcurrent::blockingFiltered(const Sequence &sequence, FilterFunction filterFunction) + + Calls \a filterFunction once for each item in \a sequence and returns a + new Sequence of kept items. If \a filterFunction returns true, a copy of + the item is put in the new Sequence. Otherwise, the item will \e not + appear in the new Sequence. + + \note This function will block until all items in the sequence have been processed. + + \sa filtered() +*/ + +/*! + \fn Sequence QtConcurrent::blockingFiltered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction) + + Calls \a filterFunction once for each item from \a begin to \a end and + returns a new Sequence of kept items. If \a filterFunction returns true, a + copy of the item is put in the new Sequence. Otherwise, the item will + \e not appear in the new Sequence. + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa filtered() +*/ + +/*! + \fn T QtConcurrent::blockingFilteredReduced(const Sequence &sequence, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + + Calls \a filterFunction once for each item in \a sequence. If + \a filterFunction returns true for an item, that item is then passed to + \a reduceFunction. In other words, the return value is the result of + \a reduceFunction for each item where \a filterFunction returns true. + + Note that while \a filterFunction is called concurrently, only one thread + at a time will call \a reduceFunction. The order in which \a reduceFunction + is called is undefined if \a reduceOptions is + QtConcurrent::UnorderedReduce. If \a reduceOptions is + QtConcurrent::OrderedReduce, \a reduceFunction is called in the order of + the original sequence. + + \note This function will block until all items in the sequence have been processed. + + \sa filteredReduced() +*/ + +/*! + \fn T QtConcurrent::blockingFilteredReduced(ConstIterator begin, ConstIterator end, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + + Calls \a filterFunction once for each item from \a begin to \a end. If + \a filterFunction returns true for an item, that item is then passed to + \a reduceFunction. In other words, the return value is the result of + \a reduceFunction for each item where \a filterFunction returns true. + + Note that while \a filterFunction is called concurrently, only one thread + at a time will call \a reduceFunction. The order in which + \a reduceFunction is called is undefined if \a reduceOptions is + QtConcurrent::UnorderedReduce. If \a reduceOptions is + QtConcurrent::OrderedReduce, the \a reduceFunction is called in the order + of the original sequence. + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa filteredReduced() +*/ diff --git a/src/corelib/concurrent/qtconcurrentfilter.h b/src/corelib/concurrent/qtconcurrentfilter.h new file mode 100644 index 0000000..3fae7d2 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentfilter.h @@ -0,0 +1,736 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_FILTER_H +#define QTCONCURRENT_FILTER_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qtconcurrentfilterkernel.h> +#include <QtCore/qtconcurrentfunctionwrappers.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifdef qdoc + +namespace QtConcurrent { + + QFuture<void> filter(Sequence &sequence, FilterFunction filterFunction); + + template <typename T> + QFuture<T> filtered(const Sequence &sequence, FilterFunction filterFunction); + template <typename T> + QFuture<T> filtered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction); + + template <typename T> + QFuture<T> filteredReduced(const Sequence &sequence, + FilterFunction filterFunction, + ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce); + template <typename T> + QFuture<T> filteredReduced(ConstIterator begin, + ConstIterator end, + FilterFunction filterFunction, + ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce); + + void blockingFilter(Sequence &sequence, FilterFunction filterFunction); + + template <typename Sequence> + Sequence blockingFiltered(const Sequence &sequence, FilterFunction filterFunction); + template <typename Sequence> + Sequence blockingFiltered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction); + + template <typename T> + T blockingFilteredReduced(const Sequence &sequence, + FilterFunction filterFunction, + ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce); + template <typename T> + T blockingFilteredReduced(ConstIterator begin, + ConstIterator end, + FilterFunction filterFunction, + ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce); + +} // namespace QtConcurrent + +#else + +namespace QtConcurrent { + +template <typename Sequence, typename KeepFunctor, typename T, typename C, typename U> +ThreadEngineStarter<void> filterInternal(Sequence &sequence, KeepFunctor keep, T (C::*reduce)(U)) +{ + typedef MemberFunctionWrapper1<T, C, U> ReduceFunctor; + typedef typename Sequence::const_iterator Iterator; + typedef FilterKernel<Sequence, KeepFunctor, ReduceFunctor> KernelType; + return startThreadEngine(new KernelType(sequence, keep, reduce)); +} + +// filter() on sequences +template <typename Sequence, typename KeepFunctor> +QFuture<void> filter(Sequence &sequence, KeepFunctor keep) +{ + return filterInternal(sequence, keep, &Sequence::push_back); +} + +template <typename Sequence, typename T> +QFuture<void> filter(Sequence &sequence, bool (keep)(T)) +{ + return filterInternal(sequence, FunctionWrapper1<bool, T>(keep), &Sequence::push_back); +} + +template <typename Sequence, typename C> +QFuture<void> filter(Sequence &sequence, bool (C::*keep)() const) +{ + return filterInternal(sequence, ConstMemberFunctionWrapper<bool, C>(keep), &Sequence::push_back); +} + +// filteredReduced() on sequences +template <typename ResultType, typename Sequence, typename KeepFunctor, typename ReduceFunctor> +QFuture<ResultType> filteredReduced(const Sequence &sequence, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startFilteredReduced<ResultType>(sequence, keep, reduce, options); + } + +template <typename ResultType, typename Sequence, typename T, typename ReduceFunctor> +QFuture<ResultType> filteredReduced(const Sequence &sequence, + bool (filter)(T), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<ResultType>(sequence, + FunctionWrapper1<bool, T>(filter), + reduce, + options); +} + +template <typename ResultType, typename Sequence, typename C, typename ReduceFunctor> +QFuture<ResultType> filteredReduced(const Sequence &sequence, + bool (C::*filter)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<ResultType>(sequence, + ConstMemberFunctionWrapper<bool, C>(filter), + reduce, + options); +} + +template <typename Sequence, typename KeepFunctor, typename T, typename U, typename V> +QFuture<U> filteredReduced(const Sequence &sequence, + KeepFunctor keep, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<U>(sequence, + keep, + FunctionWrapper2<T, U &, V>(reduce), + options); +} + +template <typename Sequence, typename KeepFunctor, typename T, typename C, typename U> +QFuture<C> filteredReduced(const Sequence &sequence, + KeepFunctor keep, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<C>(sequence, + keep, + MemberFunctionWrapper1<T, C, U>(reduce), + options); +} + +template <typename Sequence, typename T, typename U, typename V, typename W> +QFuture<V> filteredReduced(const Sequence &sequence, + bool (keep)(T), + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<V>(sequence, + FunctionWrapper1<bool, T>(keep), + FunctionWrapper2<U, V &, W>(reduce), + options); +} + +template <typename Sequence, typename C, typename T, typename U, typename V> +QFuture<U> filteredReduced(const Sequence &sequence, + bool (C::*keep)() const, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<U>(sequence, + ConstMemberFunctionWrapper<bool, C>(keep), + FunctionWrapper2<T, U &, V>(reduce), + options); +} + +template <typename Sequence, typename T, typename U, typename C, typename V> +QFuture<C> filteredReduced(const Sequence &sequence, + bool (keep)(T), + U (C::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<C>(sequence, + FunctionWrapper1<bool, T>(keep), + MemberFunctionWrapper1<U, C, V>(reduce), + options); +} + +template <typename Sequence, typename C, typename T, typename D, typename U> +QFuture<D> filteredReduced(const Sequence &sequence, + bool (C::*keep)() const, + T (D::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<D>(sequence, + ConstMemberFunctionWrapper<bool, C>(keep), + MemberFunctionWrapper1<T, D, U>(reduce), + options); +} + +// filteredReduced() on iterators +template <typename ResultType, typename Iterator, typename KeepFunctor, typename ReduceFunctor> +QFuture<ResultType> filteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startFilteredReduced<ResultType>(begin, end, keep, reduce, options); +} + +template <typename ResultType, typename Iterator, typename T, typename ReduceFunctor> +QFuture<ResultType> filteredReduced(Iterator begin, + Iterator end, + bool (filter)(T), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<ResultType>(begin, + end, + FunctionWrapper1<bool, T>(filter), + reduce, + options); +} + +template <typename ResultType, typename Iterator, typename C, typename ReduceFunctor> +QFuture<ResultType> filteredReduced(Iterator begin, + Iterator end, + bool (C::*filter)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<ResultType>(begin, + end, + ConstMemberFunctionWrapper<bool, C>(filter), + reduce, + options); +} + +template <typename Iterator, typename KeepFunctor, typename T, typename U, typename V> +QFuture<U> filteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<U>(begin, + end, + keep, + FunctionWrapper2<T, U &, V>(reduce), + options); +} + +template <typename Iterator, typename KeepFunctor, typename T, typename C, typename U> +QFuture<C> filteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<C>(begin, + end, + keep, + MemberFunctionWrapper1<T, C, U>(reduce), + options); +} + +template <typename Iterator, typename T, typename U, typename V, typename W> +QFuture<V> filteredReduced(Iterator begin, + Iterator end, + bool (keep)(T), + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<V>(begin, + end, + FunctionWrapper1<bool, T>(keep), + FunctionWrapper2<U, V &, W>(reduce), + options); +} + +template <typename Iterator, typename C, typename T, typename U, typename V> +QFuture<U> filteredReduced(Iterator begin, + Iterator end, + bool (C::*keep)() const, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<U>(begin, + end, + ConstMemberFunctionWrapper<bool, C>(keep), + FunctionWrapper2<T, U &, V>(reduce), + options); +} + +template <typename Iterator, typename T, typename U, typename C, typename V> +QFuture<C> filteredReduced(Iterator begin, + Iterator end, + bool (keep)(T), + U (C::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<C>(begin, + end, + FunctionWrapper1<bool, T>(keep), + MemberFunctionWrapper1<U, C, V>(reduce), + options); +} + +template <typename Iterator, typename C, typename T, typename D, typename U> +QFuture<D> filteredReduced(Iterator begin, + Iterator end, + bool (C::*keep)() const, + T (D::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced<D>(begin, + end, + ConstMemberFunctionWrapper<bool, C>(keep), + MemberFunctionWrapper1<T, D, U>(reduce), + options); +} + + +// filtered() on sequences +template <typename Sequence, typename KeepFunctor> +QFuture<typename Sequence::value_type> filtered(const Sequence &sequence, KeepFunctor keep) +{ + return startFiltered(sequence, keep); +} + +template <typename Sequence, typename T> +QFuture<typename Sequence::value_type> filtered(const Sequence &sequence, bool (keep)(T)) +{ + return startFiltered(sequence, FunctionWrapper1<bool, T>(keep)); +} + +template <typename Sequence, typename C> +QFuture<typename Sequence::value_type> filtered(const Sequence &sequence, bool (C::*keep)() const) +{ + return startFiltered(sequence, ConstMemberFunctionWrapper<bool, C>(keep)); +} + +// filtered() on iterators +template <typename Iterator, typename KeepFunctor> +QFuture<typename qValueType<Iterator>::value_type> filtered(Iterator begin, Iterator end, KeepFunctor keep) +{ + return startFiltered(begin, end, keep); +} + +template <typename Iterator, typename T> +QFuture<typename qValueType<Iterator>::value_type> filtered(Iterator begin, Iterator end, bool (keep)(T)) +{ + return startFiltered(begin, end, FunctionWrapper1<bool, T>(keep)); +} + +template <typename Iterator, typename C> +QFuture<typename qValueType<Iterator>::value_type> filtered(Iterator begin, + Iterator end, + bool (C::*keep)() const) +{ + return startFiltered(begin, end, ConstMemberFunctionWrapper<bool, C>(keep)); +} + + +// blocking filter() on sequences +template <typename Sequence, typename KeepFunctor> +void blockingFilter(Sequence &sequence, KeepFunctor keep) +{ + filterInternal(sequence, keep, &Sequence::push_back).startBlocking(); +} + +template <typename Sequence, typename T> +void blockingFilter(Sequence &sequence, bool (keep)(T)) +{ + filterInternal(sequence, FunctionWrapper1<bool, T>(keep), &Sequence::push_back) + .startBlocking(); +} + +template <typename Sequence, typename C> +void blockingFilter(Sequence &sequence, bool (C::*keep)() const) +{ + filterInternal(sequence, + ConstMemberFunctionWrapper<bool, C>(keep), + &Sequence::push_back) + .startBlocking(); +} + +// blocking filteredReduced() on sequences +template <typename ResultType, typename Sequence, typename KeepFunctor, typename ReduceFunctor> +ResultType blockingFilteredReduced(const Sequence &sequence, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startFilteredReduced<ResultType>(sequence, keep, reduce, options) + .startBlocking(); +} + +template <typename ResultType, typename Sequence, typename T, typename ReduceFunctor> +ResultType blockingFilteredReduced(const Sequence &sequence, + bool (filter)(T), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<ResultType> + (sequence, + FunctionWrapper1<bool, T>(filter), + reduce, + options); +} + +template <typename ResultType, typename Sequence, typename C, typename ReduceFunctor> +ResultType blockingFilteredReduced(const Sequence &sequence, + bool (C::*filter)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<ResultType> + (sequence, + ConstMemberFunctionWrapper<bool, C>(filter), + reduce, + options); +} + +template <typename Sequence, typename KeepFunctor, typename T, typename U, typename V> +U blockingFilteredReduced(const Sequence &sequence, + KeepFunctor keep, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<U> + (sequence, + keep, + FunctionWrapper2<T, U &, V>(reduce), + options); +} + +template <typename Sequence, typename KeepFunctor, typename T, typename C, typename U> +C blockingFilteredReduced(const Sequence &sequence, + KeepFunctor keep, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<C> + (sequence, + keep, + MemberFunctionWrapper1<T, C, U>(reduce), + options); +} + +template <typename Sequence, typename T, typename U, typename V, typename W> +V blockingFilteredReduced(const Sequence &sequence, + bool (keep)(T), + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<V> + (sequence, + FunctionWrapper1<bool, T>(keep), + FunctionWrapper2<U, V &, W>(reduce), + options); +} + +template <typename Sequence, typename C, typename T, typename U, typename V> +U blockingFilteredReduced(const Sequence &sequence, + bool (C::*keep)() const, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<U> + (sequence, + ConstMemberFunctionWrapper<bool, C>(keep), + FunctionWrapper2<T, U &, V>(reduce), + options); +} + +template <typename Sequence, typename T, typename U, typename C, typename V> +C blockingFilteredReduced(const Sequence &sequence, + bool (keep)(T), + U (C::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<C> + (sequence, + FunctionWrapper1<bool, T>(keep), + MemberFunctionWrapper1<U, C, V>(reduce), + options); +} + +template <typename Sequence, typename C, typename T, typename D, typename U> +D blockingFilteredReduced(const Sequence &sequence, + bool (C::*keep)() const, + T (D::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<D> + (sequence, + ConstMemberFunctionWrapper<bool, C>(keep), + MemberFunctionWrapper1<T, D, U>(reduce), + options); +} + +// blocking filteredReduced() on iterators +template <typename ResultType, typename Iterator, typename KeepFunctor, typename ReduceFunctor> +ResultType blockingFilteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startFilteredReduced<ResultType>(begin, end, keep, reduce, options) + .startBlocking(); +} + +template <typename ResultType, typename Iterator, typename T, typename ReduceFunctor> +ResultType blockingFilteredReduced(Iterator begin, + Iterator end, + bool (filter)(T), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<ResultType> + (begin, + end, + FunctionWrapper1<bool, T>(filter), + reduce, + options); +} + +template <typename ResultType, typename Iterator, typename C, typename ReduceFunctor> +ResultType blockingFilteredReduced(Iterator begin, + Iterator end, + bool (C::*filter)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<ResultType> + (begin, + end, + ConstMemberFunctionWrapper<bool, C>(filter), + reduce, + options); +} + +template <typename Iterator, typename KeepFunctor, typename T, typename U, typename V> +U blockingFilteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<U> + (begin, + end, + keep, + FunctionWrapper2<T, U &, V>(reduce), + options); +} + +template <typename Iterator, typename KeepFunctor, typename T, typename C, typename U> +C blockingFilteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<C> + (begin, + end, + keep, + MemberFunctionWrapper1<T, C, U>(reduce), + options); +} + +template <typename Iterator, typename T, typename U, typename V, typename W> +V blockingFilteredReduced(Iterator begin, + Iterator end, + bool (keep)(T), + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<V> + (begin, + end, + FunctionWrapper1<bool, T>(keep), + FunctionWrapper2<U, V &, W>(reduce), + options); +} + +template <typename Iterator, typename C, typename T, typename U, typename V> +U blockingFilteredReduced(Iterator begin, + Iterator end, + bool (C::*keep)() const, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<U> + (begin, + end, + ConstMemberFunctionWrapper<bool, C>(keep), + FunctionWrapper2<T, U &, V>(reduce), + options); +} + +template <typename Iterator, typename T, typename U, typename C, typename V> +C blockingFilteredReduced(Iterator begin, + Iterator end, + bool (keep)(T), + U (C::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<C> + (begin, + end, + FunctionWrapper1<bool, T>(keep), + MemberFunctionWrapper1<U, C, V>(reduce), + options); +} + +template <typename Iterator, typename C, typename T, typename D, typename U> +D blockingFilteredReduced(Iterator begin, + Iterator end, + bool (C::*keep)() const, + T (D::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced<D> + (begin, + end, + ConstMemberFunctionWrapper<bool, C>(keep), + MemberFunctionWrapper1<T, D, U>(reduce), + options); +} + +// blocking filtered() on sequences +template <typename Sequence, typename KeepFunctor> +Sequence blockingFiltered(const Sequence &sequence, KeepFunctor keep) +{ + return blockingFilteredReduced(sequence, keep, &Sequence::push_back, OrderedReduce); +} + +template <typename Sequence, typename T> +Sequence blockingFiltered(const Sequence &sequence, bool (keep)(T)) +{ + return blockingFilteredReduced(sequence, keep, &Sequence::push_back, OrderedReduce); +} + +template <typename Sequence, typename C> +Sequence blockingFiltered(const Sequence &sequence, bool (C::*filter)() const) +{ + return blockingFilteredReduced(sequence, + filter, + &Sequence::push_back, + OrderedReduce); +} + +// blocking filtered() on iterators +template <typename OutputSequence, typename Iterator, typename KeepFunctor> +OutputSequence blockingFiltered(Iterator begin, Iterator end, KeepFunctor keep) +{ + return blockingFilteredReduced(begin, + end, + keep, + &OutputSequence::push_back, + OrderedReduce); +} + +template <typename OutputSequence, typename Iterator, typename T> +OutputSequence blockingFiltered(Iterator begin, Iterator end, bool (keep)(T)) +{ + return blockingFilteredReduced(begin, + end, + keep, + &OutputSequence::push_back, + OrderedReduce); +} + +template <typename OutputSequence, typename Iterator, typename C> +OutputSequence blockingFiltered(Iterator begin, Iterator end, bool (C::*filter)() const) +{ + return blockingFilteredReduced(begin, + end, + filter, + &OutputSequence::push_back, + OrderedReduce); +} + +} // namespace QtConcurrent + +#endif // qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentfilterkernel.h b/src/corelib/concurrent/qtconcurrentfilterkernel.h new file mode 100644 index 0000000..2ee1246 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentfilterkernel.h @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_FILTERKERNEL_H +#define QTCONCURRENT_FILTERKERNEL_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qtconcurrentiteratekernel.h> +#include <QtCore/qtconcurrentmapkernel.h> +#include <QtCore/qtconcurrentreducekernel.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +template <typename T> +struct qValueType +{ + typedef typename T::value_type value_type; +}; + +template <typename T> +struct qValueType<const T*> +{ + typedef T value_type; +}; + +template <typename T> +struct qValueType<T*> +{ + typedef T value_type; +}; + +// Implementation of filter +template <typename Sequence, typename KeepFunctor, typename ReduceFunctor> +class FilterKernel : public IterateKernel<typename Sequence::const_iterator, void> +{ + typedef ReduceKernel<ReduceFunctor, Sequence, typename Sequence::value_type> Reducer; + typedef IterateKernel<typename Sequence::const_iterator, void> IterateKernelType; + typedef typename ReduceFunctor::result_type T; + + Sequence reducedResult; + Sequence &sequence; + KeepFunctor keep; + ReduceFunctor reduce; + Reducer reducer; + +public: + FilterKernel(Sequence &_sequence, KeepFunctor _keep, ReduceFunctor _reduce) + : IterateKernelType(const_cast<const Sequence &>(_sequence).begin(), const_cast<const Sequence &>(_sequence).end()), reducedResult(), + sequence(_sequence), + keep(_keep), + reduce(_reduce), + reducer(OrderedReduce) + { } + + bool runIteration(typename Sequence::const_iterator it, int index, T *) + { + IntermediateResults<typename Sequence::value_type> results; + results.begin = index; + results.end = index + 1; + + if (keep(*it)) + results.vector.append(*it); + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + bool runIterations(typename Sequence::const_iterator sequenceBeginIterator, int begin, int end, T *) + { + IntermediateResults<typename Sequence::value_type> results; + results.begin = begin; + results.end = end; + results.vector.reserve(end - begin); + + + typename Sequence::const_iterator it = sequenceBeginIterator; + advance(it, begin); + for (int i = begin; i < end; ++i) { + if (keep(*it)) + results.vector.append(*it); + advance(it, 1); + } + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + void finish() + { + reducer.finish(reduce, reducedResult); + sequence = reducedResult; + } + + inline bool shouldThrottleThread() + { + return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle(); + } + + inline bool shouldStartThread() + { + return IterateKernelType::shouldStartThread() && reducer.shouldStartThread(); + } + + typedef void ReturnType; + typedef void ResultType; +}; + +// Implementation of filter-reduce +template <typename ReducedResultType, + typename Iterator, + typename KeepFunctor, + typename ReduceFunctor, + typename Reducer = ReduceKernel<ReduceFunctor, + ReducedResultType, + typename qValueType<Iterator>::value_type> > +class FilteredReducedKernel : public IterateKernel<Iterator, ReducedResultType> +{ + ReducedResultType reducedResult; + KeepFunctor keep; + ReduceFunctor reduce; + Reducer reducer; + typedef IterateKernel<Iterator, ReducedResultType> IterateKernelType; + +public: + FilteredReducedKernel(Iterator begin, + Iterator end, + KeepFunctor _keep, + ReduceFunctor _reduce, + ReduceOptions reduceOption) + : IterateKernelType(begin, end), reducedResult(), keep(_keep), reduce(_reduce), reducer(reduceOption) + { } + +#if 0 + FilteredReducedKernel(ReducedResultType initialValue, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOption reduceOption) + : reducedResult(initialValue), keep(keep), reduce(reduce), reducer(reduceOption) + { } +#endif + + bool runIteration(Iterator it, int index, ReducedResultType *) + { + IntermediateResults<typename qValueType<Iterator>::value_type> results; + results.begin = index; + results.end = index + 1; + + if (keep(*it)) + results.vector.append(*it); + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + bool runIterations(Iterator sequenceBeginIterator, int begin, int end, ReducedResultType *) + { + IntermediateResults<typename qValueType<Iterator>::value_type> results; + results.begin = begin; + results.end = end; + results.vector.reserve(end - begin); + + Iterator it = sequenceBeginIterator; + advance(it, begin); + for (int i = begin; i < end; ++i) { + if (keep(*it)) + results.vector.append(*it); + advance(it, 1); + } + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + void finish() + { + reducer.finish(reduce, reducedResult); + } + + inline bool shouldThrottleThread() + { + return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle(); + } + + inline bool shouldStartThread() + { + return IterateKernelType::shouldStartThread() && reducer.shouldStartThread(); + } + + typedef ReducedResultType ReturnType; + typedef ReducedResultType ResultType; + ReducedResultType *result() + { + return &reducedResult; + } +}; + +// Implementation of filter that reports individual results via QFutureInterface +template <typename Iterator, typename KeepFunctor> +class FilteredEachKernel : public IterateKernel<Iterator, typename qValueType<Iterator>::value_type> +{ + typedef typename qValueType<Iterator>::value_type T; + typedef IterateKernel<Iterator, T> IterateKernelType; + + KeepFunctor keep; + +public: + typedef T ReturnType; + typedef T ResultType; + + FilteredEachKernel(Iterator begin, Iterator end, KeepFunctor _keep) + : IterateKernelType(begin, end), keep(_keep) + { } + + void start() + { + if (this->futureInterface) + this->futureInterface->setFilterMode(true); + IterateKernelType::start(); + } + + bool runIteration(Iterator it, int index, T *) + { + if (keep(*it)) + this->reportResult(&(*it), index); + else + this->reportResult(0, index); + return false; + } + + bool runIterations(Iterator sequenceBeginIterator, int begin, int end, T *) + { + const int count = end - begin; + IntermediateResults<typename qValueType<Iterator>::value_type> results; + results.begin = begin; + results.end = end; + results.vector.reserve(count); + + Iterator it = sequenceBeginIterator; + advance(it, begin); + for (int i = begin; i < end; ++i) { + if (keep(*it)) + results.vector.append(*it); + advance(it, 1); + } + + this->reportResults(results.vector, begin, count); + return false; + } +}; + +template <typename Iterator, typename KeepFunctor> +inline +ThreadEngineStarter<typename qValueType<Iterator>::value_type> +startFiltered(Iterator begin, Iterator end, KeepFunctor functor) +{ + return startThreadEngine(new FilteredEachKernel<Iterator, KeepFunctor>(begin, end, functor)); +} + +template <typename Sequence, typename KeepFunctor> +inline ThreadEngineStarter<typename Sequence::value_type> +startFiltered(const Sequence &sequence, KeepFunctor functor) +{ + typedef SequenceHolder1<Sequence, + FilteredEachKernel<typename Sequence::const_iterator, KeepFunctor>, + KeepFunctor> + SequenceHolderType; + return startThreadEngine(new SequenceHolderType(sequence, functor)); +} + +template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor> +inline ThreadEngineStarter<ResultType> startFilteredReduced(const Sequence & sequence, + MapFunctor mapFunctor, ReduceFunctor reduceFunctor, + ReduceOptions options) +{ + typedef typename Sequence::const_iterator Iterator; + typedef ReduceKernel<ReduceFunctor, ResultType, typename qValueType<Iterator>::value_type > Reducer; + typedef FilteredReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer> FilteredReduceType; + typedef SequenceHolder2<Sequence, FilteredReduceType, MapFunctor, ReduceFunctor> SequenceHolderType; + return startThreadEngine(new SequenceHolderType(sequence, mapFunctor, reduceFunctor, options)); +} + + +template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor> +inline ThreadEngineStarter<ResultType> startFilteredReduced(Iterator begin, Iterator end, + MapFunctor mapFunctor, ReduceFunctor reduceFunctor, + ReduceOptions options) +{ + typedef ReduceKernel<ReduceFunctor, ResultType, typename qValueType<Iterator>::value_type> Reducer; + typedef FilteredReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer> FilteredReduceType; + return startThreadEngine(new FilteredReduceType(begin, end, mapFunctor, reduceFunctor, options)); +} + + +} // namespace QtConcurrent + +#endif // qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentfunctionwrappers.h b/src/corelib/concurrent/qtconcurrentfunctionwrappers.h new file mode 100644 index 0000000..d076f73 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentfunctionwrappers.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_FUNCTIONWRAPPERS_H +#define QTCONCURRENT_FUNCTIONWRAPPERS_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +template <typename T> +class FunctionWrapper0 +{ +public: + typedef T (*FunctionPointerType)(); + typedef T result_type; + inline FunctionWrapper0(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()() + { + return functionPointer(); + } +private: + FunctionPointerType functionPointer; +}; + +template <typename T, typename U> +class FunctionWrapper1 +{ +public: + typedef T (*FunctionPointerType)(U u); + typedef T result_type; + inline FunctionWrapper1(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()(U u) + { + return functionPointer(u); + } + +private: + FunctionPointerType functionPointer; +}; + +template <typename T, typename U, typename V> +class FunctionWrapper2 +{ +public: + typedef T (*FunctionPointerType)(U u, V v); + typedef T result_type; + inline FunctionWrapper2(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()(U u, V v) + { + return functionPointer(u, v); + } +private: + FunctionPointerType functionPointer; +}; + +template <typename T, typename C> +class MemberFunctionWrapper +{ +public: + typedef T (C::*FunctionPointerType)(); + typedef T result_type; + inline MemberFunctionWrapper(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()(C &c) + { + return (c.*functionPointer)(); + } +private: + FunctionPointerType functionPointer; +}; + +template <typename T, typename C, typename U> +class MemberFunctionWrapper1 +{ +public: + typedef T (C::*FunctionPointerType)(U); + typedef T result_type; + + inline MemberFunctionWrapper1(FunctionPointerType _functionPointer) + : functionPointer(_functionPointer) + { } + + inline T operator()(C &c, U u) + { + return (c.*functionPointer)(u); + } + +private: + FunctionPointerType functionPointer; +}; + +template <typename T, typename C> +class ConstMemberFunctionWrapper +{ +public: + typedef T (C::*FunctionPointerType)() const; + typedef T result_type; + inline ConstMemberFunctionWrapper(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()(const C &c) const + { + return (c.*functionPointer)(); + } +private: + FunctionPointerType functionPointer; +}; + +} // namespace QtConcurrent. + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp new file mode 100644 index 0000000..5c20146 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtconcurrentiteratekernel.h" + +#if defined(Q_OS_MAC) + +#include <mach/mach.h> +#include <mach/mach_time.h> +#include <unistd.h> + +#elif defined(Q_OS_UNIX) + +#include <time.h> +#include <unistd.h> + +#elif defined(Q_OS_WIN) + +#include <windows.h> + +#endif + + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_NAMESPACE + +enum { + TargetRatio = 100, + MedianSize = 7 +}; + +#if defined(Q_OS_MAC) + +static qint64 getticks() +{ + return mach_absolute_time(); +} + +#elif defined(Q_OS_UNIX) + + +static qint64 getticks() +{ +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + clockid_t clockId; + +#ifndef _POSIX_THREAD_CPUTIME + clockId = CLOCK_REALTIME; +#elif (_POSIX_THREAD_CPUTIME-0 <= 0) + // if we don't have CLOCK_THREAD_CPUTIME_ID, we have to just use elapsed realtime instead + clockId = CLOCK_REALTIME; + +# if (_POSIX_THREAD_CPUTIME-0 == 0) + // detect availablility of CLOCK_THREAD_CPUTIME_ID + static long useThreadCpuTime = -2; + if (useThreadCpuTime == -2) { + // sysconf() will return either -1 or _POSIX_VERSION (don't care about thread races here) + useThreadCpuTime = sysconf(_SC_THREAD_CPUTIME); + } + if (useThreadCpuTime != -1) + clockId = CLOCK_THREAD_CPUTIME_ID; +# endif +#else + clockId = CLOCK_THREAD_CPUTIME_ID; +#endif + + struct timespec ts; + if (clock_gettime(clockId, &ts) == -1) + return 0; + return (ts.tv_sec * 1000000000) + ts.tv_nsec; +#else + // no clock_gettime(), fall back to wall time + struct timeval tv; + gettimeofday(&tv, 0); + return (tv.tv_sec * 1000000) + tv.tv_usec; +#endif +} + +#elif defined(Q_OS_WIN) + +static qint64 getticks() +{ + LARGE_INTEGER x; + if (!QueryPerformanceCounter(&x)) + return 0; + return x.QuadPart; +} + +#endif + +static double elapsed(qint64 after, qint64 before) +{ + return double(after - before); +} + +namespace QtConcurrent { + +/*! \internal + +*/ +BlockSizeManager::BlockSizeManager(int iterationCount) +: maxBlockSize(iterationCount / (QThreadPool::globalInstance()->maxThreadCount() * 2)), + beforeUser(0), afterUser(0), + controlPartElapsed(MedianSize), userPartElapsed(MedianSize), + m_blockSize(1) +{ } + +// Records the time before user code. +void BlockSizeManager::timeBeforeUser() +{ + if (blockSizeMaxed()) + return; + + beforeUser = getticks(); + controlPartElapsed.addValue(elapsed(beforeUser, afterUser)); +} + + // Records the time after user code and adjust the block size if we are spending + // to much time in the for control code compared with the user code. +void BlockSizeManager::timeAfterUser() +{ + if (blockSizeMaxed()) + return; + + afterUser = getticks(); + userPartElapsed.addValue(elapsed(afterUser, beforeUser)); + + if (controlPartElapsed.isMedianValid() == false) + return; + + if (controlPartElapsed.median() * TargetRatio < userPartElapsed.median()) + return; + + m_blockSize = qMin(m_blockSize * 2, maxBlockSize); + +#ifdef QTCONCURRENT_FOR_DEBUG + qDebug() << QThread::currentThread() << "adjusting block size" << controlPartElapsed.median() << userPartElapsed.median() << m_blockSize; +#endif + + // Reset the medians after adjusting the block size so we get + // new measurements with the new block size. + controlPartElapsed.reset(); + userPartElapsed.reset(); +} + +int BlockSizeManager::blockSize() +{ + return m_blockSize; +} + +} // namespace QtConcurrent + +QT_END_NAMESPACE + +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.h b/src/corelib/concurrent/qtconcurrentiteratekernel.h new file mode 100644 index 0000000..38d2824 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentiteratekernel.h @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_ITERATEKERNEL_H +#define QTCONCURRENT_ITERATEKERNEL_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qatomic.h> +#include <QtCore/qtconcurrentmedian.h> +#include <QtCore/qtconcurrentthreadengine.h> + +#ifndef QT_NO_STL +# include <iterator> +#endif + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +#ifndef QT_NO_STL + using std::advance; +#else + template <typename It, typename T> + void advance(It &it, T value) + { + it+=value; + } +#endif + +/* + The BlockSizeManager class manages how many iterations a thread should + reserve and process at a time. This is done by measuring the time spent + in the user code versus the control part code, and then increasing + the block size if the ratio between them is to small. The block size + management is done on the basis of the median of several timing measuremens, + and it is done induvidualy for each thread. +*/ +class Q_CORE_EXPORT BlockSizeManager +{ +public: + BlockSizeManager(int iterationCount); + void timeBeforeUser(); + void timeAfterUser(); + int blockSize(); +private: + inline bool blockSizeMaxed() + { + return (m_blockSize >= maxBlockSize); + } + + const int maxBlockSize; + qint64 beforeUser; + qint64 afterUser; + Median<double> controlPartElapsed; + Median<double> userPartElapsed; + int m_blockSize; +}; + +template <typename T> +class ResultReporter +{ +public: + ResultReporter(ThreadEngine<T> *_threadEngine) + :threadEngine(_threadEngine) + { + + } + + void reserveSpace(int resultCount) + { + currentResultCount = resultCount; + vector.resize(qMax(resultCount, vector.count())); + } + + void reportResults(int begin) + { + const int useVectorThreshold = 4; // Tunable parameter. + if (currentResultCount > useVectorThreshold) { + vector.resize(currentResultCount); + threadEngine->reportResults(vector, begin); + } else { + for (int i = 0; i < currentResultCount; ++i) + threadEngine->reportResult(&vector.at(i), begin + i); + } + } + + inline T * getPointer() + { + return vector.data(); + } + + int currentResultCount; + ThreadEngine<T> *threadEngine; + QVector<T> vector; +}; + +template <> +class ResultReporter<void> +{ +public: + inline ResultReporter(ThreadEngine<void> *) { } + inline void reserveSpace(int) { }; + inline void reportResults(int) { }; + inline void * getPointer() { return 0; } +}; + +#ifndef QT_NO_STL +inline bool selectIteration(std::bidirectional_iterator_tag) +{ + return false; // while +} + +inline bool selectIteration(std::forward_iterator_tag) +{ + return false; // while +} + +inline bool selectIteration(std::random_access_iterator_tag) +{ + return true; // for +} +#else +// no stl support, always use while iteration +template <typename T> +inline bool selectIteration(T) +{ + return false; // while +} +#endif + +template <typename Iterator, typename T> +class IterateKernel : public ThreadEngine<T> +{ +public: + typedef T ResultType; + + IterateKernel(Iterator _begin, Iterator _end) +#ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION + : begin(_begin), end(_end), current(_begin), currentIndex(0), + forIteration(selectIteration(typename std::iterator_traits<Iterator>::iterator_category())), progressReportingEnabled(true) +#else + : begin(_begin), end(_end), currentIndex(0), + forIteration(selectIteration(std::iterator_category(_begin))), progressReportingEnabled(true) +#endif + { + iterationCount = forIteration ? std::distance(_begin, _end) : 0; + } + + virtual ~IterateKernel() { } + + virtual bool runIteration(Iterator it, int index , T *result) + { Q_UNUSED(it); Q_UNUSED(index); Q_UNUSED(result); return false; } + virtual bool runIterations(Iterator _begin, int beginIndex, int endIndex, T *results) + { Q_UNUSED(_begin); Q_UNUSED(beginIndex); Q_UNUSED(endIndex); Q_UNUSED(results); return false; } + + void start() + { + progressReportingEnabled = this->isProgressReportingEnabled(); + if (progressReportingEnabled && iterationCount > 0) + this->setProgressRange(0, iterationCount); + } + + bool shouldStartThread() + { + if (forIteration) + return (currentIndex < iterationCount) && !this->shouldThrottleThread(); + else // whileIteration + return (iteratorThreads == 0); + } + + ThreadFunctionResult threadFunction() + { + if (forIteration) + return this->forThreadFunction(); + else // whileIteration + return this->whileThreadFunction(); + } + + ThreadFunctionResult forThreadFunction() + { + BlockSizeManager blockSizeManager(iterationCount); + ResultReporter<T> resultReporter(this); + + for(;;) { + if (this->isCanceled()) + break; + + const int currentBlockSize = blockSizeManager.blockSize(); + + if (currentIndex >= iterationCount) + break; + + // Atomically reserve a block of iterationCount for this thread. + const int beginIndex = currentIndex.fetchAndAddRelease(currentBlockSize); + const int endIndex = qMin(beginIndex + currentBlockSize, iterationCount); + + if (beginIndex >= endIndex) { + // No more work + break; + } + + this->waitForResume(); // (only waits if the qfuture is paused.) + + if (shouldStartThread()) + this->startThread(); + + const int finalBlockSize = endIndex - beginIndex; // block size adjusted for possible end-of-range + resultReporter.reserveSpace(finalBlockSize); + + // Call user code with the current iteration range. + blockSizeManager.timeBeforeUser(); + const bool resultsAvailable = this->runIterations(begin, beginIndex, endIndex, resultReporter.getPointer()); + blockSizeManager.timeAfterUser(); + + if (resultsAvailable) + resultReporter.reportResults(beginIndex); + + // Report progress if progress reporting enabled. + if (progressReportingEnabled) { + completed.fetchAndAddAcquire(finalBlockSize); + this->setProgressValue(this->completed); + } + + if (this->shouldThrottleThread()) + return ThrottleThread; + } + return ThreadFinished; + } + + ThreadFunctionResult whileThreadFunction() + { + if (iteratorThreads.testAndSetAcquire(0, 1) == false) + return ThreadFinished; + + ResultReporter<T> resultReporter(this); + resultReporter.reserveSpace(1); + + while (current != end) { + // The following two lines breaks support for input iterators according to + // the sgi docs: dereferencing prev after calling ++current is not allowed + // on input iterators. (prev is dereferenced inside user.runIteration()) + Iterator prev = current; + ++current; + int index = currentIndex.fetchAndAddRelaxed(1); + iteratorThreads.testAndSetRelease(1, 0); + + this->waitForResume(); // (only waits if the qfuture is paused.) + + if (shouldStartThread()) + this->startThread(); + + const bool resultAavailable = this->runIteration(prev, index, resultReporter.getPointer()); + if (resultAavailable) + resultReporter.reportResults(index); + + if (this->shouldThrottleThread()) + return ThrottleThread; + + if (iteratorThreads.testAndSetAcquire(0, 1) == false) + return ThreadFinished; + } + + return ThreadFinished; + } + + +public: + const Iterator begin; + const Iterator end; + Iterator current; + QAtomicInt currentIndex; + bool forIteration; + QAtomicInt iteratorThreads; + int iterationCount; + + bool progressReportingEnabled; + QAtomicInt completed; +}; + +} // namespace QtConcurrent + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentmap.cpp b/src/corelib/concurrent/qtconcurrentmap.cpp new file mode 100644 index 0000000..8880a87 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentmap.cpp @@ -0,0 +1,401 @@ + /**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \namespace QtConcurrent + \since 4.4 + \brief The QtConcurrent namespace provides high-level APIs that make it + possible to write multi-threaded programs without using low-level + threading primitives. + + See the \l {threads.html#qtconcurrent-intro}{Qt Concurrent} section in the \l{threads.html}{threading} documentation. + + \ingroup thread +*/ + +/*! + \namespace QtConcurrent::internal + \internal + + \brief The QtConcurrent::internal namespace contains QtConcurrent + implementation details. + + \ingroup thread +*/ + +/*! + \enum QtConcurrent::ReduceOption + This enum specifies the order of which results from the map or filter + function are passed to the reduce function. + + \value UnorderedReduce Reduction is done in an arbitrary order. + \value OrderedReduce Reduction is done in the order of the + original sequence. + \value SequentialReduce Reduction is done sequentally: only one + thread will enter the reduce function at a time. (Parallel reduction + might be supported in a future version of Qt Concurrent.) +*/ + +/*! + \headerfile <QtConcurrentMap> + \title Concurrent Map and Map-Reduce + \ingroup threading + + \brief The <QtConcurrentMap> header provides concurrent Map and MapReduce. + + These functions are a part of the \l {threads.html#qtconcurrent-intro}{Qt Concurrent} framework. + + The QtConcurrent::map(), QtConcurrent::mapped() and + QtConcurrent::mappedReduced() functions run computations in parallel on + the items in a sequence such as a QList or a QVector. QtConcurrent::map() + modifies a sequence in-place, QtConcurrent::mapped() returns a new + sequence containing the modified content, and QtConcurrent::mappedReduced() + returns a single result. + + Each of the above functions has a blocking variant that returns + the final result instead of a QFuture. You use them in the same + way as the asynchronous variants. + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 7 + + Note that the result types above are not QFuture objects, but real result + types (in this case, QList<QImage> and QImage). + + \section1 Concurrent Map + + QtConcurrent::mapped() takes an input sequence and a map function. This map + function is then called for each item in the sequence, and a new sequence + containing the return values from the map function is returned. + + The map function must be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 0 + + T and U can be any type (and they can even be the same type), but T must + match the type stored in the sequence. The function returns the modified + or \e mapped content. + + This example shows how to apply a scale function to all the items + in a sequence: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 1 + + The results of the map are made available through QFuture. See the + QFuture and QFutureWatcher documentation for more information on how to + use QFuture in your applications. + + If you want to modify a sequence in-place, use QtConcurrent::map(). The + map function must then be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 2 + + Note that the return value and return type of the map function are not + used. + + Using QtConcurrent::map() is similar to using QtConcurrent::mapped(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 3 + + Since the sequence is modified in place, QtConcurrent::map() does not + return any results via QFuture. However, you can still use QFuture and + QFutureWatcher to monitor the status of the map. + + \section1 Concurrent Map-Reduce + + QtConcurrent::mappedReduced() is similar to QtConcurrent::mapped(), but + instead of returning a sequence with the new results, the results are + combined into a single value using a reduce function. + + The reduce function must be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 4 + + T is the type of the final result, U is the return type of the map + function. Note that the return value and return type of the reduce + function are not used. + + Call QtConcurrent::mappedReduced() like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 5 + + The reduce function will be called once for each result returned by the map + function, and should merge the \e{intermediate} into the \e{result} + variable. QtConcurrent::mappedReduced() guarantees that only one thread + will call reduce at a time, so using a mutex to lock the result variable + is not neccesary. The QtConcurrent::ReduceOptions enum provides a way to + control the order in which the reduction is done. If + QtConcurrent::UnorderedReduce is used (the default), the order is + undefined, while QtConcurrent::OrderedReduce ensures that the reduction + is done in the order of the original sequence. + + \section1 Additional API Features + + \section2 Using Iterators instead of Sequence + + Each of the above functions has a variant that takes an iterator range + instead of a sequence. You use them in the same way as the sequence + variants: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 6 + + \section2 Blocking Variants + + Each of the above functions has a blocking variant that returns + the final result instead of a QFuture. You use them in the same + way as the asynchronous variants. + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 7 + + Note that the result types above are not QFuture objects, but real result + types (in this case, QList<QImage> and QImage). + + \section2 Using Member Functions + + QtConcurrent::map(), QtConcurrent::mapped(), and + QtConcurrent::mappedReduced() accept pointers to member functions. + The member function class type must match the type stored in the sequence: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 8 + + Note that when using QtConcurrent::mappedReduced(), you can mix the use of + normal and member functions freely: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 9 + + \section2 Using Function Objects + + QtConcurrent::map(), QtConcurrent::mapped(), and + QtConcurrent::mappedReduced() accept function objects, which can be used to + add state to a function call. The result_type typedef must define the + result type of the function call operator: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 14 + + \section2 Using Bound Function Arguments + + Note that Qt does not provide support for bound functions. This is + provided by 3rd party libraries like + \l{http://www.boost.org/libs/bind/bind.html}{Boost} or + \l{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf}{C++ + TR1 Library Extensions}. + + If you want to use a map function that takes more than one argument you can + use boost::bind() or std::tr1::bind() to transform it onto a function that + takes one argument. + + As an example, we'll use QImage::scaledToWidth(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 10 + + scaledToWidth takes three arguments (including the "this" pointer) and + can't be used with QtConcurrent::mapped() directly, because + QtConcurrent::mapped() expects a function that takes one argument. To use + QImage::scaledToWidth() with QtConcurrent::mapped() we have to provide a + value for the \e{width} and the \e{transformation mode}: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 11 + + The return value from boost::bind() is a function object (functor) with + the following signature: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 12 + + This matches what QtConcurrent::mapped() expects, and the complete example + becomes: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 13 +*/ + +/*! + \fn QFuture<void> QtConcurrent::map(Sequence &sequence, MapFunction function) + \relates <QtConcurrentMap> + + Calls \a function once for each item in \a sequence. The \a function is + passed a reference to the item, so that any modifications done to the item + will appear in \a sequence. +*/ + +/*! + \fn QFuture<void> QtConcurrent::map(Iterator begin, Iterator end, MapFunction function) + \relates <QtConcurrentMap> + + Calls \a function once for each item from \a begin to \a end. The + \a function is passed a reference to the item, so that any modifications + done to the item will appear in the sequence which the iterators belong to. +*/ + +/*! + \fn QFuture<T> QtConcurrent::mapped(const Sequence &sequence, MapFunction function) + \relates <QtConcurrentMap> + + Calls \a function once for each item in \a sequence and returns a future + with each mapped item as a result. You can use QFuture::const_iterator or + QFutureIterator to iterate through the results. +*/ + +/*! + \fn QFuture<T> QtConcurrent::mapped(ConstIterator begin, ConstIterator end, MapFunction function) + \relates <QtConcurrentMap> + + Calls \a function once for each item from \a begin to \a end and returns a + future with each mapped item as a result. You can use + QFuture::const_iterator or QFutureIterator to iterate through the results. +*/ + +/*! + \fn QFuture<T> QtConcurrent::mappedReduced(const Sequence &sequence, + MapFunction mapFunction, ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions) + + \relates <QtConcurrentMap> + + Calls \a mapFunction once for each item in \a sequence. The return value of + each \a mapFunction is passed to \a reduceFunction. + + Note that while \a mapFunction is called concurrently, only one thread at a + time will call \a reduceFunction. The order in which \a reduceFunction is + called is determined by \a reduceOptions. +*/ + +/*! + \fn QFuture<T> QtConcurrent::mappedReduced(ConstIterator begin, + ConstIterator end, MapFunction mapFunction, ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions) + + \relates <QtConcurrentMap> + + Calls \a mapFunction once for each item from \a begin to \a end. The return + value of each \a mapFunction is passed to \a reduceFunction. + + Note that while \a mapFunction is called concurrently, only one thread at a + time will call \a reduceFunction. By default, the order in which + \a reduceFunction is called is undefined. + + \note QtConcurrent::OrderedReduce results in the ordered reduction. +*/ + +/*! + \fn void QtConcurrent::blockingMap(Sequence &sequence, MapFunction function) + + Calls \a function once for each item in \a sequence. The \a function is + passed a reference to the item, so that any modifications done to the item + will appear in \a sequence. + + \note This function will block until all items in the sequence have been processed. + + \sa map() +*/ + +/*! + \fn void QtConcurrent::blockingMap(Iterator begin, Iterator end, MapFunction function) + + Calls \a function once for each item from \a begin to \a end. The + \a function is passed a reference to the item, so that any modifications + done to the item will appear in the sequence which the iterators belong to. + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa map() +*/ + +/*! + \fn T QtConcurrent::blockingMapped(const Sequence &sequence, MapFunction function) + + Calls \a function once for each item in \a sequence and returns a Sequence containing + the results. The type of the results will match the type returned my the MapFunction. + + \note This function will block until all items in the sequence have been processed. + + \sa mapped() +*/ + +/*! + \fn T QtConcurrent::blockingMapped(ConstIterator begin, ConstIterator end, MapFunction function) + + Calls \a function once for each item from \a begin to \a end and returns a + container with the results. Specify the type of container as the a template + argument, like this: + + \code + QList<int> ints = QtConcurrent::blockingMapped<QList<int> >(beginIterator, endIterator, fn); + \endcode + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa mapped() +*/ + +/*! + \fn T QtConcurrent::blockingMappedReduced(const Sequence &sequence, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + + \relates <QtConcurrentMap> + + Calls \a mapFunction once for each item in \a sequence. The return value of + each \a mapFunction is passed to \a reduceFunction. + + Note that while \a mapFunction is called concurrently, only one thread at a + time will call \a reduceFunction. The order in which \a reduceFunction is + called is determined by \a reduceOptions. + + \note This function will block until all items in the sequence have been processed. + + \sa mapped() +*/ + +/*! + \fn T QtConcurrent::blockingMappedReduced(ConstIterator begin, ConstIterator end, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + + \relates <QtConcurrentMap> + + Calls \a mapFunction once for each item from \a begin to \a end. The return + value of each \a mapFunction is passed to \a reduceFunction. + + Note that while \a mapFunction is called concurrently, only one thread at a + time will call \a reduceFunction. The order in which \a reduceFunction is + called is undefined. + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa blockingMappedReduced() +*/ diff --git a/src/corelib/concurrent/qtconcurrentmap.h b/src/corelib/concurrent/qtconcurrentmap.h new file mode 100644 index 0000000..0d55a74 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentmap.h @@ -0,0 +1,780 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_MAP_H +#define QTCONCURRENT_MAP_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qtconcurrentmapkernel.h> +#include <QtCore/qtconcurrentreducekernel.h> +#include <QtCore/qtconcurrentfunctionwrappers.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifdef qdoc + +namespace QtConcurrent { + + QFuture<void> map(Sequence &sequence, MapFunction function); + QFuture<void> map(Iterator begin, Iterator end, MapFunction function); + + template <typename T> + QFuture<T> mapped(const Sequence &sequence, MapFunction function); + template <typename T> + QFuture<T> mapped(ConstIterator begin, ConstIterator end, MapFunction function); + + template <typename T> + QFuture<T> mappedReduced(const Sequence &sequence, + MapFunction function, + ReduceFunction function, + QtConcurrent::ReduceOptions options = UnorderedReduce | SequentialReduce); + template <typename T> + QFuture<T> mappedReduced(ConstIterator begin, + ConstIterator end, + MapFunction function, + ReduceFunction function, + QtConcurrent::ReduceOptions options = UnorderedReduce | SequentialReduce); + + void blockingMap(Sequence &sequence, MapFunction function); + void blockingMap(Iterator begin, Iterator end, MapFunction function); + + template <typename T> + T blockingMapped(const Sequence &sequence, MapFunction function); + template <typename T> + T blockingMapped(ConstIterator begin, ConstIterator end, MapFunction function); + + template <typename T> + T blockingMappedReduced(const Sequence &sequence, + MapFunction function, + ReduceFunction function, + QtConcurrent::ReduceOptions options = UnorderedReduce | SequentialReduce); + template <typename T> + T blockingMappedReduced(ConstIterator begin, + ConstIterator end, + MapFunction function, + ReduceFunction function, + QtConcurrent::ReduceOptions options = UnorderedReduce | SequentialReduce); + +} // namespace QtConcurrent + +#else + +namespace QtConcurrent { + +// map() on sequences +template <typename Sequence, typename MapFunctor> +QFuture<void> map(Sequence &sequence, MapFunctor map) +{ + return startMap(sequence.begin(), sequence.end(), map); +} + +template <typename Sequence, typename T, typename U> +QFuture<void> map(Sequence &sequence, T (map)(U)) +{ + return startMap(sequence.begin(), sequence.end(), FunctionWrapper1<T, U>(map)); +} + +template <typename Sequence, typename T, typename C> +QFuture<void> map(Sequence &sequence, T (C::*map)()) +{ + return startMap(sequence.begin(), sequence.end(), MemberFunctionWrapper<T, C>(map)); +} + +// map() on iterators +template <typename Iterator, typename MapFunctor> +QFuture<void> map(Iterator begin, Iterator end, MapFunctor map) +{ + return startMap(begin, end, map); +} + +template <typename Iterator, typename T, typename U> +QFuture<void> map(Iterator begin, Iterator end, T (map)(U)) +{ + return startMap(begin, end, FunctionWrapper1<T, U>(map)); +} + +template <typename Iterator, typename T, typename C> +QFuture<void> map(Iterator begin, Iterator end, T (C::*map)()) +{ + return startMap(begin, end, MemberFunctionWrapper<T, C>(map)); +} + +// mappedReduced() for sequences. +template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor> +QFuture<ResultType> mappedReduced(const Sequence &sequence, + MapFunctor map, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<typename MapFunctor::result_type, ResultType> + (sequence, map, reduce, options); +} + +template <typename Sequence, typename MapFunctor, typename T, typename U, typename V> +QFuture<U> mappedReduced(const Sequence &sequence, + MapFunctor map, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<typename MapFunctor::result_type, U> + (sequence, map, FunctionWrapper2<T, U &, V>(reduce), options); +} + +template <typename Sequence, typename MapFunctor, typename T, typename C, typename U> +QFuture<C> mappedReduced(const Sequence &sequence, + MapFunctor map, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<typename MapFunctor::result_type, C> + (sequence, map, MemberFunctionWrapper1<T, C, U>(reduce), options); +} + +template <typename ResultType, typename Sequence, typename T, typename U, typename ReduceFunctor> +QFuture<ResultType> mappedReduced(const Sequence &sequence, + T (map)(U), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, ResultType> + (sequence, FunctionWrapper1<T, U>(map), reduce, options); +} + +template <typename ResultType, typename Sequence, typename T, typename C, typename ReduceFunctor> +QFuture<ResultType> mappedReduced(const Sequence &sequence, + T (C::*map)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, ResultType> + (sequence, ConstMemberFunctionWrapper<T, C>(map), reduce, options); +} + +template <typename Sequence, typename T, typename U, typename V, typename W, typename X> +QFuture<W> mappedReduced(const Sequence &sequence, + T (map)(U), + V (reduce)(W &, X), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, W> + (sequence, FunctionWrapper1<T, U>(map), FunctionWrapper2<V, W &, X>(reduce), options); +} + +template <typename Sequence, typename T, typename C, typename U, typename V, typename W> +QFuture<V> mappedReduced(const Sequence &sequence, + T (C::*map)() const, + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, V> (sequence, ConstMemberFunctionWrapper<T, C>(map), + FunctionWrapper2<U, V &, W>(reduce), options); +} + +template <typename Sequence, typename T, typename U, typename V, typename C, typename W> +QFuture<C> mappedReduced(const Sequence &sequence, + T (map)(U), + V (C::*reduce)(W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, C> (sequence, FunctionWrapper1<T, U>(map), + MemberFunctionWrapper1<V, C, W>(reduce), options); +} + +template <typename Sequence, typename T, typename C, typename U,typename D, typename V> +QFuture<D> mappedReduced(const Sequence &sequence, + T (C::*map)() const, + U (D::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, D>(sequence, ConstMemberFunctionWrapper<T, C>(map), + MemberFunctionWrapper1<U, D, V>(reduce), options); +} + +// mappedReduced() for iterators +template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor> +QFuture<ResultType> mappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<ResultType, typename MapFunctor::result_type> + (begin, end, map, reduce, options); +} + +template <typename Iterator, typename MapFunctor, typename T, typename U, typename V> +QFuture<U> mappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<typename MapFunctor::result_type, U> + (begin, end, map, FunctionWrapper2<T, U &, V>(reduce), options); +} + +template <typename Iterator, typename MapFunctor, typename T, typename C, typename U> +QFuture<C> mappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<typename MapFunctor::result_type, C> + (begin, end, map, MemberFunctionWrapper1<T, C, U>(reduce), options); +} + +template <typename ResultType, typename Iterator, typename T, typename U, typename ReduceFunctor> +QFuture<ResultType> mappedReduced(Iterator begin, + Iterator end, + T (map)(U), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, ResultType> + (begin, end, FunctionWrapper1<T, U>(map), reduce, options); +} + +template <typename ResultType, typename Iterator, typename T, typename C, typename ReduceFunctor> +QFuture<ResultType> mappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, ResultType> + (begin, end, ConstMemberFunctionWrapper<T, C>(map), reduce, options); +} + +template <typename Iterator, typename T, typename U, typename V, typename W, typename X> +QFuture<W> mappedReduced(Iterator begin, + Iterator end, + T (map)(U), + V (reduce)(W &, X), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, W> + (begin, end, FunctionWrapper1<T, U>(map), FunctionWrapper2<V, W &, X>(reduce), options); +} + +template <typename Iterator, typename T, typename C, typename U, typename V, typename W> +QFuture<V> mappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, V>(begin, end, ConstMemberFunctionWrapper<T, C>(map), + FunctionWrapper2<U, V &, W>(reduce), options); +} + +template <typename Iterator, typename T, typename U, typename V, typename C, typename W> +QFuture<C> mappedReduced(Iterator begin, + Iterator end, + T (map)(U), + V (C::*reduce)(W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, C> + (begin, end, FunctionWrapper1<T, U>(map), MemberFunctionWrapper1<V, C, W>(reduce), options); +} + +template <typename Iterator, typename T, typename C, typename U,typename D, typename V> +QFuture<D> mappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + U (D::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced<T, D>(begin, end, ConstMemberFunctionWrapper<T, C>(map), + MemberFunctionWrapper1<U, D, V>(reduce), options); +} + +// mapped() for sequences +template <typename Sequence, typename MapFunctor> +QFuture<typename MapFunctor::result_type> mapped(const Sequence &sequence, MapFunctor map) +{ + return startMapped<typename MapFunctor::result_type>(sequence, map); +} + +template <typename Sequence, typename T, typename U> +QFuture<T> mapped(const Sequence &sequence, T (map)(U)) +{ + return startMapped<T>(sequence, FunctionWrapper1<T, U>(map)); +} + +template <typename Sequence, typename T, typename C> +QFuture<T> mapped(const Sequence &sequence, T (C::*map)() const) +{ + return startMapped<T>(sequence, ConstMemberFunctionWrapper<T, C>(map)); +} + +// mapped() for iterator ranges. +template <typename Iterator, typename MapFunctor> +QFuture<typename MapFunctor::result_type> mapped(Iterator begin, Iterator end, MapFunctor map) +{ + return startMapped<Q_TYPENAME MapFunctor::result_type>(begin, end, map); +} + +template <typename Iterator, typename T, typename U> +QFuture<T> mapped(Iterator begin, Iterator end, T (map)(U)) +{ + return startMapped<T>(begin, end, FunctionWrapper1<T, U>(map)); +} + +template <typename Iterator, typename T, typename C> +QFuture<T> mapped(Iterator begin, Iterator end, T (C::*map)() const) +{ + return startMapped<T>(begin, end, ConstMemberFunctionWrapper<T, C>(map)); +} + + +template <typename Sequence, typename MapFunctor> +void blockingMap(Sequence &sequence, MapFunctor map) +{ + startMap(sequence.begin(), sequence.end(), map).startBlocking(); +} + +template <typename Sequence, typename T, typename U> +void blockingMap(Sequence &sequence, T (map)(U)) +{ + startMap(sequence.begin(), sequence.end(), QtConcurrent::FunctionWrapper1<T, U>(map)).startBlocking(); +} + +template <typename Sequence, typename T, typename C> +void blockingMap(Sequence &sequence, T (C::*map)()) +{ + startMap(sequence.begin(), sequence.end(), QtConcurrent::MemberFunctionWrapper<T, C>(map)).startBlocking(); +} + +template <typename Iterator, typename MapFunctor> +void blockingMap(Iterator begin, Iterator end, MapFunctor map) +{ + startMap(begin, end, map).startBlocking(); +} + +template <typename Iterator, typename T, typename U> +void blockingMap(Iterator begin, Iterator end, T (map)(U)) +{ + startMap(begin, end, QtConcurrent::FunctionWrapper1<T, U>(map)).startBlocking(); +} + +template <typename Iterator, typename T, typename C> +void blockingMap(Iterator begin, Iterator end, T (C::*map)()) +{ + startMap(begin, end, QtConcurrent::MemberFunctionWrapper<T, C>(map)).startBlocking(); +} + +template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor> +ResultType blockingMappedReduced(const Sequence &sequence, + MapFunctor map, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<typename MapFunctor::result_type, ResultType> + (sequence, map, reduce, options).startBlocking(); +} + +template <typename Sequence, typename MapFunctor, typename T, typename U, typename V> +U blockingMappedReduced(const Sequence &sequence, + MapFunctor map, + T (reduce)(U &, V), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<typename MapFunctor::result_type, U> + (sequence, + map, + QtConcurrent::FunctionWrapper2<T, U &, V>(reduce), + options) + .startBlocking(); +} + +template <typename Sequence, typename MapFunctor, typename T, typename C, typename U> +C blockingMappedReduced(const Sequence &sequence, + MapFunctor map, + T (C::*reduce)(U), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<typename MapFunctor::result_type, C> + (sequence, + map, + QtConcurrent::MemberFunctionWrapper1<T, C, U>(reduce), + options) + .startBlocking(); +} + +template <typename ResultType, typename Sequence, typename T, typename U, typename ReduceFunctor> +ResultType blockingMappedReduced(const Sequence &sequence, + T (map)(U), + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, ResultType> + (sequence, + QtConcurrent::FunctionWrapper1<T, U>(map), + reduce, + options) + .startBlocking(); +} + +template <typename ResultType, typename Sequence, typename T, typename C, typename ReduceFunctor> +ResultType blockingMappedReduced(const Sequence &sequence, + T (C::*map)() const, + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, ResultType> + (sequence, + QtConcurrent::ConstMemberFunctionWrapper<T, C>(map), + reduce, + options) + .startBlocking(); +} + +template <typename Sequence, typename T, typename U, typename V, typename W, typename X> +W blockingMappedReduced(const Sequence &sequence, + T (map)(U), + V (reduce)(W &, X), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, W> + (sequence, + QtConcurrent::FunctionWrapper1<T, U>(map), + QtConcurrent::FunctionWrapper2<V, W &, X>(reduce), + options) + .startBlocking(); +} + +template <typename Sequence, typename T, typename C, typename U, typename V, typename W> +V blockingMappedReduced(const Sequence &sequence, + T (C::*map)() const, + U (reduce)(V &, W), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, V> + (sequence, + QtConcurrent::ConstMemberFunctionWrapper<T, C>(map), + QtConcurrent::FunctionWrapper2<U, V &, W>(reduce), + options) + .startBlocking(); +} + +template <typename Sequence, typename T, typename U, typename V, typename C, typename W> +C blockingMappedReduced(const Sequence &sequence, + T (map)(U), + V (C::*reduce)(W), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, C> + (sequence, + QtConcurrent::FunctionWrapper1<T, U>(map), + QtConcurrent::MemberFunctionWrapper1<V, C, W>(reduce), + options) + .startBlocking(); +} + +template <typename Sequence, typename T, typename C, typename U,typename D, typename V> +D blockingMappedReduced(const Sequence &sequence, + T (C::*map)() const, + U (D::*reduce)(V), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, D> + (sequence, + QtConcurrent::ConstMemberFunctionWrapper<T, C>(map), + QtConcurrent::MemberFunctionWrapper1<U, D, V>(reduce), + options) + .startBlocking(); +} + +template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor> +ResultType blockingMappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<typename MapFunctor::result_type, ResultType> + (begin, end, map, reduce, options).startBlocking(); +} + +template <typename Iterator, typename MapFunctor, typename T, typename U, typename V> +U blockingMappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + T (reduce)(U &, V), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<typename MapFunctor::result_type, U> + (begin, + end, + map, + QtConcurrent::FunctionWrapper2<T, U &, V>(reduce), + options) + .startBlocking(); +} + +template <typename Iterator, typename MapFunctor, typename T, typename C, typename U> +C blockingMappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + T (C::*reduce)(U), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<typename MapFunctor::result_type, C> + (begin, + end, + map, + QtConcurrent::MemberFunctionWrapper1<T, C, U>(reduce), + options) + .startBlocking(); +} + +template <typename ResultType, typename Iterator, typename T, typename U, typename ReduceFunctor> +ResultType blockingMappedReduced(Iterator begin, + Iterator end, + T (map)(U), + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, ResultType> + (begin, + end, + QtConcurrent::FunctionWrapper1<T, U>(map), + reduce, + options) + .startBlocking(); +} + +template <typename ResultType, typename Iterator, typename T, typename C, typename ReduceFunctor> +ResultType blockingMappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, ResultType> + (begin, + end, + QtConcurrent::ConstMemberFunctionWrapper<T, C>(map), + reduce, + options) + .startBlocking(); +} + +template <typename Iterator, typename T, typename U, typename V, typename W, typename X> +W blockingMappedReduced(Iterator begin, + Iterator end, + T (map)(U), + V (reduce)(W &, X), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, W> + (begin, + end, + QtConcurrent::FunctionWrapper1<T, U>(map), + QtConcurrent::FunctionWrapper2<V, W &, X>(reduce), + options) + .startBlocking(); +} + +template <typename Iterator, typename T, typename C, typename U, typename V, typename W> +V blockingMappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + U (reduce)(V &, W), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, V> + (begin, + end, + QtConcurrent::ConstMemberFunctionWrapper<T, C>(map), + QtConcurrent::FunctionWrapper2<U, V &, W>(reduce), + options) + .startBlocking(); +} + +template <typename Iterator, typename T, typename U, typename V, typename C, typename W> +C blockingMappedReduced(Iterator begin, + Iterator end, + T (map)(U), + V (C::*reduce)(W), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, C> + (begin, + end, + QtConcurrent::FunctionWrapper1<T, U>(map), + QtConcurrent::MemberFunctionWrapper1<V, C, W>(reduce), + options) + .startBlocking(); +} + +template <typename Iterator, typename T, typename C, typename U,typename D, typename V> +D blockingMappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + U (D::*reduce)(V), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced<T, D> + (begin, + end, + QtConcurrent::ConstMemberFunctionWrapper<T, C>(map), + QtConcurrent::MemberFunctionWrapper1<U, D, V>(reduce), + options) + .startBlocking(); +} + +// mapped() for sequences with a different putput sequence type. +template <typename OutputSequence, typename InputSequence, typename MapFunctor> +OutputSequence blockingMapped(const InputSequence &sequence, MapFunctor map) +{ + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +template <typename OutputSequence, typename InputSequence, typename T, typename U> +OutputSequence blockingMapped(const InputSequence &sequence, T (map)(U)) +{ + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +template <typename OutputSequence, typename InputSequence, typename T, typename C> +OutputSequence blockingMapped(const InputSequence &sequence, T (C::*map)() const) +{ + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} +#ifndef QT_NO_TEMPLATE_TEMPLATE_PARAMETERS + +// overloads for changing the container value type: +template <template <typename> class Sequence, typename MapFunctor, typename T> +Sequence<typename MapFunctor::result_type> blockingMapped(const Sequence<T> &sequence, MapFunctor map) +{ + typedef Sequence<typename MapFunctor::result_type> OutputSequence; + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +template <template <typename> class Sequence, typename T, typename U, typename V> +Sequence<U> blockingMapped(const Sequence<T> &sequence, U (map)(V)) +{ + typedef Sequence<U> OutputSequence; + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +template <template <typename> class Sequence, typename T, typename U, typename C> +Sequence<U> blockingMapped(const Sequence<T> &sequence, U (C::*map)() const) +{ + typedef Sequence<U> OutputSequence; + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +#endif // QT_NO_TEMPLATE_TEMPLATE_PARAMETER + +// overloads for changing the container value type from a QStringList: +template <typename MapFunctor> +QList<typename MapFunctor::result_type> blockingMapped(const QStringList &sequence, MapFunctor map) +{ + typedef QList<typename MapFunctor::result_type> OutputSequence; + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +template <typename U, typename V> +QList<U> blockingMapped(const QStringList &sequence, U (map)(V)) +{ + typedef QList<U> OutputSequence; + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +template <typename U, typename C> +QList<U> blockingMapped(const QStringList &sequence, U (C::*map)() const) +{ + typedef QList<U> OutputSequence; + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +// mapped() for iterator ranges +template <typename Sequence, typename Iterator, typename MapFunctor> +Sequence blockingMapped(Iterator begin, Iterator end, MapFunctor map) +{ + return blockingMappedReduced(begin, end, map, &Sequence::push_back, + QtConcurrent::OrderedReduce); +} + +template <typename Sequence, typename Iterator, typename T, typename U> +Sequence blockingMapped(Iterator begin, Iterator end, T (map)(U)) +{ + return blockingMappedReduced(begin, end, map, &Sequence::push_back, + QtConcurrent::OrderedReduce); +} + +template <typename Sequence, typename Iterator, typename T, typename C> +Sequence blockingMapped(Iterator begin, Iterator end, T (C::*map)() const) +{ + return blockingMappedReduced(begin, end, map, &Sequence::push_back, + QtConcurrent::OrderedReduce); +} + +} // namespace QtConcurrent + +#endif // qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentmapkernel.h b/src/corelib/concurrent/qtconcurrentmapkernel.h new file mode 100644 index 0000000..0c6a5ad --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentmapkernel.h @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_MAPKERNEL_H +#define QTCONCURRENT_MAPKERNEL_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qtconcurrentiteratekernel.h> +#include <QtCore/qtconcurrentreducekernel.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc +namespace QtConcurrent { + +// map kernel, works with both parallel-for and parallel-while +template <typename Iterator, typename MapFunctor> +class MapKernel : public IterateKernel<Iterator, void> +{ + MapFunctor map; +public: + typedef void ReturnType; + MapKernel(Iterator begin, Iterator end, MapFunctor _map) + : IterateKernel<Iterator, void>(begin, end), map(_map) + { } + + bool runIteration(Iterator it, int, void *) + { + map(*it); + return false; + } + + bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, void *) + { + Iterator it = sequenceBeginIterator; + advance(it, beginIndex); + for (int i = beginIndex; i < endIndex; ++i) { + runIteration(it, i, 0); + advance(it, 1); + } + + return false; + } +}; + +template <typename ReducedResultType, + typename Iterator, + typename MapFunctor, + typename ReduceFunctor, + typename Reducer = ReduceKernel<ReduceFunctor, + ReducedResultType, + typename MapFunctor::result_type> > +class MappedReducedKernel : public IterateKernel<Iterator, ReducedResultType> +{ + ReducedResultType reducedResult; + MapFunctor map; + ReduceFunctor reduce; + Reducer reducer; +public: + typedef ReducedResultType ReturnType; + MappedReducedKernel(Iterator begin, Iterator end, MapFunctor _map, ReduceFunctor _reduce, ReduceOptions reduceOptions) + : IterateKernel<Iterator, ReducedResultType>(begin, end), reducedResult(), map(_map), reduce(_reduce), reducer(reduceOptions) + { } + + MappedReducedKernel(ReducedResultType initialValue, + MapFunctor _map, + ReduceFunctor _reduce) + : reducedResult(initialValue), map(_map), reduce(_reduce) + { } + + bool runIteration(Iterator it, int index, ReducedResultType *) + { + IntermediateResults<typename MapFunctor::result_type> results; + results.begin = index; + results.end = index + 1; + + results.vector.append(map(*it)); + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + bool runIterations(Iterator sequenceBeginIterator, int begin, int end, ReducedResultType *) + { + IntermediateResults<typename MapFunctor::result_type> results; + results.begin = begin; + results.end = end; + results.vector.reserve(end - begin); + + Iterator it = sequenceBeginIterator; + advance(it, begin); + for (int i = begin; i < end; ++i) { + results.vector.append(map(*(it))); + advance(it, 1); + } + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + void finish() + { + reducer.finish(reduce, reducedResult); + } + + bool shouldThrottleThread() + { + return IterateKernel<Iterator, ReducedResultType>::shouldThrottleThread() || reducer.shouldThrottle(); + } + + bool shouldStartThread() + { + return IterateKernel<Iterator, ReducedResultType>::shouldStartThread() && reducer.shouldStartThread(); + } + + typedef ReducedResultType ResultType; + ReducedResultType *result() + { + return &reducedResult; + } +}; + +template <typename Iterator, typename MapFunctor> +class MappedEachKernel : public IterateKernel<Iterator, typename MapFunctor::result_type> +{ + MapFunctor map; + typedef typename MapFunctor::result_type T; +public: + typedef T ReturnType; + typedef T ResultType; + + MappedEachKernel(Iterator begin, Iterator end, MapFunctor _map) + : IterateKernel<Iterator, T>(begin, end), map(_map) { } + + bool runIteration(Iterator it, int, T *result) + { + *result = map(*it); + return true; + } + + bool runIterations(Iterator sequenceBeginIterator, int begin, int end, T *results) + { + + Iterator it = sequenceBeginIterator; + advance(it, begin); + for (int i = begin; i < end; ++i) { + runIteration(it, i, results + (i - begin)); + advance(it, 1); + } + + return true; + } +}; + +template <typename Iterator, typename Functor> +inline ThreadEngineStarter<void> startMap(Iterator begin, Iterator end, Functor functor) +{ + return startThreadEngine(new MapKernel<Iterator, Functor>(begin, end, functor)); +} + +template <typename T, typename Iterator, typename Functor> +inline ThreadEngineStarter<T> startMapped(Iterator begin, Iterator end, Functor functor) +{ + return startThreadEngine(new MappedEachKernel<Iterator, Functor>(begin, end, functor)); +} + +/* + The SequnceHolder class is used to hold a reference to the + sequence we are working on. +*/ +template <typename Sequence, typename Base, typename Functor> +struct SequenceHolder1 : public Base +{ + SequenceHolder1(const Sequence &_sequence, Functor functor) + : Base(_sequence.begin(), _sequence.end(), functor), sequence(_sequence) + { } + + Sequence sequence; + + void finish() + { + Base::finish(); + // Clear the sequence to make sure all temporaries are destroyed + // before finished is signaled. + sequence = Sequence(); + } +}; + +template <typename T, typename Sequence, typename Functor> +inline ThreadEngineStarter<T> startMapped(const Sequence &sequence, Functor functor) +{ + typedef SequenceHolder1<Sequence, + MappedEachKernel<typename Sequence::const_iterator , Functor>, Functor> + SequenceHolderType; + + return startThreadEngine(new SequenceHolderType(sequence, functor)); +} + +template <typename IntermediateType, typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor> +inline ThreadEngineStarter<ResultType> startMappedReduced(const Sequence & sequence, + MapFunctor mapFunctor, ReduceFunctor reduceFunctor, + ReduceOptions options) +{ + typedef typename Sequence::const_iterator Iterator; + typedef ReduceKernel<ReduceFunctor, ResultType, IntermediateType> Reducer; + typedef MappedReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer> MappedReduceType; + typedef SequenceHolder2<Sequence, MappedReduceType, MapFunctor, ReduceFunctor> SequenceHolderType; + return startThreadEngine(new SequenceHolderType(sequence, mapFunctor, reduceFunctor, options)); +} + +template <typename IntermediateType, typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor> +inline ThreadEngineStarter<ResultType> startMappedReduced(Iterator begin, Iterator end, + MapFunctor mapFunctor, ReduceFunctor reduceFunctor, + ReduceOptions options) +{ + typedef ReduceKernel<ReduceFunctor, ResultType, IntermediateType> Reducer; + typedef MappedReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer> MappedReduceType; + return startThreadEngine(new MappedReduceType(begin, end, mapFunctor, reduceFunctor, options)); +} + +} // namespace QtConcurrent + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentmedian.h b/src/corelib/concurrent/qtconcurrentmedian.h new file mode 100644 index 0000000..a8ad17d --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentmedian.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_MEDIAN_H +#define QTCONCURRENT_MEDIAN_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qvector.h> +#include <QtCore/qalgorithms.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +template <typename T> +class Median +{ +public: + Median(int _bufferSize) + : currentMedian(), bufferSize(_bufferSize), currentIndex(0), valid(false), dirty(true) + { + values.resize(bufferSize); + } + + void reset() + { + values.fill(0); + currentIndex = 0; + valid = false; + dirty = true; + } + + void addValue(T value) + { + currentIndex = ((currentIndex + 1) % bufferSize); + if (valid == false && currentIndex % bufferSize == 0) + valid = true; + + // Only update the cached median value when we have to, that + // is when the new value is on then other side of the median + // compared to the current value at the index. + const T currentIndexValue = values[currentIndex]; + if ((currentIndexValue > currentMedian && currentMedian > value) + || (currentMedian > currentIndexValue && value > currentMedian)) { + dirty = true; + } + + values[currentIndex] = value; + } + + bool isMedianValid() const + { + return valid; + } + + T median() + { + if (dirty) { + dirty = false; + QVector<T> sorted = values; + qSort(sorted); + currentMedian = sorted.at(bufferSize / 2 + 1); + } + return currentMedian; + } +private: + QVector<T> values; + T currentMedian; + int bufferSize; + int currentIndex; + bool valid; + bool dirty; +}; + +} // namespace QtConcurrent + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentreducekernel.h b/src/corelib/concurrent/qtconcurrentreducekernel.h new file mode 100644 index 0000000..e863b63 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentreducekernel.h @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_REDUCEKERNEL_H +#define QTCONCURRENT_REDUCEKERNEL_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qatomic.h> +#include <QtCore/qlist.h> +#include <QtCore/qmap.h> +#include <QtCore/qmutex.h> +#include <QtCore/qthread.h> +#include <QtCore/qvector.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +namespace QtConcurrent { + +#ifndef qdoc + +/* + The ReduceQueueStartLimit and ReduceQueueThrottleLimit constants + limit the reduce queue size for MapReduce. When the number of + reduce blocks in the queue exceeds ReduceQueueStartLimit, + MapReduce won't start any new threads, and when it exceeds + ReduceQueueThrottleLimit running threads will be stopped. +*/ +enum { + ReduceQueueStartLimit = 20, + ReduceQueueThrottleLimit = 30 +}; + +// IntermediateResults holds a block of intermediate results from a +// map or filter functor. The begin/end offsets indicates the origin +// and range of the block. +template <typename T> +class IntermediateResults +{ +public: + int begin, end; + QVector<T> vector; +}; + +#endif // qdoc + +enum ReduceOption { + UnorderedReduce = 0x1, + OrderedReduce = 0x2, + SequentialReduce = 0x4 + // ParallelReduce = 0x8 +}; +Q_DECLARE_FLAGS(ReduceOptions, ReduceOption) +Q_DECLARE_OPERATORS_FOR_FLAGS(ReduceOptions) + +#ifndef qdoc + +// supports both ordered and out-of-order reduction +template <typename ReduceFunctor, typename ReduceResultType, typename T> +class ReduceKernel +{ + typedef QMap<int, IntermediateResults<T> > ResultsMap; + + const ReduceOptions reduceOptions; + + QMutex mutex; + int progress, resultsMapSize; + ResultsMap resultsMap; + + bool canReduce(int begin) const + { + return (((reduceOptions & UnorderedReduce) + && progress == 0) + || ((reduceOptions & OrderedReduce) + && progress == begin)); + } + + void reduceResult(ReduceFunctor &reduce, + ReduceResultType &r, + const IntermediateResults<T> &result) + { + for (int i = 0; i < result.vector.size(); ++i) { + reduce(r, result.vector.at(i)); + } + } + + void reduceResults(ReduceFunctor &reduce, + ReduceResultType &r, + ResultsMap &map) + { + typename ResultsMap::iterator it = map.begin(); + while (it != map.end()) { + reduceResult(reduce, r, it.value()); + ++it; + } + } + +public: + ReduceKernel(ReduceOptions _reduceOptions) + : reduceOptions(_reduceOptions), progress(0), resultsMapSize(0) + { } + + void runReduce(ReduceFunctor &reduce, + ReduceResultType &r, + const IntermediateResults<T> &result) + { + QMutexLocker locker(&mutex); + if (!canReduce(result.begin)) { + ++resultsMapSize; + resultsMap.insert(result.begin, result); + return; + } + + if (reduceOptions & UnorderedReduce) { + // UnorderedReduce + progress = -1; + + // reduce this result + locker.unlock(); + reduceResult(reduce, r, result); + locker.relock(); + + // reduce all stored results as well + while (!resultsMap.isEmpty()) { + ResultsMap resultsMapCopy = resultsMap; + resultsMap.clear(); + + locker.unlock(); + reduceResults(reduce, r, resultsMapCopy); + locker.relock(); + + resultsMapSize -= resultsMapCopy.size(); + } + + progress = 0; + } else { + // reduce this result + locker.unlock(); + reduceResult(reduce, r, result); + locker.relock(); + + // OrderedReduce + progress += result.end - result.begin; + + // reduce as many other results as possible + typename ResultsMap::iterator it = resultsMap.begin(); + while (it != resultsMap.end()) { + if (it.value().begin != progress) + break; + + locker.unlock(); + reduceResult(reduce, r, it.value()); + locker.relock(); + + --resultsMapSize; + progress += it.value().end - it.value().begin; + it = resultsMap.erase(it); + } + } + } + + // final reduction + void finish(ReduceFunctor &reduce, ReduceResultType &r) + { + reduceResults(reduce, r, resultsMap); + } + + inline bool shouldThrottle() + { + return (resultsMapSize > (ReduceQueueThrottleLimit * QThread::idealThreadCount())); + } + + inline bool shouldStartThread() + { + return (resultsMapSize <= (ReduceQueueStartLimit * QThread::idealThreadCount())); + } +}; + +template <typename Sequence, typename Base, typename Functor1, typename Functor2> +struct SequenceHolder2 : public Base +{ + SequenceHolder2(const Sequence &_sequence, + Functor1 functor1, + Functor2 functor2, + ReduceOptions reduceOptions) + : Base(_sequence.begin(), _sequence.end(), functor1, functor2, reduceOptions), + sequence(_sequence) + { } + + Sequence sequence; + + void finish() + { + Base::finish(); + // Clear the sequence to make sure all temporaries are destroyed + // before finished is signaled. + sequence = Sequence(); + } +}; + +#endif //qdoc + +} // namespace QtConcurrent + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentresultstore.cpp b/src/corelib/concurrent/qtconcurrentresultstore.cpp new file mode 100644 index 0000000..87bb2a7d --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentresultstore.cpp @@ -0,0 +1,256 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtconcurrentresultstore.h" + +#ifndef QT_NO_QFUTURE + +QT_BEGIN_NAMESPACE + +namespace QtConcurrent { + +ResultIteratorBase::ResultIteratorBase() + : mapIterator(QMap<int, ResultItem>::const_iterator()), m_vectorIndex(0) { } +ResultIteratorBase::ResultIteratorBase(QMap<int, ResultItem>::const_iterator _mapIterator, int _vectorIndex) + : mapIterator(_mapIterator), m_vectorIndex(_vectorIndex) { } + +int ResultIteratorBase::vectorIndex() const { return m_vectorIndex; } +int ResultIteratorBase::resultIndex() const { return mapIterator.key() + m_vectorIndex; } + +ResultIteratorBase ResultIteratorBase::operator++() +{ + if (canIncrementVectorIndex()) { + ++m_vectorIndex; + } else { + ++mapIterator; + m_vectorIndex = 0; + } + return *this; +} + +int ResultIteratorBase::batchSize() const +{ + return mapIterator.value().count(); +} + +void ResultIteratorBase::batchedAdvance() +{ + ++mapIterator; + m_vectorIndex = 0; +} + +bool ResultIteratorBase::operator==(const ResultIteratorBase &other) const +{ + return (mapIterator == other.mapIterator && m_vectorIndex == other.m_vectorIndex); +} + +bool ResultIteratorBase::operator!=(const ResultIteratorBase &other) const +{ + return !operator==(other); +} + +bool ResultIteratorBase::isVector() const +{ + return mapIterator.value().isVector(); +} + +bool ResultIteratorBase::canIncrementVectorIndex() const +{ + return (m_vectorIndex + 1 < mapIterator.value().m_count); +} + +ResultStoreBase::ResultStoreBase() + : insertIndex(0), resultCount(0), m_filterMode(false), filteredResults(0) { } + +void ResultStoreBase::setFilterMode(bool enable) +{ + m_filterMode = enable; +} + +bool ResultStoreBase::filterMode() const +{ + return m_filterMode; +} + +void ResultStoreBase::syncResultCount() +{ + ResultIteratorBase it = resultAt(resultCount); + while (it != end()) { + resultCount += it.batchSize(); + it = resultAt(resultCount); + } +} + +void ResultStoreBase::insertResultItemIfValid(int index, ResultItem &resultItem) +{ + if (resultItem.isValid()) { + m_results[index] = resultItem; + syncResultCount(); + } else { + filteredResults += resultItem.count(); + } +} + +int ResultStoreBase::insertResultItem(int index, ResultItem &resultItem) +{ + int storeIndex; + if (m_filterMode && index != -1 && index > insertIndex) { + pendingResults[index] = resultItem; + storeIndex = index; + } else { + storeIndex = updateInsertIndex(index, resultItem.count()); + insertResultItemIfValid(storeIndex - filteredResults, resultItem); + } + syncPendingResults(); + return storeIndex; +} + +void ResultStoreBase::syncPendingResults() +{ + // check if we can insert any of the pending results: + QMap<int, ResultItem>::iterator it = pendingResults.begin(); + while (it != pendingResults.end()) { + int index = it.key(); + if (index != resultCount + filteredResults) + break; + + ResultItem result = it.value(); + insertResultItemIfValid(index - filteredResults, result); + pendingResults.erase(it); + it = pendingResults.begin(); + } +} + +int ResultStoreBase::addResult(int index, const void *result) +{ + ResultItem resultItem(result, 0); // 0 means "not a vector" + return insertResultItem(index, resultItem); +} + +int ResultStoreBase::addResults(int index, const void *results, int vectorSize, int totalCount) +{ + if (m_filterMode == false || vectorSize == totalCount) { + ResultItem resultItem(results, vectorSize); + return insertResultItem(index, resultItem); + } else { + if (vectorSize > 0) { + ResultItem filteredIn(results, vectorSize); + insertResultItem(index, filteredIn); + } + ResultItem filteredAway(0, totalCount - vectorSize); + return insertResultItem(index + vectorSize, filteredAway); + } +} + +ResultIteratorBase ResultStoreBase::begin() const +{ + return ResultIteratorBase(m_results.begin()); +} + +ResultIteratorBase ResultStoreBase::end() const +{ + return ResultIteratorBase(m_results.end()); +} + +bool ResultStoreBase::hasNextResult() const +{ + return begin() != end(); +} + +ResultIteratorBase ResultStoreBase::resultAt(int index) const +{ + if (m_results.isEmpty()) + return ResultIteratorBase(m_results.end()); + QMap<int, ResultItem>::const_iterator it = m_results.lowerBound(index); + + // lowerBound returns either an iterator to the result or an iterator + // to the nearest greater index. If the latter happens it might be + // that the result is stored in a vector at the previous index. + if (it == m_results.end()) { + --it; + if (it.value().isVector() == false) { + return ResultIteratorBase(m_results.end()); + } + } else { + if (it.key() > index) { + if (it == m_results.begin()) + return ResultIteratorBase(m_results.end()); + --it; + } + } + + const int vectorIndex = index - it.key(); + + if (vectorIndex >= it.value().count()) + return ResultIteratorBase(m_results.end()); + else if (it.value().isVector() == false && vectorIndex != 0) + return ResultIteratorBase(m_results.end()); + return ResultIteratorBase(it, vectorIndex); +} + +bool ResultStoreBase::contains(int index) const +{ + return (resultAt(index) != end()); +} + +int ResultStoreBase::count() const +{ + return resultCount; +} + +// returns the insert index, calling this funciton with +// index equal to -1 returns the next available index. +int ResultStoreBase::updateInsertIndex(int index, int _count) +{ + if (index == -1) { + index = insertIndex; + insertIndex += _count; + } else { + insertIndex = qMax(index + _count, insertIndex); + } + return index; +} + +} // namespace QtConcurrent + +QT_END_NAMESPACE + +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qtconcurrentresultstore.h b/src/corelib/concurrent/qtconcurrentresultstore.h new file mode 100644 index 0000000..c39e921 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentresultstore.h @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_RESULTSTORE_H +#define QTCONCURRENT_RESULTSTORE_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_QFUTURE + +#include <QtCore/qmap.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +/* + ResultStore stores indexed results. Results can be added and retrieved + either individually batched in a QVector. Retriveing results and checking + which indexes are in the store can be done either by iterating or by random + accees. In addition results kan be removed from the front of the store, + either individually or in batches. +*/ + +#ifndef qdoc + +namespace QtConcurrent { + +class ResultItem +{ +public: + ResultItem(const void *_result, int _count) : m_count(_count), result(_result) { } // contruct with vector of results + ResultItem(const void *_result) : m_count(0), result(_result) { } // construct with result + ResultItem() : m_count(0), result(0) { } + bool isValid() const { return result != 0; } + bool isVector() const { return m_count != 0; } + int count() const { return (m_count == 0) ? 1 : m_count; } + int m_count; // result is either a pointer to a result or to a vector of results, + const void *result; // if count is 0 it's a result, otherwise it's a vector. +}; + +class Q_CORE_EXPORT ResultIteratorBase +{ +public: + ResultIteratorBase(); + ResultIteratorBase(QMap<int, ResultItem>::const_iterator _mapIterator, int _vectorIndex = 0); + int vectorIndex() const; + int resultIndex() const; + + ResultIteratorBase operator++(); + int batchSize() const; + void batchedAdvance(); + bool operator==(const ResultIteratorBase &other) const; + bool operator!=(const ResultIteratorBase &other) const; + bool isVector() const; + bool canIncrementVectorIndex() const; +protected: + QMap<int, ResultItem>::const_iterator mapIterator; + int m_vectorIndex; +}; + +template <typename T> +class ResultIterator : public ResultIteratorBase +{ +public: + ResultIterator(const ResultIteratorBase &base) + : ResultIteratorBase(base) { } + + const T &value() const + { + return *pointer(); + } + + const T *pointer() const + { + if (mapIterator.value().isVector()) + return &(reinterpret_cast<const QVector<T> *>(mapIterator.value().result)->at(m_vectorIndex)); + else + return reinterpret_cast<const T *>(mapIterator.value().result); + } +}; + +class Q_CORE_EXPORT ResultStoreBase +{ +public: + ResultStoreBase(); + void setFilterMode(bool enable); + bool filterMode() const; + int addResult(int index, const void *result); + int addResults(int index, const void *results, int vectorSize, int logicalCount); + ResultIteratorBase begin() const; + ResultIteratorBase end() const; + bool hasNextResult() const; + ResultIteratorBase resultAt(int index) const; + bool contains(int index) const; + int count() const; + virtual ~ResultStoreBase() { }; + +protected: + int insertResultItem(int index, ResultItem &resultItem); + void insertResultItemIfValid(int index, ResultItem &resultItem); + void syncPendingResults(); + void syncResultCount(); + int updateInsertIndex(int index, int _count); + + QMap<int, ResultItem> m_results; + int insertIndex; // The index where the next results(s) will be inserted. + int resultCount; // The number of consecutive results stored, starting at index 0. + + bool m_filterMode; + QMap<int, ResultItem> pendingResults; + int filteredResults; + +}; + +template <typename T> +class ResultStore : public ResultStoreBase +{ +public: + ResultStore() { } + + ResultStore(const ResultStoreBase &base) + : ResultStoreBase(base) { } + + int addResult(int index, const T *result) + { + if (result == 0) + return ResultStoreBase::addResult(index, result); + else + return ResultStoreBase::addResult(index, new T(*result)); + } + + int addResults(int index, const QVector<T> *results) + { + return ResultStoreBase::addResults(index, new QVector<T>(*results), results->count(), results->count()); + } + + int addResults(int index, const QVector<T> *results, int totalCount) + { + return ResultStoreBase::addResults(index, new QVector<T>(*results), results->count(), totalCount); + } + + int addCanceledResult(int index) + { + return addResult(index, 0); + } + + int addCanceledResults(int index, int _count) + { + QVector<T> empty; + return addResults(index, &empty, _count); + } + + ResultIterator<T> begin() const + { + return static_cast<ResultIterator<T> >(ResultStoreBase::begin()); + } + + ResultIterator<T> end() const + { + return static_cast<ResultIterator<T> >(ResultStoreBase::end()); + } + + ResultIterator<T> resultAt(int index) const + { + return static_cast<ResultIterator<T> >(ResultStoreBase::resultAt(index)); + } + + void clear() + { + QMap<int, ResultItem>::const_iterator mapIterator = m_results.constBegin(); + while (mapIterator != m_results.constEnd()) { + if (mapIterator.value().isVector()) + delete reinterpret_cast<const QVector<T> *>(mapIterator.value().result); + else + delete reinterpret_cast<const T *>(mapIterator.value().result); + ++mapIterator; + } + resultCount = 0; + m_results.clear(); + } + + ~ResultStore() + { + clear(); + } + +}; + +} // namespace QtConcurrent + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentrun.cpp b/src/corelib/concurrent/qtconcurrentrun.cpp new file mode 100644 index 0000000..068a913 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentrun.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \headerfile <QtConcurrentRun> + \title Asynchronous Run + + \brief The <QtConcurrentRun> header provides a way to run a function in a + separate thread. + + This function is a part of the \l {threads.html#qtconcurrent-intro}{Qt Concurrent} framework. + + The QtConcurrent::run() function runs a function in a separate thread. + The return value of the function is made available through the QFuture API. + + \section1 Running a Function in a Separate Thread + + To run a function in another thread, use QtConcurrent::run(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentrun.cpp 0 + + This will run \e aFunction in a separate thread obtained from the default + QThreadPool. You can use the QFuture and QFutureWatcher classes to monitor + the status of the function. + + \section1 Passing Arguments to the Function + + Passing arguments to the function is done by adding them to the + QtConcurrent::run() call immediately after the function name. For example: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentrun.cpp 1 + + A copy of each argument is made at the point where QtConcurrent::run() is + called, and these values are passed to the thread when it begins executing + the function. Changes made to the arguments after calling + QtConcurrent::run() are \e not visible to the thread. + + \section1 Returning Values from the Function + + Any return value from the function is available via QFuture: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentrun.cpp 2 + + As documented above, passing arguments is done like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentrun.cpp 3 + + Note that the QFuture::result() function blocks and waits for the result + to become available. Use QFutureWatcher to get notification when the + function has finished execution and the result is available. + + \section1 Additional API Features + + \section2 Using Member Functions + + QtConcurrent::run() also accepts pointers to member functions. The first + argument must be either a const reference or a pointer to an instance of + the class. Passing by const reference is useful when calling const member + functions; passing by pointer is useful for calling non-const member + functions that modify the instance. + + For example, calling QString::split() (a const member function) in a + separate thread is done like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentrun.cpp 4 + + Calling a non-const member function is done like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentrun.cpp 5 + + \section2 Using Bound Function Arguments + + Note that Qt does not provide support for bound functions. This is + provided by 3rd party libraries like + \l{http://www.boost.org/libs/bind/bind.html}{Boost} or + \l{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf} + {C++ TR1 Library Extensions}. + + You can use boost::bind() or std::tr1::bind() to \e bind a number of + arguments to a function when called. There are number of reasons for doing + this: + + \list + \o To call a function that takes more than 5 arguments. + \o To simplify calling a function with constant arguments. + \o Changing the order of arguments. + \endlist + + See the documentation for the relevant functions for details on how to use + the bind API. + + Calling a bound function is done like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentrun.cpp 6 +*/ + +/*! + \fn QFuture<T> QtConcurrent::run(Function function, ...); + \relates <QtConcurrentRun> + + Runs \a function in a separate thread. The thread is taken from the global + QThreadPool. Note that the function may not run immediately; the function + will only be run when a thread is available. + + T is the same type as the return value of \a function. Non-void return + values can be accessed via the QFuture::result() function. + + Note that the QFuture returned by QtConcurrent::run() does not support + canceling, pausing, or progress reporting. The QFuture returned can only + be used to query for the running/finished status and the return value of + the function. +*/ diff --git a/src/corelib/concurrent/qtconcurrentrun.h b/src/corelib/concurrent/qtconcurrentrun.h new file mode 100644 index 0000000..00938fa --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentrun.h @@ -0,0 +1,297 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Generated code, do not edit! Use generator at tools/qtconcurrent/generaterun/ +#ifndef QTCONCURRENT_RUN_H +#define QTCONCURRENT_RUN_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qtconcurrentrunbase.h> +#include <QtCore/qtconcurrentstoredfunctioncall.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifdef qdoc + +namespace QtConcurrent { + + template <typename T> + QFuture<T> run(Function function, ...); + +} // namespace QtConcurrent + +#else + +namespace QtConcurrent { + +template <typename T> +QFuture<T> run(T (*functionPointer)()) +{ + return (new QT_TYPENAME SelectStoredFunctorCall0<T, T (*)()>::type(functionPointer))->start(); +} +template <typename T, typename Param1, typename Arg1> +QFuture<T> run(T (*functionPointer)(Param1), const Arg1 &arg1) +{ + return (new QT_TYPENAME SelectStoredFunctorCall1<T, T (*)(Param1), Arg1>::type(functionPointer, arg1))->start(); +} +template <typename T, typename Param1, typename Arg1, typename Param2, typename Arg2> +QFuture<T> run(T (*functionPointer)(Param1, Param2), const Arg1 &arg1, const Arg2 &arg2) +{ + return (new QT_TYPENAME SelectStoredFunctorCall2<T, T (*)(Param1, Param2), Arg1, Arg2>::type(functionPointer, arg1, arg2))->start(); +} +template <typename T, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +QFuture<T> run(T (*functionPointer)(Param1, Param2, Param3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) +{ + return (new QT_TYPENAME SelectStoredFunctorCall3<T, T (*)(Param1, Param2, Param3), Arg1, Arg2, Arg3>::type(functionPointer, arg1, arg2, arg3))->start(); +} +template <typename T, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +QFuture<T> run(T (*functionPointer)(Param1, Param2, Param3, Param4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) +{ + return (new QT_TYPENAME SelectStoredFunctorCall4<T, T (*)(Param1, Param2, Param3, Param4), Arg1, Arg2, Arg3, Arg4>::type(functionPointer, arg1, arg2, arg3, arg4))->start(); +} +template <typename T, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +QFuture<T> run(T (*functionPointer)(Param1, Param2, Param3, Param4, Param5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) +{ + return (new QT_TYPENAME SelectStoredFunctorCall5<T, T (*)(Param1, Param2, Param3, Param4, Param5), Arg1, Arg2, Arg3, Arg4, Arg5>::type(functionPointer, arg1, arg2, arg3, arg4, arg5))->start(); +} + +template <typename FunctionObject> +QFuture<typename FunctionObject::result_type> run(FunctionObject functionObject) +{ + return (new QT_TYPENAME SelectStoredFunctorCall0<QT_TYPENAME FunctionObject::result_type, FunctionObject>::type(functionObject))->start(); +} +template <typename FunctionObject, typename Arg1> +QFuture<typename FunctionObject::result_type> run(FunctionObject functionObject, const Arg1 &arg1) +{ + return (new QT_TYPENAME SelectStoredFunctorCall1<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1>::type(functionObject, arg1))->start(); +} +template <typename FunctionObject, typename Arg1, typename Arg2> +QFuture<typename FunctionObject::result_type> run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2) +{ + return (new QT_TYPENAME SelectStoredFunctorCall2<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1, Arg2>::type(functionObject, arg1, arg2))->start(); +} +template <typename FunctionObject, typename Arg1, typename Arg2, typename Arg3> +QFuture<typename FunctionObject::result_type> run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) +{ + return (new QT_TYPENAME SelectStoredFunctorCall3<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1, Arg2, Arg3>::type(functionObject, arg1, arg2, arg3))->start(); +} +template <typename FunctionObject, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +QFuture<typename FunctionObject::result_type> run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) +{ + return (new QT_TYPENAME SelectStoredFunctorCall4<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1, Arg2, Arg3, Arg4>::type(functionObject, arg1, arg2, arg3, arg4))->start(); +} +template <typename FunctionObject, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> +QFuture<typename FunctionObject::result_type> run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) +{ + return (new QT_TYPENAME SelectStoredFunctorCall5<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1, Arg2, Arg3, Arg4, Arg5>::type(functionObject, arg1, arg2, arg3, arg4, arg5))->start(); +} + +template <typename FunctionObject> +QFuture<typename FunctionObject::result_type> run(FunctionObject *functionObject) +{ + return (new QT_TYPENAME SelectStoredFunctorPointerCall0<QT_TYPENAME FunctionObject::result_type, FunctionObject>::type(functionObject))->start(); +} +template <typename FunctionObject, typename Arg1> +QFuture<typename FunctionObject::result_type> run(FunctionObject *functionObject, const Arg1 &arg1) +{ + return (new QT_TYPENAME SelectStoredFunctorPointerCall1<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1>::type(functionObject, arg1))->start(); +} +template <typename FunctionObject, typename Arg1, typename Arg2> +QFuture<typename FunctionObject::result_type> run(FunctionObject *functionObject, const Arg1 &arg1, const Arg2 &arg2) +{ + return (new QT_TYPENAME SelectStoredFunctorPointerCall2<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1, Arg2>::type(functionObject, arg1, arg2))->start(); +} +template <typename FunctionObject, typename Arg1, typename Arg2, typename Arg3> +QFuture<typename FunctionObject::result_type> run(FunctionObject *functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) +{ + return (new QT_TYPENAME SelectStoredFunctorPointerCall3<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1, Arg2, Arg3>::type(functionObject, arg1, arg2, arg3))->start(); +} +template <typename FunctionObject, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +QFuture<typename FunctionObject::result_type> run(FunctionObject *functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) +{ + return (new QT_TYPENAME SelectStoredFunctorPointerCall4<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1, Arg2, Arg3, Arg4>::type(functionObject, arg1, arg2, arg3, arg4))->start(); +} +template <typename FunctionObject, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> +QFuture<typename FunctionObject::result_type> run(FunctionObject *functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) +{ + return (new QT_TYPENAME SelectStoredFunctorPointerCall5<QT_TYPENAME FunctionObject::result_type, FunctionObject, Arg1, Arg2, Arg3, Arg4, Arg5>::type(functionObject, arg1, arg2, arg3, arg4, arg5))->start(); +} + +template <typename T, typename Class> +QFuture<T> run(const Class &object, T (Class::*fn)()) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionCall0<T, Class>::type(fn, object))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1), const Arg1 &arg1) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionCall1<T, Class, Param1, Arg1>::type(fn, object, arg1))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1, Param2), const Arg1 &arg1, const Arg2 &arg2) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionCall2<T, Class, Param1, Arg1, Param2, Arg2>::type(fn, object, arg1, arg2))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1, Param2, Param3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionCall3<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3>::type(fn, object, arg1, arg2, arg3))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1, Param2, Param3, Param4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionCall4<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4>::type(fn, object, arg1, arg2, arg3, arg4))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1, Param2, Param3, Param4, Param5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionCall5<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5>::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); +} + +template <typename T, typename Class> +QFuture<T> run(const Class &object, T (Class::*fn)() const) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionCall0<T, Class>::type(fn, object))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1) const, const Arg1 &arg1) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionCall1<T, Class, Param1, Arg1>::type(fn, object, arg1))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1, Param2) const, const Arg1 &arg1, const Arg2 &arg2) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionCall2<T, Class, Param1, Arg1, Param2, Arg2>::type(fn, object, arg1, arg2))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1, Param2, Param3) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionCall3<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3>::type(fn, object, arg1, arg2, arg3))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1, Param2, Param3, Param4) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionCall4<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4>::type(fn, object, arg1, arg2, arg3, arg4))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +QFuture<T> run(const Class &object, T (Class::*fn)(Param1, Param2, Param3, Param4, Param5) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionCall5<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5>::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); +} + +template <typename T, typename Class> +QFuture<T> run(Class *object, T (Class::*fn)()) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall0<T, Class>::type(fn, object))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1> +QFuture<T> run(Class *object, T (Class::*fn)(Param1), const Arg1 &arg1) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall1<T, Class, Param1, Arg1>::type(fn, object, arg1))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +QFuture<T> run(Class *object, T (Class::*fn)(Param1, Param2), const Arg1 &arg1, const Arg2 &arg2) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall2<T, Class, Param1, Arg1, Param2, Arg2>::type(fn, object, arg1, arg2))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +QFuture<T> run(Class *object, T (Class::*fn)(Param1, Param2, Param3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall3<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3>::type(fn, object, arg1, arg2, arg3))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +QFuture<T> run(Class *object, T (Class::*fn)(Param1, Param2, Param3, Param4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall4<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4>::type(fn, object, arg1, arg2, arg3, arg4))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +QFuture<T> run(Class *object, T (Class::*fn)(Param1, Param2, Param3, Param4, Param5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) +{ + return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall5<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5>::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); +} + +template <typename T, typename Class> +QFuture<T> run(const Class *object, T (Class::*fn)() const) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall0<T, Class>::type(fn, object))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1> +QFuture<T> run(const Class *object, T (Class::*fn)(Param1) const, const Arg1 &arg1) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall1<T, Class, Param1, Arg1>::type(fn, object, arg1))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +QFuture<T> run(const Class *object, T (Class::*fn)(Param1, Param2) const, const Arg1 &arg1, const Arg2 &arg2) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall2<T, Class, Param1, Arg1, Param2, Arg2>::type(fn, object, arg1, arg2))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +QFuture<T> run(const Class *object, T (Class::*fn)(Param1, Param2, Param3) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall3<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3>::type(fn, object, arg1, arg2, arg3))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +QFuture<T> run(const Class *object, T (Class::*fn)(Param1, Param2, Param3, Param4) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall4<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4>::type(fn, object, arg1, arg2, arg3, arg4))->start(); +} +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +QFuture<T> run(const Class *object, T (Class::*fn)(Param1, Param2, Param3, Param4, Param5) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) +{ + return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall5<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5>::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); +} + +} //namespace QtConcurrent + +#endif // qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentrunbase.h b/src/corelib/concurrent/qtconcurrentrunbase.h new file mode 100644 index 0000000..51f5aa1 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentrunbase.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_RUNBASE_H +#define QTCONCURRENT_RUNBASE_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qfuture.h> +#include <QtCore/qrunnable.h> +#include <QtCore/qthreadpool.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +template <typename T> +struct SelectSpecialization +{ + template <class Normal, class Void> + struct Type { typedef Normal type; }; +}; + +template <> +struct SelectSpecialization<void> +{ + template <class Normal, class Void> + struct Type { typedef Void type; }; +}; + +template <typename T> +class RunFunctionTaskBase : public QFutureInterface<T> , public QRunnable +{ +public: + QFuture<T> start() + { + this->setRunnable(this); + this->reportStarted(); + QFuture<T> future = this->future(); + QThreadPool::globalInstance()->start(this, /*m_priority*/ 0); + return future; + } + + void run() {} + virtual void runFunctor() = 0; +}; + +template <typename T> +class RunFunctionTask : public RunFunctionTaskBase<T> +{ +public: + void run() + { + if (this->isCanceled()) { + this->reportFinished(); + return; + } + this->runFunctor(); + this->reportResult(result); + this->reportFinished(); + } + T result; +}; + +template <> +class RunFunctionTask<void> : public RunFunctionTaskBase<void> +{ +public: + void run() + { + if (this->isCanceled()) { + this->reportFinished(); + return; + } + this->runFunctor(); + this->reportFinished(); + } +}; + +} //namespace QtConcurrent + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentstoredfunctioncall.h b/src/corelib/concurrent/qtconcurrentstoredfunctioncall.h new file mode 100644 index 0000000..c7aeb9d --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentstoredfunctioncall.h @@ -0,0 +1,1328 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Generated code, do not edit! Use generator at tools/qtconcurrent/generaterun/ +#ifndef QTCONCURRENT_STOREDFUNCTIONCALL_H +#define QTCONCURRENT_STOREDFUNCTIONCALL_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT +#include <QtCore/qtconcurrentrunbase.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { +template <typename T, typename FunctionPointer> +struct StoredFunctorCall0: public RunFunctionTask<T> +{ + inline StoredFunctorCall0(FunctionPointer _function) + : function(_function) {} + void runFunctor() { this->result = function(); } + FunctionPointer function; + +}; + +template <typename T, typename FunctionPointer> +struct VoidStoredFunctorCall0: public RunFunctionTask<T> +{ + inline VoidStoredFunctorCall0(FunctionPointer _function) + : function(_function) {} + void runFunctor() { function(); } + FunctionPointer function; + +}; + +template <typename T, typename FunctionPointer> +struct SelectStoredFunctorCall0 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorCall0 <T, FunctionPointer>, + VoidStoredFunctorCall0<T, FunctionPointer> >::type type; +}; +template <typename T, typename FunctionPointer> +struct StoredFunctorPointerCall0: public RunFunctionTask<T> +{ + inline StoredFunctorPointerCall0(FunctionPointer * _function) + : function(_function) {} + void runFunctor() { this->result =(*function)(); } + FunctionPointer * function; + +}; + +template <typename T, typename FunctionPointer> +struct VoidStoredFunctorPointerCall0: public RunFunctionTask<T> +{ + inline VoidStoredFunctorPointerCall0(FunctionPointer * _function) + : function(_function) {} + void runFunctor() {(*function)(); } + FunctionPointer * function; + +}; + +template <typename T, typename FunctionPointer> +struct SelectStoredFunctorPointerCall0 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorPointerCall0 <T, FunctionPointer>, + VoidStoredFunctorPointerCall0<T, FunctionPointer> >::type type; +}; +template <typename T, typename Class> +class StoredMemberFunctionCall0 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionCall0(T (Class::*_fn)() , const Class &_object) + : fn(_fn), object(_object){ } + + void runFunctor() + { + this->result = (object.*fn)(); + } +private: + T (Class::*fn)(); + Class object; + +}; +template <typename T, typename Class> +class VoidStoredMemberFunctionCall0 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionCall0(T (Class::*_fn)() , const Class &_object) + : fn(_fn), object(_object){ } + + void runFunctor() + { + (object.*fn)(); + } +private: + T (Class::*fn)(); + Class object; + +}; +template <typename T, typename Class> +struct SelectStoredMemberFunctionCall0 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionCall0 <T, Class>, + VoidStoredMemberFunctionCall0<T, Class> >::type type; +}; +template <typename T, typename Class> +class StoredConstMemberFunctionCall0 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionCall0(T (Class::*_fn)() const, const Class &_object) + : fn(_fn), object(_object){ } + + void runFunctor() + { + this->result = (object.*fn)(); + } +private: + T (Class::*fn)()const; + const Class object; + +}; +template <typename T, typename Class> +class VoidStoredConstMemberFunctionCall0 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionCall0(T (Class::*_fn)() const, const Class &_object) + : fn(_fn), object(_object){ } + + void runFunctor() + { + (object.*fn)(); + } +private: + T (Class::*fn)()const; + const Class object; + +}; +template <typename T, typename Class> +struct SelectStoredConstMemberFunctionCall0 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionCall0 <T, Class>, + VoidStoredConstMemberFunctionCall0<T, Class> >::type type; +}; +template <typename T, typename Class> +class StoredMemberFunctionPointerCall0 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionPointerCall0(T (Class::*_fn)() , Class *_object) + : fn(_fn), object(_object){ } + + void runFunctor() + { + this->result = (object->*fn)(); + } +private: + T (Class::*fn)(); + Class *object; + +}; +template <typename T, typename Class> +class VoidStoredMemberFunctionPointerCall0 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionPointerCall0(T (Class::*_fn)() , Class *_object) + : fn(_fn), object(_object){ } + + void runFunctor() + { + (object->*fn)(); + } +private: + T (Class::*fn)(); + Class *object; + +}; +template <typename T, typename Class> +struct SelectStoredMemberFunctionPointerCall0 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionPointerCall0 <T, Class>, + VoidStoredMemberFunctionPointerCall0<T, Class> >::type type; +}; +template <typename T, typename Class> +class StoredConstMemberFunctionPointerCall0 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionPointerCall0(T (Class::*_fn)() const, Class const *_object) + : fn(_fn), object(_object){ } + + void runFunctor() + { + this->result = (object->*fn)(); + } +private: + T (Class::*fn)()const; + Class const *object; + +}; +template <typename T, typename Class> +class VoidStoredConstMemberFunctionPointerCall0 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionPointerCall0(T (Class::*_fn)() const, Class const *_object) + : fn(_fn), object(_object){ } + + void runFunctor() + { + (object->*fn)(); + } +private: + T (Class::*fn)()const; + Class const *object; + +}; +template <typename T, typename Class> +struct SelectStoredConstMemberFunctionPointerCall0 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionPointerCall0 <T, Class>, + VoidStoredConstMemberFunctionPointerCall0<T, Class> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1> +struct StoredFunctorCall1: public RunFunctionTask<T> +{ + inline StoredFunctorCall1(FunctionPointer _function, const Arg1 &_arg1) + : function(_function), arg1(_arg1) {} + void runFunctor() { this->result = function(arg1); } + FunctionPointer function; + Arg1 arg1; +}; + +template <typename T, typename FunctionPointer, typename Arg1> +struct VoidStoredFunctorCall1: public RunFunctionTask<T> +{ + inline VoidStoredFunctorCall1(FunctionPointer _function, const Arg1 &_arg1) + : function(_function), arg1(_arg1) {} + void runFunctor() { function(arg1); } + FunctionPointer function; + Arg1 arg1; +}; + +template <typename T, typename FunctionPointer, typename Arg1> +struct SelectStoredFunctorCall1 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorCall1 <T, FunctionPointer, Arg1>, + VoidStoredFunctorCall1<T, FunctionPointer, Arg1> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1> +struct StoredFunctorPointerCall1: public RunFunctionTask<T> +{ + inline StoredFunctorPointerCall1(FunctionPointer * _function, const Arg1 &_arg1) + : function(_function), arg1(_arg1) {} + void runFunctor() { this->result =(*function)(arg1); } + FunctionPointer * function; + Arg1 arg1; +}; + +template <typename T, typename FunctionPointer, typename Arg1> +struct VoidStoredFunctorPointerCall1: public RunFunctionTask<T> +{ + inline VoidStoredFunctorPointerCall1(FunctionPointer * _function, const Arg1 &_arg1) + : function(_function), arg1(_arg1) {} + void runFunctor() {(*function)(arg1); } + FunctionPointer * function; + Arg1 arg1; +}; + +template <typename T, typename FunctionPointer, typename Arg1> +struct SelectStoredFunctorPointerCall1 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorPointerCall1 <T, FunctionPointer, Arg1>, + VoidStoredFunctorPointerCall1<T, FunctionPointer, Arg1> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +class StoredMemberFunctionCall1 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionCall1(T (Class::*_fn)(Param1) , const Class &_object, const Arg1 &_arg1) + : fn(_fn), object(_object), arg1(_arg1){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1); + } +private: + T (Class::*fn)(Param1); + Class object; + Arg1 arg1; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +class VoidStoredMemberFunctionCall1 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionCall1(T (Class::*_fn)(Param1) , const Class &_object, const Arg1 &_arg1) + : fn(_fn), object(_object), arg1(_arg1){ } + + void runFunctor() + { + (object.*fn)(arg1); + } +private: + T (Class::*fn)(Param1); + Class object; + Arg1 arg1; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +struct SelectStoredMemberFunctionCall1 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionCall1 <T, Class, Param1, Arg1>, + VoidStoredMemberFunctionCall1<T, Class, Param1, Arg1> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +class StoredConstMemberFunctionCall1 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionCall1(T (Class::*_fn)(Param1) const, const Class &_object, const Arg1 &_arg1) + : fn(_fn), object(_object), arg1(_arg1){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1); + } +private: + T (Class::*fn)(Param1)const; + const Class object; + Arg1 arg1; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +class VoidStoredConstMemberFunctionCall1 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionCall1(T (Class::*_fn)(Param1) const, const Class &_object, const Arg1 &_arg1) + : fn(_fn), object(_object), arg1(_arg1){ } + + void runFunctor() + { + (object.*fn)(arg1); + } +private: + T (Class::*fn)(Param1)const; + const Class object; + Arg1 arg1; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +struct SelectStoredConstMemberFunctionCall1 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionCall1 <T, Class, Param1, Arg1>, + VoidStoredConstMemberFunctionCall1<T, Class, Param1, Arg1> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +class StoredMemberFunctionPointerCall1 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionPointerCall1(T (Class::*_fn)(Param1) , Class *_object, const Arg1 &_arg1) + : fn(_fn), object(_object), arg1(_arg1){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1); + } +private: + T (Class::*fn)(Param1); + Class *object; + Arg1 arg1; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +class VoidStoredMemberFunctionPointerCall1 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionPointerCall1(T (Class::*_fn)(Param1) , Class *_object, const Arg1 &_arg1) + : fn(_fn), object(_object), arg1(_arg1){ } + + void runFunctor() + { + (object->*fn)(arg1); + } +private: + T (Class::*fn)(Param1); + Class *object; + Arg1 arg1; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +struct SelectStoredMemberFunctionPointerCall1 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionPointerCall1 <T, Class, Param1, Arg1>, + VoidStoredMemberFunctionPointerCall1<T, Class, Param1, Arg1> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +class StoredConstMemberFunctionPointerCall1 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionPointerCall1(T (Class::*_fn)(Param1) const, Class const *_object, const Arg1 &_arg1) + : fn(_fn), object(_object), arg1(_arg1){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1); + } +private: + T (Class::*fn)(Param1)const; + Class const *object; + Arg1 arg1; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +class VoidStoredConstMemberFunctionPointerCall1 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionPointerCall1(T (Class::*_fn)(Param1) const, Class const *_object, const Arg1 &_arg1) + : fn(_fn), object(_object), arg1(_arg1){ } + + void runFunctor() + { + (object->*fn)(arg1); + } +private: + T (Class::*fn)(Param1)const; + Class const *object; + Arg1 arg1; +}; +template <typename T, typename Class, typename Param1, typename Arg1> +struct SelectStoredConstMemberFunctionPointerCall1 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionPointerCall1 <T, Class, Param1, Arg1>, + VoidStoredConstMemberFunctionPointerCall1<T, Class, Param1, Arg1> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2> +struct StoredFunctorCall2: public RunFunctionTask<T> +{ + inline StoredFunctorCall2(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2) + : function(_function), arg1(_arg1), arg2(_arg2) {} + void runFunctor() { this->result = function(arg1, arg2); } + FunctionPointer function; + Arg1 arg1; Arg2 arg2; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2> +struct VoidStoredFunctorCall2: public RunFunctionTask<T> +{ + inline VoidStoredFunctorCall2(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2) + : function(_function), arg1(_arg1), arg2(_arg2) {} + void runFunctor() { function(arg1, arg2); } + FunctionPointer function; + Arg1 arg1; Arg2 arg2; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2> +struct SelectStoredFunctorCall2 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorCall2 <T, FunctionPointer, Arg1, Arg2>, + VoidStoredFunctorCall2<T, FunctionPointer, Arg1, Arg2> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2> +struct StoredFunctorPointerCall2: public RunFunctionTask<T> +{ + inline StoredFunctorPointerCall2(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2) + : function(_function), arg1(_arg1), arg2(_arg2) {} + void runFunctor() { this->result =(*function)(arg1, arg2); } + FunctionPointer * function; + Arg1 arg1; Arg2 arg2; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2> +struct VoidStoredFunctorPointerCall2: public RunFunctionTask<T> +{ + inline VoidStoredFunctorPointerCall2(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2) + : function(_function), arg1(_arg1), arg2(_arg2) {} + void runFunctor() {(*function)(arg1, arg2); } + FunctionPointer * function; + Arg1 arg1; Arg2 arg2; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2> +struct SelectStoredFunctorPointerCall2 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorPointerCall2 <T, FunctionPointer, Arg1, Arg2>, + VoidStoredFunctorPointerCall2<T, FunctionPointer, Arg1, Arg2> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +class StoredMemberFunctionCall2 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionCall2(T (Class::*_fn)(Param1, Param2) , const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1, arg2); + } +private: + T (Class::*fn)(Param1, Param2); + Class object; + Arg1 arg1; Arg2 arg2; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +class VoidStoredMemberFunctionCall2 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionCall2(T (Class::*_fn)(Param1, Param2) , const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2){ } + + void runFunctor() + { + (object.*fn)(arg1, arg2); + } +private: + T (Class::*fn)(Param1, Param2); + Class object; + Arg1 arg1; Arg2 arg2; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +struct SelectStoredMemberFunctionCall2 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionCall2 <T, Class, Param1, Arg1, Param2, Arg2>, + VoidStoredMemberFunctionCall2<T, Class, Param1, Arg1, Param2, Arg2> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +class StoredConstMemberFunctionCall2 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionCall2(T (Class::*_fn)(Param1, Param2) const, const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1, arg2); + } +private: + T (Class::*fn)(Param1, Param2)const; + const Class object; + Arg1 arg1; Arg2 arg2; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +class VoidStoredConstMemberFunctionCall2 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionCall2(T (Class::*_fn)(Param1, Param2) const, const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2){ } + + void runFunctor() + { + (object.*fn)(arg1, arg2); + } +private: + T (Class::*fn)(Param1, Param2)const; + const Class object; + Arg1 arg1; Arg2 arg2; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +struct SelectStoredConstMemberFunctionCall2 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionCall2 <T, Class, Param1, Arg1, Param2, Arg2>, + VoidStoredConstMemberFunctionCall2<T, Class, Param1, Arg1, Param2, Arg2> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +class StoredMemberFunctionPointerCall2 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionPointerCall2(T (Class::*_fn)(Param1, Param2) , Class *_object, const Arg1 &_arg1, const Arg2 &_arg2) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1, arg2); + } +private: + T (Class::*fn)(Param1, Param2); + Class *object; + Arg1 arg1; Arg2 arg2; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +class VoidStoredMemberFunctionPointerCall2 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionPointerCall2(T (Class::*_fn)(Param1, Param2) , Class *_object, const Arg1 &_arg1, const Arg2 &_arg2) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2){ } + + void runFunctor() + { + (object->*fn)(arg1, arg2); + } +private: + T (Class::*fn)(Param1, Param2); + Class *object; + Arg1 arg1; Arg2 arg2; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +struct SelectStoredMemberFunctionPointerCall2 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionPointerCall2 <T, Class, Param1, Arg1, Param2, Arg2>, + VoidStoredMemberFunctionPointerCall2<T, Class, Param1, Arg1, Param2, Arg2> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +class StoredConstMemberFunctionPointerCall2 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionPointerCall2(T (Class::*_fn)(Param1, Param2) const, Class const *_object, const Arg1 &_arg1, const Arg2 &_arg2) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1, arg2); + } +private: + T (Class::*fn)(Param1, Param2)const; + Class const *object; + Arg1 arg1; Arg2 arg2; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +class VoidStoredConstMemberFunctionPointerCall2 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionPointerCall2(T (Class::*_fn)(Param1, Param2) const, Class const *_object, const Arg1 &_arg1, const Arg2 &_arg2) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2){ } + + void runFunctor() + { + (object->*fn)(arg1, arg2); + } +private: + T (Class::*fn)(Param1, Param2)const; + Class const *object; + Arg1 arg1; Arg2 arg2; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2> +struct SelectStoredConstMemberFunctionPointerCall2 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionPointerCall2 <T, Class, Param1, Arg1, Param2, Arg2>, + VoidStoredConstMemberFunctionPointerCall2<T, Class, Param1, Arg1, Param2, Arg2> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3> +struct StoredFunctorCall3: public RunFunctionTask<T> +{ + inline StoredFunctorCall3(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3) {} + void runFunctor() { this->result = function(arg1, arg2, arg3); } + FunctionPointer function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3> +struct VoidStoredFunctorCall3: public RunFunctionTask<T> +{ + inline VoidStoredFunctorCall3(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3) {} + void runFunctor() { function(arg1, arg2, arg3); } + FunctionPointer function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3> +struct SelectStoredFunctorCall3 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorCall3 <T, FunctionPointer, Arg1, Arg2, Arg3>, + VoidStoredFunctorCall3<T, FunctionPointer, Arg1, Arg2, Arg3> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3> +struct StoredFunctorPointerCall3: public RunFunctionTask<T> +{ + inline StoredFunctorPointerCall3(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3) {} + void runFunctor() { this->result =(*function)(arg1, arg2, arg3); } + FunctionPointer * function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3> +struct VoidStoredFunctorPointerCall3: public RunFunctionTask<T> +{ + inline VoidStoredFunctorPointerCall3(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3) {} + void runFunctor() {(*function)(arg1, arg2, arg3); } + FunctionPointer * function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3> +struct SelectStoredFunctorPointerCall3 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorPointerCall3 <T, FunctionPointer, Arg1, Arg2, Arg3>, + VoidStoredFunctorPointerCall3<T, FunctionPointer, Arg1, Arg2, Arg3> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +class StoredMemberFunctionCall3 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionCall3(T (Class::*_fn)(Param1, Param2, Param3) , const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1, arg2, arg3); + } +private: + T (Class::*fn)(Param1, Param2, Param3); + Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +class VoidStoredMemberFunctionCall3 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionCall3(T (Class::*_fn)(Param1, Param2, Param3) , const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3){ } + + void runFunctor() + { + (object.*fn)(arg1, arg2, arg3); + } +private: + T (Class::*fn)(Param1, Param2, Param3); + Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +struct SelectStoredMemberFunctionCall3 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionCall3 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3>, + VoidStoredMemberFunctionCall3<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +class StoredConstMemberFunctionCall3 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionCall3(T (Class::*_fn)(Param1, Param2, Param3) const, const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1, arg2, arg3); + } +private: + T (Class::*fn)(Param1, Param2, Param3)const; + const Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +class VoidStoredConstMemberFunctionCall3 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionCall3(T (Class::*_fn)(Param1, Param2, Param3) const, const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3){ } + + void runFunctor() + { + (object.*fn)(arg1, arg2, arg3); + } +private: + T (Class::*fn)(Param1, Param2, Param3)const; + const Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +struct SelectStoredConstMemberFunctionCall3 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionCall3 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3>, + VoidStoredConstMemberFunctionCall3<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +class StoredMemberFunctionPointerCall3 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionPointerCall3(T (Class::*_fn)(Param1, Param2, Param3) , Class *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1, arg2, arg3); + } +private: + T (Class::*fn)(Param1, Param2, Param3); + Class *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +class VoidStoredMemberFunctionPointerCall3 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionPointerCall3(T (Class::*_fn)(Param1, Param2, Param3) , Class *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3){ } + + void runFunctor() + { + (object->*fn)(arg1, arg2, arg3); + } +private: + T (Class::*fn)(Param1, Param2, Param3); + Class *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +struct SelectStoredMemberFunctionPointerCall3 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionPointerCall3 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3>, + VoidStoredMemberFunctionPointerCall3<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +class StoredConstMemberFunctionPointerCall3 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionPointerCall3(T (Class::*_fn)(Param1, Param2, Param3) const, Class const *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1, arg2, arg3); + } +private: + T (Class::*fn)(Param1, Param2, Param3)const; + Class const *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +class VoidStoredConstMemberFunctionPointerCall3 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionPointerCall3(T (Class::*_fn)(Param1, Param2, Param3) const, Class const *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3){ } + + void runFunctor() + { + (object->*fn)(arg1, arg2, arg3); + } +private: + T (Class::*fn)(Param1, Param2, Param3)const; + Class const *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3> +struct SelectStoredConstMemberFunctionPointerCall3 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionPointerCall3 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3>, + VoidStoredConstMemberFunctionPointerCall3<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +struct StoredFunctorCall4: public RunFunctionTask<T> +{ + inline StoredFunctorCall4(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4) {} + void runFunctor() { this->result = function(arg1, arg2, arg3, arg4); } + FunctionPointer function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +struct VoidStoredFunctorCall4: public RunFunctionTask<T> +{ + inline VoidStoredFunctorCall4(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4) {} + void runFunctor() { function(arg1, arg2, arg3, arg4); } + FunctionPointer function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +struct SelectStoredFunctorCall4 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorCall4 <T, FunctionPointer, Arg1, Arg2, Arg3, Arg4>, + VoidStoredFunctorCall4<T, FunctionPointer, Arg1, Arg2, Arg3, Arg4> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +struct StoredFunctorPointerCall4: public RunFunctionTask<T> +{ + inline StoredFunctorPointerCall4(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4) {} + void runFunctor() { this->result =(*function)(arg1, arg2, arg3, arg4); } + FunctionPointer * function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +struct VoidStoredFunctorPointerCall4: public RunFunctionTask<T> +{ + inline VoidStoredFunctorPointerCall4(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4) {} + void runFunctor() {(*function)(arg1, arg2, arg3, arg4); } + FunctionPointer * function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +struct SelectStoredFunctorPointerCall4 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorPointerCall4 <T, FunctionPointer, Arg1, Arg2, Arg3, Arg4>, + VoidStoredFunctorPointerCall4<T, FunctionPointer, Arg1, Arg2, Arg3, Arg4> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +class StoredMemberFunctionCall4 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionCall4(T (Class::*_fn)(Param1, Param2, Param3, Param4) , const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1, arg2, arg3, arg4); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4); + Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +class VoidStoredMemberFunctionCall4 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionCall4(T (Class::*_fn)(Param1, Param2, Param3, Param4) , const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4){ } + + void runFunctor() + { + (object.*fn)(arg1, arg2, arg3, arg4); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4); + Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +struct SelectStoredMemberFunctionCall4 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionCall4 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4>, + VoidStoredMemberFunctionCall4<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +class StoredConstMemberFunctionCall4 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionCall4(T (Class::*_fn)(Param1, Param2, Param3, Param4) const, const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1, arg2, arg3, arg4); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4)const; + const Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +class VoidStoredConstMemberFunctionCall4 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionCall4(T (Class::*_fn)(Param1, Param2, Param3, Param4) const, const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4){ } + + void runFunctor() + { + (object.*fn)(arg1, arg2, arg3, arg4); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4)const; + const Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +struct SelectStoredConstMemberFunctionCall4 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionCall4 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4>, + VoidStoredConstMemberFunctionCall4<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +class StoredMemberFunctionPointerCall4 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionPointerCall4(T (Class::*_fn)(Param1, Param2, Param3, Param4) , Class *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1, arg2, arg3, arg4); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4); + Class *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +class VoidStoredMemberFunctionPointerCall4 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionPointerCall4(T (Class::*_fn)(Param1, Param2, Param3, Param4) , Class *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4){ } + + void runFunctor() + { + (object->*fn)(arg1, arg2, arg3, arg4); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4); + Class *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +struct SelectStoredMemberFunctionPointerCall4 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionPointerCall4 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4>, + VoidStoredMemberFunctionPointerCall4<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +class StoredConstMemberFunctionPointerCall4 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionPointerCall4(T (Class::*_fn)(Param1, Param2, Param3, Param4) const, Class const *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1, arg2, arg3, arg4); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4)const; + Class const *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +class VoidStoredConstMemberFunctionPointerCall4 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionPointerCall4(T (Class::*_fn)(Param1, Param2, Param3, Param4) const, Class const *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4){ } + + void runFunctor() + { + (object->*fn)(arg1, arg2, arg3, arg4); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4)const; + Class const *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4> +struct SelectStoredConstMemberFunctionPointerCall4 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionPointerCall4 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4>, + VoidStoredConstMemberFunctionPointerCall4<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> +struct StoredFunctorCall5: public RunFunctionTask<T> +{ + inline StoredFunctorCall5(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5) {} + void runFunctor() { this->result = function(arg1, arg2, arg3, arg4, arg5); } + FunctionPointer function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> +struct VoidStoredFunctorCall5: public RunFunctionTask<T> +{ + inline VoidStoredFunctorCall5(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5) {} + void runFunctor() { function(arg1, arg2, arg3, arg4, arg5); } + FunctionPointer function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> +struct SelectStoredFunctorCall5 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorCall5 <T, FunctionPointer, Arg1, Arg2, Arg3, Arg4, Arg5>, + VoidStoredFunctorCall5<T, FunctionPointer, Arg1, Arg2, Arg3, Arg4, Arg5> >::type type; +}; +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> +struct StoredFunctorPointerCall5: public RunFunctionTask<T> +{ + inline StoredFunctorPointerCall5(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5) {} + void runFunctor() { this->result =(*function)(arg1, arg2, arg3, arg4, arg5); } + FunctionPointer * function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> +struct VoidStoredFunctorPointerCall5: public RunFunctionTask<T> +{ + inline VoidStoredFunctorPointerCall5(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5) {} + void runFunctor() {(*function)(arg1, arg2, arg3, arg4, arg5); } + FunctionPointer * function; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; + +template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> +struct SelectStoredFunctorPointerCall5 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredFunctorPointerCall5 <T, FunctionPointer, Arg1, Arg2, Arg3, Arg4, Arg5>, + VoidStoredFunctorPointerCall5<T, FunctionPointer, Arg1, Arg2, Arg3, Arg4, Arg5> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +class StoredMemberFunctionCall5 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionCall5(T (Class::*_fn)(Param1, Param2, Param3, Param4, Param5) , const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1, arg2, arg3, arg4, arg5); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4, Param5); + Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +class VoidStoredMemberFunctionCall5 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionCall5(T (Class::*_fn)(Param1, Param2, Param3, Param4, Param5) , const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5){ } + + void runFunctor() + { + (object.*fn)(arg1, arg2, arg3, arg4, arg5); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4, Param5); + Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +struct SelectStoredMemberFunctionCall5 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionCall5 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5>, + VoidStoredMemberFunctionCall5<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +class StoredConstMemberFunctionCall5 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionCall5(T (Class::*_fn)(Param1, Param2, Param3, Param4, Param5) const, const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5){ } + + void runFunctor() + { + this->result = (object.*fn)(arg1, arg2, arg3, arg4, arg5); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4, Param5)const; + const Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +class VoidStoredConstMemberFunctionCall5 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionCall5(T (Class::*_fn)(Param1, Param2, Param3, Param4, Param5) const, const Class &_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5){ } + + void runFunctor() + { + (object.*fn)(arg1, arg2, arg3, arg4, arg5); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4, Param5)const; + const Class object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +struct SelectStoredConstMemberFunctionCall5 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionCall5 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5>, + VoidStoredConstMemberFunctionCall5<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +class StoredMemberFunctionPointerCall5 : public RunFunctionTask<T> +{ +public: + StoredMemberFunctionPointerCall5(T (Class::*_fn)(Param1, Param2, Param3, Param4, Param5) , Class *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1, arg2, arg3, arg4, arg5); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4, Param5); + Class *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +class VoidStoredMemberFunctionPointerCall5 : public RunFunctionTask<T> +{ +public: + VoidStoredMemberFunctionPointerCall5(T (Class::*_fn)(Param1, Param2, Param3, Param4, Param5) , Class *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5){ } + + void runFunctor() + { + (object->*fn)(arg1, arg2, arg3, arg4, arg5); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4, Param5); + Class *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +struct SelectStoredMemberFunctionPointerCall5 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredMemberFunctionPointerCall5 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5>, + VoidStoredMemberFunctionPointerCall5<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5> >::type type; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +class StoredConstMemberFunctionPointerCall5 : public RunFunctionTask<T> +{ +public: + StoredConstMemberFunctionPointerCall5(T (Class::*_fn)(Param1, Param2, Param3, Param4, Param5) const, Class const *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5){ } + + void runFunctor() + { + this->result = (object->*fn)(arg1, arg2, arg3, arg4, arg5); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4, Param5)const; + Class const *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +class VoidStoredConstMemberFunctionPointerCall5 : public RunFunctionTask<T> +{ +public: + VoidStoredConstMemberFunctionPointerCall5(T (Class::*_fn)(Param1, Param2, Param3, Param4, Param5) const, Class const *_object, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + : fn(_fn), object(_object), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5){ } + + void runFunctor() + { + (object->*fn)(arg1, arg2, arg3, arg4, arg5); + } +private: + T (Class::*fn)(Param1, Param2, Param3, Param4, Param5)const; + Class const *object; + Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; +}; +template <typename T, typename Class, typename Param1, typename Arg1, typename Param2, typename Arg2, typename Param3, typename Arg3, typename Param4, typename Arg4, typename Param5, typename Arg5> +struct SelectStoredConstMemberFunctionPointerCall5 +{ + typedef typename SelectSpecialization<T>::template + Type<StoredConstMemberFunctionPointerCall5 <T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5>, + VoidStoredConstMemberFunctionPointerCall5<T, Class, Param1, Arg1, Param2, Arg2, Param3, Arg3, Param4, Arg4, Param5, Arg5> >::type type; +}; +} //namespace QtConcurrent + +#endif // qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentthreadengine.cpp b/src/corelib/concurrent/qtconcurrentthreadengine.cpp new file mode 100644 index 0000000..d6e6057 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentthreadengine.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtconcurrentthreadengine.h" + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_NAMESPACE + +namespace QtConcurrent { + +ThreadEngineBase::ThreadEngineBase() +:futureInterface(0), threadPool(QThreadPool::globalInstance()) +{ + setAutoDelete(false); +} + +ThreadEngineBase::~ThreadEngineBase() {} + +void ThreadEngineBase::startSingleThreaded() +{ + start(); + while (threadFunction() != ThreadFinished) + ; + finish(); +} + +void ThreadEngineBase::startBlocking() +{ + start(); + semaphore.acquire(); + startThreads(); + + bool throttled = false; +#ifndef QT_NO_EXCEPTIONS + try { +#endif + while (threadFunction() == ThrottleThread) { + if (threadThrottleExit()) { + throttled = true; + break; + } + } +#ifndef QT_NO_EXCEPTIONS + } catch (QtConcurrent::Exception &e) { + handleException(e); + } catch (...) { + handleException(QtConcurrent::UnhandledException()); + } +#endif + + if (throttled == false) { + semaphore.release(); + } + + semaphore.wait(); + finish(); + exceptionStore.throwPossibleException(); +} + +void ThreadEngineBase::startThread() +{ + startThreadInternal(); +} + +bool ThreadEngineBase::isCanceled() +{ + if (futureInterface) + return futureInterface->isCanceled(); + else + return false; +} + +void ThreadEngineBase::waitForResume() +{ + if (futureInterface) + futureInterface->waitForResume(); +} + +bool ThreadEngineBase::isProgressReportingEnabled() +{ + // If we don't have a QFuture, there is no-one to report the progress to. + return (futureInterface != 0); +} + +void ThreadEngineBase::setProgressValue(int progress) +{ + if (futureInterface) + futureInterface->setProgressValue(progress); +} + +void ThreadEngineBase::setProgressRange(int minimum, int maximum) +{ + if (futureInterface) + futureInterface->setProgressRange(minimum, maximum); +} + +bool ThreadEngineBase::startThreadInternal() +{ + if (this->isCanceled()) + return false; + + semaphore.acquire(); + if (!threadPool->tryStart(this)) { + semaphore.release(); + return false; + } + return true; +} + +void ThreadEngineBase::startThreads() +{ + while (shouldStartThread() && startThreadInternal()) + ; +} + +void ThreadEngineBase::threadExit() +{ + const bool asynchronous = futureInterface != 0; + const int lastThread = (semaphore.release() == 0); + + if (lastThread && asynchronous) + this->asynchronousFinish(); +} + +// Called by a worker thread that wants to be throttled. If the current number +// of running threads is larger than one the thread is allowed to exit and +// this function returns one. +bool ThreadEngineBase::threadThrottleExit() +{ + return semaphore.releaseUnlessLast(); +} + +void ThreadEngineBase::run() // implements QRunnable. +{ + if (this->isCanceled()) { + threadExit(); + return; + } + + startThreads(); + +#ifndef QT_NO_EXCEPTIONS + try { +#endif + while (threadFunction() == ThrottleThread) { + // threadFunction returning ThrottleThread means it that the user + // struct wants to be throttled by making a worker thread exit. + // Respect that request unless this is the only worker thread left + // running, in which case it has to keep going. + if (threadThrottleExit()) + return; + } + +#ifndef QT_NO_EXCEPTIONS + } catch (QtConcurrent::Exception &e) { + handleException(e); + } catch (...) { + handleException(QtConcurrent::UnhandledException()); + } +#endif + threadExit(); +} + +#ifndef QT_NO_EXCEPTIONS + +void ThreadEngineBase::handleException(const QtConcurrent::Exception &exception) +{ + if (futureInterface) + futureInterface->reportException(exception); + else + exceptionStore.setException(exception); +} +#endif + + +} // namepsace QtConcurrent + +QT_END_NAMESPACE + +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qtconcurrentthreadengine.h b/src/corelib/concurrent/qtconcurrentthreadengine.h new file mode 100644 index 0000000..9e7d12e --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentthreadengine.h @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_THREADENGINE_H +#define QTCONCURRENT_THREADENGINE_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CONCURRENT + +#include <QtCore/qthreadpool.h> +#include <QtCore/qfuture.h> +#include <QtCore/qdebug.h> +#include <QtCore/qtconcurrentexception.h> +#include <QtCore/qwaitcondition.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +// A Semaphore that can wait until all resources are returned. +class ThreadEngineSemaphore +{ +public: + ThreadEngineSemaphore() + :count(0) { } + + void acquire() + { + QMutexLocker lock(&mutex); + ++count; + } + + int release() + { + QMutexLocker lock(&mutex); + if (--count == 0) + waitCondition.wakeAll(); + return count; + } + + // Wait until all resources are released. + void wait() + { + QMutexLocker lock(&mutex); + if (count != 0) + waitCondition.wait(&mutex); + } + + int currentCount() + { + return count; + } + + // releases a resource, unless this is the last resource. + // returns true if a resource was released. + bool releaseUnlessLast() + { + QMutexLocker lock(&mutex); + if (count == 1) + return false; + --count; + return true; + } + +private: + QMutex mutex; + int count; + QWaitCondition waitCondition; +}; + +enum ThreadFunctionResult { ThrottleThread, ThreadFinished }; + +// The ThreadEngine controls the threads used in the computation. +// Can be run in three modes: single threaded, multi-threaded blocking +// and multi-threaded asynchronous. +// The code for the single threaded mode is +class Q_CORE_EXPORT ThreadEngineBase: public QRunnable +{ +public: + // Public API: + ThreadEngineBase(); + virtual ~ThreadEngineBase(); + void startSingleThreaded(); + void startBlocking(); + void startThread(); + bool isCanceled(); + void waitForResume(); + bool isProgressReportingEnabled(); + void setProgressValue(int progress); + void setProgressRange(int minimum, int maximum); + +protected: // The user overrides these: + virtual void start() {} + virtual void finish() {} + virtual ThreadFunctionResult threadFunction() { return ThreadFinished; } + virtual bool shouldStartThread() { return futureInterface ? !futureInterface->isPaused() : true; } + virtual bool shouldThrottleThread() { return futureInterface ? futureInterface->isPaused() : false; } +private: + bool startThreadInternal(); + void startThreads(); + void threadExit(); + bool threadThrottleExit(); + void run(); + virtual void asynchronousFinish() = 0; +#ifndef QT_NO_EXCEPTIONS + void handleException(const QtConcurrent::Exception &exception); +#endif +protected: + QFutureInterfaceBase *futureInterface; + QThreadPool *threadPool; + ThreadEngineSemaphore semaphore; + QtConcurrent::internal::ExceptionStore exceptionStore; +}; + + +template <typename T> +class ThreadEngine : public virtual ThreadEngineBase +{ +public: + typedef T ResultType; + + virtual T *result() { return 0; } + + QFutureInterface<T> *futureInterfaceTyped() + { + return static_cast<QFutureInterface<T> *>(futureInterface); + } + + // Runs the user algorithm using a single thread. + T *startSingleThreaded() + { + ThreadEngineBase::startSingleThreaded(); + return result(); + } + + // Runs the user algorithm using multiple threads. + // This function blocks until the algorithm is finished, + // and then returns the result. + T *startBlocking() + { + ThreadEngineBase::startBlocking(); + return result(); + } + + // Runs the user algorithm using multiple threads. + // Does not block, returns a future. + QFuture<T> startAsynchronously() + { + futureInterface = new QFutureInterface<T>(); + + // reportStart() must be called before starting threads, otherwise the + // user algorithm might finish while reportStart() is running, which + // is very bad. + futureInterface->reportStarted(); + QFuture<T> future = QFuture<T>(futureInterfaceTyped()); + start(); + + semaphore.acquire(); + threadPool->start(this); + return future; + } + + void asynchronousFinish() + { + finish(); + futureInterfaceTyped()->reportFinished(result()); + delete futureInterfaceTyped(); + delete this; + } + + + void reportResult(const T *_result, int index = -1) + { + if (futureInterface) + futureInterfaceTyped()->reportResult(_result, index); + } + + void reportResults(const QVector<T> &_result, int index = -1, int count = -1) + { + if (futureInterface) + futureInterfaceTyped()->reportResults(_result, index, count); + } +}; + +// The ThreadEngineStarter class ecapsulates the return type +// from the thread engine. +// Depending on how the it is used, it will run +// the engine in either blocking mode or asynchronous mode. +template <typename T> +class ThreadEngineStarterBase +{ +public: + ThreadEngineStarterBase(ThreadEngine<T> *_threadEngine) + : threadEngine(_threadEngine) { } + + inline ThreadEngineStarterBase(const ThreadEngineStarterBase &other) + : threadEngine(other.threadEngine) { } + + QFuture<T> startAsynchronously() + { + return threadEngine->startAsynchronously(); + } + + operator QFuture<T>() + { + return startAsynchronously(); + } + +protected: + ThreadEngine<T> *threadEngine; +}; + + +// We need to factor out the code that dereferences the T pointer, +// with a specialization where T is void. (code that dereferences a void * +// won't compile) +template <typename T> +class ThreadEngineStarter : public ThreadEngineStarterBase<T> +{ +public: + ThreadEngineStarter(ThreadEngine<T> *threadEngine) + :ThreadEngineStarterBase<T>(threadEngine) {} + + T startBlocking() + { + T t = *this->threadEngine->startBlocking(); + delete this->threadEngine; + return t; + } +}; + +// Full template specialization where T is void. +template <> +class ThreadEngineStarter<void> : public ThreadEngineStarterBase<void> +{ +public: + ThreadEngineStarter<void>(ThreadEngine<void> *_threadEngine) + :ThreadEngineStarterBase<void>(_threadEngine) {} + + void startBlocking() + { + this->threadEngine->startBlocking(); + delete this->threadEngine; + } +}; + +template <typename ThreadEngine> +inline ThreadEngineStarter<typename ThreadEngine::ResultType> startThreadEngine(ThreadEngine *threadEngine) +{ + return ThreadEngineStarter<typename ThreadEngine::ResultType>(threadEngine); +} + +} // namespace QtConcurrent + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qthreadpool.cpp b/src/corelib/concurrent/qthreadpool.cpp new file mode 100644 index 0000000..30edfd4 --- /dev/null +++ b/src/corelib/concurrent/qthreadpool.cpp @@ -0,0 +1,614 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qthreadpool.h" +#include "qthreadpool_p.h" + +#ifndef QT_NO_THREAD + +QT_BEGIN_NAMESPACE + +inline bool operator<(int priority, const QPair<QRunnable *, int> &p) +{ + return p.second < priority; +} +inline bool operator<(const QPair<QRunnable *, int> &p, int priority) +{ + return priority < p.second; +} + +Q_GLOBAL_STATIC(QThreadPool, theInstance) + +/* + QThread wrapper, provides synchronizitaion against a ThreadPool +*/ +class QThreadPoolThread : public QThread +{ +public: + QThreadPoolThread(QThreadPoolPrivate *manager); + void run(); + void registerTheadInactive(); + + QThreadPoolPrivate *manager; + QRunnable *runnable; +}; + +/* + QThreadPool private class. +*/ + + +/*!\internal + +*/ +QThreadPoolThread::QThreadPoolThread(QThreadPoolPrivate *manager) + :manager(manager), runnable(0) +{ } + +/* \internal + +*/ +void QThreadPoolThread::run() +{ + QMutexLocker locker(&manager->mutex); + for(;;) { + QRunnable *r = runnable; + runnable = 0; + + do { + if (r) { + const bool autoDelete = r->autoDelete(); + + + // run the task + locker.unlock(); +#ifndef QT_NO_EXCEPTIONS + try { +#endif + r->run(); +#ifndef QT_NO_EXCEPTIONS + } catch (...) { + qWarning("Qt Concurrent has caught an exception thrown from a worker thread.\n" + "This is not supported, exceptions thrown in worker threads must be\n" + "caught before control returns to Qt Concurrent."); + registerTheadInactive(); + throw; + } +#endif + locker.relock(); + + if (autoDelete && !--r->ref) + delete r; + } + + // if too many threads are active, expire this thread + if (manager->tooManyThreadsActive()) + break; + + r = !manager->queue.isEmpty() ? manager->queue.takeFirst().first : 0; + } while (r != 0); + + if (manager->isExiting) { + registerTheadInactive(); + break; + } + + // if too many threads are active, expire this thread + bool expired = manager->tooManyThreadsActive(); + if (!expired) { + ++manager->waitingThreads; + registerTheadInactive(); + // wait for work, exiting after the expiry timeout is reached + expired = !manager->runnableReady.wait(locker.mutex(), manager->expiryTimeout); + ++manager->activeThreads; + + if (expired) + --manager->waitingThreads; + } + if (expired) { + manager->expiredThreads.enqueue(this); + registerTheadInactive(); + break; + } + } +} + +void QThreadPoolThread::registerTheadInactive() +{ + if (--manager->activeThreads == 0) + manager->noActiveThreads.wakeAll(); +} + + +/* \internal + +*/ +QThreadPoolPrivate:: QThreadPoolPrivate() + : isExiting(false), + expiryTimeout(30000), + maxThreadCount(qAbs(QThread::idealThreadCount())), + reservedThreads(0), + waitingThreads(0), + activeThreads(0) +{ } + +bool QThreadPoolPrivate::tryStart(QRunnable *task) +{ + if (allThreads.isEmpty()) { + // always create at least one thread + startThread(task); + return true; + } + + // can't do anything if we're over the limit + if (activeThreadCount() >= maxThreadCount) + return false; + + if (waitingThreads > 0) { + // recycle an available thread + --waitingThreads; + enqueueTask(task); + return true; + } + + if (!expiredThreads.isEmpty()) { + // restart an expired thread + QThreadPoolThread *thread = expiredThreads.dequeue(); + Q_ASSERT(thread->runnable == 0); + + ++activeThreads; + + if (task->autoDelete()) + ++task->ref; + thread->runnable = task; + thread->start(); + return true; + } + + // start a new thread + startThread(task); + return true; +} + +void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) +{ + if (runnable->autoDelete()) + ++runnable->ref; + + // put it on the queue + QList<QPair<QRunnable *, int> >::iterator at = + qUpperBound(queue.begin(), queue.end(), priority); + queue.insert(at, qMakePair(runnable, priority)); + runnableReady.wakeOne(); +} + +int QThreadPoolPrivate::activeThreadCount() const +{ + return (allThreads.count() + - expiredThreads.count() + - waitingThreads + + reservedThreads); +} + +void QThreadPoolPrivate::tryToStartMoreThreads() +{ + // try to push tasks on the queue to any available threads + while (!queue.isEmpty() && tryStart(queue.first().first)) + queue.removeFirst(); +} + +bool QThreadPoolPrivate::tooManyThreadsActive() const +{ + const int activeThreadCount = this->activeThreadCount(); + return activeThreadCount > maxThreadCount && (activeThreadCount - reservedThreads) > 1; +} + +/*! \internal + +*/ +void QThreadPoolPrivate::startThread(QRunnable *runnable) +{ + QThreadPoolThread *thread = new QThreadPoolThread(this); + allThreads.insert(thread); + ++activeThreads; + + if (runnable->autoDelete()) + ++runnable->ref; + thread->runnable = runnable; + thread->start(); +} + +/*! \internal + Makes all threads exit, waits for each tread to exit and deletes it. +*/ +void QThreadPoolPrivate::reset() +{ + QMutexLocker locker(&mutex); + isExiting = true; + runnableReady.wakeAll(); + + do { + // make a copy of the set so that we can iterate without the lock + QSet<QThreadPoolThread *> allThreadsCopy = allThreads; + allThreads.clear(); + locker.unlock(); + + foreach (QThreadPoolThread *thread, allThreadsCopy) { + thread->wait(); + delete thread; + } + + locker.relock(); + // repeat until all newly arrived threads have also completed + } while (!allThreads.isEmpty()); + + waitingThreads = 0; + expiredThreads.clear(); + + isExiting = false; +} + +void QThreadPoolPrivate::waitForDone() +{ + QMutexLocker locker(&mutex); + while (!(queue.isEmpty() && activeThreads == 0)) + noActiveThreads.wait(locker.mutex()); +} + +/*! \internal + Pulls a runnable from the front queue and runs it in the current thread. Blocks + until the runnable has completed. Returns true if a runnable was found. +*/ +bool QThreadPoolPrivate::startFrontRunnable() +{ + QMutexLocker locker(&mutex); + if (queue.isEmpty()) + return false; + + QRunnable *runnable = queue.takeFirst().first; + const bool autoDelete = runnable->autoDelete(); + bool del = autoDelete && !--runnable->ref; + + locker.unlock(); + runnable->run(); + locker.relock(); + + if (del) { + delete runnable; + } + + return true; +} + +/*! \internal + Seaches for \a runnable in the queue, removes it from the queue and + runs it if found. This functon does not return until the runnable + has completed. +*/ +void QThreadPoolPrivate::stealRunnable(QRunnable *runnable) +{ + if (runnable == 0 || queue.isEmpty()) + return; + bool found = false; + { + QMutexLocker locker(&mutex); + QList<QPair<QRunnable *, int> >::iterator it = queue.begin(); + QList<QPair<QRunnable *, int> >::iterator end = queue.end(); + + while (it != end) { + if (it->first == runnable) { + found = true; + queue.erase(it); + break; + } + ++it; + } + } + + if (!found) + return; + + const bool autoDelete = runnable->autoDelete(); + bool del = autoDelete && !--runnable->ref; + + runnable->run(); + + if (del) { + delete runnable; + } +} + +/*! + \class QThreadPool + \brief The QThreadPool class manages a collection of QThreads. + \since 4.4 + \threadsafe + + QThreadPool manages and recyles individual QThread objects to help reduce + thread creation costs in programs that use threads. Each Qt application + has one global QThreadPool object, which can be accessed by calling + globalInstance(). + + To use one of the QThreadPool threads, subclass QRunnable and implement + the run() virtual function. Then create an object of that class and pass + it to QThreadPool::start(). + + \snippet doc/src/snippets/code/src_corelib_concurrent_qthreadpool.cpp 0 + + QThreadPool deletes the QRunnable automatically by default. Use + QRunnable::setAutoDelete() to change the auto-deletion flag. + + QThreadPool supports executing the same QRunnable more than once + by calling tryStart(this) from within QRunnable::run(). + If autoDelete is enabled the QRunnable will be deleted when + the last thread exits the run function. Calling start() + multiple times with the same QRunnable when autoDelete is enabled + creates a race condition and is not recommended. + + Threads that are unused for a certain amount of time will expire. The + default expiry timeout is 30000 milliseconds (30 seconds). This can be + changed using setExpiryTimeout(). Setting a negative expiry timeout + disables the expiry mechanism. + + Call maxThreadCount() to query the maximum number of threads to be used. + If needed, you can change the limit with setMaxThreadCount(). The default + maxThreadCount() is QThread::idealThreadCount(). The activeThreadCount() + function returns the number of threads currently doing work. + + The reserveThread() function reserves a thread for external + use. Use releaseThread() when your are done with the thread, so + that it may be reused. Essentially, these functions temporarily + increase or reduce the active thread count and are useful when + implementing time-consuming operations that are not visible to the + QThreadPool. + + Note that QThreadPool is a low-level class for managing threads, see + QtConcurrent::run() or the other + \l {threads.html#qtconcurrent-intro}{Qt Concurrent} APIs for higher + level alternatives. + + \sa QRunnable +*/ + +/*! + Constructs a thread pool with the given \a parent. +*/ +QThreadPool::QThreadPool(QObject *parent) + : QObject(*new QThreadPoolPrivate, parent) +{ } + +/*! + Destroys the QThreadPool. + This function will block until all runnables have been completed. +*/ +QThreadPool::~QThreadPool() +{ + d_func()->waitForDone(); + d_func()->reset(); +} + +/*! + Returns the global QThreadPool instance. +*/ +QThreadPool *QThreadPool::globalInstance() +{ + return theInstance(); +} + +/*! + Reserves a thread and uses it to run \a runnable, unless this thread will + make the current thread count exceed maxThreadCount(). In that case, + \a runnable is added to a run queue instead. The \a priority argument can + be used to control the run queue's order of execution. + + Note that the thread pool takes ownership of the \a runnable if + \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns true, + and the \a runnable will be deleted automatically by the thread + pool after the \l{QRunnable::run()}{runnable->run()} returns. If + \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns false, + ownership of \a runnable remains with the caller. Note that + changing the auto-deletion on \a runnable after calling this + functions results in undefined behavior. +*/ +void QThreadPool::start(QRunnable *runnable, int priority) +{ + if (!runnable) + return; + + Q_D(QThreadPool); + QMutexLocker locker(&d->mutex); + if (!d->tryStart(runnable)) + d->enqueueTask(runnable, priority); +} + +/*! + Attempts to reserve a thread to run \a runnable. + + If no threads are available at the time of calling, then this function + does nothing and returns false. Otherwise, \a runnable is run immediately + using one available thread and this function returns true. + + Note that the thread pool takes ownership of the \a runnable if + \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns true, + and the \a runnable will be deleted automatically by the thread + pool after the \l{QRunnable::run()}{runnable->run()} returns. If + \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns false, + ownership of \a runnable remains with the caller. Note that + changing the auto-deletion on \a runnable after calling this + function results in undefined behavior. +*/ +bool QThreadPool::tryStart(QRunnable *runnable) +{ + if (!runnable) + return false; + + Q_D(QThreadPool); + QMutexLocker locker(&d->mutex); + return d->tryStart(runnable); +} + +/*! \property QThreadPool::expiryTimeout + + Threads that are unused for \a expiryTimeout milliseconds are considered + to have expired and will exit. Such threads will be restarted as needed. + The default \a expiryTimeout is 30000 milliseconds (30 seconds). If + \a expiryTimeout is negative, newly created threads will not expire, e.g., + they will not exit until the thread pool is destroyed. + + Note that setting \a expiryTimeout has no effect on already running + threads. Only newly created threads will use the new \a expiryTimeout. + We recommend setting the \a expiryTimeout immediately after creating the + thread pool, but before calling start(). +*/ + +int QThreadPool::expiryTimeout() const +{ + Q_D(const QThreadPool); + return d->expiryTimeout; +} + +void QThreadPool::setExpiryTimeout(int expiryTimeout) +{ + Q_D(QThreadPool); + if (d->expiryTimeout == expiryTimeout) + return; + d->expiryTimeout = expiryTimeout; +} + +/*! \property QThreadPool::maxThreadCount + + This property represents the maximum number of threads used by the thread + pool. + + \note The thread pool will always use at least 1 thread, even if + \a maxThreadCount limit is zero or negative. + + The default \a maxThreadCount is QThread::idealThreadCount(). +*/ + +int QThreadPool::maxThreadCount() const +{ + Q_D(const QThreadPool); + QMutexLocker locker(&d->mutex); + return d->maxThreadCount; +} + +void QThreadPool::setMaxThreadCount(int maxThreadCount) +{ + Q_D(QThreadPool); + QMutexLocker locker(&d->mutex); + + if (maxThreadCount == d->maxThreadCount) + return; + + d->maxThreadCount = maxThreadCount; + d->tryToStartMoreThreads(); +} + +/*! \property QThreadPool::activeThreadCount + + This property represents the number of active threads in the thread pool. + + \note It is possible for this function to return a value that is greater + than maxThreadCount(). See reserveThread() for more details. + + \sa reserveThread(), releaseThread() +*/ + +int QThreadPool::activeThreadCount() const +{ + Q_D(const QThreadPool); + QMutexLocker locker(&d->mutex); + return d->activeThreadCount(); +} + +/*! + Reserves one thread, disregarding activeThreadCount() and maxThreadCount(). + + Once you are done with the thread, call releaseThread() to allow it to be + reused. + + \note This function will always increase the number of active threads. + This means that by using this function, it is possible for + activeThreadCount() to return a value greater than maxThreadCount() . + + \sa releaseThread() + */ +void QThreadPool::reserveThread() +{ + Q_D(QThreadPool); + QMutexLocker locker(&d->mutex); + ++d->reservedThreads; +} + +/*! + Releases a thread previously reserved by a call to reserveThread(). + + \note Calling this function without previously reserving a thread + temporarily increases maxThreadCount(). This is useful when a + thread goes to sleep waiting for more work, allowing other threads + to continue. Be sure to call reserveThread() when done waiting, so + that the thread pool can correctly maintain the + activeThreadCount(). + + \sa reserveThread() +*/ +void QThreadPool::releaseThread() +{ + Q_D(QThreadPool); + QMutexLocker locker(&d->mutex); + --d->reservedThreads; + d->tryToStartMoreThreads(); +} + +/*! + Waits for each thread to exit and removes all threads from the thread pool. +*/ +void QThreadPool::waitForDone() +{ + Q_D(QThreadPool); + d->waitForDone(); + d->reset(); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/concurrent/qthreadpool.h b/src/corelib/concurrent/qthreadpool.h new file mode 100644 index 0000000..f3dd96c --- /dev/null +++ b/src/corelib/concurrent/qthreadpool.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTHREADPOOL_H +#define QTHREADPOOL_H + +#include <QtCore/qglobal.h> + +#include <QtCore/qthread.h> +#include <QtCore/qrunnable.h> + +#ifndef QT_NO_THREAD + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QThreadPoolPrivate; +class Q_CORE_EXPORT QThreadPool : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QThreadPool) + Q_PROPERTY(int expiryTimeout READ expiryTimeout WRITE setExpiryTimeout) + Q_PROPERTY(int maxThreadCount READ maxThreadCount WRITE setMaxThreadCount) + Q_PROPERTY(int activeThreadCount READ activeThreadCount) + friend class QFutureInterfaceBase; + +public: + QThreadPool(QObject *parent = 0); + ~QThreadPool(); + + static QThreadPool *globalInstance(); + + void start(QRunnable *runnable, int priority = 0); + bool tryStart(QRunnable *runnable); + + int expiryTimeout() const; + void setExpiryTimeout(int expiryTimeout); + + int maxThreadCount() const; + void setMaxThreadCount(int maxThreadCount); + + int activeThreadCount() const; + + void reserveThread(); + void releaseThread(); + + void waitForDone(); +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_THREAD + +#endif diff --git a/src/corelib/concurrent/qthreadpool_p.h b/src/corelib/concurrent/qthreadpool_p.h new file mode 100644 index 0000000..6948ee1 --- /dev/null +++ b/src/corelib/concurrent/qthreadpool_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTHREADPOOL_P_H +#define QTHREADPOOL_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 "QtCore/qmutex.h" +#include "QtCore/qwaitcondition.h" +#include "QtCore/qset.h" +#include "QtCore/qqueue.h" +#include "private/qobject_p.h" + +#ifndef QT_NO_THREAD + +QT_BEGIN_NAMESPACE + +class QThreadPoolThread; +class QThreadPoolPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QThreadPool) + friend class QThreadPoolThread; + +public: + QThreadPoolPrivate(); + + bool tryStart(QRunnable *task); + void enqueueTask(QRunnable *task, int priority = 0); + int activeThreadCount() const; + + void tryToStartMoreThreads(); + bool tooManyThreadsActive() const; + + void startThread(QRunnable *runnable = 0); + void reset(); + void waitForDone(); + bool startFrontRunnable(); + void stealRunnable(QRunnable *); + + mutable QMutex mutex; + QWaitCondition runnableReady; + QSet<QThreadPoolThread *> allThreads; + QQueue<QThreadPoolThread *> expiredThreads; + QList<QPair<QRunnable *, int> > queue; + QWaitCondition noActiveThreads; + + bool isExiting; + int expiryTimeout; + int maxThreadCount; + int reservedThreads; + int waitingThreads; + int activeThreads; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_THREAD +#endif |