Files
Alex Jbanca c503073f6b perf(LeftJoinModel): Add LRU cache for right model data access
The right model data access is expensive because we need to search the right model for a matching key on every `data` call. This commit adds a LRU cache to the `data` call, storing by default up to 1000 rows.

The cache mechanism uses a QCache for fast index lookup and a std::list to preserve the access order and to ensure a controlled cache removal.

+ fix compilation errors on ConcatModel and WritableProxyModel
2025-08-15 16:07:26 +03:00

91 lines
2.5 KiB
C++

#pragma once
#include <QAbstractListModel>
#include <QPointer>
#include <QCache>
namespace qtmt {
class LeftJoinModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QAbstractItemModel* leftModel READ leftModel
WRITE setLeftModel NOTIFY leftModelChanged)
Q_PROPERTY(QAbstractItemModel* rightModel READ rightModel
WRITE setRightModel NOTIFY rightModelChanged)
Q_PROPERTY(QString joinRole READ joinRole
WRITE setJoinRole NOTIFY joinRoleChanged)
Q_PROPERTY(QStringList rolesToJoin READ rolesToJoin
WRITE setRolesToJoin NOTIFY rolesToJoinChanged)
Q_PROPERTY(qsizetype cacheSize READ cacheSize WRITE setCacheSize NOTIFY cacheSizeChanged)
public:
explicit LeftJoinModel(QObject* parent = nullptr);
void setLeftModel(QAbstractItemModel* model);
QAbstractItemModel* leftModel() const;
void setRightModel(QAbstractItemModel* model);
QAbstractItemModel* rightModel() const;
void setJoinRole(const QString& joinRole);
const QString& joinRole() const;
void setRolesToJoin(const QStringList& roles);
const QStringList& rolesToJoin() const;
qsizetype cacheSize() const;
void setCacheSize(qsizetype size);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex& index, int role) const override;
signals:
void leftModelChanged();
void rightModelChanged();
void joinRoleChanged();
void rolesToJoinChanged();
void cacheSizeChanged();
private:
void initializeIfReady(bool reset);
void initialize(bool reset);
void connectLeftModelSignals();
void connectRightModelSignals();
void clearCache();
int m_rightModelRolesOffset = 0;
QHash<int, QByteArray> m_leftRoleNames;
QHash<int, QByteArray> m_rightRoleNames;
QHash<int, QByteArray> m_roleNames;
mutable bool m_rolesFetched = false;
QVector<int> m_joinedRoles;
QString m_joinRole;
QStringList m_rolesToJoin;
int m_leftModelJoinRole = 0;
int m_rightModelJoinRole = 0;
QPointer<QAbstractItemModel> m_leftModel;
QPointer<QAbstractItemModel> m_rightModel;
bool m_initialized = false;
// LRU cache for right model
qsizetype m_cacheSize = 1000;
mutable QCache<QVariant, QPersistentModelIndex> m_rightModelCache;
// helpers for handling layoutChanged from source
QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
QModelIndexList m_proxyIndexes;
};
} // namespace qtmt