Greatly improve case-insensitive lookup speed

By using hash tables, the algorithmic complexity of the case-insensitive
lookup has been reduced from O(n * k) to amortized O(k), where n is the
number of files in each level and k is the number of directory levels
that need to be traversed.

This massively improves performance on Linux when loading characters,
especially when there are many missing characters, since it is no longer
necessary to scan the entire character folder repeatedly.
This commit is contained in:
oldmud0 2021-06-05 22:27:56 -05:00
parent 037d96a5d9
commit 7a1c3f385e

View File

@ -5,6 +5,7 @@
#include <QDir> #include <QDir>
#include <QRegExp> #include <QRegExp>
#include <QStandardPaths> #include <QStandardPaths>
#include <QStringBuilder>
#ifdef BASE_OVERRIDE #ifdef BASE_OVERRIDE
#include "base_override.h" #include "base_override.h"
@ -195,6 +196,7 @@ QString AOApplication::get_case_sensitive_path(QString p_file)
if (exists(p_file)) if (exists(p_file))
return p_file; return p_file;
QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); QString file_parent_dir = get_case_sensitive_path(file.absolutePath());
// second, does it exist in the new parent dir? // second, does it exist in the new parent dir?
@ -204,12 +206,22 @@ QString AOApplication::get_case_sensitive_path(QString p_file)
// last resort, dirlist parent dir and find case insensitive match // last resort, dirlist parent dir and find case insensitive match
QRegExp file_rx = QRegExp file_rx =
QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString);
static QHash<uint, QString> listing_cache;
static QHash<uint, bool> listing_exist_cache;
if (!listing_exist_cache.contains(qHash(file_parent_dir))) {
QStringList files = QDir(file_parent_dir).entryList(); QStringList files = QDir(file_parent_dir).entryList();
for (const QString &file : files) {
listing_cache.insert(qHash(file_parent_dir % QChar('/') % file.toLower()), file);
}
listing_exist_cache.insert(qHash(file_parent_dir), true);
}
QString found_file = listing_cache.value(qHash(file_parent_dir % QChar('/') % file_basename.toLower()));
int result = files.indexOf(file_rx); if (!found_file.isEmpty()) {
return file_parent_dir + "/" + found_file;
if (result != -1) }
return file_parent_dir + "/" + files.at(result);
// if nothing is found, let the caller handle the missing file // if nothing is found, let the caller handle the missing file
return file_parent_dir + "/" + file_basename; return file_parent_dir + "/" + file_basename;