From d392c38a738e8c2c34a8edd472e5cd408088024b Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 3 Sep 2024 11:20:20 -0400 Subject: [PATCH] LibUnicode: Cache all created icu::TimeZone objects This cache works exactly the same as the existing icu::Locale cache. --- .../Libraries/LibUnicode/DateTimeFormat.cpp | 4 +-- Userland/Libraries/LibUnicode/ICU.cpp | 25 +++++++++++++++++++ Userland/Libraries/LibUnicode/ICU.h | 13 ++++++++++ Userland/Libraries/LibUnicode/TimeZone.cpp | 6 ++--- Userland/Libraries/LibUnicode/TimeZone.h | 4 +-- 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibUnicode/DateTimeFormat.cpp b/Userland/Libraries/LibUnicode/DateTimeFormat.cpp index 841006a4bbd..ed486395b6f 100644 --- a/Userland/Libraries/LibUnicode/DateTimeFormat.cpp +++ b/Userland/Libraries/LibUnicode/DateTimeFormat.cpp @@ -622,9 +622,9 @@ static void apply_time_zone_to_formatter(icu::SimpleDateFormat& formatter, icu:: { UErrorCode status = U_ZERO_ERROR; - auto* time_zone = icu::TimeZone::createTimeZone(icu_string(time_zone_identifier)); + auto time_zone_data = TimeZoneData::for_time_zone(time_zone_identifier); - auto* calendar = icu::Calendar::createInstance(time_zone, locale, status); + auto* calendar = icu::Calendar::createInstance(time_zone_data->time_zone(), locale, status); VERIFY(icu_success(status)); if (calendar->getDynamicClassID() == icu::GregorianCalendar::getStaticClassID()) { diff --git a/Userland/Libraries/LibUnicode/ICU.cpp b/Userland/Libraries/LibUnicode/ICU.cpp index fc63292ed6f..0b6cf867c29 100644 --- a/Userland/Libraries/LibUnicode/ICU.cpp +++ b/Userland/Libraries/LibUnicode/ICU.cpp @@ -17,6 +17,7 @@ namespace Unicode { static HashMap> s_locale_cache; +static HashMap> s_time_zone_cache; Optional LocaleData::for_locale(StringView locale) { @@ -113,6 +114,30 @@ icu::TimeZoneNames& LocaleData::time_zone_names() return *m_time_zone_names; } +Optional TimeZoneData::for_time_zone(StringView time_zone) +{ + auto time_zone_data = s_time_zone_cache.get(time_zone); + + if (!time_zone_data.has_value()) { + time_zone_data = s_time_zone_cache.ensure(MUST(String::from_utf8(time_zone)), [&]() -> OwnPtr { + auto icu_time_zone = adopt_own_if_nonnull(icu::TimeZone::createTimeZone(icu_string(time_zone))); + if (!icu_time_zone || *icu_time_zone == icu::TimeZone::getUnknown()) + return nullptr; + + return adopt_own(*new TimeZoneData { icu_time_zone.release_nonnull() }); + }); + } + + if (time_zone_data.value()) + return *time_zone_data.value(); + return {}; +} + +TimeZoneData::TimeZoneData(NonnullOwnPtr time_zone) + : m_time_zone(move(time_zone)) +{ +} + Vector icu_string_list(ReadonlySpan strings) { Vector result; diff --git a/Userland/Libraries/LibUnicode/ICU.h b/Userland/Libraries/LibUnicode/ICU.h index c6af66b2ae2..a436a378a68 100644 --- a/Userland/Libraries/LibUnicode/ICU.h +++ b/Userland/Libraries/LibUnicode/ICU.h @@ -24,6 +24,7 @@ U_NAMESPACE_BEGIN class DateTimePatternGenerator; class LocaleDisplayNames; class NumberingSystem; +class TimeZone; class TimeZoneNames; U_NAMESPACE_END @@ -63,6 +64,18 @@ private: Optional m_digital_format; }; +class TimeZoneData { +public: + static Optional for_time_zone(StringView time_zone); + + ALWAYS_INLINE icu::TimeZone& time_zone() { return *m_time_zone; } + +private: + explicit TimeZoneData(NonnullOwnPtr); + + NonnullOwnPtr m_time_zone; +}; + constexpr bool icu_success(UErrorCode code) { return static_cast(U_SUCCESS(code)); diff --git a/Userland/Libraries/LibUnicode/TimeZone.cpp b/Userland/Libraries/LibUnicode/TimeZone.cpp index 817101a2e7c..382f37fce0e 100644 --- a/Userland/Libraries/LibUnicode/TimeZone.cpp +++ b/Userland/Libraries/LibUnicode/TimeZone.cpp @@ -131,14 +131,14 @@ Optional time_zone_offset(StringView time_zone, UnixDateTime tim { UErrorCode status = U_ZERO_ERROR; - auto icu_time_zone = adopt_own_if_nonnull(icu::TimeZone::createTimeZone(icu_string(time_zone))); - if (!icu_time_zone || *icu_time_zone == icu::TimeZone::getUnknown()) + auto time_zone_data = TimeZoneData::for_time_zone(time_zone); + if (!time_zone_data.has_value()) return {}; i32 raw_offset = 0; i32 dst_offset = 0; - icu_time_zone->getOffset(static_cast(time.milliseconds_since_epoch()), 0, raw_offset, dst_offset, status); + time_zone_data->time_zone().getOffset(static_cast(time.milliseconds_since_epoch()), 0, raw_offset, dst_offset, status); if (icu_failure(status)) return {}; diff --git a/Userland/Libraries/LibUnicode/TimeZone.h b/Userland/Libraries/LibUnicode/TimeZone.h index 4b8cbf8b958..518589d1fd7 100644 --- a/Userland/Libraries/LibUnicode/TimeZone.h +++ b/Userland/Libraries/LibUnicode/TimeZone.h @@ -4,13 +4,13 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#pragma once + #include #include #include #include -#pragma once - namespace Unicode { struct TimeZoneOffset {