Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: runtime/lib/integers_patch.dart

Issue 596763002: Optimize int.parse with a radix. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add missing return in error handling. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/lib/string_patch.dart » ('j') | runtime/lib/string_patch.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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++;
(...skipping 10 matching lines...) Expand all
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 }
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) return _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);
Florian Schneider 2014/09/25 11:38:39 Maybe factor out the multiplication with sign out
Lasse Reichstein Nielsen 2014/09/25 14:37:16 This makes all the multiplications Smi operations,
Florian Schneider 2014/09/26 11:57:05 I see - that makes sense.
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;
Florian Schneider 2014/09/25 11:38:39 Is this computation of the digit actually faster t
Lasse Reichstein Nielsen 2014/09/25 14:37:16 Testing just for hex, it seems to be pretty much t
Florian Schneider 2014/09/26 11:57:05 Acknowledged.
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 }
OLDNEW
« no previous file with comments | « no previous file | runtime/lib/string_patch.dart » ('j') | runtime/lib/string_patch.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698