From 1ed9823b56a382c2dfc621baedca48b443a85367 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:02:37 -0700 Subject: [PATCH] [CardInfo] use QString QHash instead of QVariantHash for properties (#7063) * [CardInfo] use QString QHash instead of QVariantHash for properties * bump CACHE_VERSION * cleanups --- .../libcockatrice/card/card_info.cpp | 17 +++++----- .../libcockatrice/card/card_info.h | 28 ++++++++-------- .../card/card_info_comparator.cpp | 2 +- .../card/database/card_database_cache.cpp | 9 +++-- .../card/database/parser/cockatrice_xml_3.cpp | 4 +-- .../card/database/parser/cockatrice_xml_4.cpp | 8 ++--- .../card/database/parser/cockatrice_xml_4.h | 6 ++-- .../card/printing/printing_info.cpp | 10 +++--- .../card/printing/printing_info.h | 18 +++++----- oracle/src/oracleimporter.cpp | 33 +++++++++---------- oracle/src/oracleimporter.h | 8 ++--- 11 files changed, 70 insertions(+), 73 deletions(-) diff --git a/libcockatrice_card/libcockatrice/card/card_info.cpp b/libcockatrice_card/libcockatrice/card/card_info.cpp index d37408a58..786c6cd9f 100644 --- a/libcockatrice_card/libcockatrice/card/card_info.cpp +++ b/libcockatrice_card/libcockatrice/card/card_info.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -24,7 +23,7 @@ using CardInfoPtr = QSharedPointer; namespace { -QByteArray serializeProperties(const QVariantHash &props) +QByteArray serializeProperties(const QHash &props) { QByteArray blob; QDataStream out(&blob, QIODevice::WriteOnly); @@ -48,7 +47,7 @@ void CardInfo::ensurePropertiesLoaded() const propertiesLoaded = true; } -const QVariantHash &CardInfo::getPropertiesHash() const +const QHash &CardInfo::getPropertiesHash() const { ensurePropertiesLoaded(); return propertiesCache; @@ -57,7 +56,7 @@ const QVariantHash &CardInfo::getPropertiesHash() const void CardInfo::setProperty(const QString &_name, const QString &_value) { ensurePropertiesLoaded(); - if (propertiesCache.value(_name).toString() == _value) { + if (propertiesCache.value(_name) == _value) { return; } propertiesCache.insert(_name, _value); @@ -65,7 +64,7 @@ void CardInfo::setProperty(const QString &_name, const QString &_value) emit cardInfoChanged(smartThis); } -void CardInfo::setProperties(const QVariantHash &_props) +void CardInfo::setProperties(const QHash &_props) { ensurePropertiesLoaded(); propertiesCache = _props; @@ -76,7 +75,7 @@ void CardInfo::setProperties(const QVariantHash &_props) CardInfo::CardInfo(const QString &_name, const QString &_text, bool _isToken, - QVariantHash _properties, + QHash _properties, const QList &_relatedCards, const QList &_reverseRelatedCards, SetToPrintingsMap _sets, @@ -122,7 +121,7 @@ CardInfoPtr CardInfo::newInstance(const QString &_name) CardInfoPtr CardInfo::newInstance(const QString &_name, const QString &_text, bool _isToken, - QVariantHash _properties, + QHash _properties, const QList &_relatedCards, const QList &_reverseRelatedCards, SetToPrintingsMap _sets, @@ -210,10 +209,10 @@ void CardInfo::addToSet(const CardSetPtr &_set, const PrintingInfo &_info) refreshCachedSets(); } -void CardInfo::combineLegalities(const QVariantHash &props) +void CardInfo::combineLegalities(const QHash &props) { ensurePropertiesLoaded(); - QHashIterator it(props); + QHashIterator it(props); while (it.hasNext()) { it.next(); if (it.key().startsWith("format-")) { diff --git a/libcockatrice_card/libcockatrice/card/card_info.h b/libcockatrice_card/libcockatrice/card/card_info.h index ad99864c8..e625a0748 100644 --- a/libcockatrice_card/libcockatrice/card/card_info.h +++ b/libcockatrice_card/libcockatrice/card/card_info.h @@ -76,12 +76,12 @@ private: QString text; ///< Text description or rules text of the card. bool isToken; ///< Whether this card is a token or not. // Properties are stored as a pre-serialized blob (cheap to load) and the - // QVariantHash is materialized on first query, so database load avoids - // constructing thousands of QVariants per card. - mutable QByteArray propertiesBlob; ///< Serialized properties (load form). - mutable QVariantHash propertiesCache; ///< Materialized properties (query form). - mutable bool propertiesLoaded = false; ///< Whether propertiesCache is valid. - mutable QMutex propertiesMutex; ///< Guards lazy materialization. + // QHash is materialized on first query, so database load avoids + // constructing thousands of QStrings per card. + mutable QByteArray propertiesBlob; ///< Serialized properties (load form). + mutable QHash propertiesCache; ///< Materialized properties (query form). + mutable bool propertiesLoaded = false; ///< Whether propertiesCache is valid. + mutable QMutex propertiesMutex; ///< Guards lazy materialization. /** * @brief Materializes propertiesCache from propertiesBlob if not already done. @@ -114,7 +114,7 @@ public: explicit CardInfo(const QString &_name, const QString &_text, bool _isToken, - QVariantHash _properties, + QHash _properties, const QList &_relatedCards, const QList &_reverseRelatedCards, SetToPrintingsMap _sets, @@ -127,7 +127,7 @@ public: * Used by the binary cache reader to skip recomputing @p _simpleName and * @p _altNames (which otherwise require a Unicode normalization and a full * printing scan). Properties are supplied as a pre-serialized @p _propertiesBlob - * so the QVariantHash is not built at load time (it is materialized on first + * so the QHash is not built at load time (it is materialized on first * query). * * @param _name The card name. @@ -194,7 +194,7 @@ public: static CardInfoPtr newInstance(const QString &_name, const QString &_text, bool _isToken, - QVariantHash _properties, + QHash _properties, const QList &_relatedCards, const QList &_reverseRelatedCards, SetToPrintingsMap _sets, @@ -288,12 +288,12 @@ public: { return getPropertiesHash().keys(); } - [[nodiscard]] const QVariantHash &getPropertiesHash() const; + [[nodiscard]] const QHash &getPropertiesHash() const; /** * @brief Stores the pre-serialized properties blob and invalidates the * materialized cache. Used by the binary cache reader so the - * QVariantHash is not built at load time. + * QHash is not built at load time. * @param _blob The serialized properties (as written by the cache writer). */ void setPropertiesBlob(QByteArray _blob) const @@ -305,10 +305,10 @@ public: } [[nodiscard]] QString getProperty(const QString &propertyName) const { - return getPropertiesHash().value(propertyName).toString(); + return getPropertiesHash().value(propertyName); } void setProperty(const QString &_name, const QString &_value); - void setProperties(const QVariantHash &_props); + void setProperties(const QHash &_props); [[nodiscard]] bool hasProperty(const QString &propertyName) const { return getPropertiesHash().contains(propertyName); @@ -415,7 +415,7 @@ public: * * @param props Key-value mapping of format legalities. */ - void combineLegalities(const QVariantHash &props); + void combineLegalities(const QHash &props); /** * @brief Refreshes all cached fields that are calculated from the contained sets and printings. diff --git a/libcockatrice_card/libcockatrice/card/card_info_comparator.cpp b/libcockatrice_card/libcockatrice/card/card_info_comparator.cpp index 821cc8675..f4a74194c 100644 --- a/libcockatrice_card/libcockatrice/card/card_info_comparator.cpp +++ b/libcockatrice_card/libcockatrice/card/card_info_comparator.cpp @@ -66,7 +66,7 @@ QVariant CardInfoComparator::getProperty(const CardInfoPtr &card, const QString return card->getIsToken(); } - // Otherwise, check if it's a custom property in the QVariantHash + // Otherwise, check if it's a custom property in the properties hash if (card->hasProperty(property)) { return card->getProperty(property); } diff --git a/libcockatrice_card/libcockatrice/card/database/card_database_cache.cpp b/libcockatrice_card/libcockatrice/card/database/card_database_cache.cpp index 0b68a389a..dfa684dbe 100644 --- a/libcockatrice_card/libcockatrice/card/database/card_database_cache.cpp +++ b/libcockatrice_card/libcockatrice/card/database/card_database_cache.cpp @@ -13,12 +13,11 @@ #include #include #include -#include namespace { constexpr quint32 CACHE_MAGIC = 0x43445243; // "CDRC" -constexpr quint32 CACHE_VERSION = 1; +constexpr quint32 CACHE_VERSION = 2; // ---- Primitives ----------------------------------------------------------- @@ -34,11 +33,11 @@ QString readString(QDataStream &in) return s; } -// Stores a QVariantHash as a single pre-serialized blob. The reader keeps the -// blob as-is and materializes the QVariantHash lazily on first query, which is +// Stores a QHash as a single pre-serialized blob. The reader keeps the +// blob as-is and materializes the QHash lazily on first query, which is // what removes the allocation storm from database load (see card_info.cpp / // printing_info.cpp). -void writeHashBlob(QDataStream &out, const QVariantHash &h) +void writeHashBlob(QDataStream &out, const QHash &h) { QByteArray blob; QDataStream blobOut(&blob, QIODevice::WriteOnly); diff --git a/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_3.cpp b/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_3.cpp index 2dd5e91e9..e403a641d 100644 --- a/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_3.cpp +++ b/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_3.cpp @@ -172,7 +172,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) if (xmlName == "card") { QString name = QString(""); QString text = QString(""); - QVariantHash properties = QVariantHash(); + QHash properties; QString colors = QString(""); QList relatedCards, reverseRelatedCards; auto _sets = SetToPrintingsMap(); @@ -229,7 +229,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) // behaviour. Without this check, disabling a set has no effect on v3 databases. if (set->getEnabled()) { PrintingInfo setInfo(set); - QVariantHash printingProps; + QHash printingProps; if (attrs.hasAttribute("muId")) { printingProps.insert("muid", attrs.value("muId").toString()); } diff --git a/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.cpp b/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.cpp index 129bae9bc..df92618da 100644 --- a/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.cpp +++ b/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.cpp @@ -243,9 +243,9 @@ void CockatriceXml4Parser::loadSetsFromXml(QXmlStreamReader &xml) } } -QVariantHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &xml) +QHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &xml) { - QVariantHash properties = QVariantHash(); + QHash properties; while (!xml.atEnd()) { if (xml.readNext() == QXmlStreamReader::EndElement) { break; @@ -272,7 +272,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) if (xmlName == "card") { QString name = QString(""); QString text = QString(""); - QVariantHash properties = QVariantHash(); + QHash properties; QList relatedCards, reverseRelatedCards; auto _sets = SetToPrintingsMap(); int tableRow = 0; @@ -315,7 +315,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) auto set = internalAddSet(setName); if (set->getEnabled()) { PrintingInfo printingInfo(set); - QVariantHash printingProps; + QHash printingProps; for (QXmlStreamAttribute attr : attrs) { QString attrName = attr.name().toString(); if (attrName == "picURL") { diff --git a/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.h b/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.h index 92c967a0c..55f7c5a3b 100644 --- a/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.h +++ b/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.h @@ -19,7 +19,7 @@ inline Q_LOGGING_CATEGORY(CockatriceXml4Log, "cockatrice_xml.xml_4_parser"); * making the parser more extensible and schema-compliant. * * @note Differences from v3: - * - Card properties are stored in blocks as a QVariantHash. + * - Card properties are stored in blocks as a QHash. * - Sets can include a element. * - Supports user preferences via ICardPreferenceProvider (e.g., skipping rebalanced cards). * - Related cards support persistent relations and multiple attach types (e.g., transform). @@ -70,9 +70,9 @@ private: /** * @brief Loads a generic block from a element. * @param xml The open QXmlStreamReader positioned at a element. - * @return A QVariantHash mapping property names to values. + * @return A QHash mapping property names to values. */ - QVariantHash loadCardPropertiesFromXml(QXmlStreamReader &xml); + QHash loadCardPropertiesFromXml(QXmlStreamReader &xml); /** * @brief Load all elements from the XML stream. diff --git a/libcockatrice_card/libcockatrice/card/printing/printing_info.cpp b/libcockatrice_card/libcockatrice/card/printing/printing_info.cpp index 5df3680a0..ee5b1329b 100644 --- a/libcockatrice_card/libcockatrice/card/printing/printing_info.cpp +++ b/libcockatrice_card/libcockatrice/card/printing/printing_info.cpp @@ -27,14 +27,14 @@ void PrintingInfo::ensurePropertiesLoaded() const void PrintingInfo::setProperty(const QString &_name, const QString &_value) { ensurePropertiesLoaded(); - if (propertiesCache.value(_name).toString() == _value) { + if (propertiesCache.value(_name) == _value) { return; } propertiesCache.insert(_name, _value); setProperties(propertiesCache); } -void PrintingInfo::setProperties(const QVariantHash &_props) +void PrintingInfo::setProperties(const QHash &_props) { ensurePropertiesLoaded(); propertiesCache = _props; @@ -48,10 +48,10 @@ void PrintingInfo::setProperties(const QVariantHash &_props) */ QString PrintingInfo::getUuid() const { - return getPropertiesHash().value("uuid").toString(); + return getPropertiesHash().value("uuid"); } QString PrintingInfo::getFlavorName() const { - return getPropertiesHash().value("flavorName").toString(); -} \ No newline at end of file + return getPropertiesHash().value("flavorName"); +} diff --git a/libcockatrice_card/libcockatrice/card/printing/printing_info.h b/libcockatrice_card/libcockatrice/card/printing/printing_info.h index adec2010c..f7ca90aad 100644 --- a/libcockatrice_card/libcockatrice/card/printing/printing_info.h +++ b/libcockatrice_card/libcockatrice/card/printing/printing_info.h @@ -70,11 +70,11 @@ private: CardSetPtr set; ///< The set this variation belongs to. // Properties are stored as a pre-serialized blob (cheap to load) and the - // QVariantHash is materialized on first query. This avoids constructing - // thousands of QVariants per card at database-load time. - mutable QByteArray propertiesBlob; ///< Serialized properties (load form). - mutable QVariantHash propertiesCache; ///< Materialized properties (query form). - mutable bool propertiesLoaded = false; ///< Whether propertiesCache is valid. + // QHash is materialized on first query. This avoids constructing + // thousands of QStrings per card at database-load time. + mutable QByteArray propertiesBlob; ///< Serialized properties (load form). + mutable QHash propertiesCache; ///< Materialized properties (query form). + mutable bool propertiesLoaded = false; ///< Whether propertiesCache is valid. mutable QSharedPointer propertiesMutex = QSharedPointer::create(); ///< Guards lazy materialization. @@ -101,7 +101,7 @@ public: return getPropertiesHash().keys(); } - [[nodiscard]] const QVariantHash &getPropertiesHash() const + [[nodiscard]] const QHash &getPropertiesHash() const { ensurePropertiesLoaded(); return propertiesCache; @@ -115,7 +115,7 @@ public: */ [[nodiscard]] QString getProperty(const QString &propertyName) const { - return getPropertiesHash().value(propertyName).toString(); + return getPropertiesHash().value(propertyName); } /** @@ -127,12 +127,12 @@ public: * @param _value The string value to assign. */ void setProperty(const QString &_name, const QString &_value); - void setProperties(const QVariantHash &_props); + void setProperties(const QHash &_props); /** * @brief Stores the pre-serialized properties blob and marks the materialized * cache as invalid. Used by the binary cache reader to avoid building a - * QVariantHash at load time. + * QHash at load time. * @param _blob The serialized properties (as written by the cache writer). */ void setPropertiesBlob(QByteArray _blob) const diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index 4eeb6ecc4..3d7b7b555 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -18,7 +18,7 @@ static const QList kSingletonCounts = {{1, "legal"}, {0, "banned"} SplitCardPart::SplitCardPart(const QString &_name, const QString &_text, - const QVariantHash &_properties, + const QHash &_properties, const PrintingInfo &_printingInfo) : name(_name), text(_text), properties(_properties), printingInfo(_printingInfo) { @@ -135,7 +135,7 @@ static void sortAndReduceColors(QString &colors) CardInfoPtr OracleImporter::addCard(QString name, const QString &text, bool isToken, - QVariantHash properties, + QHash properties, const QList &relatedCards, const PrintingInfo &printingInfo) { @@ -152,7 +152,7 @@ CardInfoPtr OracleImporter::addCard(QString name, } // Remove {} around mana costs, except if it's split cost - QString manacost = properties.value("manacost").toString(); + QString manacost = properties.value("manacost"); if (!manacost.isEmpty()) { QStringList symbols = manacost.split("}"); QString formattedCardCost; @@ -169,12 +169,12 @@ CardInfoPtr OracleImporter::addCard(QString name, } // fix colors - QString allColors = properties.value("colors").toString(); + QString allColors = properties.value("colors"); if (allColors.size() > 1) { sortAndReduceColors(allColors); properties.insert("colors", allColors); } - QString allColorIdent = properties.value("coloridentity").toString(); + QString allColorIdent = properties.value("coloridentity"); if (allColorIdent.size() > 1) { sortAndReduceColors(allColorIdent); properties.insert("coloridentity", allColorIdent); @@ -182,16 +182,15 @@ CardInfoPtr OracleImporter::addCard(QString name, // DETECT CARD POSITIONING INFO - bool landscapeOrientation = properties.value("maintype").toString() == "Battle" || - properties.value("layout").toString() == "split" || - properties.value("layout").toString() == "planar"; + bool landscapeOrientation = properties.value("maintype") == "Battle" || properties.value("layout") == "split" || + properties.value("layout") == "planar"; // cards that enter the field tapped bool cipt = parseCipt(name, text) || landscapeOrientation; // table row int tableRow = 1; - QString mainCardType = properties.value("maintype").toString(); + QString mainCardType = properties.value("maintype"); if (mainCardType == "Land") { tableRow = 0; } else if (mainCardType == "Sorcery" || mainCardType == "Instant") { @@ -201,11 +200,11 @@ CardInfoPtr OracleImporter::addCard(QString name, } // card side - QString side = properties.value("side").toString() == "b" ? "back" : "front"; + QString side = properties.value("side") == "b" ? "back" : "front"; properties.insert("side", side); // upsideDown (flip cards) - QString layout = properties.value("layout").toString(); + QString layout = properties.value("layout"); bool upsideDown = layout == "flip" && side == "back"; // insert the card and its properties @@ -279,7 +278,7 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList } // card properties - QVariantHash properties; + QHash properties; for (auto i = cardProperties.cbegin(), end = cardProperties.cend(); i != end; ++i) { QString mtgjsonProperty = i.key(); QString xmlPropertyName = i.value(); @@ -291,7 +290,7 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList // per-set properties PrintingInfo printingInfo = PrintingInfo(currentSet); - QVariantHash printingProps; + QHash printingProps; for (auto i = setInfoProperties.cbegin(), end = setInfoProperties.cend(); i != end; ++i) { QString mtgjsonProperty = i.key(); QString xmlPropertyName = i.value(); @@ -431,7 +430,7 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList QList, QString>> partsAndNames = splitCards.values(); for (auto [splitCardParts, name] : partsAndNames) { QString text; - QVariantHash properties; + QHash properties; PrintingInfo printingInfo; for (const SplitCardPart &tmp : splitCardParts) { @@ -444,11 +443,11 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList properties = tmp.getProperties(); printingInfo = tmp.getPrintingInfo(); } else { - const QVariantHash &tmpProps = tmp.getProperties(); + const QHash &tmpProps = tmp.getProperties(); for (auto i = tmpProps.cbegin(), end = tmpProps.cend(); i != end; ++i) { QString prop = i.key(); - QString originalPropertyValue = properties.value(prop).toString(); - QString thisCardPropertyValue = i.value().toString(); + QString originalPropertyValue = properties.value(prop); + QString thisCardPropertyValue = i.value(); if (!thisCardPropertyValue.isEmpty() && originalPropertyValue != thisCardPropertyValue) { if (originalPropertyValue.isEmpty()) { // don't create //es if one field is empty properties.insert(prop, thisCardPropertyValue); diff --git a/oracle/src/oracleimporter.h b/oracle/src/oracleimporter.h index 5bf352594..99644f9ce 100644 --- a/oracle/src/oracleimporter.h +++ b/oracle/src/oracleimporter.h @@ -95,7 +95,7 @@ class SplitCardPart public: SplitCardPart(const QString &_name, const QString &_text, - const QVariantHash &_properties, + const QHash &_properties, const PrintingInfo &_printingInfo); inline const QString &getName() const { @@ -105,7 +105,7 @@ public: { return text; } - inline const QVariantHash &getProperties() const + inline const QHash &getProperties() const { return properties; } @@ -117,7 +117,7 @@ public: private: QString name; QString text; - QVariantHash properties; + QHash properties; PrintingInfo printingInfo; }; @@ -142,7 +142,7 @@ private: CardInfoPtr addCard(QString name, const QString &text, bool isToken, - QVariantHash properties, + QHash properties, const QList &relatedCards, const PrintingInfo &printingInfo); signals: