Chromium Code Reviews| Index: runtime/lib/double_patch.dart |
| diff --git a/runtime/lib/double_patch.dart b/runtime/lib/double_patch.dart |
| index d8e0cbd0c8450825ce4460e4af4e0a60d7291337..5becf9a8ae17cc7ecc710d6caceaa2baa813072d 100644 |
| --- a/runtime/lib/double_patch.dart |
| +++ b/runtime/lib/double_patch.dart |
| @@ -10,13 +10,114 @@ patch class double { |
| static double _nativeParse(String str, |
| int start, int end) native "Double_parse"; |
| + static double _tryParseDouble(var str, var start, var end) { |
| + assert(start < end); |
| + const int _DOT = 0x2e; // '.' |
| + const int _ZERO = 0x30; // '0' |
| + const int _MINUS = 0x2d; // '-' |
| + const int _N = 0x4e; // 'N' |
| + const int _a = 0x61; // 'a' |
| + const int _I = 0x49; // 'I' |
| + const int _e = 0x65; // 'e' |
| + int exponent = 0; |
| + // Set to non-zero if a digit is seen. Avoids accepting ".". |
| + int digitsSeen = 0; |
|
Vyacheslav Egorov (Google)
2014/10/02 14:27:41
please change this to boolean
Lasse Reichstein Nielsen
2014/10/02 14:36:44
Done. Please optimize booleans :)
|
| + // Added to exponent for each digit. Set to -1 when seeing '.'. |
| + int exponentDelta = 0; |
| + double doubleValue = 0.0; |
| + double sign = 1.0; |
| + int firstChar = str.codeUnitAt(start); |
| + if (firstChar == _MINUS) { |
| + sign = -1.0; |
| + start++; |
| + if (start == end) return null; |
| + firstChar = str.codeUnitAt(start); |
| + } |
| + if (firstChar == _I) { |
| + if (end == start + 8 && str.startsWith("nfinity", start + 1)) { |
| + return sign * double.INFINITY; |
| + } |
| + return null; |
| + } |
| + if (firstChar == _N) { |
| + if (end == start + 3 && str.codeUnitAt(start + 1) == _a |
|
Vyacheslav Egorov (Google)
2014/10/02 14:27:40
1 line &&
1 line &&
1 line
Lasse Reichstein Nielsen
2014/10/02 14:36:44
Done.
|
| + && str.codeUnitAt(start + 2) == _N) { |
| + return double.NAN; |
| + } |
| + return null; |
| + } |
| + |
| + int firstDigit = firstChar ^ _ZERO; |
| + if (firstDigit <= 9) { |
| + start++; |
| + doubleValue = firstDigit.toDouble(); |
| + digitsSeen = 1; |
| + } |
| + for (int i = start; i < end; i++) { |
| + int c = str.codeUnitAt(i); |
| + int digit = c ^ _ZERO; // '0'-'9' characters are now 0-9 integers. |
| + if (digit <= 9) { |
| + doubleValue = doubleValue * 10 + digit; |
| + if (doubleValue >= 9007199254740992.0) return null; // Maybe unprecise. |
|
Vyacheslav Egorov (Google)
2014/10/02 14:27:41
I would make this a const with a good name.
Lasse Reichstein Nielsen
2014/10/02 14:36:44
Done.
|
| + exponent += exponentDelta; |
| + digitsSeen = 1; |
| + } else if ((c == _DOT) && (exponentDelta == 0)) { |
|
Vyacheslav Egorov (Google)
2014/10/02 14:27:40
there is an inconsistency when you parenthesize ==
Lasse Reichstein Nielsen
2014/10/02 14:36:43
Done, without the parentheses.
|
| + exponentDelta = -1; |
| + } else if ((c | 0x20) == _e) { |
| + i++; |
| + if (i == end) return null; |
| + int expPart = int._tryParseSmi(str, i, end - 1); |
|
Vyacheslav Egorov (Google)
2014/10/02 14:27:41
I find this end - 1 confusing. Is it because our p
Lasse Reichstein Nielsen
2014/10/02 14:36:44
The _tryParseSmi is unconventional in having end i
|
| + if (expPart == null) return null; |
| + exponent += expPart; |
| + break; |
| + } else { |
| + return null; |
| + } |
| + } |
| + if (digitsSeen == 0) return null; // No digits. |
| + if (exponent == 0) return sign * doubleValue; |
| + // Powers of 10 up to 10^22 are exact doubles. |
|
Vyacheslav Egorov (Google)
2014/10/02 14:27:41
It would be good to use something more elaborate i
Lasse Reichstein Nielsen
2014/10/02 14:36:44
Added comment.
|
| + const P10 = const [ |
| + 1.0, /* 0 */ |
| + 10.0, |
| + 100.0, |
| + 1000.0, |
| + 10000.0, |
| + 100000.0, /* 5 */ |
| + 1000000.0, |
| + 10000000.0, |
| + 100000000.0, |
| + 1000000000.0, |
| + 10000000000.0, /* 10 */ |
| + 100000000000.0, |
| + 1000000000000.0, |
| + 10000000000000.0, |
| + 100000000000000.0, |
| + 1000000000000000.0, /* 15 */ |
| + 10000000000000000.0, |
| + 100000000000000000.0, |
| + 1000000000000000000.0, |
| + 10000000000000000000.0, |
| + 100000000000000000000.0, /* 20 */ |
| + 1000000000000000000000.0, |
| + 10000000000000000000000.0, |
| + ]; |
| + if (exponent < 0) { |
| + if (exponent < -22) return null; |
|
Vyacheslav Egorov (Google)
2014/10/02 14:27:41
maybe use P10.length here instead of 22?
Lasse Reichstein Nielsen
2014/10/02 14:36:44
That does appear to be just as fast. Done.
|
| + return sign * (doubleValue / P10[-exponent]); |
| + } |
| + if (exponent > 22) return null; |
|
Vyacheslav Egorov (Google)
2014/10/02 14:27:41
Ditto
Lasse Reichstein Nielsen
2014/10/02 14:36:44
Done.
|
| + return sign * (doubleValue * P10[exponent]); |
| + } |
| + |
| static double _parse(var str) { |
| int len = str.length; |
| int start = str._firstNonWhitespace(); |
| if (start == len) return null; // All whitespace. |
| int end = str._lastNonWhitespace() + 1; |
| assert(start < end); |
| - |
| + var result = _tryParseDouble(str, start, end); |
| + if (result != null) return result; |
| return _nativeParse(str, start, end); |
| } |