• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "ecmascript/mem/c_string.h"
17 
18 #include "ecmascript/base/dtoa_helper.h"
19 #include "ecmascript/base/number_helper.h"
20 #include "ecmascript/base/json_helper.h"
21 #include "ecmascript/ecma_string-inl.h"
22 #include "ecmascript/js_symbol.h"
23 
24 namespace panda::ecmascript {
CStringToL(const CString & str)25 long CStringToL(const CString &str)
26 {
27     char *endPtr = nullptr;
28     int64_t result = std::strtol(str.c_str(), &endPtr, DEC_BASE);
29     ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not long int");
30     return result;
31 }
32 
CStringToLL(const CString & str)33 int64_t CStringToLL(const CString &str)
34 {
35     char *endPtr = nullptr;
36     int64_t result = std::strtoll(str.c_str(), &endPtr, DEC_BASE);
37     ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not long long int");
38     return result;
39 }
40 
CStringToULL(const CString & str)41 uint64_t CStringToULL(const CString &str)
42 {
43     char *endPtr = nullptr;
44     uint64_t result = std::strtoull(str.c_str(), &endPtr, DEC_BASE);
45     ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not unsigned long long int");
46     return result;
47 }
48 
CStringToF(const CString & str)49 float CStringToF(const CString &str)
50 {
51     char *endPtr = nullptr;
52     float result = std::strtof(str.c_str(), &endPtr);
53     ASSERT(result != HUGE_VALF && "CString argument is not float");
54     ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not float");
55     return result;
56 }
57 
CStringToD(const CString & str)58 double CStringToD(const CString &str)
59 {
60     char *endPtr = nullptr;
61     double result = std::strtod(str.c_str(), &endPtr);
62     ASSERT(result != HUGE_VALF && "CString argument is not double");
63     ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not double");
64     return result;
65 }
66 
67 template<class T>
ConvertToString(T sp)68 CString ConvertToString(T sp)
69 {
70     CString res;
71     res.reserve(sp.size());
72 
73     // Also support ascii that great than 127, so using unsigned char here
74     constexpr size_t maxChar = std::numeric_limits<unsigned char>::max();
75 
76     for (const auto &c : sp) {
77         if (c > maxChar) {
78             return "";
79         }
80         res.push_back(c);
81     }
82 
83     return res;
84 }
85 
ConvertToString(const JSThread * thread,JSTaggedValue key)86 CString ConvertToString(const JSThread *thread, JSTaggedValue key)
87 {
88     ASSERT(key.IsStringOrSymbol());
89     if (key.IsString()) {
90         return ConvertToString(thread, EcmaString::ConstCast(key.GetTaggedObject()));
91     }
92 
93     ecmascript::JSTaggedValue desc = JSSymbol::Cast(key.GetTaggedObject())->GetDescription(thread);
94     if (desc.IsUndefined()) {
95         return CString("Symbol()");
96     }
97 
98     return ConvertToString(thread, EcmaString::ConstCast(desc.GetTaggedObject()));
99 }
100 
101 // NB! the following function need additional mem allocation, don't use when unnecessary!
ConvertToString(const std::string & str)102 CString ConvertToString(const std::string &str)
103 {
104     CString res;
105     res.reserve(str.size());
106     for (auto c : str) {
107         res.push_back(c);
108     }
109     return res;
110 }
111 
ConvertToString(const JSThread * thread,const EcmaString * s,StringConvertedUsage usage,bool cesu8)112 CString ConvertToString(const JSThread *thread, const EcmaString *s, StringConvertedUsage usage, bool cesu8)
113 {
114     if (s == nullptr) {
115         return CString("");
116     }
117     return EcmaStringAccessor(const_cast<EcmaString *>(s)).ToCString(thread, usage, cesu8);
118 }
119 
ConvertToStdString(const CString & str)120 std::string ConvertToStdString(const CString &str)
121 {
122     std::string res;
123     res.reserve(str.size());
124     for (auto c : str) {
125         res.push_back(c);
126     }
127     return res;
128 }
129 
130 #if ENABLE_NEXT_OPTIMIZATION
131 template <typename DstType>
AppendIntToCString(DstType & str,int number)132 void AppendIntToCString(DstType &str, int number)
133 {
134     using CharT = typename DstType::value_type;
135     int64_t n = static_cast<int64_t>(number);
136     uint32_t preSize = str.size();
137     bool isNeg = true;
138     if (n >= 0) {
139         n = -n;
140         isNeg = false;
141     }
142     do {
143         str.push_back(static_cast<CharT>('0' - (n % DEC_BASE)));
144         n /= DEC_BASE;
145     } while (n);
146     if (isNeg) {
147         str.push_back(static_cast<CharT>('-'));
148     }
149     std::reverse(str.begin() + preSize, str.end());
150 }
151 
152 template void AppendIntToCString<CString>(CString &str, int number);
153 template void AppendIntToCString<C16String>(C16String &str, int number);
154 
155 template <typename DstType>
AppendSpecialDouble(DstType & str,double d)156 bool AppendSpecialDouble(DstType &str, double d)
157 {
158     if (d == 0.0) {
159         AppendCString(str, base::NumberHelper::ZERO_STR);
160         return true;
161     }
162     if (std::isnan(d)) {
163         AppendCString(str, base::NumberHelper::NAN_STR);
164         return true;
165     }
166     if (std::isinf(d)) {
167         AppendCString(str, d < 0 ? base::NumberHelper::MINUS_INFINITY_STR : base::NumberHelper::INFINITY_STR);
168         return true;
169     }
170     return false;
171 }
172 template bool AppendSpecialDouble<CString>(CString &str, double d);
173 template bool AppendSpecialDouble<C16String>(C16String &str, double d);
174 
175 template <typename DstType>
AppendDoubleToString(DstType & str,double d)176 void AppendDoubleToString(DstType &str, double d)
177 {
178     if (AppendSpecialDouble(str, d)) {
179         return;
180     }
181     bool isNeg = d < 0;
182     if (isNeg) {
183         d = -d;
184     }
185     ASSERT(d > 0);
186     constexpr int startIdx = 8; // when (isNeg and n = -5), result moves left for 8times
187     char buff[base::JS_DTOA_BUF_SIZE] = {0};
188     char *result = buff + startIdx;
189     ASSERT(startIdx < base::JS_DTOA_BUF_SIZE);
190     int n = 0;
191     int k = 0;
192     int len = 0;
193     base::DtoaHelper::Dtoa(d, result, &n, &k);
194     if (n > 0 && n <= base::MAX_DIGITS) {
195         if (k <= n) {
196             std::fill(result + k, result + n, '0');
197             len = n;
198         } else {
199             --result;
200             std::copy(result + 1, result + 1 + n, result);
201             result[n] = '.';
202             len = k + 1;
203         }
204     } else if (base::MIN_DIGITS < n && n <= 0) {
205         constexpr int prefixLen = 2;
206         result -= (-n + prefixLen);
207         ASSERT(result >= buff);
208         ASSERT(result + prefixLen - n <= buff + base::JS_DTOA_BUF_SIZE);
209         result[0] = '0';
210         result[1] = '.';
211         std::fill(result + prefixLen, result + prefixLen - n, '0');
212         len = -n + prefixLen + k;
213     } else {
214         int pos = k;
215         if (k != 1) {
216             --result;
217             result[0] = result[1];
218             result[1] = '.';
219             ++pos;
220         }
221         result[pos++] = 'e';
222         if (n >= 1) {
223             result[pos++] = '+';
224         }
225         auto expo = std::to_string(n - 1);
226         for (size_t i = 0; i < expo.length(); ++i) {
227             result[pos++] = expo[i];
228         }
229         len = pos;
230     }
231     if (isNeg) {
232         --result;
233         result[0] = '-';
234         len += 1;
235     }
236     AppendString(str, result, len);
237 }
238 template void AppendDoubleToString<CString>(CString &str, double d);
239 template void AppendDoubleToString<C16String>(C16String &str, double d);
240 
241 template <typename DstType>
ConvertNumberToCStringAndAppend(DstType & str,JSTaggedValue num)242 void ConvertNumberToCStringAndAppend(DstType &str, JSTaggedValue num)
243 {
244     ASSERT(num.IsNumber());
245     if (num.IsInt()) {
246         int intVal = num.GetInt();
247         AppendIntToCString(str, intVal);
248     } else {
249         double d = num.GetDouble();
250         AppendDoubleToString(str, d);
251     }
252 }
253 template void ConvertNumberToCStringAndAppend<CString>(CString &str, JSTaggedValue num);
254 template void ConvertNumberToCStringAndAppend<C16String>(C16String &str, JSTaggedValue num);
255 
ConvertQuotedAndAppendToCString(const JSThread * thread,CString & str,const EcmaString * s)256 void ConvertQuotedAndAppendToCString(const JSThread *thread, CString &str, const EcmaString *s)
257 {
258     ASSERT(s != nullptr);
259 
260     uint32_t strLen = EcmaStringAccessor(const_cast<EcmaString *>(s)).GetLength();
261     CVector<uint8_t> buf;
262     const uint8_t *data = EcmaStringAccessor::GetUtf8DataFlat(thread, s, buf);
263     const Span<const uint8_t> dataSpan(data, strLen);
264     base::JsonHelper::AppendValueToQuotedString(dataSpan, str);
265 }
266 
ConvertQuotedAndAppendToC16String(const JSThread * thread,C16String & str,const EcmaString * s)267 void ConvertQuotedAndAppendToC16String(const JSThread *thread, C16String &str, const EcmaString *s)
268 {
269     ASSERT(s != nullptr);
270 
271     uint32_t strLen = EcmaStringAccessor(const_cast<EcmaString *>(s)).GetLength();
272     if (EcmaStringAccessor(const_cast<EcmaString *>(s)).IsUtf8()) {
273         CVector<uint8_t> buf;
274         const uint8_t *data = EcmaStringAccessor::GetUtf8DataFlat(thread, s, buf);
275         const Span<const uint8_t> dataSpan(data, strLen);
276         base::JsonHelper::AppendValueToQuotedString(dataSpan, str);
277     } else {
278         CVector<uint16_t> buf;
279         const uint16_t *data = EcmaStringAccessor::GetUtf16DataFlat(thread, s, buf);
280         const Span<const uint16_t> dataSpan(data, strLen);
281         base::JsonHelper::AppendValueToQuotedString(dataSpan, str);
282     }
283 }
284 #endif
285 
286 }  // namespace panda::ecmascript
287