[CardDB] Cache CardDatabaseQuerier count maps (#7114)

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-08-14 07:19:34 +02:00 committed by GitHub
parent 2eca362e2b
commit a40969003c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 50 additions and 30 deletions

View file

@ -12,6 +12,17 @@ CardDatabaseQuerier::CardDatabaseQuerier(QObject *_parent,
const ICardPreferenceProvider *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
{
QSet<QString> types;
for (const auto &card : db->cards.values()) {
types.insert(card->getMainCardType());
}
return types.values();
return getAllMainCardTypesWithCount().keys();
}
QMap<QString, int> CardDatabaseQuerier::getAllMainCardTypesWithCount() const
{
QMap<QString, int> typeCounts;
for (const auto &card : db->cards.values()) {
QString type = card->getMainCardType();
typeCounts[type]++;
// 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()) {
QString type = card->getMainCardType();
mainCardTypeCountsCache[type]++;
}
}
return typeCounts;
return mainCardTypeCountsCache;
}
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()) {
QString type = card->getCardType();
QStringList parts = type.split("");
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
QStringList subtypes = parts[1].split(" ", Qt::SkipEmptyParts);
for (const QString &subtype : subtypes) {
typeCounts[subtype]++;
for (const QString &subtype : subtypes) {
subCardTypeCountsCache[subtype]++;
}
}
}
}
return typeCounts;
return subCardTypeCountsCache;
}
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> formatCounts;
if (formatsCountCache.isEmpty()) {
for (const auto &card : db->cards.values()) {
QStringList allProps = card->getProperties();
for (const auto &card : db->cards.values()) {
QStringList allProps = card->getProperties();
for (const QString &prop : allProps) {
if (prop.startsWith("format-")) {
QString formatName = prop.mid(QStringLiteral("format-").size());
formatCounts[formatName]++;
for (const QString &prop : allProps) {
if (prop.startsWith("format-")) {
QString formatName = prop.mid(QStringLiteral("format-").size());
formatsCountCache[formatName]++;
}
}
}
}
return formatCounts;
return formatsCountCache;
}

View file

@ -220,6 +220,16 @@ public:
private:
const CardDatabase *db; //!< Card database used for all lookups.
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