diff options
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/thread/qresultstore.cpp | 256 | ||||
-rw-r--r-- | src/corelib/thread/qresultstore.h | 238 | ||||
-rw-r--r-- | src/corelib/thread/thread.pri | 2 |
3 files changed, 496 insertions, 0 deletions
diff --git a/src/corelib/thread/qresultstore.cpp b/src/corelib/thread/qresultstore.cpp new file mode 100644 index 0000000000..93a8d456b8 --- /dev/null +++ b/src/corelib/thread/qresultstore.cpp @@ -0,0 +1,256 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qresultstore.h" + +#ifndef QT_NO_QFUTURE + +QT_BEGIN_NAMESPACE + +namespace QtPrivate { + +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 function 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 QtPrivate + +QT_END_NAMESPACE + +#endif // QT_NO_QFUTURE diff --git a/src/corelib/thread/qresultstore.h b/src/corelib/thread/qresultstore.h new file mode 100644 index 0000000000..3314cd7aaf --- /dev/null +++ b/src/corelib/thread/qresultstore.h @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCORE_RESULTSTORE_H +#define QTCORE_RESULTSTORE_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_QFUTURE + +#include <QtCore/qmap.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + + +/* + 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 QtPrivate { + +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 QtPrivate + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_QFUTURE + +#endif diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index 215e56628c..d9468cc3a4 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -11,6 +11,7 @@ HEADERS += thread/qmutex.h \ thread/qwaitcondition.h \ thread/qatomic.h \ thread/qexception.h \ + thread/qresultstore.h \ thread/qbasicatomic.h \ thread/qgenericatomic.h \ thread/qoldbasicatomic.h @@ -25,6 +26,7 @@ HEADERS += thread/qmutex_p.h \ SOURCES += thread/qatomic.cpp \ thread/qexception.cpp \ + thread/qresultstore.cpp \ thread/qmutex.cpp \ thread/qreadwritelock.cpp \ thread/qrunnable.cpp \ |