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: pkg/dev_compiler/tool/input_sdk/private/js_number.dart

Issue 2994203002: Optimize DDC private library files. (Closed)
Patch Set: Address comments Created 3 years, 4 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
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 4
5 part of dart._interceptors; 5 part of dart._interceptors;
6 6
7 /** 7 /**
8 * The implementation of Dart's int & double methods. 8 * The implementation of Dart's int & double methods.
9 * These are made available as extension methods on `Number` in JS. 9 * These are made available as extension methods on `Number` in JS.
10 */ 10 */
11 @JsPeerInterface(name: 'Number') 11 @JsPeerInterface(name: 'Number')
12 class JSNumber extends Interceptor implements int, double { 12 class JSNumber extends Interceptor implements int, double {
13 const JSNumber(); 13 const JSNumber();
14 14
15 int compareTo(num b) { 15 @notNull
16 int compareTo(@nullCheck num b) {
16 if (this < b) { 17 if (this < b) {
17 return -1; 18 return -1;
18 } else if (this > b) { 19 } else if (this > b) {
19 return 1; 20 return 1;
20 } else if (this == b) { 21 } else if (this == b) {
21 if (this == 0) { 22 if (this == 0) {
22 bool bIsNegative = b.isNegative; 23 bool bIsNegative = b.isNegative;
23 if (isNegative == bIsNegative) return 0; 24 if (isNegative == bIsNegative) return 0;
24 if (isNegative) return -1; 25 if (isNegative) return -1;
25 return 1; 26 return 1;
26 } 27 }
27 return 0; 28 return 0;
28 } else if (isNaN) { 29 } else if (isNaN) {
29 if (b.isNaN) { 30 if (b.isNaN) {
30 return 0; 31 return 0;
31 } 32 }
32 return 1; 33 return 1;
33 } else { 34 } else {
34 return -1; 35 return -1;
35 } 36 }
36 } 37 }
37 38
39 @notNull
38 bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0; 40 bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0;
39 41
42 @notNull
40 bool get isNaN => JS('bool', r'isNaN(#)', this); 43 bool get isNaN => JS('bool', r'isNaN(#)', this);
41 44
45 @notNull
42 bool get isInfinite { 46 bool get isInfinite {
43 return JS('bool', r'# == (1/0)', this) || JS('bool', r'# == (-1/0)', this); 47 return JS('bool', r'# == (1/0)', this) || JS('bool', r'# == (-1/0)', this);
44 } 48 }
45 49
50 @notNull
46 bool get isFinite => JS('bool', r'isFinite(#)', this); 51 bool get isFinite => JS('bool', r'isFinite(#)', this);
47 52
48 JSNumber remainder(num b) { 53 @notNull
49 if (b is! num) throw argumentErrorValue(b); 54 JSNumber remainder(@nullCheck num b) {
50 return JS('num', r'# % #', this, b); 55 return JS('num', r'# % #', this, b);
51 } 56 }
52 57
58 @notNull
53 JSNumber abs() => JS('num', r'Math.abs(#)', this); 59 JSNumber abs() => JS('num', r'Math.abs(#)', this);
54 60
61 @notNull
55 JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this; 62 JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this;
56 63
64 @notNull
57 static const int _MIN_INT32 = -0x80000000; 65 static const int _MIN_INT32 = -0x80000000;
66 @notNull
58 static const int _MAX_INT32 = 0x7FFFFFFF; 67 static const int _MAX_INT32 = 0x7FFFFFFF;
59 68
69 @notNull
60 int toInt() { 70 int toInt() {
61 if (this >= _MIN_INT32 && this <= _MAX_INT32) { 71 if (this >= _MIN_INT32 && this <= _MAX_INT32) {
62 return JS('int', '# | 0', this); 72 return JS('int', '# | 0', this);
63 } 73 }
64 if (JS('bool', r'isFinite(#)', this)) { 74 if (JS('bool', r'isFinite(#)', this)) {
65 return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0. 75 return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0.
66 } 76 }
67 // This is either NaN, Infinity or -Infinity. 77 // This is either NaN, Infinity or -Infinity.
68 throw new UnsupportedError(JS("String", '"" + #', this)); 78 throw new UnsupportedError(JS("String", '"" + #', this));
69 } 79 }
70 80
81 @notNull
71 int truncate() => toInt(); 82 int truncate() => toInt();
72 83
84 @notNull
73 int ceil() => ceilToDouble().toInt(); 85 int ceil() => ceilToDouble().toInt();
74 86
87 @notNull
75 int floor() => floorToDouble().toInt(); 88 int floor() => floorToDouble().toInt();
76 89
90 @notNull
77 int round() { 91 int round() {
78 if (this > 0) { 92 if (this > 0) {
79 // This path excludes the special cases -0.0, NaN and -Infinity, leaving 93 // This path excludes the special cases -0.0, NaN and -Infinity, leaving
80 // only +Infinity, for which a direct test is faster than [isFinite]. 94 // only +Infinity, for which a direct test is faster than [isFinite].
81 if (JS('bool', r'# !== (1/0)', this)) { 95 if (JS('bool', r'# !== (1/0)', this)) {
82 return JS('int', r'Math.round(#)', this); 96 return JS('int', r'Math.round(#)', this);
83 } 97 }
84 } else if (JS('bool', '# > (-1/0)', this)) { 98 } else if (JS('bool', '# > (-1/0)', this)) {
85 // This test excludes NaN and -Infinity, leaving only -0.0. 99 // This test excludes NaN and -Infinity, leaving only -0.0.
86 // 100 //
87 // Subtraction from zero rather than negation forces -0.0 to 0.0 so code 101 // Subtraction from zero rather than negation forces -0.0 to 0.0 so code
88 // inside Math.round and code to handle result never sees -0.0, which on 102 // inside Math.round and code to handle result never sees -0.0, which on
89 // some JavaScript VMs can be a slow path. 103 // some JavaScript VMs can be a slow path.
90 return JS('int', r'0 - Math.round(0 - #)', this); 104 return JS('int', r'0 - Math.round(0 - #)', this);
91 } 105 }
92 // This is either NaN, Infinity or -Infinity. 106 // This is either NaN, Infinity or -Infinity.
93 throw new UnsupportedError(JS("String", '"" + #', this)); 107 throw new UnsupportedError(JS("String", '"" + #', this));
94 } 108 }
95 109
110 @notNull
96 double ceilToDouble() => JS('num', r'Math.ceil(#)', this); 111 double ceilToDouble() => JS('num', r'Math.ceil(#)', this);
97 112
113 @notNull
98 double floorToDouble() => JS('num', r'Math.floor(#)', this); 114 double floorToDouble() => JS('num', r'Math.floor(#)', this);
99 115
116 @notNull
100 double roundToDouble() { 117 double roundToDouble() {
101 if (this < 0) { 118 if (this < 0) {
102 return JS('num', r'-Math.round(-#)', this); 119 return JS('num', r'-Math.round(-#)', this);
103 } else { 120 } else {
104 return JS('num', r'Math.round(#)', this); 121 return JS('num', r'Math.round(#)', this);
105 } 122 }
106 } 123 }
107 124
125 @notNull
108 double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble(); 126 double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble();
109 127
110 num clamp(num lowerLimit, num upperLimit) { 128 @notNull
129 num clamp(@nullCheck num lowerLimit, @nullCheck num upperLimit) {
111 if (lowerLimit.compareTo(upperLimit) > 0) { 130 if (lowerLimit.compareTo(upperLimit) > 0) {
112 throw argumentErrorValue(lowerLimit); 131 throw argumentErrorValue(lowerLimit);
113 } 132 }
114 if (this.compareTo(lowerLimit) < 0) return lowerLimit; 133 if (this.compareTo(lowerLimit) < 0) return lowerLimit;
115 if (this.compareTo(upperLimit) > 0) return upperLimit; 134 if (this.compareTo(upperLimit) > 0) return upperLimit;
116 return this; 135 return this;
117 } 136 }
118 137
138 @notNull
119 double toDouble() => this; 139 double toDouble() => this;
120 140
121 String toStringAsFixed(int fractionDigits) { 141 @notNull
122 checkInt(fractionDigits); 142 String toStringAsFixed(@notNull int fractionDigits) {
123 if (fractionDigits < 0 || fractionDigits > 20) { 143 if (fractionDigits < 0 || fractionDigits > 20) {
124 throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits"); 144 throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
125 } 145 }
126 String result = JS('String', r'#.toFixed(#)', this, fractionDigits); 146 String result = JS('String', r'#.toFixed(#)', this, fractionDigits);
127 if (this == 0 && isNegative) return "-$result"; 147 if (this == 0 && isNegative) return "-$result";
128 return result; 148 return result;
129 } 149 }
130 150
151 @notNull
131 String toStringAsExponential([int fractionDigits]) { 152 String toStringAsExponential([int fractionDigits]) {
132 String result; 153 String result;
133 if (fractionDigits != null) { 154 if (fractionDigits != null) {
134 checkInt(fractionDigits); 155 @notNull
135 if (fractionDigits < 0 || fractionDigits > 20) { 156 var _fractionDigits = fractionDigits;
136 throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits"); 157 if (_fractionDigits < 0 || _fractionDigits > 20) {
158 throw new RangeError.range(_fractionDigits, 0, 20, "fractionDigits");
137 } 159 }
138 result = JS('String', r'#.toExponential(#)', this, fractionDigits); 160 result = JS('String', r'#.toExponential(#)', this, _fractionDigits);
139 } else { 161 } else {
140 result = JS('String', r'#.toExponential()', this); 162 result = JS('String', r'#.toExponential()', this);
141 } 163 }
142 if (this == 0 && isNegative) return "-$result"; 164 if (this == 0 && isNegative) return "-$result";
143 return result; 165 return result;
144 } 166 }
145 167
146 String toStringAsPrecision(int precision) { 168 @notNull
147 checkInt(precision); 169 String toStringAsPrecision(@nullCheck int precision) {
148 if (precision < 1 || precision > 21) { 170 if (precision < 1 || precision > 21) {
149 throw new RangeError.range(precision, 1, 21, "precision"); 171 throw new RangeError.range(precision, 1, 21, "precision");
150 } 172 }
151 String result = JS('String', r'#.toPrecision(#)', this, precision); 173 String result = JS('String', r'#.toPrecision(#)', this, precision);
152 if (this == 0 && isNegative) return "-$result"; 174 if (this == 0 && isNegative) return "-$result";
153 return result; 175 return result;
154 } 176 }
155 177
156 String toRadixString(int radix) { 178 @notNull
157 checkInt(radix); 179 String toRadixString(@nullCheck int radix) {
158 if (radix < 2 || radix > 36) { 180 if (radix < 2 || radix > 36) {
159 throw new RangeError.range(radix, 2, 36, "radix"); 181 throw new RangeError.range(radix, 2, 36, "radix");
160 } 182 }
161 String result = JS('String', r'#.toString(#)', this, radix); 183 String result = JS('String', r'#.toString(#)', this, radix);
162 const int rightParenCode = 0x29; 184 const int rightParenCode = 0x29;
163 if (result.codeUnitAt(result.length - 1) != rightParenCode) { 185 if (result.codeUnitAt(result.length - 1) != rightParenCode) {
164 return result; 186 return result;
165 } 187 }
166 return _handleIEtoString(result); 188 return _handleIEtoString(result);
167 } 189 }
168 190
191 @notNull
169 static String _handleIEtoString(String result) { 192 static String _handleIEtoString(String result) {
170 // Result is probably IE's untraditional format for large numbers, 193 // Result is probably IE's untraditional format for large numbers,
171 // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16). 194 // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16).
172 var match = JS('List|Null', 195 var match = JS('List|Null',
173 r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', result); 196 r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', result);
174 if (match == null) { 197 if (match == null) {
175 // Then we don't know how to handle it at all. 198 // Then we don't know how to handle it at all.
176 throw new UnsupportedError("Unexpected toString result: $result"); 199 throw new UnsupportedError("Unexpected toString result: $result");
177 } 200 }
178 result = JS('String', '#', match[1]); 201 result = JS('String', '#', match[1]);
179 int exponent = JS("int", "+#", match[3]); 202 int exponent = JS("int", "+#", match[3]);
180 if (match[2] != null) { 203 if (match[2] != null) {
181 result = JS('String', '# + #', result, match[2]); 204 result = JS('String', '# + #', result, match[2]);
182 exponent -= JS('int', '#.length', match[2]); 205 exponent -= JS('int', '#.length', match[2]);
183 } 206 }
184 return result + "0" * exponent; 207 return result + "0" * exponent;
185 } 208 }
186 209
187 // Note: if you change this, also change the function [S]. 210 // Note: if you change this, also change the function [S].
211 @notNull
188 String toString() { 212 String toString() {
189 if (this == 0 && JS('bool', '(1 / #) < 0', this)) { 213 if (this == 0 && JS('bool', '(1 / #) < 0', this)) {
190 return '-0.0'; 214 return '-0.0';
191 } else { 215 } else {
192 return JS('String', r'"" + (#)', this); 216 return JS('String', r'"" + (#)', this);
193 } 217 }
194 } 218 }
195 219
220 @notNull
196 int get hashCode => JS('int', '# & 0x1FFFFFFF', this); 221 int get hashCode => JS('int', '# & 0x1FFFFFFF', this);
197 222
223 @notNull
198 JSNumber operator -() => JS('num', r'-#', this); 224 JSNumber operator -() => JS('num', r'-#', this);
199 225
200 JSNumber operator +(num other) { 226 @notNull
201 if (other is! num) throw argumentErrorValue(other); 227 JSNumber operator +(@nullCheck num other) {
202 return JS('num', '# + #', this, other); 228 return JS('num', '# + #', this, other);
203 } 229 }
204 230
205 JSNumber operator -(num other) { 231 @notNull
206 if (other is! num) throw argumentErrorValue(other); 232 JSNumber operator -(@nullCheck num other) {
207 return JS('num', '# - #', this, other); 233 return JS('num', '# - #', this, other);
208 } 234 }
209 235
210 double operator /(num other) { 236 @notNull
211 if (other is! num) throw argumentErrorValue(other); 237 double operator /(@nullCheck num other) {
212 return JS('num', '# / #', this, other); 238 return JS('num', '# / #', this, other);
213 } 239 }
214 240
215 JSNumber operator *(num other) { 241 @notNull
216 if (other is! num) throw argumentErrorValue(other); 242 JSNumber operator *(@nullCheck num other) {
217 return JS('num', '# * #', this, other); 243 return JS('num', '# * #', this, other);
218 } 244 }
219 245
220 JSNumber operator %(num other) { 246 @notNull
221 if (other is! num) throw argumentErrorValue(other); 247 JSNumber operator %(@nullCheck num other) {
222 // Euclidean Modulo. 248 // Euclidean Modulo.
223 num result = JS('num', r'# % #', this, other); 249 num result = JS('num', r'# % #', this, other);
224 if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0. 250 if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0.
225 if (result > 0) return result; 251 if (result > 0) return result;
226 if (JS('num', '#', other) < 0) { 252 if (JS('num', '#', other) < 0) {
227 return result - JS('num', '#', other); 253 return result - JS('num', '#', other);
228 } else { 254 } else {
229 return result + JS('num', '#', other); 255 return result + JS('num', '#', other);
230 } 256 }
231 } 257 }
232 258
233 bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value); 259 @notNull
260 bool _isInt32(@notNull num value) =>
261 JS('bool', '(# | 0) === #', value, value);
234 262
235 int operator ~/(num other) { 263 @notNull
264 int operator ~/(@nullCheck num other) {
236 if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) { 265 if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) {
237 return JS('int', r'(# / #) | 0', this, other); 266 return JS('int', r'(# / #) | 0', this, other);
238 } else { 267 } else {
239 return _tdivSlow(other); 268 return _tdivSlow(other);
240 } 269 }
241 } 270 }
242 271
272 @notNull
243 int _tdivSlow(num other) { 273 int _tdivSlow(num other) {
244 if (other is! num) throw argumentErrorValue(other);
245 return (JS('num', r'# / #', this, other)).toInt(); 274 return (JS('num', r'# / #', this, other)).toInt();
246 } 275 }
247 276
248 // TODO(ngeoffray): Move the bit operations below to [JSInt] and 277 // TODO(ngeoffray): Move the bit operations below to [JSInt] and
249 // make them take an int. Because this will make operations slower, 278 // make them take an int. Because this will make operations slower,
250 // we define these methods on number for now but we need to decide 279 // we define these methods on number for now but we need to decide
251 // the grain at which we do the type checks. 280 // the grain at which we do the type checks.
252 281
253 int operator <<(num other) { 282 @notNull
254 if (other is! num) throw argumentErrorValue(other); 283 int operator <<(@nullCheck num other) {
255 if (JS('num', '#', other) < 0) throw argumentErrorValue(other); 284 if (other < 0) throwArgumentErrorValue(other);
256 return _shlPositive(other); 285 return _shlPositive(other);
257 } 286 }
258 287
259 int _shlPositive(num other) { 288 @notNull
289 int _shlPositive(@notNull num other) {
260 // JavaScript only looks at the last 5 bits of the shift-amount. Shifting 290 // JavaScript only looks at the last 5 bits of the shift-amount. Shifting
261 // by 33 is hence equivalent to a shift by 1. 291 // by 33 is hence equivalent to a shift by 1.
262 return JS('bool', r'# > 31', other) 292 return JS('bool', r'# > 31', other)
263 ? 0 293 ? 0
264 : JS('int', r'(# << #) >>> 0', this, other); 294 : JS('int', r'(# << #) >>> 0', this, other);
265 } 295 }
266 296
267 int operator >>(num other) { 297 @notNull
268 if (other is! num) throw argumentErrorValue(other); 298 int operator >>(@nullCheck num other) {
269 if (JS('num', '#', other) < 0) throw argumentErrorValue(other); 299 if (JS('num', '#', other) < 0) throwArgumentErrorValue(other);
270 return _shrOtherPositive(other); 300 return _shrOtherPositive(other);
271 } 301 }
272 302
273 int _shrOtherPositive(num other) { 303 @notNull
304 int _shrOtherPositive(@notNull num other) {
274 return JS('num', '#', this) > 0 305 return JS('num', '#', this) > 0
275 ? _shrBothPositive(other) 306 ? _shrBothPositive(other)
276 // For negative numbers we just clamp the shift-by amount. 307 // For negative numbers we just clamp the shift-by amount.
277 // `this` could be negative but not have its 31st bit set. 308 // `this` could be negative but not have its 31st bit set.
278 // The ">>" would then shift in 0s instead of 1s. Therefore 309 // The ">>" would then shift in 0s instead of 1s. Therefore
279 // we cannot simply return 0xFFFFFFFF. 310 // we cannot simply return 0xFFFFFFFF.
280 : JS('int', r'(# >> #) >>> 0', this, other > 31 ? 31 : other); 311 : JS('int', r'(# >> #) >>> 0', this, other > 31 ? 31 : other);
281 } 312 }
282 313
283 int _shrBothPositive(num other) { 314 @notNull
315 int _shrBothPositive(@notNull num other) {
284 return JS('bool', r'# > 31', other) 316 return JS('bool', r'# > 31', other)
285 // JavaScript only looks at the last 5 bits of the shift-amount. In JS 317 // JavaScript only looks at the last 5 bits of the shift-amount. In JS
286 // shifting by 33 is hence equivalent to a shift by 1. Shortcut the 318 // shifting by 33 is hence equivalent to a shift by 1. Shortcut the
287 // computation when that happens. 319 // computation when that happens.
288 ? 0 320 ? 0
289 // Given that `this` is positive we must not use '>>'. Otherwise a 321 // Given that `this` is positive we must not use '>>'. Otherwise a
290 // number that has the 31st bit set would be treated as negative and 322 // number that has the 31st bit set would be treated as negative and
291 // shift in ones. 323 // shift in ones.
292 : JS('int', r'# >>> #', this, other); 324 : JS('int', r'# >>> #', this, other);
293 } 325 }
294 326
295 int operator &(num other) { 327 @notNull
296 if (other is! num) throw argumentErrorValue(other); 328 int operator &(@nullCheck num other) {
297 return JS('int', r'(# & #) >>> 0', this, other); 329 return JS('int', r'(# & #) >>> 0', this, other);
298 } 330 }
299 331
300 int operator |(num other) { 332 @notNull
301 if (other is! num) throw argumentErrorValue(other); 333 int operator |(@nullCheck num other) {
302 return JS('int', r'(# | #) >>> 0', this, other); 334 return JS('int', r'(# | #) >>> 0', this, other);
303 } 335 }
304 336
305 int operator ^(num other) { 337 @notNull
306 if (other is! num) throw argumentErrorValue(other); 338 int operator ^(@nullCheck num other) {
307 return JS('int', r'(# ^ #) >>> 0', this, other); 339 return JS('int', r'(# ^ #) >>> 0', this, other);
308 } 340 }
309 341
310 bool operator <(num other) { 342 @notNull
311 if (other is! num) throw argumentErrorValue(other); 343 bool operator <(@nullCheck num other) {
312 return JS('bool', '# < #', this, other); 344 return JS('bool', '# < #', this, other);
313 } 345 }
314 346
315 bool operator >(num other) { 347 @notNull
316 if (other is! num) throw argumentErrorValue(other); 348 bool operator >(@nullCheck num other) {
317 return JS('bool', '# > #', this, other); 349 return JS('bool', '# > #', this, other);
318 } 350 }
319 351
320 bool operator <=(num other) { 352 @notNull
321 if (other is! num) throw argumentErrorValue(other); 353 bool operator <=(@nullCheck num other) {
322 return JS('bool', '# <= #', this, other); 354 return JS('bool', '# <= #', this, other);
323 } 355 }
324 356
325 bool operator >=(num other) { 357 @notNull
326 if (other is! num) throw argumentErrorValue(other); 358 bool operator >=(@nullCheck num other) {
327 return JS('bool', '# >= #', this, other); 359 return JS('bool', '# >= #', this, other);
328 } 360 }
329 361
330 // int members. 362 // int members.
331 // TODO(jmesserly): all numbers will have these in dynamic dispatch. 363 // TODO(jmesserly): all numbers will have these in dynamic dispatch.
332 // We can fix by checking it at dispatch time but we'd need to structure them 364 // We can fix by checking it at dispatch time but we'd need to structure them
333 // differently. 365 // differently.
334 366
367 @notNull
335 bool get isEven => (this & 1) == 0; 368 bool get isEven => (this & 1) == 0;
336 369
370 @notNull
337 bool get isOdd => (this & 1) == 1; 371 bool get isOdd => (this & 1) == 1;
338 372
339 int toUnsigned(int width) { 373 @notNull
374 int toUnsigned(@nullCheck int width) {
340 return this & ((1 << width) - 1); 375 return this & ((1 << width) - 1);
341 } 376 }
342 377
343 int toSigned(int width) { 378 @notNull
379 int toSigned(@nullCheck int width) {
344 int signMask = 1 << (width - 1); 380 int signMask = 1 << (width - 1);
345 return (this & (signMask - 1)) - (this & signMask); 381 return (this & (signMask - 1)) - (this & signMask);
346 } 382 }
347 383
384 @notNull
348 int get bitLength { 385 int get bitLength {
349 int nonneg = this < 0 ? -this - 1 : this; 386 int nonneg = this < 0 ? -this - 1 : this;
350 if (nonneg >= 0x100000000) { 387 if (nonneg >= 0x100000000) {
351 nonneg = nonneg ~/ 0x100000000; 388 nonneg = nonneg ~/ 0x100000000;
352 return _bitCount(_spread(nonneg)) + 32; 389 return _bitCount(_spread(nonneg)) + 32;
353 } 390 }
354 return _bitCount(_spread(nonneg)); 391 return _bitCount(_spread(nonneg));
355 } 392 }
356 393
357 // Returns pow(this, e) % m. 394 // Returns pow(this, e) % m.
358 int modPow(int e, int m) { 395 @notNull
359 if (e is! int) { 396 int modPow(@nullCheck int e, @nullCheck int m) {
360 throw new ArgumentError.value(e, "exponent", "not an integer");
361 }
362 if (m is! int) {
363 throw new ArgumentError.value(m, "modulus", "not an integer");
364 }
365 if (e < 0) throw new RangeError.range(e, 0, null, "exponent"); 397 if (e < 0) throw new RangeError.range(e, 0, null, "exponent");
366 if (m <= 0) throw new RangeError.range(m, 1, null, "modulus"); 398 if (m <= 0) throw new RangeError.range(m, 1, null, "modulus");
367 if (e == 0) return 1; 399 if (e == 0) return 1;
368 int b = this; 400 int b = this;
369 if (b < 0 || b > m) { 401 if (b < 0 || b > m) {
370 b %= m; 402 b %= m;
371 } 403 }
372 int r = 1; 404 int r = 1;
373 while (e > 0) { 405 while (e > 0) {
374 if (e.isOdd) { 406 if (e.isOdd) {
375 r = (r * b) % m; 407 r = (r * b) % m;
376 } 408 }
377 e ~/= 2; 409 e ~/= 2;
378 b = (b * b) % m; 410 b = (b * b) % m;
379 } 411 }
380 return r; 412 return r;
381 } 413 }
382 414
383 // If inv is false, returns gcd(x, y). 415 // If inv is false, returns gcd(x, y).
384 // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1. 416 // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
385 // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime"). 417 // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
386 static int _binaryGcd(int x, int y, bool inv) { 418 @notNull
419 static int _binaryGcd(@notNull int x, @notNull int y, @notNull bool inv) {
387 int s = 1; 420 int s = 1;
388 if (!inv) { 421 if (!inv) {
389 while (x.isEven && y.isEven) { 422 while (x.isEven && y.isEven) {
390 x ~/= 2; 423 x ~/= 2;
391 y ~/= 2; 424 y ~/= 2;
392 s *= 2; 425 s *= 2;
393 } 426 }
394 if (y.isOdd) { 427 if (y.isOdd) {
395 var t = x; 428 var t = x;
396 x = y; 429 x = y;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 d += x; 477 d += x;
445 if (d < 0) d += x; 478 if (d < 0) d += x;
446 } else if (d > x) { 479 } else if (d > x) {
447 d -= x; 480 d -= x;
448 if (d > x) d -= x; 481 if (d > x) d -= x;
449 } 482 }
450 return d; 483 return d;
451 } 484 }
452 485
453 // Returns 1/this % m, with m > 0. 486 // Returns 1/this % m, with m > 0.
454 int modInverse(int m) { 487 @notNull
455 if (m is! int) { 488 int modInverse(@nullCheck int m) {
456 throw new ArgumentError.value(m, "modulus", "not an integer");
457 }
458 if (m <= 0) throw new RangeError.range(m, 1, null, "modulus"); 489 if (m <= 0) throw new RangeError.range(m, 1, null, "modulus");
459 if (m == 1) return 0; 490 if (m == 1) return 0;
460 int t = this; 491 int t = this;
461 if ((t < 0) || (t >= m)) t %= m; 492 if ((t < 0) || (t >= m)) t %= m;
462 if (t == 1) return 1; 493 if (t == 1) return 1;
463 if ((t == 0) || (t.isEven && m.isEven)) { 494 if ((t == 0) || (t.isEven && m.isEven)) {
464 throw new Exception("Not coprime"); 495 throw new Exception("Not coprime");
465 } 496 }
466 return _binaryGcd(m, t, true); 497 return _binaryGcd(m, t, true);
467 } 498 }
468 499
469 // Returns gcd of abs(this) and abs(other). 500 // Returns gcd of abs(this) and abs(other).
470 int gcd(int other) { 501 @notNull
471 if (other is! int) { 502 int gcd(@nullCheck int other) {
472 throw new ArgumentError.value(other, "other", "not an integer");
473 }
474 int x = this.abs(); 503 int x = this.abs();
475 int y = other.abs(); 504 int y = other.abs();
476 if (x == 0) return y; 505 if (x == 0) return y;
477 if (y == 0) return x; 506 if (y == 0) return x;
478 if ((x == 1) || (y == 1)) return 1; 507 if ((x == 1) || (y == 1)) return 1;
479 return _binaryGcd(x, y, false); 508 return _binaryGcd(x, y, false);
480 } 509 }
481 510
482 // Assumes i is <= 32-bit and unsigned. 511 // Assumes i is <= 32-bit and unsigned.
483 static int _bitCount(int i) { 512 @notNull
513 static int _bitCount(@notNull int i) {
484 // See "Hacker's Delight", section 5-1, "Counting 1-Bits". 514 // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
485 515
486 // The basic strategy is to use "divide and conquer" to 516 // The basic strategy is to use "divide and conquer" to
487 // add pairs (then quads, etc.) of bits together to obtain 517 // add pairs (then quads, etc.) of bits together to obtain
488 // sub-counts. 518 // sub-counts.
489 // 519 //
490 // A straightforward approach would look like: 520 // A straightforward approach would look like:
491 // 521 //
492 // i = (i & 0x55555555) + ((i >> 1) & 0x55555555); 522 // i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
493 // i = (i & 0x33333333) + ((i >> 2) & 0x33333333); 523 // i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
494 // i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F); 524 // i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
495 // i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF); 525 // i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF);
496 // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF); 526 // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
497 // 527 //
498 // The code below removes unnecessary &'s and uses a 528 // The code below removes unnecessary &'s and uses a
499 // trick to remove one instruction in the first line. 529 // trick to remove one instruction in the first line.
500 530
501 i = _shru(i, 0) - (_shru(i, 1) & 0x55555555); 531 i = _shru(i, 0) - (_shru(i, 1) & 0x55555555);
502 i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333); 532 i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333);
503 i = 0x0F0F0F0F & (i + _shru(i, 4)); 533 i = 0x0F0F0F0F & (i + _shru(i, 4));
504 i += _shru(i, 8); 534 i += _shru(i, 8);
505 i += _shru(i, 16); 535 i += _shru(i, 16);
506 return (i & 0x0000003F); 536 return (i & 0x0000003F);
507 } 537 }
508 538
539 @notNull
509 static int _shru(int value, int shift) => JS('int', '# >>> #', value, shift); 540 static int _shru(int value, int shift) => JS('int', '# >>> #', value, shift);
541 @notNull
510 static int _shrs(int value, int shift) => JS('int', '# >> #', value, shift); 542 static int _shrs(int value, int shift) => JS('int', '# >> #', value, shift);
543 @notNull
511 static int _ors(int a, int b) => JS('int', '# | #', a, b); 544 static int _ors(int a, int b) => JS('int', '# | #', a, b);
512 545
513 // Assumes i is <= 32-bit 546 // Assumes i is <= 32-bit
514 static int _spread(int i) { 547 @notNull
548 static int _spread(@notNull int i) {
515 i = _ors(i, _shrs(i, 1)); 549 i = _ors(i, _shrs(i, 1));
516 i = _ors(i, _shrs(i, 2)); 550 i = _ors(i, _shrs(i, 2));
517 i = _ors(i, _shrs(i, 4)); 551 i = _ors(i, _shrs(i, 4));
518 i = _ors(i, _shrs(i, 8)); 552 i = _ors(i, _shrs(i, 8));
519 i = _shru(_ors(i, _shrs(i, 16)), 0); 553 i = _shru(_ors(i, _shrs(i, 16)), 0);
520 return i; 554 return i;
521 } 555 }
522 556
523 int operator ~() => JS('int', r'(~#) >>> 0', this); 557 int operator ~() => JS('int', r'(~#) >>> 0', this);
524 } 558 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698