mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Cache UTF-16 strings on Windows during sorting
Converting between UTF-8 and UTF-16 is surprisingly slow, this improves sorting performance by 16%.
This commit is contained in:
@@ -182,11 +182,21 @@ std::string FromWinWide(const std::wstring& wstr) {
|
||||
|
||||
int CompareFilenames(const std::string& lhs, const std::string& rhs) {
|
||||
#ifdef _WIN32
|
||||
// On Windows, use CompareStringOrdinal as that will perform case conversion
|
||||
return CompareFilenames(ToWinWide(lhs), ToWinWide(rhs));
|
||||
#else
|
||||
auto unicodeLhs = icu::UnicodeString::fromUTF8(lhs);
|
||||
auto unicodeRhs = icu::UnicodeString::fromUTF8(rhs);
|
||||
return unicodeLhs.caseCompare(unicodeRhs, U_FOLD_CASE_DEFAULT);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int CompareFilenames(const std::wstring& lhs, const std::wstring& rhs) {
|
||||
// Use CompareStringOrdinal as that will perform case conversion
|
||||
// using the operating system uppercase table information, which (I think)
|
||||
// will give results that match the filesystem, and is not locale-dependent.
|
||||
int result = CompareStringOrdinal(
|
||||
ToWinWide(lhs).c_str(), -1, ToWinWide(rhs).c_str(), -1, true);
|
||||
lhs.c_str(), -1, rhs.c_str(), -1, true);
|
||||
switch (result) {
|
||||
case CSTR_LESS_THAN:
|
||||
return -1;
|
||||
@@ -198,12 +208,8 @@ int CompareFilenames(const std::string& lhs, const std::string& rhs) {
|
||||
throw std::invalid_argument(
|
||||
"One of the filenames to compare was invalid.");
|
||||
}
|
||||
#else
|
||||
auto unicodeLhs = icu::UnicodeString::fromUTF8(lhs);
|
||||
auto unicodeRhs = icu::UnicodeString::fromUTF8(rhs);
|
||||
return unicodeLhs.caseCompare(unicodeRhs, U_FOLD_CASE_DEFAULT);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string NormalizeFilename(const std::string& filename) {
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -46,6 +46,12 @@ std::optional<std::string> ExtractVersion(const std::string& text);
|
||||
// locale-invariant.
|
||||
int CompareFilenames(const std::string& lhs, const std::string& rhs);
|
||||
|
||||
#ifdef _WIN32
|
||||
std::wstring ToWinWide(const std::string& str);
|
||||
|
||||
int CompareFilenames(const std::wstring& lhs, const std::wstring& rhs);
|
||||
#endif
|
||||
|
||||
// Normalize the given filename in a way that is locale-invariant. On Windows,
|
||||
// this uppercases the filename according to the same case mapping rules as used
|
||||
// by the filesystem. On Linux, case folding is used and gives results that are
|
||||
|
||||
@@ -590,6 +590,19 @@ void PathsCache::CachePath(const vertex_t& fromVertex,
|
||||
}
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
const std::wstring& WideStringsCache::GetOrInsert(
|
||||
const std::string& narrowString) {
|
||||
auto vertexNameIt = wideStringsCache_.find(narrowString);
|
||||
if (vertexNameIt == wideStringsCache_.end()) {
|
||||
vertexNameIt =
|
||||
wideStringsCache_.emplace(narrowString, ToWinWide(narrowString)).first;
|
||||
}
|
||||
|
||||
return vertexNameIt->second;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t PluginGraph::CountVertices() const {
|
||||
return boost::num_vertices(graph_);
|
||||
}
|
||||
@@ -601,7 +614,16 @@ std::pair<vertex_it, vertex_it> PluginGraph::GetVertices() const {
|
||||
std::optional<vertex_t> PluginGraph::GetVertexByName(
|
||||
const std::string& name) const {
|
||||
for (const auto& vertex : boost::make_iterator_range(GetVertices())) {
|
||||
if (CompareFilenames(GetPlugin(vertex).GetName(), name) == 0) {
|
||||
#if _WIN32
|
||||
auto& wideVertexName =
|
||||
wideStringCache_.GetOrInsert(GetPlugin(vertex).GetName());
|
||||
auto& wideName = wideStringCache_.GetOrInsert(name);
|
||||
|
||||
int comparison = CompareFilenames(wideVertexName, wideName);
|
||||
#else
|
||||
int comparison = CompareFilenames(GetPlugin(vertex).GetName(), name);
|
||||
#endif
|
||||
if (comparison == 0) {
|
||||
return vertex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,16 @@ private:
|
||||
std::unordered_map<vertex_t, std::unordered_set<vertex_t>> pathsCache_;
|
||||
};
|
||||
|
||||
#if _WIN32
|
||||
class WideStringsCache {
|
||||
public:
|
||||
const std::wstring& GetOrInsert(const std::string& narrowString);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::wstring> wideStringsCache_;
|
||||
};
|
||||
#endif
|
||||
|
||||
class PluginGraph {
|
||||
public:
|
||||
size_t CountVertices() const;
|
||||
@@ -99,6 +109,9 @@ public:
|
||||
private:
|
||||
RawPluginGraph graph_;
|
||||
PathsCache pathsCache_;
|
||||
#if _WIN32
|
||||
mutable WideStringsCache wideStringCache_;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user