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 double. | 6 // VM implementation of double. |
| 7 | 7 |
| 8 patch class double { | 8 patch class double { |
| 9 | 9 |
| 10 static double _nativeParse(String str, | 10 static double _nativeParse(String str, |
| 11 int start, int end) native "Double_parse"; | 11 int start, int end) native "Double_parse"; |
| 12 | 12 |
| 13 static double _tryParseDouble(var str, var start, var end) { | |
| 14 assert(start < end); | |
| 15 const int _DOT = 0x2e; // '.' | |
| 16 const int _ZERO = 0x30; // '0' | |
| 17 const int _MINUS = 0x2d; // '-' | |
| 18 const int _N = 0x4e; // 'N' | |
| 19 const int _a = 0x61; // 'a' | |
| 20 const int _I = 0x49; // 'I' | |
| 21 const int _e = 0x65; // 'e' | |
| 22 int exponent = 0; | |
| 23 // Set to non-zero if a digit is seen. Avoids accepting ".". | |
| 24 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 :)
| |
| 25 // Added to exponent for each digit. Set to -1 when seeing '.'. | |
| 26 int exponentDelta = 0; | |
| 27 double doubleValue = 0.0; | |
| 28 double sign = 1.0; | |
| 29 int firstChar = str.codeUnitAt(start); | |
| 30 if (firstChar == _MINUS) { | |
| 31 sign = -1.0; | |
| 32 start++; | |
| 33 if (start == end) return null; | |
| 34 firstChar = str.codeUnitAt(start); | |
| 35 } | |
| 36 if (firstChar == _I) { | |
| 37 if (end == start + 8 && str.startsWith("nfinity", start + 1)) { | |
| 38 return sign * double.INFINITY; | |
| 39 } | |
| 40 return null; | |
| 41 } | |
| 42 if (firstChar == _N) { | |
| 43 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.
| |
| 44 && str.codeUnitAt(start + 2) == _N) { | |
| 45 return double.NAN; | |
| 46 } | |
| 47 return null; | |
| 48 } | |
| 49 | |
| 50 int firstDigit = firstChar ^ _ZERO; | |
| 51 if (firstDigit <= 9) { | |
| 52 start++; | |
| 53 doubleValue = firstDigit.toDouble(); | |
| 54 digitsSeen = 1; | |
| 55 } | |
| 56 for (int i = start; i < end; i++) { | |
| 57 int c = str.codeUnitAt(i); | |
| 58 int digit = c ^ _ZERO; // '0'-'9' characters are now 0-9 integers. | |
| 59 if (digit <= 9) { | |
| 60 doubleValue = doubleValue * 10 + digit; | |
| 61 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.
| |
| 62 exponent += exponentDelta; | |
| 63 digitsSeen = 1; | |
| 64 } 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.
| |
| 65 exponentDelta = -1; | |
| 66 } else if ((c | 0x20) == _e) { | |
| 67 i++; | |
| 68 if (i == end) return null; | |
| 69 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
| |
| 70 if (expPart == null) return null; | |
| 71 exponent += expPart; | |
| 72 break; | |
| 73 } else { | |
| 74 return null; | |
| 75 } | |
| 76 } | |
| 77 if (digitsSeen == 0) return null; // No digits. | |
| 78 if (exponent == 0) return sign * doubleValue; | |
| 79 // 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.
| |
| 80 const P10 = const [ | |
| 81 1.0, /* 0 */ | |
| 82 10.0, | |
| 83 100.0, | |
| 84 1000.0, | |
| 85 10000.0, | |
| 86 100000.0, /* 5 */ | |
| 87 1000000.0, | |
| 88 10000000.0, | |
| 89 100000000.0, | |
| 90 1000000000.0, | |
| 91 10000000000.0, /* 10 */ | |
| 92 100000000000.0, | |
| 93 1000000000000.0, | |
| 94 10000000000000.0, | |
| 95 100000000000000.0, | |
| 96 1000000000000000.0, /* 15 */ | |
| 97 10000000000000000.0, | |
| 98 100000000000000000.0, | |
| 99 1000000000000000000.0, | |
| 100 10000000000000000000.0, | |
| 101 100000000000000000000.0, /* 20 */ | |
| 102 1000000000000000000000.0, | |
| 103 10000000000000000000000.0, | |
| 104 ]; | |
| 105 if (exponent < 0) { | |
| 106 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.
| |
| 107 return sign * (doubleValue / P10[-exponent]); | |
| 108 } | |
| 109 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.
| |
| 110 return sign * (doubleValue * P10[exponent]); | |
| 111 } | |
| 112 | |
| 13 static double _parse(var str) { | 113 static double _parse(var str) { |
| 14 int len = str.length; | 114 int len = str.length; |
| 15 int start = str._firstNonWhitespace(); | 115 int start = str._firstNonWhitespace(); |
| 16 if (start == len) return null; // All whitespace. | 116 if (start == len) return null; // All whitespace. |
| 17 int end = str._lastNonWhitespace() + 1; | 117 int end = str._lastNonWhitespace() + 1; |
| 18 assert(start < end); | 118 assert(start < end); |
| 19 | 119 var result = _tryParseDouble(str, start, end); |
| 120 if (result != null) return result; | |
| 20 return _nativeParse(str, start, end); | 121 return _nativeParse(str, start, end); |
| 21 } | 122 } |
| 22 | 123 |
| 23 /* patch */ static double parse(String str, | 124 /* patch */ static double parse(String str, |
| 24 [double onError(String str)]) { | 125 [double onError(String str)]) { |
| 25 var result = _parse(str); | 126 var result = _parse(str); |
| 26 if (result == null) { | 127 if (result == null) { |
| 27 if (onError == null) throw new FormatException("Invalid double", str); | 128 if (onError == null) throw new FormatException("Invalid double", str); |
| 28 return onError(str); | 129 return onError(str); |
| 29 } | 130 } |
| 30 return result; | 131 return result; |
| 31 } | 132 } |
| 32 } | 133 } |
| OLD | NEW |