Qt: Eliminate heap allocations in GameListSortModel

More of an issue since the filter is now checking multiple fields.
This commit is contained in:
Stenzek 2025-05-13 21:43:28 +10:00
parent b91d219524
commit 4bacbc8958
No known key found for this signature in database
2 changed files with 31 additions and 10 deletions

View File

@ -29,6 +29,16 @@
namespace StringUtil {
/// Returns the given character in uppercase.
ALWAYS_INLINE static char ToLower(char ch)
{
return ch + ((static_cast<u8>(ch) >= 'A' && static_cast<u8>(ch) <= 'Z') ? ('a' - 'A') : 0);
}
ALWAYS_INLINE static char ToUpper(char ch)
{
return ch - ((static_cast<u8>(ch) >= 'a' && static_cast<u8>(ch) <= 'z') ? ('a' - 'A') : 0);
}
/// Checks if a wildcard matches a search string.
bool WildcardMatch(const char* subject, const char* mask, bool case_sensitive = true);
@ -81,6 +91,11 @@ static inline int CompareNoCase(std::string_view s1, std::string_view s2)
const int compare_res = (compare_len > 0) ? Strncasecmp(s1.data(), s2.data(), compare_len) : 0;
return (compare_len != 0) ? compare_res : ((s1_len < s2_len) ? -1 : ((s1_len > s2_len) ? 1 : 0));
}
static inline bool ContainsNoCase(std::string_view s1, std::string_view s2)
{
return (std::search(s1.begin(), s1.end(), s2.begin(), s2.end(),
[](char lhs, char rhs) { return (ToLower(lhs) == ToLower(rhs)); }) != s1.end());
}
/// Wrapper around std::from_chars
template<typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
@ -234,7 +249,7 @@ inline std::string ToChars(bool value, int base)
}
/// Returns true if the given character is whitespace.
static inline bool IsWhitespace(char ch)
ALWAYS_INLINE static bool IsWhitespace(char ch)
{
return ((ch >= 0x09 && ch <= 0x0D) || // horizontal tab, line feed, vertical tab, form feed, carriage return
ch == 0x20); // space

View File

@ -30,6 +30,7 @@
#include <QtWidgets/QMenu>
#include <QtWidgets/QScrollBar>
#include <QtWidgets/QStyledItemDelegate>
#include <algorithm>
static constexpr float MIN_SCALE = 0.1f;
static constexpr float MAX_SCALE = 2.0f;
@ -938,9 +939,10 @@ public:
m_filter_region = region;
invalidateRowsFilter();
}
void setFilterName(const QString& name)
void setFilterName(std::string name)
{
m_filter_name = name;
m_filter_name = std::move(name);
std::transform(m_filter_name.begin(), m_filter_name.end(), m_filter_name.begin(), StringUtil::ToLower);
invalidateRowsFilter();
}
@ -970,11 +972,15 @@ public:
if (m_filter_region != DiscRegion::Count && entry->region != m_filter_region)
return false;
if (!m_filter_name.isEmpty() &&
!QString::fromStdString(entry->path).contains(m_filter_name, Qt::CaseInsensitive) &&
!QString::fromStdString(entry->serial).contains(m_filter_name, Qt::CaseInsensitive) &&
!QString::fromStdString(entry->title).contains(m_filter_name, Qt::CaseInsensitive))
return false;
if (!m_filter_name.empty())
{
if (!((!entry->IsDiscSet() && !entry->path.empty() && StringUtil::ContainsNoCase(entry->path, m_filter_name)) ||
(!entry->serial.empty() && StringUtil::ContainsNoCase(entry->serial, m_filter_name)) ||
(!entry->title.empty() && StringUtil::ContainsNoCase(entry->title, m_filter_name))))
{
return false;
}
}
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
@ -988,7 +994,7 @@ private:
GameListModel* m_model;
GameList::EntryType m_filter_type = GameList::EntryType::MaxCount;
DiscRegion m_filter_region = DiscRegion::Count;
QString m_filter_name;
std::string m_filter_name;
bool m_merge_disc_sets = true;
};
@ -1155,7 +1161,7 @@ void GameListWidget::initialize()
m_sort_model->setFilterRegion((index == 0) ? DiscRegion::Count : static_cast<DiscRegion>(index - 1));
});
connect(m_ui.searchText, &QLineEdit::textChanged, this,
[this](const QString& text) { m_sort_model->setFilterName(text); });
[this](const QString& text) { m_sort_model->setFilterName(text.toStdString()); });
connect(m_ui.searchText, &QLineEdit::returnPressed, this, &GameListWidget::onSearchReturnPressed);
GameListCenterIconStyleDelegate* center_icon_delegate = new GameListCenterIconStyleDelegate(this);