/src/icu/source/i18n/double-conversion-string-to-double.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // © 2018 and later: Unicode, Inc. and others. |
2 | | // License & terms of use: http://www.unicode.org/copyright.html |
3 | | // |
4 | | // From the double-conversion library. Original license: |
5 | | // |
6 | | // Copyright 2010 the V8 project authors. All rights reserved. |
7 | | // Redistribution and use in source and binary forms, with or without |
8 | | // modification, are permitted provided that the following conditions are |
9 | | // met: |
10 | | // |
11 | | // * Redistributions of source code must retain the above copyright |
12 | | // notice, this list of conditions and the following disclaimer. |
13 | | // * Redistributions in binary form must reproduce the above |
14 | | // copyright notice, this list of conditions and the following |
15 | | // disclaimer in the documentation and/or other materials provided |
16 | | // with the distribution. |
17 | | // * Neither the name of Google Inc. nor the names of its |
18 | | // contributors may be used to endorse or promote products derived |
19 | | // from this software without specific prior written permission. |
20 | | // |
21 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
24 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
25 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
26 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
27 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
28 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
29 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
30 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
31 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | | |
33 | | // ICU PATCH: ifdef around UCONFIG_NO_FORMATTING |
34 | | #include "unicode/utypes.h" |
35 | | #if !UCONFIG_NO_FORMATTING |
36 | | |
37 | | // ICU PATCH: Do not include std::locale. |
38 | | |
39 | | #include <climits> |
40 | | // #include <locale> |
41 | | #include <cmath> |
42 | | |
43 | | // ICU PATCH: Customize header file paths for ICU. |
44 | | |
45 | | #include "double-conversion-string-to-double.h" |
46 | | |
47 | | #include "double-conversion-ieee.h" |
48 | | #include "double-conversion-strtod.h" |
49 | | #include "double-conversion-utils.h" |
50 | | |
51 | | // ICU PATCH: Wrap in ICU namespace |
52 | | U_NAMESPACE_BEGIN |
53 | | |
54 | | #ifdef _MSC_VER |
55 | | # if _MSC_VER >= 1900 |
56 | | // Fix MSVC >= 2015 (_MSC_VER == 1900) warning |
57 | | // C4244: 'argument': conversion from 'const uc16' to 'char', possible loss of data |
58 | | // against Advance and friends, when instantiated with **it as char, not uc16. |
59 | | __pragma(warning(disable: 4244)) |
60 | | # endif |
61 | | # if _MSC_VER <= 1700 // VS2012, see IsDecimalDigitForRadix warning fix, below |
62 | | # define VS2012_RADIXWARN |
63 | | # endif |
64 | | #endif |
65 | | |
66 | | namespace double_conversion { |
67 | | |
68 | | namespace { |
69 | | |
70 | 0 | inline char ToLower(char ch) { |
71 | | #if 0 // do not include std::locale in ICU |
72 | | static const std::ctype<char>& cType = |
73 | | std::use_facet<std::ctype<char> >(std::locale::classic()); |
74 | | return cType.tolower(ch); |
75 | | #else |
76 | 0 | (void)ch; |
77 | 0 | DOUBLE_CONVERSION_UNREACHABLE(); |
78 | 0 | #endif |
79 | 0 | } |
80 | | |
81 | 0 | inline char Pass(char ch) { |
82 | 0 | return ch; |
83 | 0 | } |
84 | | |
85 | | template <class Iterator, class Converter> |
86 | | static inline bool ConsumeSubStringImpl(Iterator* current, |
87 | | Iterator end, |
88 | | const char* substring, |
89 | 0 | Converter converter) { |
90 | 0 | DOUBLE_CONVERSION_ASSERT(converter(**current) == *substring); |
91 | 0 | for (substring++; *substring != '\0'; substring++) { |
92 | 0 | ++*current; |
93 | 0 | if (*current == end || converter(**current) != *substring) { |
94 | 0 | return false; |
95 | 0 | } |
96 | 0 | } |
97 | 0 | ++*current; |
98 | 0 | return true; |
99 | 0 | } Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::(anonymous namespace)::ConsumeSubStringImpl<char const*, char (*)(char)>(char const**, char const*, char const*, char (*)(char)) Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::(anonymous namespace)::ConsumeSubStringImpl<unsigned short const*, char (*)(char)>(unsigned short const**, unsigned short const*, char const*, char (*)(char)) |
100 | | |
101 | | // Consumes the given substring from the iterator. |
102 | | // Returns false, if the substring does not match. |
103 | | template <class Iterator> |
104 | | static bool ConsumeSubString(Iterator* current, |
105 | | Iterator end, |
106 | | const char* substring, |
107 | 0 | bool allow_case_insensitivity) { |
108 | 0 | if (allow_case_insensitivity) { |
109 | 0 | return ConsumeSubStringImpl(current, end, substring, ToLower); |
110 | 0 | } else { |
111 | 0 | return ConsumeSubStringImpl(current, end, substring, Pass); |
112 | 0 | } |
113 | 0 | } Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::(anonymous namespace)::ConsumeSubString<char const*>(char const**, char const*, char const*, bool) Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::(anonymous namespace)::ConsumeSubString<unsigned short const*>(unsigned short const**, unsigned short const*, char const*, bool) |
114 | | |
115 | | // Consumes first character of the str is equal to ch |
116 | | inline bool ConsumeFirstCharacter(char ch, |
117 | | const char* str, |
118 | 0 | bool case_insensitivity) { |
119 | 0 | return case_insensitivity ? ToLower(ch) == str[0] : ch == str[0]; |
120 | 0 | } |
121 | | } // namespace |
122 | | |
123 | | // Maximum number of significant digits in decimal representation. |
124 | | // The longest possible double in decimal representation is |
125 | | // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074 |
126 | | // (768 digits). If we parse a number whose first digits are equal to a |
127 | | // mean of 2 adjacent doubles (that could have up to 769 digits) the result |
128 | | // must be rounded to the bigger one unless the tail consists of zeros, so |
129 | | // we don't need to preserve all the digits. |
130 | | const int kMaxSignificantDigits = 772; |
131 | | |
132 | | |
133 | | static const char kWhitespaceTable7[] = { 32, 13, 10, 9, 11, 12 }; |
134 | | static const int kWhitespaceTable7Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespaceTable7); |
135 | | |
136 | | |
137 | | static const uc16 kWhitespaceTable16[] = { |
138 | | 160, 8232, 8233, 5760, 6158, 8192, 8193, 8194, 8195, |
139 | | 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 65279 |
140 | | }; |
141 | | static const int kWhitespaceTable16Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespaceTable16); |
142 | | |
143 | | |
144 | 0 | static bool isWhitespace(int x) { |
145 | 0 | if (x < 128) { |
146 | 0 | for (int i = 0; i < kWhitespaceTable7Length; i++) { |
147 | 0 | if (kWhitespaceTable7[i] == x) return true; |
148 | 0 | } |
149 | 0 | } else { |
150 | 0 | for (int i = 0; i < kWhitespaceTable16Length; i++) { |
151 | 0 | if (kWhitespaceTable16[i] == x) return true; |
152 | 0 | } |
153 | 0 | } |
154 | 0 | return false; |
155 | 0 | } |
156 | | |
157 | | |
158 | | // Returns true if a nonspace found and false if the end has reached. |
159 | | template <class Iterator> |
160 | 0 | static inline bool AdvanceToNonspace(Iterator* current, Iterator end) { |
161 | 0 | while (*current != end) { |
162 | 0 | if (!isWhitespace(**current)) return true; |
163 | 0 | ++*current; |
164 | 0 | } |
165 | 0 | return false; |
166 | 0 | } Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::AdvanceToNonspace<char const*>(char const**, char const*) Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::AdvanceToNonspace<char*>(char**, char*) Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::AdvanceToNonspace<unsigned short const*>(unsigned short const**, unsigned short const*) |
167 | | |
168 | | |
169 | 0 | static bool isDigit(int x, int radix) { |
170 | 0 | return (x >= '0' && x <= '9' && x < '0' + radix) |
171 | 0 | || (radix > 10 && x >= 'a' && x < 'a' + radix - 10) |
172 | 0 | || (radix > 10 && x >= 'A' && x < 'A' + radix - 10); |
173 | 0 | } |
174 | | |
175 | | |
176 | 0 | static double SignedZero(bool sign) { |
177 | 0 | return sign ? -0.0 : 0.0; |
178 | 0 | } |
179 | | |
180 | | |
181 | | // Returns true if 'c' is a decimal digit that is valid for the given radix. |
182 | | // |
183 | | // The function is small and could be inlined, but VS2012 emitted a warning |
184 | | // because it constant-propagated the radix and concluded that the last |
185 | | // condition was always true. Moving it into a separate function and |
186 | | // suppressing optimisation keeps the compiler from warning. |
187 | | #ifdef VS2012_RADIXWARN |
188 | | #pragma optimize("",off) |
189 | | static bool IsDecimalDigitForRadix(int c, int radix) { |
190 | | return '0' <= c && c <= '9' && (c - '0') < radix; |
191 | | } |
192 | | #pragma optimize("",on) |
193 | | #else |
194 | 0 | static bool inline IsDecimalDigitForRadix(int c, int radix) { |
195 | 0 | return '0' <= c && c <= '9' && (c - '0') < radix; |
196 | 0 | } |
197 | | #endif |
198 | | // Returns true if 'c' is a character digit that is valid for the given radix. |
199 | | // The 'a_character' should be 'a' or 'A'. |
200 | | // |
201 | | // The function is small and could be inlined, but VS2012 emitted a warning |
202 | | // because it constant-propagated the radix and concluded that the first |
203 | | // condition was always false. By moving it into a separate function the |
204 | | // compiler wouldn't warn anymore. |
205 | 0 | static bool IsCharacterDigitForRadix(int c, int radix, char a_character) { |
206 | 0 | return radix > 10 && c >= a_character && c < a_character + radix - 10; |
207 | 0 | } |
208 | | |
209 | | // Returns true, when the iterator is equal to end. |
210 | | template<class Iterator> |
211 | 0 | static bool Advance (Iterator* it, uc16 separator, int base, Iterator& end) { |
212 | 0 | if (separator == StringToDoubleConverter::kNoSeparator) { |
213 | 0 | ++(*it); |
214 | 0 | return *it == end; |
215 | 0 | } |
216 | 0 | if (!isDigit(**it, base)) { |
217 | 0 | ++(*it); |
218 | 0 | return *it == end; |
219 | 0 | } |
220 | 0 | ++(*it); |
221 | 0 | if (*it == end) return true; |
222 | 0 | if (*it + 1 == end) return false; |
223 | 0 | if (**it == separator && isDigit(*(*it + 1), base)) { |
224 | 0 | ++(*it); |
225 | 0 | } |
226 | 0 | return *it == end; |
227 | 0 | } Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::Advance<char const*>(char const**, unsigned short, int, char const*&) Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::Advance<char*>(char**, unsigned short, int, char*&) Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::Advance<unsigned short const*>(unsigned short const**, unsigned short, int, unsigned short const*&) |
228 | | |
229 | | // Checks whether the string in the range start-end is a hex-float string. |
230 | | // This function assumes that the leading '0x'/'0X' is already consumed. |
231 | | // |
232 | | // Hex float strings are of one of the following forms: |
233 | | // - hex_digits+ 'p' ('+'|'-')? exponent_digits+ |
234 | | // - hex_digits* '.' hex_digits+ 'p' ('+'|'-')? exponent_digits+ |
235 | | // - hex_digits+ '.' 'p' ('+'|'-')? exponent_digits+ |
236 | | template<class Iterator> |
237 | | static bool IsHexFloatString(Iterator start, |
238 | | Iterator end, |
239 | | uc16 separator, |
240 | 0 | bool allow_trailing_junk) { |
241 | 0 | DOUBLE_CONVERSION_ASSERT(start != end); |
242 | |
|
243 | 0 | Iterator current = start; |
244 | |
|
245 | 0 | bool saw_digit = false; |
246 | 0 | while (isDigit(*current, 16)) { |
247 | 0 | saw_digit = true; |
248 | 0 | if (Advance(¤t, separator, 16, end)) return false; |
249 | 0 | } |
250 | 0 | if (*current == '.') { |
251 | 0 | if (Advance(¤t, separator, 16, end)) return false; |
252 | 0 | while (isDigit(*current, 16)) { |
253 | 0 | saw_digit = true; |
254 | 0 | if (Advance(¤t, separator, 16, end)) return false; |
255 | 0 | } |
256 | 0 | } |
257 | 0 | if (!saw_digit) return false; |
258 | 0 | if (*current != 'p' && *current != 'P') return false; |
259 | 0 | if (Advance(¤t, separator, 16, end)) return false; |
260 | 0 | if (*current == '+' || *current == '-') { |
261 | 0 | if (Advance(¤t, separator, 16, end)) return false; |
262 | 0 | } |
263 | 0 | if (!isDigit(*current, 10)) return false; |
264 | 0 | if (Advance(¤t, separator, 16, end)) return true; |
265 | 0 | while (isDigit(*current, 10)) { |
266 | 0 | if (Advance(¤t, separator, 16, end)) return true; |
267 | 0 | } |
268 | 0 | return allow_trailing_junk || !AdvanceToNonspace(¤t, end); |
269 | 0 | } Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::IsHexFloatString<char const*>(char const*, char const*, unsigned short, bool) Unexecuted instantiation: double-conversion-string-to-double.cpp:bool icu_70::double_conversion::IsHexFloatString<unsigned short const*>(unsigned short const*, unsigned short const*, unsigned short, bool) |
270 | | |
271 | | |
272 | | // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end. |
273 | | // |
274 | | // If parse_as_hex_float is true, then the string must be a valid |
275 | | // hex-float. |
276 | | template <int radix_log_2, class Iterator> |
277 | | static double RadixStringToIeee(Iterator* current, |
278 | | Iterator end, |
279 | | bool sign, |
280 | | uc16 separator, |
281 | | bool parse_as_hex_float, |
282 | | bool allow_trailing_junk, |
283 | | double junk_string_value, |
284 | | bool read_as_double, |
285 | 0 | bool* result_is_junk) { |
286 | 0 | DOUBLE_CONVERSION_ASSERT(*current != end); |
287 | 0 | DOUBLE_CONVERSION_ASSERT(!parse_as_hex_float || |
288 | 0 | IsHexFloatString(*current, end, separator, allow_trailing_junk)); |
289 | |
|
290 | 0 | const int kDoubleSize = Double::kSignificandSize; |
291 | 0 | const int kSingleSize = Single::kSignificandSize; |
292 | 0 | const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize; |
293 | |
|
294 | 0 | *result_is_junk = true; |
295 | |
|
296 | 0 | int64_t number = 0; |
297 | 0 | int exponent = 0; |
298 | 0 | const int radix = (1 << radix_log_2); |
299 | | // Whether we have encountered a '.' and are parsing the decimal digits. |
300 | | // Only relevant if parse_as_hex_float is true. |
301 | 0 | bool post_decimal = false; |
302 | | |
303 | | // Skip leading 0s. |
304 | 0 | while (**current == '0') { |
305 | 0 | if (Advance(current, separator, radix, end)) { |
306 | 0 | *result_is_junk = false; |
307 | 0 | return SignedZero(sign); |
308 | 0 | } |
309 | 0 | } |
310 | | |
311 | 0 | while (true) { |
312 | 0 | int digit; |
313 | 0 | if (IsDecimalDigitForRadix(**current, radix)) { |
314 | 0 | digit = static_cast<char>(**current) - '0'; |
315 | 0 | if (post_decimal) exponent -= radix_log_2; |
316 | 0 | } else if (IsCharacterDigitForRadix(**current, radix, 'a')) { |
317 | 0 | digit = static_cast<char>(**current) - 'a' + 10; |
318 | 0 | if (post_decimal) exponent -= radix_log_2; |
319 | 0 | } else if (IsCharacterDigitForRadix(**current, radix, 'A')) { |
320 | 0 | digit = static_cast<char>(**current) - 'A' + 10; |
321 | 0 | if (post_decimal) exponent -= radix_log_2; |
322 | 0 | } else if (parse_as_hex_float && **current == '.') { |
323 | 0 | post_decimal = true; |
324 | 0 | Advance(current, separator, radix, end); |
325 | 0 | DOUBLE_CONVERSION_ASSERT(*current != end); |
326 | 0 | continue; |
327 | 0 | } else if (parse_as_hex_float && (**current == 'p' || **current == 'P')) { |
328 | 0 | break; |
329 | 0 | } else { |
330 | 0 | if (allow_trailing_junk || !AdvanceToNonspace(current, end)) { |
331 | 0 | break; |
332 | 0 | } else { |
333 | 0 | return junk_string_value; |
334 | 0 | } |
335 | 0 | } |
336 | | |
337 | 0 | number = number * radix + digit; |
338 | 0 | int overflow = static_cast<int>(number >> kSignificandSize); |
339 | 0 | if (overflow != 0) { |
340 | | // Overflow occurred. Need to determine which direction to round the |
341 | | // result. |
342 | 0 | int overflow_bits_count = 1; |
343 | 0 | while (overflow > 1) { |
344 | 0 | overflow_bits_count++; |
345 | 0 | overflow >>= 1; |
346 | 0 | } |
347 | |
|
348 | 0 | int dropped_bits_mask = ((1 << overflow_bits_count) - 1); |
349 | 0 | int dropped_bits = static_cast<int>(number) & dropped_bits_mask; |
350 | 0 | number >>= overflow_bits_count; |
351 | 0 | exponent += overflow_bits_count; |
352 | |
|
353 | 0 | bool zero_tail = true; |
354 | 0 | for (;;) { |
355 | 0 | if (Advance(current, separator, radix, end)) break; |
356 | 0 | if (parse_as_hex_float && **current == '.') { |
357 | | // Just run over the '.'. We are just trying to see whether there is |
358 | | // a non-zero digit somewhere. |
359 | 0 | Advance(current, separator, radix, end); |
360 | 0 | DOUBLE_CONVERSION_ASSERT(*current != end); |
361 | 0 | post_decimal = true; |
362 | 0 | } |
363 | 0 | if (!isDigit(**current, radix)) break; |
364 | 0 | zero_tail = zero_tail && **current == '0'; |
365 | 0 | if (!post_decimal) exponent += radix_log_2; |
366 | 0 | } |
367 | |
|
368 | 0 | if (!parse_as_hex_float && |
369 | 0 | !allow_trailing_junk && |
370 | 0 | AdvanceToNonspace(current, end)) { |
371 | 0 | return junk_string_value; |
372 | 0 | } |
373 | | |
374 | 0 | int middle_value = (1 << (overflow_bits_count - 1)); |
375 | 0 | if (dropped_bits > middle_value) { |
376 | 0 | number++; // Rounding up. |
377 | 0 | } else if (dropped_bits == middle_value) { |
378 | | // Rounding to even to consistency with decimals: half-way case rounds |
379 | | // up if significant part is odd and down otherwise. |
380 | 0 | if ((number & 1) != 0 || !zero_tail) { |
381 | 0 | number++; // Rounding up. |
382 | 0 | } |
383 | 0 | } |
384 | | |
385 | | // Rounding up may cause overflow. |
386 | 0 | if ((number & ((int64_t)1 << kSignificandSize)) != 0) { |
387 | 0 | exponent++; |
388 | 0 | number >>= 1; |
389 | 0 | } |
390 | 0 | break; |
391 | 0 | } |
392 | 0 | if (Advance(current, separator, radix, end)) break; |
393 | 0 | } |
394 | | |
395 | 0 | DOUBLE_CONVERSION_ASSERT(number < ((int64_t)1 << kSignificandSize)); |
396 | 0 | DOUBLE_CONVERSION_ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number); |
397 | |
|
398 | 0 | *result_is_junk = false; |
399 | |
|
400 | 0 | if (parse_as_hex_float) { |
401 | 0 | DOUBLE_CONVERSION_ASSERT(**current == 'p' || **current == 'P'); |
402 | 0 | Advance(current, separator, radix, end); |
403 | 0 | DOUBLE_CONVERSION_ASSERT(*current != end); |
404 | 0 | bool is_negative = false; |
405 | 0 | if (**current == '+') { |
406 | 0 | Advance(current, separator, radix, end); |
407 | 0 | DOUBLE_CONVERSION_ASSERT(*current != end); |
408 | 0 | } else if (**current == '-') { |
409 | 0 | is_negative = true; |
410 | 0 | Advance(current, separator, radix, end); |
411 | 0 | DOUBLE_CONVERSION_ASSERT(*current != end); |
412 | 0 | } |
413 | 0 | int written_exponent = 0; |
414 | 0 | while (IsDecimalDigitForRadix(**current, 10)) { |
415 | | // No need to read exponents if they are too big. That could potentially overflow |
416 | | // the `written_exponent` variable. |
417 | 0 | if (abs(written_exponent) <= 100 * Double::kMaxExponent) { |
418 | 0 | written_exponent = 10 * written_exponent + **current - '0'; |
419 | 0 | } |
420 | 0 | if (Advance(current, separator, radix, end)) break; |
421 | 0 | } |
422 | 0 | if (is_negative) written_exponent = -written_exponent; |
423 | 0 | exponent += written_exponent; |
424 | 0 | } |
425 | |
|
426 | 0 | if (exponent == 0 || number == 0) { |
427 | 0 | if (sign) { |
428 | 0 | if (number == 0) return -0.0; |
429 | 0 | number = -number; |
430 | 0 | } |
431 | 0 | return static_cast<double>(number); |
432 | 0 | } |
433 | | |
434 | 0 | DOUBLE_CONVERSION_ASSERT(number != 0); |
435 | 0 | double result = Double(DiyFp(number, exponent)).value(); |
436 | 0 | return sign ? -result : result; |
437 | 0 | } Unexecuted instantiation: double-conversion-string-to-double.cpp:double icu_70::double_conversion::RadixStringToIeee<4, char const*>(char const**, char const*, bool, unsigned short, bool, bool, double, bool, bool*) Unexecuted instantiation: double-conversion-string-to-double.cpp:double icu_70::double_conversion::RadixStringToIeee<3, char*>(char**, char*, bool, unsigned short, bool, bool, double, bool, bool*) Unexecuted instantiation: double-conversion-string-to-double.cpp:double icu_70::double_conversion::RadixStringToIeee<4, unsigned short const*>(unsigned short const**, unsigned short const*, bool, unsigned short, bool, bool, double, bool, bool*) |
438 | | |
439 | | template <class Iterator> |
440 | | double StringToDoubleConverter::StringToIeee( |
441 | | Iterator input, |
442 | | int length, |
443 | | bool read_as_double, |
444 | 0 | int* processed_characters_count) const { |
445 | 0 | Iterator current = input; |
446 | 0 | Iterator end = input + length; |
447 | |
|
448 | 0 | *processed_characters_count = 0; |
449 | |
|
450 | 0 | const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0; |
451 | 0 | const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0; |
452 | 0 | const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0; |
453 | 0 | const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0; |
454 | 0 | const bool allow_case_insensitivity = (flags_ & ALLOW_CASE_INSENSITIVITY) != 0; |
455 | | |
456 | | // To make sure that iterator dereferencing is valid the following |
457 | | // convention is used: |
458 | | // 1. Each '++current' statement is followed by check for equality to 'end'. |
459 | | // 2. If AdvanceToNonspace returned false then current == end. |
460 | | // 3. If 'current' becomes equal to 'end' the function returns or goes to |
461 | | // 'parsing_done'. |
462 | | // 4. 'current' is not dereferenced after the 'parsing_done' label. |
463 | | // 5. Code before 'parsing_done' may rely on 'current != end'. |
464 | 0 | if (current == end) return empty_string_value_; |
465 | | |
466 | 0 | if (allow_leading_spaces || allow_trailing_spaces) { |
467 | 0 | if (!AdvanceToNonspace(¤t, end)) { |
468 | 0 | *processed_characters_count = static_cast<int>(current - input); |
469 | 0 | return empty_string_value_; |
470 | 0 | } |
471 | 0 | if (!allow_leading_spaces && (input != current)) { |
472 | | // No leading spaces allowed, but AdvanceToNonspace moved forward. |
473 | 0 | return junk_string_value_; |
474 | 0 | } |
475 | 0 | } |
476 | | |
477 | | // Exponent will be adjusted if insignificant digits of the integer part |
478 | | // or insignificant leading zeros of the fractional part are dropped. |
479 | 0 | int exponent = 0; |
480 | 0 | int significant_digits = 0; |
481 | 0 | int insignificant_digits = 0; |
482 | 0 | bool nonzero_digit_dropped = false; |
483 | |
|
484 | 0 | bool sign = false; |
485 | |
|
486 | 0 | if (*current == '+' || *current == '-') { |
487 | 0 | sign = (*current == '-'); |
488 | 0 | ++current; |
489 | 0 | Iterator next_non_space = current; |
490 | | // Skip following spaces (if allowed). |
491 | 0 | if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_; |
492 | 0 | if (!allow_spaces_after_sign && (current != next_non_space)) { |
493 | 0 | return junk_string_value_; |
494 | 0 | } |
495 | 0 | current = next_non_space; |
496 | 0 | } |
497 | | |
498 | 0 | if (infinity_symbol_ != NULL) { |
499 | 0 | if (ConsumeFirstCharacter(*current, infinity_symbol_, allow_case_insensitivity)) { |
500 | 0 | if (!ConsumeSubString(¤t, end, infinity_symbol_, allow_case_insensitivity)) { |
501 | 0 | return junk_string_value_; |
502 | 0 | } |
503 | | |
504 | 0 | if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
505 | 0 | return junk_string_value_; |
506 | 0 | } |
507 | 0 | if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
508 | 0 | return junk_string_value_; |
509 | 0 | } |
510 | | |
511 | 0 | *processed_characters_count = static_cast<int>(current - input); |
512 | 0 | return sign ? -Double::Infinity() : Double::Infinity(); |
513 | 0 | } |
514 | 0 | } |
515 | | |
516 | 0 | if (nan_symbol_ != NULL) { |
517 | 0 | if (ConsumeFirstCharacter(*current, nan_symbol_, allow_case_insensitivity)) { |
518 | 0 | if (!ConsumeSubString(¤t, end, nan_symbol_, allow_case_insensitivity)) { |
519 | 0 | return junk_string_value_; |
520 | 0 | } |
521 | | |
522 | 0 | if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
523 | 0 | return junk_string_value_; |
524 | 0 | } |
525 | 0 | if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
526 | 0 | return junk_string_value_; |
527 | 0 | } |
528 | | |
529 | 0 | *processed_characters_count = static_cast<int>(current - input); |
530 | 0 | return sign ? -Double::NaN() : Double::NaN(); |
531 | 0 | } |
532 | 0 | } |
533 | | |
534 | 0 | bool leading_zero = false; |
535 | 0 | if (*current == '0') { |
536 | 0 | if (Advance(¤t, separator_, 10, end)) { |
537 | 0 | *processed_characters_count = static_cast<int>(current - input); |
538 | 0 | return SignedZero(sign); |
539 | 0 | } |
540 | | |
541 | 0 | leading_zero = true; |
542 | | |
543 | | // It could be hexadecimal value. |
544 | 0 | if (((flags_ & ALLOW_HEX) || (flags_ & ALLOW_HEX_FLOATS)) && |
545 | 0 | (*current == 'x' || *current == 'X')) { |
546 | 0 | ++current; |
547 | |
|
548 | 0 | if (current == end) return junk_string_value_; // "0x" |
549 | | |
550 | 0 | bool parse_as_hex_float = (flags_ & ALLOW_HEX_FLOATS) && |
551 | 0 | IsHexFloatString(current, end, separator_, allow_trailing_junk); |
552 | |
|
553 | 0 | if (!parse_as_hex_float && !isDigit(*current, 16)) { |
554 | 0 | return junk_string_value_; |
555 | 0 | } |
556 | | |
557 | 0 | bool result_is_junk; |
558 | 0 | double result = RadixStringToIeee<4>(¤t, |
559 | 0 | end, |
560 | 0 | sign, |
561 | 0 | separator_, |
562 | 0 | parse_as_hex_float, |
563 | 0 | allow_trailing_junk, |
564 | 0 | junk_string_value_, |
565 | 0 | read_as_double, |
566 | 0 | &result_is_junk); |
567 | 0 | if (!result_is_junk) { |
568 | 0 | if (allow_trailing_spaces) AdvanceToNonspace(¤t, end); |
569 | 0 | *processed_characters_count = static_cast<int>(current - input); |
570 | 0 | } |
571 | 0 | return result; |
572 | 0 | } |
573 | | |
574 | | // Ignore leading zeros in the integer part. |
575 | 0 | while (*current == '0') { |
576 | 0 | if (Advance(¤t, separator_, 10, end)) { |
577 | 0 | *processed_characters_count = static_cast<int>(current - input); |
578 | 0 | return SignedZero(sign); |
579 | 0 | } |
580 | 0 | } |
581 | 0 | } |
582 | | |
583 | 0 | bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0; |
584 | | |
585 | | // The longest form of simplified number is: "-<significant digits>.1eXXX\0". |
586 | 0 | const int kBufferSize = kMaxSignificantDigits + 10; |
587 | 0 | DOUBLE_CONVERSION_STACK_UNINITIALIZED char |
588 | 0 | buffer[kBufferSize]; // NOLINT: size is known at compile time. |
589 | 0 | int buffer_pos = 0; |
590 | | |
591 | | // Copy significant digits of the integer part (if any) to the buffer. |
592 | 0 | while (*current >= '0' && *current <= '9') { |
593 | 0 | if (significant_digits < kMaxSignificantDigits) { |
594 | 0 | DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize); |
595 | 0 | buffer[buffer_pos++] = static_cast<char>(*current); |
596 | 0 | significant_digits++; |
597 | | // Will later check if it's an octal in the buffer. |
598 | 0 | } else { |
599 | 0 | insignificant_digits++; // Move the digit into the exponential part. |
600 | 0 | nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; |
601 | 0 | } |
602 | 0 | octal = octal && *current < '8'; |
603 | 0 | if (Advance(¤t, separator_, 10, end)) goto parsing_done; |
604 | 0 | } |
605 | | |
606 | 0 | if (significant_digits == 0) { |
607 | 0 | octal = false; |
608 | 0 | } |
609 | |
|
610 | 0 | if (*current == '.') { |
611 | 0 | if (octal && !allow_trailing_junk) return junk_string_value_; |
612 | 0 | if (octal) goto parsing_done; |
613 | | |
614 | 0 | if (Advance(¤t, separator_, 10, end)) { |
615 | 0 | if (significant_digits == 0 && !leading_zero) { |
616 | 0 | return junk_string_value_; |
617 | 0 | } else { |
618 | 0 | goto parsing_done; |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | 0 | if (significant_digits == 0) { |
623 | | // octal = false; |
624 | | // Integer part consists of 0 or is absent. Significant digits start after |
625 | | // leading zeros (if any). |
626 | 0 | while (*current == '0') { |
627 | 0 | if (Advance(¤t, separator_, 10, end)) { |
628 | 0 | *processed_characters_count = static_cast<int>(current - input); |
629 | 0 | return SignedZero(sign); |
630 | 0 | } |
631 | 0 | exponent--; // Move this 0 into the exponent. |
632 | 0 | } |
633 | 0 | } |
634 | | |
635 | | // There is a fractional part. |
636 | | // We don't emit a '.', but adjust the exponent instead. |
637 | 0 | while (*current >= '0' && *current <= '9') { |
638 | 0 | if (significant_digits < kMaxSignificantDigits) { |
639 | 0 | DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize); |
640 | 0 | buffer[buffer_pos++] = static_cast<char>(*current); |
641 | 0 | significant_digits++; |
642 | 0 | exponent--; |
643 | 0 | } else { |
644 | | // Ignore insignificant digits in the fractional part. |
645 | 0 | nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; |
646 | 0 | } |
647 | 0 | if (Advance(¤t, separator_, 10, end)) goto parsing_done; |
648 | 0 | } |
649 | 0 | } |
650 | | |
651 | 0 | if (!leading_zero && exponent == 0 && significant_digits == 0) { |
652 | | // If leading_zeros is true then the string contains zeros. |
653 | | // If exponent < 0 then string was [+-]\.0*... |
654 | | // If significant_digits != 0 the string is not equal to 0. |
655 | | // Otherwise there are no digits in the string. |
656 | 0 | return junk_string_value_; |
657 | 0 | } |
658 | | |
659 | | // Parse exponential part. |
660 | 0 | if (*current == 'e' || *current == 'E') { |
661 | 0 | if (octal && !allow_trailing_junk) return junk_string_value_; |
662 | 0 | if (octal) goto parsing_done; |
663 | 0 | Iterator junk_begin = current; |
664 | 0 | ++current; |
665 | 0 | if (current == end) { |
666 | 0 | if (allow_trailing_junk) { |
667 | 0 | current = junk_begin; |
668 | 0 | goto parsing_done; |
669 | 0 | } else { |
670 | 0 | return junk_string_value_; |
671 | 0 | } |
672 | 0 | } |
673 | 0 | char exponen_sign = '+'; |
674 | 0 | if (*current == '+' || *current == '-') { |
675 | 0 | exponen_sign = static_cast<char>(*current); |
676 | 0 | ++current; |
677 | 0 | if (current == end) { |
678 | 0 | if (allow_trailing_junk) { |
679 | 0 | current = junk_begin; |
680 | 0 | goto parsing_done; |
681 | 0 | } else { |
682 | 0 | return junk_string_value_; |
683 | 0 | } |
684 | 0 | } |
685 | 0 | } |
686 | | |
687 | 0 | if (current == end || *current < '0' || *current > '9') { |
688 | 0 | if (allow_trailing_junk) { |
689 | 0 | current = junk_begin; |
690 | 0 | goto parsing_done; |
691 | 0 | } else { |
692 | 0 | return junk_string_value_; |
693 | 0 | } |
694 | 0 | } |
695 | | |
696 | 0 | const int max_exponent = INT_MAX / 2; |
697 | 0 | DOUBLE_CONVERSION_ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); |
698 | 0 | int num = 0; |
699 | 0 | do { |
700 | | // Check overflow. |
701 | 0 | int digit = *current - '0'; |
702 | 0 | if (num >= max_exponent / 10 |
703 | 0 | && !(num == max_exponent / 10 && digit <= max_exponent % 10)) { |
704 | 0 | num = max_exponent; |
705 | 0 | } else { |
706 | 0 | num = num * 10 + digit; |
707 | 0 | } |
708 | 0 | ++current; |
709 | 0 | } while (current != end && *current >= '0' && *current <= '9'); |
710 | |
|
711 | 0 | exponent += (exponen_sign == '-' ? -num : num); |
712 | 0 | } |
713 | | |
714 | 0 | if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
715 | 0 | return junk_string_value_; |
716 | 0 | } |
717 | 0 | if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
718 | 0 | return junk_string_value_; |
719 | 0 | } |
720 | 0 | if (allow_trailing_spaces) { |
721 | 0 | AdvanceToNonspace(¤t, end); |
722 | 0 | } |
723 | |
|
724 | 0 | parsing_done: |
725 | 0 | exponent += insignificant_digits; |
726 | |
|
727 | 0 | if (octal) { |
728 | 0 | double result; |
729 | 0 | bool result_is_junk; |
730 | 0 | char* start = buffer; |
731 | 0 | result = RadixStringToIeee<3>(&start, |
732 | 0 | buffer + buffer_pos, |
733 | 0 | sign, |
734 | 0 | separator_, |
735 | 0 | false, // Don't parse as hex_float. |
736 | 0 | allow_trailing_junk, |
737 | 0 | junk_string_value_, |
738 | 0 | read_as_double, |
739 | 0 | &result_is_junk); |
740 | 0 | DOUBLE_CONVERSION_ASSERT(!result_is_junk); |
741 | 0 | *processed_characters_count = static_cast<int>(current - input); |
742 | 0 | return result; |
743 | 0 | } |
744 | | |
745 | 0 | if (nonzero_digit_dropped) { |
746 | 0 | buffer[buffer_pos++] = '1'; |
747 | 0 | exponent--; |
748 | 0 | } |
749 | |
|
750 | 0 | DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize); |
751 | 0 | buffer[buffer_pos] = '\0'; |
752 | | |
753 | | // Code above ensures there are no leading zeros and the buffer has fewer than |
754 | | // kMaxSignificantDecimalDigits characters. Trim trailing zeros. |
755 | 0 | Vector<const char> chars(buffer, buffer_pos); |
756 | 0 | chars = TrimTrailingZeros(chars); |
757 | 0 | exponent += buffer_pos - chars.length(); |
758 | |
|
759 | 0 | double converted; |
760 | 0 | if (read_as_double) { |
761 | 0 | converted = StrtodTrimmed(chars, exponent); |
762 | 0 | } else { |
763 | 0 | converted = StrtofTrimmed(chars, exponent); |
764 | 0 | } |
765 | 0 | *processed_characters_count = static_cast<int>(current - input); |
766 | 0 | return sign? -converted: converted; |
767 | 0 | } Unexecuted instantiation: double icu_70::double_conversion::StringToDoubleConverter::StringToIeee<char const*>(char const*, int, bool, int*) const Unexecuted instantiation: double icu_70::double_conversion::StringToDoubleConverter::StringToIeee<unsigned short const*>(unsigned short const*, int, bool, int*) const |
768 | | |
769 | | |
770 | | double StringToDoubleConverter::StringToDouble( |
771 | | const char* buffer, |
772 | | int length, |
773 | 0 | int* processed_characters_count) const { |
774 | 0 | return StringToIeee(buffer, length, true, processed_characters_count); |
775 | 0 | } |
776 | | |
777 | | |
778 | | double StringToDoubleConverter::StringToDouble( |
779 | | const uc16* buffer, |
780 | | int length, |
781 | 0 | int* processed_characters_count) const { |
782 | 0 | return StringToIeee(buffer, length, true, processed_characters_count); |
783 | 0 | } |
784 | | |
785 | | |
786 | | float StringToDoubleConverter::StringToFloat( |
787 | | const char* buffer, |
788 | | int length, |
789 | 0 | int* processed_characters_count) const { |
790 | 0 | return static_cast<float>(StringToIeee(buffer, length, false, |
791 | 0 | processed_characters_count)); |
792 | 0 | } |
793 | | |
794 | | |
795 | | float StringToDoubleConverter::StringToFloat( |
796 | | const uc16* buffer, |
797 | | int length, |
798 | 0 | int* processed_characters_count) const { |
799 | 0 | return static_cast<float>(StringToIeee(buffer, length, false, |
800 | 0 | processed_characters_count)); |
801 | 0 | } |
802 | | |
803 | | } // namespace double_conversion |
804 | | |
805 | | // ICU PATCH: Close ICU namespace |
806 | | U_NAMESPACE_END |
807 | | #endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING |