OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "wtf/text/StringToNumber.h" | 5 #include "wtf/text/StringToNumber.h" |
6 | 6 |
7 #include "wtf/ASCIICType.h" | 7 #include "wtf/ASCIICType.h" |
8 #include "wtf/dtoa.h" | 8 #include "wtf/dtoa.h" |
9 #include "wtf/text/StringImpl.h" | 9 #include "wtf/text/StringImpl.h" |
| 10 #include <type_traits> |
10 | 11 |
11 namespace WTF { | 12 namespace WTF { |
12 | 13 |
13 static bool isCharacterAllowedInBase(UChar c, int base) { | 14 static bool isCharacterAllowedInBase(UChar c, int base) { |
14 if (c > 0x7F) | 15 if (c > 0x7F) |
15 return false; | 16 return false; |
16 if (isASCIIDigit(c)) | 17 if (isASCIIDigit(c)) |
17 return c - '0' < base; | 18 return c - '0' < base; |
18 if (isASCIIAlpha(c)) { | 19 if (isASCIIAlpha(c)) { |
19 if (base > 36) | 20 if (base > 36) |
20 base = 36; | 21 base = 36; |
21 return (c >= 'a' && c < 'a' + base - 10) || | 22 return (c >= 'a' && c < 'a' + base - 10) || |
22 (c >= 'A' && c < 'A' + base - 10); | 23 (c >= 'A' && c < 'A' + base - 10); |
23 } | 24 } |
24 return false; | 25 return false; |
25 } | 26 } |
26 | 27 |
27 template <typename IntegralType, typename CharType> | 28 template <typename IntegralType, typename CharType> |
28 static inline IntegralType toIntegralType(const CharType* data, | 29 static inline IntegralType toIntegralType(const CharType* data, |
29 size_t length, | 30 size_t length, |
30 bool* ok, | 31 bool* ok, |
31 int base) { | 32 int base) { |
32 static const IntegralType integralMax = | 33 static_assert(std::is_integral<IntegralType>::value, |
| 34 "IntegralType must be an integral type."); |
| 35 static constexpr IntegralType integralMax = |
33 std::numeric_limits<IntegralType>::max(); | 36 std::numeric_limits<IntegralType>::max(); |
34 static const bool isSigned = std::numeric_limits<IntegralType>::is_signed; | 37 static constexpr IntegralType integralMin = |
35 const IntegralType maxMultiplier = integralMax / base; | 38 std::numeric_limits<IntegralType>::min(); |
| 39 static constexpr bool isSigned = std::numeric_limits<IntegralType>::is_signed; |
36 | 40 |
37 IntegralType value = 0; | 41 IntegralType value = 0; |
38 bool isOk = false; | 42 bool isOk = false; |
39 bool isNegative = false; | 43 bool isNegative = false; |
40 | 44 |
41 if (!data) | 45 if (!data) |
42 goto bye; | 46 goto bye; |
43 | 47 |
44 // skip leading whitespace | 48 // skip leading whitespace |
45 while (length && isSpaceOrNewline(*data)) { | 49 while (length && isSpaceOrNewline(*data)) { |
(...skipping 17 matching lines...) Expand all Loading... |
63 --length; | 67 --length; |
64 IntegralType digitValue; | 68 IntegralType digitValue; |
65 CharType c = *data; | 69 CharType c = *data; |
66 if (isASCIIDigit(c)) | 70 if (isASCIIDigit(c)) |
67 digitValue = c - '0'; | 71 digitValue = c - '0'; |
68 else if (c >= 'a') | 72 else if (c >= 'a') |
69 digitValue = c - 'a' + 10; | 73 digitValue = c - 'a' + 10; |
70 else | 74 else |
71 digitValue = c - 'A' + 10; | 75 digitValue = c - 'A' + 10; |
72 | 76 |
73 if (value > maxMultiplier || | 77 bool overflow; |
74 (value == maxMultiplier && | 78 if (isNegative) { |
75 digitValue > (integralMax % base) + isNegative)) | 79 // Overflow condition: |
| 80 // value * base - digitValue < integralMin |
| 81 // <=> value < (integralMin + digitValue) / base |
| 82 // We must be careful of rounding errors here, but the default rounding |
| 83 // mode (round to zero) works well, so we can use this formula as-is. |
| 84 overflow = value < (integralMin + digitValue) / base; |
| 85 } else { |
| 86 // Overflow condition: |
| 87 // value * base + digitValue > integralMax |
| 88 // <=> value > (integralMax + digitValue) / base |
| 89 // Ditto regarding rounding errors. |
| 90 overflow = value > (integralMax - digitValue) / base; |
| 91 } |
| 92 if (overflow) |
76 goto bye; | 93 goto bye; |
77 | 94 |
78 value = base * value + digitValue; | 95 if (isNegative) |
| 96 value = base * value - digitValue; |
| 97 else |
| 98 value = base * value + digitValue; |
79 ++data; | 99 ++data; |
80 } | 100 } |
81 | 101 |
82 #if COMPILER(MSVC) | |
83 #pragma warning(push, 0) | |
84 #pragma warning(disable : 4146) | |
85 #endif | |
86 | |
87 if (isNegative) | |
88 value = -value; | |
89 | |
90 #if COMPILER(MSVC) | |
91 #pragma warning(pop) | |
92 #endif | |
93 | |
94 // skip trailing space | 102 // skip trailing space |
95 while (length && isSpaceOrNewline(*data)) { | 103 while (length && isSpaceOrNewline(*data)) { |
96 --length; | 104 --length; |
97 ++data; | 105 ++data; |
98 } | 106 } |
99 | 107 |
100 if (!length) | 108 if (!length) |
101 isOk = true; | 109 isOk = true; |
102 bye: | 110 bye: |
103 if (ok) | 111 if (ok) |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 float charactersToFloat(const UChar* data, | 313 float charactersToFloat(const UChar* data, |
306 size_t length, | 314 size_t length, |
307 size_t& parsedLength) { | 315 size_t& parsedLength) { |
308 // FIXME: This will return ok even when the string fits into a double but | 316 // FIXME: This will return ok even when the string fits into a double but |
309 // not a float. | 317 // not a float. |
310 return static_cast<float>( | 318 return static_cast<float>( |
311 toDoubleType<UChar, AllowTrailingJunk>(data, length, 0, parsedLength)); | 319 toDoubleType<UChar, AllowTrailingJunk>(data, length, 0, parsedLength)); |
312 } | 320 } |
313 | 321 |
314 } // namespace WTF | 322 } // namespace WTF |
OLD | NEW |