diff --git a/src/api/helpers/text.cpp b/src/api/helpers/text.cpp index 933b74e3..c2a26f6e 100644 --- a/src/api/helpers/text.cpp +++ b/src/api/helpers/text.cpp @@ -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 diff --git a/src/api/helpers/text.h b/src/api/helpers/text.h index bdf93548..72d9e9e1 100644 --- a/src/api/helpers/text.h +++ b/src/api/helpers/text.h @@ -46,6 +46,12 @@ std::optional 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 diff --git a/src/api/sorting/plugin_graph.cpp b/src/api/sorting/plugin_graph.cpp index abbaf5b5..1c5452b8 100644 --- a/src/api/sorting/plugin_graph.cpp +++ b/src/api/sorting/plugin_graph.cpp @@ -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 PluginGraph::GetVertices() const { std::optional 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; } } diff --git a/src/api/sorting/plugin_graph.h b/src/api/sorting/plugin_graph.h index b776fb78..71930992 100644 --- a/src/api/sorting/plugin_graph.h +++ b/src/api/sorting/plugin_graph.h @@ -55,6 +55,16 @@ private: std::unordered_map> pathsCache_; }; +#if _WIN32 +class WideStringsCache { +public: + const std::wstring& GetOrInsert(const std::string& narrowString); + +private: + std::unordered_map 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 }; }