| 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 | 4 |
| 5 // TODO(srdjan): fix limitations. | 5 // TODO(srdjan): fix limitations. |
| 6 // - shift amount must be a Smi. | 6 // - shift amount must be a Smi. |
| 7 class _IntegerImplementation { | 7 class _IntegerImplementation { |
| 8 factory _IntegerImplementation._uninstantiable() { | 8 factory _IntegerImplementation._uninstantiable() { |
| 9 throw new UnsupportedError( | 9 throw new UnsupportedError( |
| 10 "_IntegerImplementation can only be allocated by the VM"); | 10 "_IntegerImplementation can only be allocated by the VM"); |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 } | 253 } |
| 254 int get _identityHashCode { | 254 int get _identityHashCode { |
| 255 return this; | 255 return this; |
| 256 } | 256 } |
| 257 int operator ~() native "Smi_bitNegate"; | 257 int operator ~() native "Smi_bitNegate"; |
| 258 int get bitLength native "Smi_bitLength"; | 258 int get bitLength native "Smi_bitLength"; |
| 259 | 259 |
| 260 int _shrFromInt(int other) native "Smi_shrFromInt"; | 260 int _shrFromInt(int other) native "Smi_shrFromInt"; |
| 261 int _shlFromInt(int other) native "Smi_shlFromInt"; | 261 int _shlFromInt(int other) native "Smi_shlFromInt"; |
| 262 | 262 |
| 263 /** |
| 264 * The digits of '00', '01', ... '99' as a single array. |
| 265 * |
| 266 * Get the digits of `n`, with `0 <= n < 100`, as |
| 267 * `_digitTable[n * 2]` and `_digitTable[n * 2 + 1]`. |
| 268 */ |
| 269 static const _digitTable = const [ |
| 270 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, |
| 271 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, |
| 272 0x30, 0x38, 0x30, 0x39, 0x31, 0x30, 0x31, 0x31, |
| 273 0x31, 0x32, 0x31, 0x33, 0x31, 0x34, 0x31, 0x35, |
| 274 0x31, 0x36, 0x31, 0x37, 0x31, 0x38, 0x31, 0x39, |
| 275 0x32, 0x30, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33, |
| 276 0x32, 0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, |
| 277 0x32, 0x38, 0x32, 0x39, 0x33, 0x30, 0x33, 0x31, |
| 278 0x33, 0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35, |
| 279 0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39, |
| 280 0x34, 0x30, 0x34, 0x31, 0x34, 0x32, 0x34, 0x33, |
| 281 0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x34, 0x37, |
| 282 0x34, 0x38, 0x34, 0x39, 0x35, 0x30, 0x35, 0x31, |
| 283 0x35, 0x32, 0x35, 0x33, 0x35, 0x34, 0x35, 0x35, |
| 284 0x35, 0x36, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39, |
| 285 0x36, 0x30, 0x36, 0x31, 0x36, 0x32, 0x36, 0x33, |
| 286 0x36, 0x34, 0x36, 0x35, 0x36, 0x36, 0x36, 0x37, |
| 287 0x36, 0x38, 0x36, 0x39, 0x37, 0x30, 0x37, 0x31, |
| 288 0x37, 0x32, 0x37, 0x33, 0x37, 0x34, 0x37, 0x35, |
| 289 0x37, 0x36, 0x37, 0x37, 0x37, 0x38, 0x37, 0x39, |
| 290 0x38, 0x30, 0x38, 0x31, 0x38, 0x32, 0x38, 0x33, |
| 291 0x38, 0x34, 0x38, 0x35, 0x38, 0x36, 0x38, 0x37, |
| 292 0x38, 0x38, 0x38, 0x39, 0x39, 0x30, 0x39, 0x31, |
| 293 0x39, 0x32, 0x39, 0x33, 0x39, 0x34, 0x39, 0x35, |
| 294 0x39, 0x36, 0x39, 0x37, 0x39, 0x38, 0x39, 0x39 |
| 295 ]; |
| 296 |
| 297 // Powers of 10 above 1000000 are indistinguishable. |
| 298 static const int _POW_10_7 = 10000000; |
| 299 static const int _POW_10_8 = 100000000; |
| 300 static const int _POW_10_9 = 1000000000; |
| 301 static const int _POW_10_10 = 10000000000; |
| 302 |
| 303 // Find the number of decimal digits in a positive smi. |
| 304 static int _positiveBase10Length(var smi) { |
| 305 // A positive smi has length <= 19 if 63-bit, <=10 if 31-bit. |
| 306 // Avoid comparing a 31-bit smi to a non-smi. |
| 307 if (smi < 1000) return 3; |
| 308 if (smi < 10000) return 4; |
| 309 if (smi < _POW_10_7) { |
| 310 if (smi < 100000) return 5; |
| 311 if (smi < 1000000) return 6; |
| 312 return 7; |
| 313 } |
| 314 if (smi < _POW_10_10) { |
| 315 if (smi < _POW_10_8) return 8; |
| 316 if (smi < _POW_10_9) return 9; |
| 317 return 10; |
| 318 } |
| 319 smi = smi ~/ _POW_10_10; |
| 320 if (smi < 10) return 11; |
| 321 if (smi < 100) return 12; |
| 322 return 10 + _positiveBase10Length(smi); |
| 323 } |
| 324 |
| 263 String toString() { | 325 String toString() { |
| 264 if (this == 0) return "0"; | 326 if (this < 0) return _negativeToString(this); |
| 265 var reversed = _toStringBuffer; | 327 // Inspired by Andrei Alexandrescu: "Three Optimization Tips for C++" |
| 266 var negative = false; | 328 // Avoid expensive remainder operation by doing it on more than |
| 267 var val = this; | 329 // one digit at a time. |
| 268 int index = 0; | 330 const int DIGIT_ZERO = 0x30; |
| 331 if (this < 10) { |
| 332 return _OneByteString._allocate(1).._setAt(0, DIGIT_ZERO + this); |
| 333 } |
| 334 if (this < 100) { |
| 335 int digitIndex = 2 * this; |
| 336 return _OneByteString._allocate(2) |
| 337 .._setAt(0, _digitTable[digitIndex]) |
| 338 .._setAt(1, _digitTable[digitIndex + 1]); |
| 339 } |
| 340 int length = _positiveBase10Length(this); |
| 341 _OneByteString result = _OneByteString._allocate(length); |
| 342 int index = length - 1; |
| 343 var smi = this; |
| 344 do { |
| 345 // Two digits at a time. |
| 346 var twoDigits = smi.remainder(100); |
| 347 smi = smi ~/ 100; |
| 348 int digitIndex = twoDigits * 2; |
| 349 result._setAt(index, _digitTable[digitIndex + 1]); |
| 350 result._setAt(index - 1, _digitTable[digitIndex]); |
| 351 index -= 2; |
| 352 } while (smi >= 100); |
| 353 if (smi < 10) { |
| 354 // Character code for '0'. |
| 355 result._setAt(index, DIGIT_ZERO + smi); |
| 356 } else { |
| 357 // No remainder for this case. |
| 358 int digitIndex = smi * 2; |
| 359 result._setAt(index, _digitTable[digitIndex + 1]); |
| 360 result._setAt(index - 1, _digitTable[digitIndex]); |
| 361 } |
| 362 return result; |
| 363 } |
| 269 | 364 |
| 270 if (this < 0) { | 365 // Find the number of decimal digits in a negative smi. |
| 271 negative = true; | 366 static int _negativeBase10Length(var negSmi) { |
| 272 // Handle the first digit as negative to avoid negating the minimum | 367 // A negative smi has length <= 19 if 63-bit, <=10 if 31-bit. |
| 273 // smi, for which the negation is not a smi. | 368 // Avoid comparing a 31-bit smi to a non-smi. |
| 274 int digit = -(val.remainder(10)); | 369 if (negSmi > -1000) return 3; |
| 275 reversed[index++] = digit + 0x30; | 370 if (negSmi > -10000) return 4; |
| 276 val = -(val ~/ 10); | 371 if (negSmi > -_POW_10_7) { |
| 372 if (negSmi > -100000) return 5; |
| 373 if (negSmi > -1000000) return 6; |
| 374 return 7; |
| 277 } | 375 } |
| 376 if (negSmi > -_POW_10_10) { |
| 377 if (negSmi > -_POW_10_8) return 8; |
| 378 if (negSmi > -_POW_10_9) return 9; |
| 379 return 10; |
| 380 } |
| 381 negSmi = negSmi ~/ _POW_10_10; |
| 382 if (negSmi > -10) return 11; |
| 383 if (negSmi > -100) return 12; |
| 384 return 10 + _negativeBase10Length(negSmi); |
| 385 } |
| 278 | 386 |
| 279 while (val > 0) { | 387 // Convert a negative smi to a string. |
| 280 int digit = val % 10; | 388 // Doesn't negate the smi to avoid negating the most negative smi, which |
| 281 val = val ~/ 10; | 389 // would become a non-smi. |
| 282 reversed[index++] = (digit + 0x30); | 390 static String _negativeToString(int negSmi) { |
| 391 // Character code for '-' |
| 392 const int MINUS_SIGN = 0x2d; |
| 393 // Character code for '0'. |
| 394 const int DIGIT_ZERO = 0x30; |
| 395 if (negSmi > -10) { |
| 396 return _OneByteString._allocate(2).._setAt(0, MINUS_SIGN) |
| 397 .._setAt(1, DIGIT_ZERO - negSmi); |
| 283 } | 398 } |
| 284 if (negative) reversed[index++] = 0x2D; // '-'. | 399 if (negSmi > -100) { |
| 285 | 400 int digitIndex = 2 * -negSmi; |
| 286 _OneByteString string = _OneByteString._allocate(index); | 401 return _OneByteString._allocate(3) |
| 287 for (int i = 0, j = index; i < index; i++) { | 402 .._setAt(0, MINUS_SIGN) |
| 288 string._setAt(i, reversed[--j]); | 403 .._setAt(1, _digitTable[digitIndex]) |
| 404 .._setAt(2, _digitTable[digitIndex + 1]); |
| 289 } | 405 } |
| 290 return string; | 406 // Number of digits, not including minus. |
| 407 int digitCount = _negativeBase10Length(negSmi); |
| 408 _OneByteString result = _OneByteString._allocate(digitCount + 1); |
| 409 result._setAt(0, MINUS_SIGN); // '-'. |
| 410 int index = digitCount; |
| 411 do { |
| 412 var twoDigits = negSmi.remainder(100); |
| 413 negSmi = negSmi ~/ 100; |
| 414 int digitIndex = -twoDigits * 2; |
| 415 result._setAt(index, _digitTable[digitIndex + 1]); |
| 416 result._setAt(index - 1, _digitTable[digitIndex]); |
| 417 index -= 2; |
| 418 } while (negSmi <= -100); |
| 419 if (negSmi > -10) { |
| 420 result._setAt(index, DIGIT_ZERO - negSmi); |
| 421 } else { |
| 422 // No remainder necessary for this case. |
| 423 int digitIndex = -negSmi * 2; |
| 424 result._setAt(index, _digitTable[digitIndex + 1]); |
| 425 result._setAt(index - 1, _digitTable[digitIndex]); |
| 426 } |
| 427 return result; |
| 291 } | 428 } |
| 292 } | 429 } |
| 293 | 430 |
| 294 // Reusable buffer used by smi.toString. | |
| 295 final List _toStringBuffer = new Uint8List(20); | |
| 296 | |
| 297 // Represents integers that cannot be represented by Smi but fit into 64bits. | 431 // Represents integers that cannot be represented by Smi but fit into 64bits. |
| 298 class _Mint extends _IntegerImplementation implements int { | 432 class _Mint extends _IntegerImplementation implements int { |
| 299 factory _Mint._uninstantiable() { | 433 factory _Mint._uninstantiable() { |
| 300 throw new UnsupportedError( | 434 throw new UnsupportedError( |
| 301 "_Mint can only be allocated by the VM"); | 435 "_Mint can only be allocated by the VM"); |
| 302 } | 436 } |
| 303 int get _identityHashCode { | 437 int get _identityHashCode { |
| 304 return this; | 438 return this; |
| 305 } | 439 } |
| 306 int operator ~() native "Mint_bitNegate"; | 440 int operator ~() native "Mint_bitNegate"; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 337 } else { | 471 } else { |
| 338 return 0; | 472 return 0; |
| 339 } | 473 } |
| 340 } | 474 } |
| 341 int _shlFromInt(int other) native "Bigint_shlFromInt"; | 475 int _shlFromInt(int other) native "Bigint_shlFromInt"; |
| 342 | 476 |
| 343 int pow(int exponent) { | 477 int pow(int exponent) { |
| 344 throw "Bigint.pow not implemented"; | 478 throw "Bigint.pow not implemented"; |
| 345 } | 479 } |
| 346 } | 480 } |
| OLD | NEW |