From 3bdf320f5cc3719b61266a3c0361f51764a51d47 Mon Sep 17 00:00:00 2001 From: Terry Yiu Date: Thu, 10 Sep 2026 12:35:39 +0300 Subject: [PATCH] Cache region display-name lookups used by currency search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit matchesCurrencySearch() re-derives a country name for every currency on every keystroke; region codes don't change during a session, so this was redoing the same locale lookups repeatedly — worst on web, where each lookup constructs a fresh Intl.DisplayNames instance. Caches by region code instead, including null results (regions the platform doesn't recognize), so each code's lookup happens once ever. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy --- .../kotlin/xyz/tyiu/satsprice/SystemCurrencies.kt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/SystemCurrencies.kt b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/SystemCurrencies.kt index 312da89..8182859 100644 --- a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/SystemCurrencies.kt +++ b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/SystemCurrencies.kt @@ -17,14 +17,25 @@ fun matchesCurrencySearch(info: CurrencyInfo, query: String): Boolean { } } +// Region codes are static for the life of the app (they don't depend on [query]), but +// [matchesCurrencySearch] re-derives a name for every currency on every keystroke — caching here +// turns that back into a one-time-per-region-code cost. A plain Map (not getOrPut) since a cached +// null result — a region [regionDisplayName] doesn't recognize — must stay cached rather than +// being retried every time, which getOrPut would do for a null value. +private val regionDisplayNameCache = mutableMapOf() + /** * A localized display name for ISO 3166-1 alpha-2 [regionCode] (e.g. "Canada"), or null if the * platform doesn't recognize it. "EU" is handled directly since it's not a real ISO 3166-1 * country code — it's [issuingCountryCodes]' own stand-in for EUR's region/flag — and platform * locale data doesn't reliably resolve it to a name the way it does real country codes. */ -private fun localizedRegionName(regionCode: String): String? = - if (regionCode == "EU") "European Union" else regionDisplayName(regionCode) +private fun localizedRegionName(regionCode: String): String? { + if (regionCode in regionDisplayNameCache) return regionDisplayNameCache[regionCode] + val name = if (regionCode == "EU") "European Union" else regionDisplayName(regionCode) + regionDisplayNameCache[regionCode] = name + return name +} /** The current platform's localized display name for ISO 3166-1 alpha-2 [regionCode], if known. */ expect fun regionDisplayName(regionCode: String): String?