[CardDB] Cache CardDatabaseQuerier count maps

This commit is contained in:
Lukas Brübach 2026-08-13 22:52:32 +02:00
parent 2086deff5c
commit f439f605fd
2 changed files with 50 additions and 30 deletions

View file

@ -12,6 +12,17 @@ CardDatabaseQuerier::CardDatabaseQuerier(QObject *_parent,
const ICardPreferenceProvider *prefs) const ICardPreferenceProvider *prefs)
: QObject(_parent), db(_db), prefs(prefs) : QObject(_parent), db(_db), prefs(prefs)
{ {
// Invalidate the cached count maps whenever the database contents change.
connect(db, &CardDatabase::cardAdded, this, &CardDatabaseQuerier::invalidateCaches);
connect(db, &CardDatabase::cardRemoved, this, &CardDatabaseQuerier::invalidateCaches);
connect(db, &CardDatabase::cardDatabaseReset, this, &CardDatabaseQuerier::invalidateCaches);
}
void CardDatabaseQuerier::invalidateCaches()
{
mainCardTypeCountsCache.clear();
subCardTypeCountsCache.clear();
formatsCountCache.clear();
} }
/** /**
@ -304,44 +315,43 @@ QString CardDatabaseQuerier::getPreferredPrintingProviderId(const QString &cardN
QStringList CardDatabaseQuerier::getAllMainCardTypes() const QStringList CardDatabaseQuerier::getAllMainCardTypes() const
{ {
QSet<QString> types; return getAllMainCardTypesWithCount().keys();
for (const auto &card : db->cards.values()) {
types.insert(card->getMainCardType());
}
return types.values();
} }
QMap<QString, int> CardDatabaseQuerier::getAllMainCardTypesWithCount() const QMap<QString, int> CardDatabaseQuerier::getAllMainCardTypesWithCount() const
{ {
QMap<QString, int> typeCounts; // An empty cache is always recomputed correctly: a database with no cards
// produces an empty map, so the cache is only ever empty when it needs a
for (const auto &card : db->cards.values()) { // (trivially cheap) rebuild.
QString type = card->getMainCardType(); if (mainCardTypeCountsCache.isEmpty()) {
typeCounts[type]++; for (const auto &card : db->cards.values()) {
QString type = card->getMainCardType();
mainCardTypeCountsCache[type]++;
}
} }
return typeCounts; return mainCardTypeCountsCache;
} }
QMap<QString, int> CardDatabaseQuerier::getAllSubCardTypesWithCount() const QMap<QString, int> CardDatabaseQuerier::getAllSubCardTypesWithCount() const
{ {
QMap<QString, int> typeCounts; if (subCardTypeCountsCache.isEmpty()) {
for (const auto &card : db->cards.values()) {
QString type = card->getCardType();
for (const auto &card : db->cards.values()) { QStringList parts = type.split(" — ");
QString type = card->getCardType();
QStringList parts = type.split(" — "); if (parts.size() > 1) { // Ensure there are subtypes
QStringList subtypes = parts[1].split(" ", Qt::SkipEmptyParts);
if (parts.size() > 1) { // Ensure there are subtypes for (const QString &subtype : subtypes) {
QStringList subtypes = parts[1].split(" ", Qt::SkipEmptyParts); subCardTypeCountsCache[subtype]++;
}
for (const QString &subtype : subtypes) {
typeCounts[subtype]++;
} }
} }
} }
return typeCounts; return subCardTypeCountsCache;
} }
FormatRulesPtr CardDatabaseQuerier::getFormat(const QString &formatName) const FormatRulesPtr CardDatabaseQuerier::getFormat(const QString &formatName) const
@ -351,18 +361,18 @@ FormatRulesPtr CardDatabaseQuerier::getFormat(const QString &formatName) const
QMap<QString, int> CardDatabaseQuerier::getAllFormatsWithCount() const QMap<QString, int> CardDatabaseQuerier::getAllFormatsWithCount() const
{ {
QMap<QString, int> formatCounts; if (formatsCountCache.isEmpty()) {
for (const auto &card : db->cards.values()) {
QStringList allProps = card->getProperties();
for (const auto &card : db->cards.values()) { for (const QString &prop : allProps) {
QStringList allProps = card->getProperties(); if (prop.startsWith("format-")) {
QString formatName = prop.mid(QStringLiteral("format-").size());
for (const QString &prop : allProps) { formatsCountCache[formatName]++;
if (prop.startsWith("format-")) { }
QString formatName = prop.mid(QStringLiteral("format-").size());
formatCounts[formatName]++;
} }
} }
} }
return formatCounts; return formatsCountCache;
} }

View file

@ -220,6 +220,16 @@ public:
private: private:
const CardDatabase *db; //!< Card database used for all lookups. const CardDatabase *db; //!< Card database used for all lookups.
const ICardPreferenceProvider *prefs; //!< Preference provider for preferred printings. const ICardPreferenceProvider *prefs; //!< Preference provider for preferred printings.
// Count maps are expensive to compute (they iterate the whole database) and are
// queried every time a filter widget is built, so cache them and invalidate on
// any database mutation. Only the main thread reads or writes these.
mutable QMap<QString, int> mainCardTypeCountsCache;
mutable QMap<QString, int> subCardTypeCountsCache;
mutable QMap<QString, int> formatsCountCache;
private slots:
void invalidateCaches();
}; };
#endif // COCKATRICE_CARD_DATABASE_QUERIER_H #endif // COCKATRICE_CARD_DATABASE_QUERIER_H