mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
* [CardDB] Sort power/toughness without splitting every comparison
When the card database is sorted by the P/T column, lessThan() runs
O(n log n) times over the whole view, and each call split both strings
into a QStringList ("power/toughness") and then read the two elements
back. For the roughly 36k cards in the database that is millions of
list and string allocations, all for a value that contains at most one
separator.
The comparator now locates the single '/' with indexOf and passes the
two halves as QStringView to lessThanNumerically(), which is changed
from QString to QStringView. The numeric parsing, the "1+*" fallback and
the locale-aware tie-break are unchanged, and strings with no separator
or more than one still fall through to the plain string comparison,
exactly as split()-based size checks did before.
lessThanNumerically() also initializes its two bool out-parameters; they
were declared uninitialized, which only worked because toFloat() always
assigns them.
Compared old and new comparator over a corpus of 2024 power/toughness
strings (4096576 ordered pairs, including malformed values): zero
differences. Full build and ctest (628 tests) pass.
* Extract well-formedness checks in P/T comparator
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
102 lines
3 KiB
C++
102 lines
3 KiB
C++
/**
|
|
* @file card_database_display_model.h
|
|
* @ingroup CardDatabaseModels
|
|
* @brief The CardDatabaseDisplayModel is a QSortFilterProxyModel that allows applying filters and sorting to a
|
|
* CardDatabaseModel.
|
|
*/
|
|
|
|
#ifndef COCKATRICE_CARD_DATABASE_DISPLAY_MODEL_H
|
|
#define COCKATRICE_CARD_DATABASE_DISPLAY_MODEL_H
|
|
|
|
#include "libcockatrice/card/card_info.h"
|
|
|
|
#include <QModelIndex>
|
|
#include <QSet>
|
|
#include <QSortFilterProxyModel>
|
|
#include <QString>
|
|
#include <QStringView>
|
|
#include <QTimer>
|
|
#include <libcockatrice/card/card_localization.h>
|
|
#include <libcockatrice/filters/filter_string.h>
|
|
#include <qtmetamacros.h>
|
|
|
|
class FilterTree;
|
|
class QObject;
|
|
template <class Key, class T> class QMap;
|
|
|
|
class CardDatabaseDisplayModel : public QSortFilterProxyModel
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
enum FilterBool
|
|
{
|
|
ShowTrue,
|
|
ShowFalse,
|
|
ShowAll
|
|
};
|
|
|
|
private:
|
|
FilterBool isToken;
|
|
QString cardName, cardText;
|
|
QSet<QString> cardNameSet, cardTypes, cardColors;
|
|
FilterTree *filterTree;
|
|
FilterString *filterString;
|
|
int loadedRowCount;
|
|
QTimer dirtyTimer;
|
|
CardSearchLanguage searchLanguage;
|
|
QString searchText;
|
|
|
|
/** The translation table that will be used for sanitizeCardName. */
|
|
static QMap<wchar_t, wchar_t> characterTranslation;
|
|
|
|
public:
|
|
explicit CardDatabaseDisplayModel(QObject *parent = nullptr);
|
|
void setSourceModel(QAbstractItemModel *model) override;
|
|
void setFilterTree(FilterTree *_filterTree);
|
|
void setIsToken(FilterBool _isToken)
|
|
{
|
|
isToken = _isToken;
|
|
dirty();
|
|
}
|
|
|
|
void setCardName(const QString &_cardName)
|
|
{
|
|
if (filterString != nullptr) {
|
|
delete filterString;
|
|
filterString = nullptr;
|
|
}
|
|
cardName = sanitizeCardName(_cardName, characterTranslation);
|
|
dirty();
|
|
}
|
|
void setStringFilter(const QString &_src);
|
|
void setCardNameSet(const QSet<QString> &_cardNameSet)
|
|
{
|
|
cardNameSet = _cardNameSet;
|
|
dirty();
|
|
}
|
|
void setSearchLanguage(const CardSearchLanguage &searchLang);
|
|
|
|
void dirty()
|
|
{
|
|
dirtyTimer.start(20);
|
|
}
|
|
void clearFilterAll();
|
|
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
[[nodiscard]] bool canFetchMore(const QModelIndex &parent) const override;
|
|
void fetchMore(const QModelIndex &parent) override;
|
|
signals:
|
|
void modelDirty();
|
|
|
|
protected:
|
|
[[nodiscard]] bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
|
static int lessThanNumerically(QStringView left, QStringView right);
|
|
[[nodiscard]] bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
|
[[nodiscard]] bool rowMatchesCardName(CardInfoPtr info) const;
|
|
|
|
private slots:
|
|
void filterTreeChanged();
|
|
/** Will translate all undesirable characters in DIRTYNAME according to the TABLE. */
|
|
const QString sanitizeCardName(const QString &dirtyName, const QMap<wchar_t, wchar_t> &table);
|
|
};
|
|
|
|
#endif // COCKATRICE_CARD_DATABASE_DISPLAY_MODEL_H
|