• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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