1 /** 2 * Copyright (c) 2021-2022 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 #ifndef ECMASCRIPT_BASE_GLOBAL_INTL_HELPER_H 17 #define ECMASCRIPT_BASE_GLOBAL_INTL_HELPER_H 18 19 #include <iostream> 20 #include <cstdint> 21 #include <cmath> 22 #include <vector> 23 #include <map> 24 #include <string> 25 #include <chrono> 26 #include <math.h> 27 28 #include "ecmascript/ecma_vm.h" 29 #include "ecmascript/mem/native_area_allocator.h" 30 #include "ecmascript/js_handle.h" 31 #include "base/global/i18n/frameworks/intl/include/collator.h" 32 #if defined(__clang__) 33 #pragma clang diagnostic push 34 #pragma clang diagnostic ignored "-Wshadow" 35 #elif defined(__GNUC__) 36 #pragma GCC diagnostic push 37 #pragma GCC diagnostic ignored "-Wshadow" 38 #endif 39 #include "base/global/i18n/frameworks/intl/include/number_format.h" 40 #include "base/global/i18n/frameworks/intl/include/date_time_format.h" 41 #if defined(__clang__) 42 #pragma clang diagnostic pop 43 #elif defined(__GNUC__) 44 #pragma GCC diagnostic pop 45 #endif 46 47 namespace panda::ecmascript::intl { 48 using GlobalCollator = OHOS::Global::I18n::Collator; 49 using GlobalNumberFormat = OHOS::Global::I18n::NumberFormat; 50 using GlobalDateFormatter = OHOS::Global::I18n::DateTimeFormat; 51 using GlobalCompareResult = OHOS::Global::I18n::CompareResult; 52 53 enum class GlobalFormatterType { 54 DateFormatter, 55 SimpleDateFormatDate, 56 SimpleDateFormatTime, 57 NumberFormatter, 58 Collator 59 }; 60 61 class GlobalIntlHelper { 62 public: 63 GlobalIntlHelper(JSThread *thread, const GlobalFormatterType matterType); ~GlobalIntlHelper()64 ~GlobalIntlHelper() 65 { 66 if (dateUnitArr != nullptr) { 67 delete[] dateUnitArr; 68 } 69 globalObject = nullptr; 70 } 71 72 template<typename T> GetGlobalObject(JSThread * thread,const JSHandle<JSTaggedValue> & locales,const JSHandle<JSTaggedValue> & options,GlobalFormatterType types)73 std::unique_ptr<T> GetGlobalObject(JSThread *thread, const JSHandle<JSTaggedValue> &locales, 74 const JSHandle<JSTaggedValue> &options, GlobalFormatterType types) 75 { 76 std::vector<std::string> cacheEntryVector; 77 cacheEntryVector = LocalesToVector(thread, locales); 78 std::map<std::string, std::string> inputOptions; 79 if (!options->IsUndefined()) { 80 inputOptions = OptionsToMap(thread, options, types); 81 } 82 auto result = std::make_unique<T>(cacheEntryVector, inputOptions); 83 return result; 84 } 85 86 template<typename T> GetGlobalObject(JSThread * thread,const JSHandle<JSTaggedValue> & locales,const JSHandle<JSTaggedValue> & options,GlobalFormatterType types,const bool cache)87 T *GetGlobalObject(JSThread *thread, const JSHandle<JSTaggedValue> &locales, 88 const JSHandle<JSTaggedValue> &options, GlobalFormatterType types, const bool cache) 89 { 90 IcuFormatterType icuType; 91 switch (types) { 92 case GlobalFormatterType::Collator: 93 icuType = IcuFormatterType::COLLATOR; 94 break; 95 case GlobalFormatterType::SimpleDateFormatDate: 96 icuType = IcuFormatterType::SIMPLE_DATE_FORMAT_DATE; 97 break; 98 case GlobalFormatterType::SimpleDateFormatTime: 99 icuType = IcuFormatterType::SIMPLE_DATE_FORMAT_TIME; 100 break; 101 case GlobalFormatterType::DateFormatter: 102 icuType = IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT; 103 break; 104 case GlobalFormatterType::NumberFormatter: 105 icuType = IcuFormatterType::NUMBER_FORMATTER; 106 break; 107 } 108 EcmaVM *ecmaVm = thread->GetEcmaVM(); 109 std::string cacheEntry = locales->IsUndefined() ? "" : 110 EcmaStringAccessor(locales.GetTaggedValue()).ToStdString(); 111 if (cache) { 112 void *cachedCollator = ecmaVm->GetIcuFormatterFromCache(icuType, cacheEntry); 113 if (cachedCollator != nullptr) { 114 return reinterpret_cast<T *>(cachedCollator); 115 } 116 } 117 std::unique_ptr<T> tObject = GetGlobalObject<T>(thread, locales, options, types); 118 if (cache) { 119 T *cacheObject = tObject.release(); 120 switch (icuType) { 121 case IcuFormatterType::COLLATOR: 122 ecmaVm->SetIcuFormatterToCache(icuType, cacheEntry, cacheObject, FreeCollatorFormat); 123 break; 124 case IcuFormatterType::SIMPLE_DATE_FORMAT_DATE: 125 case IcuFormatterType::SIMPLE_DATE_FORMAT_TIME: 126 case IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT: 127 ecmaVm->SetIcuFormatterToCache(icuType, cacheEntry, cacheObject, FreeDateTimeFormat); 128 break; 129 case IcuFormatterType::NUMBER_FORMATTER: 130 ecmaVm->SetIcuFormatterToCache(icuType, cacheEntry, cacheObject, FreeNumberFormat); 131 break; 132 } 133 return cacheObject; 134 } 135 globalObject = tObject.release(); 136 return reinterpret_cast<T *>(globalObject); 137 } FreeCollatorFormat(void * pointer,void * data)138 static void FreeCollatorFormat(void *pointer, void *data) 139 { 140 if (pointer == nullptr) { 141 return; 142 } 143 auto globalCollator = reinterpret_cast<GlobalCollator*>(pointer); 144 globalCollator->~Collator(); 145 if (data != nullptr) { 146 reinterpret_cast<EcmaVM *>(data)->GetNativeAreaAllocator()->FreeBuffer(pointer); 147 } 148 } FreeNumberFormat(void * pointer,void * data)149 static void FreeNumberFormat(void *pointer, void *data) 150 { 151 if (pointer == nullptr) { 152 return; 153 } 154 auto globalNumberFormat = reinterpret_cast<GlobalNumberFormat*>(pointer); 155 globalNumberFormat->~NumberFormat(); 156 if (data != nullptr) { 157 reinterpret_cast<EcmaVM *>(data)->GetNativeAreaAllocator()->FreeBuffer(pointer); 158 } 159 } FreeDateTimeFormat(void * pointer,void * data)160 static void FreeDateTimeFormat(void *pointer, void *data) 161 { 162 if (pointer == nullptr) { 163 return; 164 } 165 auto globalDateFormatter = reinterpret_cast<GlobalDateFormatter*>(pointer); 166 globalDateFormatter->~DateTimeFormat(); 167 if (data != nullptr) { 168 reinterpret_cast<EcmaVM *>(data)->GetNativeAreaAllocator()->FreeBuffer(pointer); 169 } 170 } 171 std::vector<std::string> LocalesToVector(JSThread *thread, const JSHandle<JSTaggedValue> &locales); 172 std::map<std::string, std::string> OptionsToMap(JSThread *thread, 173 const JSHandle<JSTaggedValue> &options, GlobalFormatterType types); 174 uint64_t *ConvertDateToUnit(uint64_t timestamp); 175 static int64_t DoubleToInt64(double value); 176 private: 177 void *globalObject = nullptr; 178 uint64_t *dateUnitArr = nullptr; 179 void InitCollatorData(const GlobalEnvConstants *globalConst); 180 void InitNumberData(const GlobalEnvConstants *globalConst); 181 void InitDateData(const GlobalEnvConstants *globalConst); 182 std::map<std::string, std::string> OptionsWithDataFormatter(std::map<std::string, 183 std::string> &options, GlobalFormatterType &types); 184 std::map<GlobalFormatterType, std::map<std::string, JSHandle<JSTaggedValue>>> optionMaps; 185 std::string EcmaConvertToStr(const JSHandle<EcmaString> &string); 186 std::vector<std::string> TaggedArrayToVector(JSThread *thread, JSHandle<TaggedArray> &taggedarray); 187 }; 188 } // panda::ecmascript::base 189 #endif // ECMASCRIPT_BASE_GLOBAL_INTL_HELPER_H