[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,29 +315,27 @@ 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
// (trivially cheap) rebuild.
if (mainCardTypeCountsCache.isEmpty()) {
for (const auto &card : db->cards.values()) { for (const auto &card : db->cards.values()) {
QString type = card->getMainCardType(); QString type = card->getMainCardType();
typeCounts[type]++; 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()) { for (const auto &card : db->cards.values()) {
QString type = card->getCardType(); QString type = card->getCardType();
@ -336,12 +345,13 @@ QMap<QString, int> CardDatabaseQuerier::getAllSubCardTypesWithCount() const
QStringList subtypes = parts[1].split(" ", Qt::SkipEmptyParts); QStringList subtypes = parts[1].split(" ", Qt::SkipEmptyParts);
for (const QString &subtype : subtypes) { for (const QString &subtype : subtypes) {
typeCounts[subtype]++; subCardTypeCountsCache[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()) { for (const auto &card : db->cards.values()) {
QStringList allProps = card->getProperties(); QStringList allProps = card->getProperties();
for (const QString &prop : allProps) { for (const QString &prop : allProps) {
if (prop.startsWith("format-")) { if (prop.startsWith("format-")) {
QString formatName = prop.mid(QStringLiteral("format-").size()); QString formatName = prop.mid(QStringLiteral("format-").size());
formatCounts[formatName]++; formatsCountCache[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