Files
sdk/runtime/lib/integers_patch.dart
T
Sigmund Cherem 053e0ee720 Minor adjustments to patch files
The implementation of patching in analyzer checks that signatures are identical.
This is stricter than it needs to be, but the required fixes in dart:core are
pretty simple.

BUG=
R=hausner@google.com

Review-Url: https://codereview.chromium.org/2655223005 .
2017-01-27 14:24:06 -08:00

212 lines
7.4 KiB
Dart

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Dart core library.
// VM implementation of int.
@patch class int {
@patch const factory int.fromEnvironment(String name,
{int defaultValue})
native "Integer_fromEnvironment";
static int _tryParseSmi(String str, int first, int last) {
assert(first <= last);
var ix = first;
var sign = 1;
var c = str.codeUnitAt(ix);
// Check for leading '+' or '-'.
if ((c == 0x2b) || (c == 0x2d)) {
ix++;
sign = 0x2c - c; // -1 for '-', +1 for '+'.
if (ix > last) {
return null; // Empty.
}
}
var smiLimit = internal.is64Bit ? 18 : 9;
if ((last - ix) >= smiLimit) {
return null; // May not fit into a Smi.
}
var result = 0;
for (int i = ix; i <= last; i++) {
var c = 0x30 ^ str.codeUnitAt(i);
if (9 < c) {
return null;
}
result = 10 * result + c;
}
return sign * result;
}
@patch static int parse(String source,
{ int radix,
int onError(String source) }) {
if (source == null) throw new ArgumentError("The source must not be null");
if (source.isEmpty) return _throwFormatException(onError, source, 0, radix);
if (radix == null || radix == 10) {
// Try parsing immediately, without trimming whitespace.
int result = _tryParseSmi(source, 0, source.length - 1);
if (result != null) return result;
} else if (radix < 2 || radix > 36) {
throw new RangeError("Radix $radix not in range 2..36");
}
// Split here so improve odds of parse being inlined and the checks omitted.
return _parse(source, radix, onError);
}
static int _parse(String source, int radix, onError) {
int end = source._lastNonWhitespace() + 1;
if (end == 0) {
return _throwFormatException(onError, source, source.length, radix);
}
int start = source._firstNonWhitespace();
int first = source.codeUnitAt(start);
int sign = 1;
if (first == 0x2b /* + */ || first == 0x2d /* - */) {
sign = 0x2c - first; // -1 if '-', +1 if '+'.
start++;
if (start == end) {
return _throwFormatException(onError, source, end, radix);
}
first = source.codeUnitAt(start);
}
if (radix == null) {
// check for 0x prefix.
int index = start;
if (first == 0x30 /* 0 */) {
index++;
if (index == end) return 0;
first = source.codeUnitAt(index);
if ((first | 0x20) == 0x78 /* x */) {
index++;
if (index == end) {
return _throwFormatException(onError, source, index, null);
}
int result = _parseRadix(source, 16, index, end, sign);
if (result == null) {
return _throwFormatException(onError, source, null, null);
}
return result;
}
}
radix = 10;
}
int result = _parseRadix(source, radix, start, end, sign);
if (result == null) {
return _throwFormatException(onError, source, null, radix);
}
return result;
}
static int _throwFormatException(onError, source, index, radix) {
if (onError != null) return onError(source);
if (radix == null) {
throw new FormatException("Invalid number", source, index);
}
throw new FormatException("Invalid radix-$radix number", source, index);
}
static int _parseRadix(String source, int radix,
int start, int end, int sign) {
int tableIndex = (radix - 2) * 4 + (internal.is64Bit ? 2 : 0);
int blockSize = _PARSE_LIMITS[tableIndex];
int length = end - start;
if (length <= blockSize) {
_Smi smi = _parseBlock(source, radix, start, end);
if (smi != null) return sign * smi;
return null;
}
// Often cheaper than: int smallBlockSize = length % blockSize;
// because digit count generally tends towards smaller. rather
// than larger.
int smallBlockSize = length;
while (smallBlockSize >= blockSize) smallBlockSize -= blockSize;
int result = 0;
if (smallBlockSize > 0) {
int blockEnd = start + smallBlockSize;
_Smi smi = _parseBlock(source, radix, start, blockEnd);
if (smi == null) return null;
result = sign * smi;
start = blockEnd;
}
int multiplier = _PARSE_LIMITS[tableIndex + 1];
int blockEnd = start + blockSize;
do {
_Smi smi = _parseBlock(source, radix, start, blockEnd);
if (smi == null) return null;
result = (result * multiplier) + (sign * smi);
start = blockEnd;
blockEnd = start + blockSize;
} while (blockEnd <= end);
return result;
}
// Parse block of digits into a Smi.
static _Smi _parseBlock(String source, int radix, int start, int end) {
_Smi result = 0;
if (radix <= 10) {
for (int i = start; i < end; i++) {
int digit = source.codeUnitAt(i) ^ 0x30;
if (digit >= radix) return null;
result = radix * result + digit;
}
} else {
for (int i = start; i < end; i++) {
int char = source.codeUnitAt(i);
int digit = char ^ 0x30;
if (digit > 9) {
digit = (char | 0x20) - (0x61 - 10);
if (digit < 10 || digit >= radix) return null;
}
result = radix * result + digit;
}
}
return result;
}
// For each radix, 2-36, how many digits are guaranteed to fit in a smi,
// and magnitude of such a block (radix ** digit-count).
// 32-bit limit/multiplier at (radix - 2)*4, 64-bit limit at (radix-2)*4+2
static const _PARSE_LIMITS = const [
30, 1073741824, 62, 4611686018427387904, /* radix: 2 */
18, 387420489, 39, 4052555153018976267,
15, 1073741824, 30, 1152921504606846976,
12, 244140625, 26, 1490116119384765625, /* radix: 5 */
11, 362797056, 23, 789730223053602816,
10, 282475249, 22, 3909821048582988049,
10, 1073741824, 20, 1152921504606846976,
9, 387420489, 19, 1350851717672992089,
9, 1000000000, 18, 1000000000000000000, /* radix: 10 */
8, 214358881, 17, 505447028499293771,
8, 429981696, 17, 2218611106740436992,
8, 815730721, 16, 665416609183179841,
7, 105413504, 16, 2177953337809371136,
7, 170859375, 15, 437893890380859375, /* radix: 15 */
7, 268435456, 15, 1152921504606846976,
7, 410338673, 15, 2862423051509815793,
7, 612220032, 14, 374813367582081024,
7, 893871739, 14, 799006685782884121,
6, 64000000, 14, 1638400000000000000, /* radix: 20 */
6, 85766121, 14, 3243919932521508681,
6, 113379904, 13, 282810057883082752,
6, 148035889, 13, 504036361936467383,
6, 191102976, 13, 876488338465357824,
6, 244140625, 13, 1490116119384765625, /* radix: 25 */
6, 308915776, 13, 2481152873203736576,
6, 387420489, 13, 4052555153018976267,
6, 481890304, 12, 232218265089212416,
6, 594823321, 12, 353814783205469041,
6, 729000000, 12, 531441000000000000, /* radix: 30 */
6, 887503681, 12, 787662783788549761,
6, 1073741824, 12, 1152921504606846976,
5, 39135393, 12, 1667889514952984961,
5, 45435424, 12, 2386420683693101056,
5, 52521875, 12, 3379220508056640625, /* radix: 35 */
5, 60466176, 11, 131621703842267136,
];
}