1 /**
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "plugins/ets/stdlib/native/core/IntlFormattersCache.h"
17
18 namespace ark::ets::stdlib {
19
IntlFormattersCache()20 IntlFormattersCache::IntlFormattersCache()
21 {
22 ASSERT(MAX_SIZE_CACHE > 1U);
23 ASSERT(ERASE_RATIO > 0);
24 ASSERT(ERASE_RATIO < 1);
25 ASSERT(ERASE_AMOUNT > 0);
26 }
27
NumFmtsCacheInvalidation(const std::string & locTag,const icu::Locale & loc)28 icu::number::LocalizedNumberFormatter &IntlFormattersCache::NumFmtsCacheInvalidation(const std::string &locTag,
29 const icu::Locale &loc)
30 {
31 CacheUMapIterator it;
32 {
33 os::memory::LockHolder lh(mtx_);
34 it = cache_.find(locTag);
35 if (it == cache_.end()) {
36 EraseRandFmtsGroupByEraseRatio();
37 // Create new number formatter, number range formatter is empty
38 // Number range formatter will be created via call RangeIntlFormattersCacheInvalidation
39 auto *ptr = new icu::number::LocalizedNumberFormatter(icu::number::NumberFormatter::withLocale(loc));
40 NumberFormatters f;
41 f.numFmt.reset(ptr);
42 auto [iter, isNumFmtInserted] = cache_.insert_or_assign(locTag, std::move(f));
43 ASSERT(isNumFmtInserted);
44 it = iter;
45 } else if (it->second.numFmt == nullptr) {
46 // Create new number formatter, range formatter is not changed
47 auto *ptr = new icu::number::LocalizedNumberFormatter(icu::number::NumberFormatter::withLocale(loc));
48 it->second.numFmt.reset(ptr);
49 }
50 }
51 ASSERT(it->second.numFmt != nullptr);
52 return *(it->second.numFmt);
53 }
54
NumRangeFmtsCacheInvalidation(const std::string & locTag,const icu::Locale & loc)55 icu::number::LocalizedNumberRangeFormatter &IntlFormattersCache::NumRangeFmtsCacheInvalidation(
56 const std::string &locTag, const icu::Locale &loc)
57 {
58 CacheUMapIterator it;
59 {
60 os::memory::LockHolder lh(mtx_);
61 it = cache_.find(locTag);
62 if (it == cache_.end()) {
63 EraseRandFmtsGroupByEraseRatio();
64 // Create new number range formatter, number formatter is empty
65 // Number formatter will be created via call IntlFormattersCacheInvalidation
66 auto *ptr =
67 new icu::number::LocalizedNumberRangeFormatter(icu::number::NumberRangeFormatter::withLocale(loc));
68 NumberFormatters f;
69 f.numRangeFmt.reset(ptr);
70 auto [iter, isNumRangeFmtInserted] = cache_.insert_or_assign(locTag, std::move(f));
71 ASSERT(isNumRangeFmtInserted);
72 it = iter;
73 } else if (it->second.numRangeFmt == nullptr) {
74 // Create new number range formatter, number formatter is not changed
75 auto *ptr =
76 new icu::number::LocalizedNumberRangeFormatter(icu::number::NumberRangeFormatter::withLocale(loc));
77 it->second.numRangeFmt.reset(ptr);
78 }
79 }
80 ASSERT(it->second.numRangeFmt != nullptr);
81 return *(it->second.numRangeFmt);
82 }
83
EraseRandFmtsGroupByEraseRatio()84 void IntlFormattersCache::EraseRandFmtsGroupByEraseRatio()
85 {
86 os::memory::LockHolder lh(mtx_);
87 // Remove random N "neighbours" items (group) from cache_ if size is maximum
88 if (cache_.size() == MAX_SIZE_CACHE) {
89 // NOLINTNEXTLINE(cert-msc51-cpp)
90 static std::minstd_rand simpleRand(std::time(nullptr));
91 auto delta = static_cast<uint32_t>(simpleRand() % (MAX_SIZE_CACHE - ERASE_AMOUNT + 1U));
92 // delta is in random range [0; MAX_SIZE_CACHE - ERASE_AMOUNT]
93 auto firstIt = cache_.begin();
94 std::advance(firstIt, delta);
95 auto lastIt = firstIt;
96 std::advance(lastIt, ERASE_AMOUNT);
97 cache_.erase(firstIt, lastIt);
98 }
99 }
100
101 } // namespace ark::ets::stdlib
102