summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMårten Nordheim <marten.nordheim@qt.io>2024-10-22 16:36:45 +0200
committerMårten Nordheim <marten.nordheim@qt.io>2024-10-29 20:46:46 +0200
commit1558811a8485f6dcc51a50a2bba0846091ca8bf6 (patch)
treefa1f14ff7d4c3e3f1df66064abdecc3d9ceb2638 /src
parentbfc76fa39c2bab67ef1857407be539b1f88919e5 (diff)
Wrap QModelIndex in QSortFilterProxyModel for hash performance
The qHash implementation for QModelIndex is not very good resulting in hundreds of collisions in the hash table. This means most lookups in the table essentially becomes a linear search. This was 'generically' fixed for Qt 7, but couldn't be fixed for 6 because of the qHash implementation is inline and would result in different hash values for the same QModelIndex in different translation units. To work around this for this particular instance, we wrap the QModelIndex in a struct that has the fixed qHash implementation. Fixes: QTBUG-130309 Pick-to: 6.8 6.5 Change-Id: I586fb10cadf73900f3d644f421c37b381224a419 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp2
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel_p.h22
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.cpp14
3 files changed, 29 insertions, 9 deletions
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index df944296293..c3ff18e8afe 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -35,7 +35,7 @@ QPersistentModelIndexData *QPersistentModelIndexData::create(const QModelIndex &
Q_ASSERT(index.isValid()); // we will _never_ insert an invalid index in the list
QPersistentModelIndexData *d = nullptr;
QAbstractItemModel *model = const_cast<QAbstractItemModel *>(index.model());
- QMultiHash<QModelIndex, QPersistentModelIndexData *> &indexes = model->d_func()->persistent.indexes;
+ QMultiHash<QtPrivate::QModelIndexWrapper, QPersistentModelIndexData *> &indexes = model->d_func()->persistent.indexes;
const auto it = indexes.constFind(index);
if (it != indexes.cend()) {
d = (*it);
diff --git a/src/corelib/itemmodels/qabstractitemmodel_p.h b/src/corelib/itemmodels/qabstractitemmodel_p.h
index c2113fde9aa..d22a0a50823 100644
--- a/src/corelib/itemmodels/qabstractitemmodel_p.h
+++ b/src/corelib/itemmodels/qabstractitemmodel_p.h
@@ -37,6 +37,26 @@ public:
static void destroy(QPersistentModelIndexData *data);
};
+namespace QtPrivate {
+// This class is just a wrapper so we can use the fixed qHash() function for QModelIndex.
+struct QModelIndexWrapper // ### Qt 7: Remove again, use QModelIndex directly.
+{
+ QModelIndex index;
+ Q_IMPLICIT QModelIndexWrapper(const QModelIndex &i) : index(i) { }
+ Q_IMPLICIT inline operator QModelIndex() const { return index; }
+ friend bool operator==(const QModelIndexWrapper &l, const QModelIndexWrapper &r) { return l.index == r.index; }
+ friend bool operator!=(const QModelIndexWrapper &l, const QModelIndexWrapper &r) { return !(operator==(l,r)); }
+ friend bool operator==(const QModelIndexWrapper &l, const QModelIndex &r) { return l.index == r; }
+ friend bool operator!=(const QModelIndexWrapper &l, const QModelIndex &r) { return !(operator==(l.index,r)); }
+ friend bool operator==(const QModelIndex &l, const QModelIndexWrapper &r) { return l == r.index; }
+ friend bool operator!=(const QModelIndex &l, const QModelIndexWrapper &r) { return !(operator==(l,r.index)); }
+ friend inline size_t qHash(const QtPrivate::QModelIndexWrapper &index, size_t seed = 0) noexcept
+ {
+ return qHashMulti(seed, index.index.row(), index.index.column(), index.index.internalId());
+ }
+};
+}
+
class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QAbstractItemModel)
@@ -111,7 +131,7 @@ public:
struct Persistent {
Persistent() {}
- QMultiHash<QModelIndex, QPersistentModelIndexData *> indexes;
+ QMultiHash<QtPrivate::QModelIndexWrapper, QPersistentModelIndexData *> indexes;
QStack<QList<QPersistentModelIndexData *>> moved;
QStack<QList<QPersistentModelIndexData *>> invalidated;
void insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data);
diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
index 6c71f131451..774dcfd9794 100644
--- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp
+++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
@@ -126,7 +126,7 @@ public:
QModelIndex source_parent;
};
- mutable QHash<QModelIndex, Mapping*> source_index_mapping;
+ mutable QHash<QtPrivate::QModelIndexWrapper, Mapping*> source_index_mapping;
void setSortCaseSensitivityForwarder(Qt::CaseSensitivity cs)
{
@@ -239,9 +239,9 @@ public:
std::array<QMetaObject::Connection, 18> sourceConnections;
- QHash<QModelIndex, Mapping *>::const_iterator create_mapping(
+ QHash<QtPrivate::QModelIndexWrapper, Mapping *>::const_iterator create_mapping(
const QModelIndex &source_parent) const;
- QHash<QModelIndex, Mapping *>::const_iterator create_mapping_recursive(
+ QHash<QtPrivate::QModelIndexWrapper, Mapping *>::const_iterator create_mapping_recursive(
const QModelIndex &source_parent) const;
QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const;
QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const;
@@ -265,14 +265,14 @@ public:
filter_regularexpression.setValueBypassingBindings(re);
}
- inline QHash<QModelIndex, Mapping *>::const_iterator index_to_iterator(
+ inline QHash<QtPrivate::QModelIndexWrapper, Mapping *>::const_iterator index_to_iterator(
const QModelIndex &proxy_index) const
{
Q_ASSERT(proxy_index.isValid());
Q_ASSERT(proxy_index.model() == q_func());
const void *p = proxy_index.internalPointer();
Q_ASSERT(p);
- QHash<QModelIndex, Mapping *>::const_iterator it =
+ QHash<QtPrivate::QModelIndexWrapper, Mapping *>::const_iterator it =
source_index_mapping.constFind(static_cast<const Mapping*>(p)->source_parent);
Q_ASSERT(it != source_index_mapping.constEnd());
Q_ASSERT(it.value());
@@ -280,7 +280,7 @@ public:
}
inline QModelIndex create_index(int row, int column,
- QHash<QModelIndex, Mapping*>::const_iterator it) const
+ QHash<QtPrivate::QModelIndexWrapper, Mapping*>::const_iterator it) const
{
return q_func()->createIndex(row, column, *it);
}
@@ -382,7 +382,7 @@ public:
bool recursiveParentAcceptsRow(const QModelIndex &source_parent) const;
};
-typedef QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping *> IndexMap;
+typedef QHash<QtPrivate::QModelIndexWrapper, QSortFilterProxyModelPrivate::Mapping *> IndexMap;
static bool operator&(QSortFilterProxyModelPrivate::Direction a, QSortFilterProxyModelPrivate::Direction b)
{