Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 // Dart core library. | 4 // Dart core library. |
| 5 | 5 |
| 6 // VM implementation of int. | 6 // VM implementation of int. |
| 7 | 7 |
| 8 patch class int { | 8 patch class int { |
| 9 | 9 |
| 10 /* patch */ const factory int.fromEnvironment(String name, | |
| 11 {int defaultValue}) | |
| 12 native "Integer_fromEnvironment"; | |
| 13 | |
| 10 static bool is64Bit() => 1 << 32 is _Smi; | 14 static bool is64Bit() => 1 << 32 is _Smi; |
| 11 | 15 |
| 12 static int _tryParseSmi(String str, int first, int last) { | 16 static int _tryParseSmi(String str, int first, int last) { |
| 13 assert(first <= last); | 17 assert(first <= last); |
| 14 var ix = first; | 18 var ix = first; |
| 15 var sign = 1; | 19 var sign = 1; |
| 16 var c = str.codeUnitAt(ix); | 20 var c = str.codeUnitAt(ix); |
| 17 // Check for leading '+' or '-'. | 21 // Check for leading '+' or '-'. |
| 18 if ((c == 0x2b) || (c == 0x2d)) { | 22 if ((c == 0x2b) || (c == 0x2d)) { |
| 19 ix++; | 23 ix++; |
| 20 sign = 0x2c - c; // -1 for '-', +1 for '+'. | 24 sign = 0x2c - c; // -1 for '-', +1 for '+'. |
| 21 if (ix > last) { | 25 if (ix > last) { |
| 22 return null; // Empty. | 26 return null; // Empty. |
| 23 } | 27 } |
| 24 } | 28 } |
| 25 var smiLimit = is64Bit() ? 18 : 9; | 29 var smiLimit = is64Bit() ? 18 : 9; |
| 26 if ((last - ix) >= smiLimit) { | 30 if ((last - ix) >= smiLimit) { |
| 27 return null; // May not fit into a Smi. | 31 return null; // May not fit into a Smi. |
| 28 } | 32 } |
| 29 var result = 0; | 33 var result = 0; |
| 30 for (int i = ix; i <= last; i++) { | 34 for (int i = ix; i <= last; i++) { |
| 31 var c = 0x30 ^ str.codeUnitAt(i); | 35 var c = 0x30 ^ str.codeUnitAt(i); |
| 32 if (9 < c) { | 36 if (9 < c) { |
| 33 return null; | 37 return null; |
| 34 } | 38 } |
| 35 result = 10 * result + c; | 39 result = 10 * result + c; |
| 36 } | 40 } |
|
Lasse Reichstein Nielsen
2014/09/23 11:34:45
This was what was already on the tip of tree.
| |
| 37 return sign * result; | 41 return sign * result; |
| 38 } | 42 } |
| 39 | 43 |
| 40 static int _tryParseSmiWhitespace(String str) { | |
| 41 int first = str._firstNonWhitespace(); | |
| 42 if (first < str.length) { | |
| 43 int last = str._lastNonWhitespace(); | |
| 44 int res = _tryParseSmi(str, first, last); | |
| 45 if (res != null) return res; | |
| 46 } | |
| 47 return _native_parse(str); | |
| 48 } | |
| 49 | |
| 50 static int _parse(String str) { | |
| 51 int res = _tryParseSmi(str, 0, str.length - 1); | |
| 52 if (res != null) return res; | |
| 53 return _tryParseSmiWhitespace(str); | |
| 54 } | |
| 55 | |
| 56 static int _native_parse(String str) native "Integer_parse"; | |
| 57 | |
| 58 static int _throwFormatException(String source, int position) { | |
| 59 throw new FormatException("", source, position); | |
| 60 } | |
| 61 | |
| 62 /* patch */ static int parse(String source, | 44 /* patch */ static int parse(String source, |
| 63 { int radix, | 45 { int radix, |
| 64 int onError(String str) }) { | 46 int onError(String str) }) { |
| 65 if (source == null) throw new ArgumentError(source); | 47 if (source == null) throw new ArgumentError("The source must not be null"); |
| 66 if (radix == null) { | 48 if (source.isEmpty) _throwFormatException(onError, source, 0, radix); |
| 67 int result; | 49 if (radix == null || radix == 10) { |
| 68 if (source.isNotEmpty) result = _parse(source); | 50 // Try parsing immediately, without trimming whitespace. |
| 69 if (result == null) { | 51 int result = _tryParseSmi(source, 0, source.length - 1); |
| 70 if (onError == null) { | 52 if (result != null) return result; |
| 71 throw new FormatException("", source); | 53 } else if (radix < 2 || radix > 36) { |
| 72 } | 54 throw new RangeError("Radix $radix not in range 2..36"); |
| 73 return onError(source); | |
| 74 } | |
| 75 return result; | |
| 76 } | 55 } |
| 77 return _slowParse(source, radix, onError); | 56 // Split here so improve odds of parse being inlined and the checks omitted. |
| 57 return _parse(source, radix, onError); | |
| 78 } | 58 } |
| 79 | 59 |
| 80 /* patch */ const factory int.fromEnvironment(String name, | 60 static int _parse(String source, int radix, onError) { |
| 81 {int defaultValue}) | 61 int end = source._lastNonWhitespace() + 1; |
| 82 native "Integer_fromEnvironment"; | 62 if (end == 0) { |
| 63 return _throwFormatException(onError, source, source.length, radix); | |
| 64 } | |
| 65 int start = source._firstNonWhitespace(); | |
| 83 | 66 |
| 84 static int _slowParse(String source, int radix, int onError(String str)) { | 67 int first = source.codeUnitAt(start); |
| 85 if (source is! String) throw new ArgumentError(source); | 68 int sign = 1; |
| 86 if (radix is! int) throw new ArgumentError("Radix is not an integer"); | 69 if (first == 0x2b /* + */ || first == 0x2d /* - */) { |
| 87 if (radix < 2 || radix > 36) { | 70 sign = 0x2c - first; // -1 if '-', +1 if '+'. |
| 88 throw new RangeError("Radix $radix not in range 2..36"); | 71 start++; |
| 72 if (start == end) { | |
| 73 return _throwFormatException(onError, source, end, radix); | |
| 74 } | |
| 89 } | 75 } |
| 90 // Remove leading and trailing white space. | 76 if (radix == null) { |
| 91 int start = source._firstNonWhitespace(); | 77 // check for 0x prefix. |
| 92 int i = start; | 78 int index = start; |
| 93 if (onError == null) onError = (source) { | 79 first = source.codeUnitAt(index); |
| 94 throw new FormatException("Invalid radix-$radix number", source, i); | 80 if (first == 0x30 /* 0 */) { |
| 95 }; | 81 index++; |
| 96 if (start == source.length) return onError(source); | 82 if (index == end) return 0; |
| 97 int end = source._lastNonWhitespace() + 1; | 83 first = source.codeUnitAt(index); |
| 84 if ((first | 0x20) == 0x78 /* x */) { | |
| 85 index++; | |
| 86 if (index == end) { | |
| 87 return _throwFormatException(onError, source, index, null); | |
| 88 } | |
| 89 int result = _parseRadix(source, 16, index, end, sign); | |
| 90 if (result == null) { | |
| 91 return _throwFormatException(onError, source, null, null); | |
| 92 } | |
| 93 return result; | |
| 94 } | |
| 95 } | |
| 96 radix = 10; | |
| 97 } | |
| 98 int result = _parseRadix(source, radix, start, end, sign); | |
| 99 if (result == null) { | |
| 100 return _throwFormatException(onError, source, null, radix); | |
| 101 } | |
| 102 return result; | |
| 103 } | |
| 98 | 104 |
| 99 bool negative = false; | 105 static int _throwFormatException(onError, source, index, radix) { |
| 106 if (onError != null) return onError(source); | |
| 107 if (radix == null) { | |
| 108 throw new FormatException("Invalid number", source, index); | |
| 109 } | |
| 110 throw new FormatException("Invalid radix-$radix number", source, index); | |
| 111 } | |
| 112 | |
| 113 static int _parseRadix(String source, int radix, | |
| 114 int start, int end, int sign) { | |
| 115 int tableIndex = (radix - 2) * 4 + (int.is64Bit() ? 2 : 0); | |
| 116 int blockSize = _PARSE_LIMITS[tableIndex]; | |
| 117 int length = end - start; | |
| 118 if (length <= blockSize) { | |
| 119 _Smi smi = _parseBlock(source, radix, start, end); | |
| 120 if (smi != null) return sign * smi; | |
| 121 return null; | |
| 122 } | |
| 123 int smallBlockSize = length % blockSize; | |
| 100 int result = 0; | 124 int result = 0; |
| 125 if (smallBlockSize > 0) { | |
| 126 int blockEnd = start + smallBlockSize; | |
| 127 _Smi smi = _parseBlock(source, radix, start, blockEnd); | |
| 128 if (smi == null) return null; | |
| 129 result = sign * smi; | |
| 130 start = blockEnd; | |
| 131 } | |
| 132 _Smi multiplier = _PARSE_LIMITS[tableIndex + 1]; | |
| 133 int blockEnd = start + blockSize; | |
| 134 do { | |
| 135 _Smi smi = _parseBlock(source, radix, start, blockEnd); | |
| 136 if (smi == null) return null; | |
| 137 result = (result * multiplier) + (sign * smi); | |
| 138 start = blockEnd; | |
| 139 blockEnd = start + blockSize; | |
| 140 } while (blockEnd <= end); | |
| 141 return result; | |
| 142 } | |
| 101 | 143 |
| 102 // The value 99 is used to represent a non-digit. It is too large to be | 144 // Parse block of digits with radix > 10. |
| 103 // a digit value in any of the used bases. | 145 static _Smi _parseBlock(String source, int radix, int start, int end) { |
| 104 const NA = 99; | 146 _Smi result = 0; |
| 105 const List<int> digits = const <int>[ | 147 if (radix <= 10) { |
| 106 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, NA, NA, NA, NA, NA, NA, // 0x30 | 148 for (int i = start; i < end; i++) { |
| 107 NA, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40 | 149 int digit = source.codeUnitAt(i) ^ 0x30; |
| 108 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, NA, NA, NA, NA, NA, // 0x50 | 150 if (digit >= radix) return null; |
| 109 NA, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x60 | 151 result = radix * result + digit; |
| 110 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, NA, NA, NA, NA, NA, // 0x70 | 152 } |
| 111 ]; | 153 } else { |
| 154 for (int i = start; i < end; i++) { | |
| 155 int char = source.codeUnitAt(i); | |
| 156 int digit = char ^ 0x30; | |
| 157 if (digit > 9) { | |
| 158 digit = (char | 0x20) - (0x61 - 10); | |
| 159 if (digit < 10 || digit >= radix) return null; | |
| 160 } | |
| 161 result = radix * result + digit; | |
| 162 } | |
| 163 } | |
| 164 return result; | |
| 165 } | |
| 112 | 166 |
| 113 int code = source.codeUnitAt(i); | 167 // For each radix, 2-36, how many digits are guaranteed to fit in a smi, |
| 114 if (code == 0x2d || code == 0x2b) { // Starts with a plus or minus-sign. | 168 // and magnitude of such a block (radix ** digit-count). |
| 115 negative = (code == 0x2d); | 169 // 32-bit limit/multiplier at (radix - 2)*4, 64-bit limit at (radix-2)*4+1 |
| 116 i++; | 170 static const _PARSE_LIMITS = const [ |
| 117 if (i == end) return onError(source); | 171 30, 1073741824, 62, 4611686018427387904, /* radix: 2 */ |
| 118 code = source.codeUnitAt(i); | 172 18, 387420489, 39, 4052555153018976267, |
| 119 } | 173 15, 1073741824, 30, 1152921504606846976, |
| 120 do { | 174 12, 244140625, 26, 1490116119384765625, /* radix: 5 */ |
| 121 if (code < 0x30 || code > 0x7f) return onError(source); | 175 11, 362797056, 23, 789730223053602816, |
| 122 int digit = digits[code - 0x30]; | 176 10, 282475249, 22, 3909821048582988049, |
| 123 if (digit >= radix) return onError(source); | 177 10, 1073741824, 20, 1152921504606846976, |
| 124 result = result * radix + digit; | 178 9, 387420489, 19, 1350851717672992089, |
| 125 i++; | 179 9, 1000000000, 18, 1000000000000000000, /* radix: 10 */ |
| 126 if (i == end) break; | 180 8, 214358881, 17, 505447028499293771, |
| 127 code = source.codeUnitAt(i); | 181 8, 429981696, 17, 2218611106740436992, |
| 128 } while (true); | 182 8, 815730721, 16, 665416609183179841, |
| 129 return negative ? -result : result; | 183 7, 105413504, 16, 2177953337809371136, |
| 130 } | 184 7, 170859375, 15, 437893890380859375, /* radix: 15 */ |
| 185 7, 268435456, 15, 1152921504606846976, | |
| 186 7, 410338673, 15, 2862423051509815793, | |
| 187 7, 612220032, 14, 374813367582081024, | |
| 188 7, 893871739, 14, 799006685782884121, | |
| 189 6, 64000000, 14, 1638400000000000000, /* radix: 20 */ | |
| 190 6, 85766121, 14, 3243919932521508681, | |
| 191 6, 113379904, 13, 282810057883082752, | |
| 192 6, 148035889, 13, 504036361936467383, | |
| 193 6, 191102976, 13, 876488338465357824, | |
| 194 6, 244140625, 13, 1490116119384765625, /* radix: 25 */ | |
| 195 6, 308915776, 13, 2481152873203736576, | |
| 196 6, 387420489, 13, 4052555153018976267, | |
| 197 6, 481890304, 12, 232218265089212416, | |
| 198 6, 594823321, 12, 353814783205469041, | |
| 199 6, 729000000, 12, 531441000000000000, /* radix: 30 */ | |
| 200 6, 887503681, 12, 787662783788549761, | |
| 201 6, 1073741824, 12, 1152921504606846976, | |
| 202 5, 39135393, 12, 1667889514952984961, | |
| 203 5, 45435424, 12, 2386420683693101056, | |
| 204 5, 52521875, 12, 3379220508056640625, /* radix: 35 */ | |
| 205 5, 60466176, 11, 131621703842267136, | |
| 206 ]; | |
| 131 } | 207 } |
| OLD | NEW |