diff --git a/libgnucash/core-utils/gnc-unicode.cpp b/libgnucash/core-utils/gnc-unicode.cpp index 2933c57695e..4f182cf0387 100644 --- a/libgnucash/core-utils/gnc-unicode.cpp +++ b/libgnucash/core-utils/gnc-unicode.cpp @@ -24,6 +24,7 @@ #include "gnc-unicode.h" #include +#include #include #include #include @@ -161,10 +162,15 @@ gnc_unicode_has_substring_identical(const char* needle, return false; } -static int -unicode_compare_internal(const char* one, const char* two, - CompareStrength strength) +static icu::Collator* +get_collator(CompareStrength strength) { + thread_local std::vector>> cache; + + for (const auto& kvp : cache) + if (kvp.first == strength) + return kvp.second.get(); + UErrorCode status{U_ZERO_ERROR}; auto locale{gnc_locale_name()}; std::unique_ptr coll( @@ -179,21 +185,37 @@ unicode_compare_internal(const char* one, const char* two, "Failed to create collator for locale %s: %s", locale, u_errorName(status)); g_free(locale); - return -99; + cache.push_back ({strength, nullptr}); + return nullptr; } + auto* ptr = coll.get(); + cache.push_back ({strength, std::move(coll)}); + + g_free(locale); + return ptr; +} + + +static int +unicode_compare_internal(const char* one, const char* two, + CompareStrength strength) +{ + auto coll = get_collator (strength); + if (!coll) + return -99; + + UErrorCode status{U_ZERO_ERROR}; auto result = coll->compare(one, two, status); if (U_FAILURE(status)) { g_log(logdomain, G_LOG_LEVEL_ERROR, - "Comparison of %s and %s in locale %s failed: %s", - one, two, locale, u_errorName(status)); - g_free(locale); + "Comparison of %s and %s failed: %s", + one, two, u_errorName(status)); return -99; } - g_free(locale); return result == UCOL_LESS ? -1 : result == UCOL_EQUAL ? 0 : 1; } diff --git a/libgnucash/core-utils/test/gtest-gnc-unicode.cpp b/libgnucash/core-utils/test/gtest-gnc-unicode.cpp index 9f56f142dd6..32b5c775a37 100644 --- a/libgnucash/core-utils/test/gtest-gnc-unicode.cpp +++ b/libgnucash/core-utils/test/gtest-gnc-unicode.cpp @@ -136,7 +136,10 @@ TEST(GncUnicode, test_german_ss_decorated_accented_nocap) TEST (GncUnicode, test_simple_identical) { - EXPECT_EQ (gnc_unicode_compare_identical ("alice", "alice"), 0); - EXPECT_EQ (gnc_unicode_compare_identical ("alice", "bob"), -1); - EXPECT_EQ (gnc_unicode_compare_identical ("bob", "alice"), 1); + for (int i = 0; i < 5000000; ++i) + { + EXPECT_EQ (gnc_unicode_compare_identical ("alice", "alice"), 0); + EXPECT_EQ (gnc_unicode_compare_identical ("alice", "bob"), -1); + EXPECT_EQ (gnc_unicode_compare_identical ("bob", "alice"), 1); + } }