diff --git a/cockatrice/src/deck/deck_list_model.cpp b/cockatrice/src/deck/deck_list_model.cpp index cd3c9bcf1..0005777c9 100644 --- a/cockatrice/src/deck/deck_list_model.cpp +++ b/cockatrice/src/deck/deck_list_model.cpp @@ -262,7 +262,7 @@ bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, con } emitRecursiveUpdates(index); - deckList->updateDeckHash(); + deckList->refreshDeckHash(); return true; } @@ -398,7 +398,7 @@ QModelIndex DeckListModel::addCard(const QString &cardName, cardNode->setCardSetShortName(cardSetName); cardNode->setCardCollectorNumber(cardInfoSet.getProperty("num")); cardNode->setCardProviderId(cardInfoSet.getProperty("uuid")); - deckList->updateDeckHash(); + deckList->refreshDeckHash(); } sort(lastKnownColumn, lastKnownOrder); emitRecursiveUpdates(parentIndex); diff --git a/common/decklist.cpp b/common/decklist.cpp index 708912a29..cf1240d8a 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -368,8 +368,8 @@ DeckList::DeckList() // TODO: https://qt-project.org/doc/qt-4.8/qobject.html#no-copy-constructor-or-assignment-operator DeckList::DeckList(const DeckList &other) - : QObject(), name(other.name), comments(other.comments), bannerCard(other.bannerCard), deckHash(other.deckHash), - lastLoadedTimestamp(other.lastLoadedTimestamp), tags(other.tags) + : QObject(), name(other.name), comments(other.comments), bannerCard(other.bannerCard), + lastLoadedTimestamp(other.lastLoadedTimestamp), tags(other.tags), cachedDeckHash(other.cachedDeckHash) { root = new InnerDecklistNode(other.getRoot()); @@ -378,7 +378,6 @@ DeckList::DeckList(const DeckList &other) spIterator.next(); sideboardPlans.insert(spIterator.key(), new SideboardPlan(spIterator.key(), spIterator.value()->getMoveList())); } - updateDeckHash(); } DeckList::DeckList(const QString &nativeString) @@ -507,7 +506,7 @@ bool DeckList::loadFromXml(QXmlStreamReader *xml) } } } - updateDeckHash(); + refreshDeckHash(); if (xml->error()) { qDebug() << "Error loading deck from xml: " << xml->errorString(); return false; @@ -734,7 +733,7 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) new DecklistCardNode(cardName, amount, getZoneObjFromName(zoneName), setCode, collectorNumber); } - updateDeckHash(); + refreshDeckHash(); return true; } @@ -808,8 +807,7 @@ void DeckList::cleanList() setName(); setComments(); setTags(); - deckHash = QString(); - emit deckHashChanged(); + refreshDeckHash(); } void DeckList::getCardListHelper(InnerDecklistNode *item, QSet &result) const @@ -881,7 +879,7 @@ DecklistCardNode *DeckList::addCard(const QString &cardName, } auto *node = new DecklistCardNode(cardName, 1, zoneNode, cardSetName, cardSetCollectorNumber, cardProviderId); - updateDeckHash(); + refreshDeckHash(); return node; } @@ -907,7 +905,7 @@ bool DeckList::deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNod } if (updateHash) { - updateDeckHash(); + refreshDeckHash(); } return true; @@ -918,7 +916,7 @@ bool DeckList::deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNod if (inner) { if (deleteNode(node, inner)) { if (updateHash) { - updateDeckHash(); + refreshDeckHash(); } return true; @@ -929,7 +927,7 @@ bool DeckList::deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNod return false; } -void DeckList::updateDeckHash() +static QString computeDeckHash(const InnerDecklistNode *root) { QStringList cardList; QSet hashZones, optionalZones; @@ -955,7 +953,30 @@ void DeckList::updateDeckHash() (((quint64)(unsigned char)deckHashArray[1]) << 24) + (((quint64)(unsigned char)deckHashArray[2] << 16)) + (((quint64)(unsigned char)deckHashArray[3]) << 8) + (quint64)(unsigned char)deckHashArray[4]; - deckHash = QString::number(number, 32).rightJustified(8, '0'); + return QString::number(number, 32).rightJustified(8, '0'); +} +/** + * Gets the deck hash. + * The hash is computed on the first call to this method, and is cached until the decklist is modified. + * + * @return The deck hash + */ +QString DeckList::getDeckHash() const +{ + if (!cachedDeckHash.isEmpty()) { + return cachedDeckHash; + } + + cachedDeckHash = computeDeckHash(root); + return cachedDeckHash; +} + +/** + * Invalidates the cached deckHash and emits the deckHashChanged signal. + */ +void DeckList::refreshDeckHash() +{ + cachedDeckHash = QString(); emit deckHashChanged(); } diff --git a/common/decklist.h b/common/decklist.h index 9c291cfba..8acbd4945 100644 --- a/common/decklist.h +++ b/common/decklist.h @@ -252,7 +252,6 @@ class DeckList : public QObject private: QString name, comments; QPair bannerCard; - QString deckHash; QString lastLoadedTimestamp; QStringList tags; QMap sideboardPlans; @@ -261,6 +260,11 @@ private: void getCardListWithProviderIdHelper(InnerDecklistNode *item, QMap &result) const; InnerDecklistNode *getZoneObjFromName(const QString &zoneName); + /** + * Empty string indicates invalidated cache. + */ + mutable QString cachedDeckHash; + protected: virtual QString getCardZoneFromName(const QString /*cardName*/, QString currentZoneName) { @@ -363,12 +367,6 @@ public: int getSideboardSize() const; - QString getDeckHash() const - { - return deckHash; - } - void updateDeckHash(); - InnerDecklistNode *getRoot() const { return root; @@ -380,6 +378,9 @@ public: const QString &cardProviderId = QString()); bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = nullptr); + QString getDeckHash() const; + void refreshDeckHash(); + /** * Calls a given function object for each card in the deck. It must * take a InnerDecklistNode* as its first argument and a