| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // part of "core_patch.dart"; |
| |
| abstract class _IntegerImplementation implements int { |
| @pragma("vm:non-nullable-result-type") |
| num operator +(num other) => other._addFromInteger(this); |
| @pragma("vm:non-nullable-result-type") |
| num operator -(num other) => other._subFromInteger(this); |
| @pragma("vm:non-nullable-result-type") |
| num operator *(num other) => other._mulFromInteger(this); |
| |
| @pragma("vm:non-nullable-result-type") |
| int operator ~/(num other) { |
| if ((other is int) && (other == 0)) { |
| throw const IntegerDivisionByZeroException(); |
| } |
| return other._truncDivFromInteger(this); |
| } |
| |
| double operator /(num other) { |
| return this.toDouble() / other.toDouble(); |
| } |
| |
| @pragma("vm:non-nullable-result-type") |
| num operator %(num other) { |
| if ((other is int) && (other == 0)) { |
| throw const IntegerDivisionByZeroException(); |
| } |
| return other._moduloFromInteger(this); |
| } |
| |
| @pragma("vm:non-nullable-result-type") |
| int operator -() { |
| return 0 - this; |
| } |
| |
| @pragma("vm:non-nullable-result-type") |
| int operator &(int other) => other._bitAndFromInteger(this); |
| @pragma("vm:non-nullable-result-type") |
| int operator |(int other) => other._bitOrFromInteger(this); |
| @pragma("vm:non-nullable-result-type") |
| int operator ^(int other) => other._bitXorFromInteger(this); |
| |
| num remainder(num other) { |
| return other._remainderFromInteger(this); |
| } |
| |
| @pragma("vm:non-nullable-result-type") |
| int _bitAndFromSmi(_Smi other) native "Integer_bitAndFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _bitAndFromInteger(int other) native "Integer_bitAndFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _bitOrFromInteger(int other) native "Integer_bitOrFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _bitXorFromInteger(int other) native "Integer_bitXorFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _shrFromInteger(int other) native "Integer_shrFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _shlFromInteger(int other) native "Integer_shlFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _addFromInteger(int other) native "Integer_addFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _subFromInteger(int other) native "Integer_subFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _mulFromInteger(int other) native "Integer_mulFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _truncDivFromInteger(int other) native "Integer_truncDivFromInteger"; |
| @pragma("vm:non-nullable-result-type") |
| int _moduloFromInteger(int other) native "Integer_moduloFromInteger"; |
| int _remainderFromInteger(int other) { |
| return other - (other ~/ this) * this; |
| } |
| |
| @pragma("vm:non-nullable-result-type") |
| int operator >>(int other) => other._shrFromInteger(this); |
| @pragma("vm:non-nullable-result-type") |
| int operator <<(int other) => other._shlFromInteger(this); |
| |
| @pragma("vm:exact-result-type", bool) |
| bool operator <(num other) { |
| return other > this; |
| } |
| |
| @pragma("vm:exact-result-type", bool) |
| bool operator >(num other) { |
| return other._greaterThanFromInteger(this); |
| } |
| |
| @pragma("vm:exact-result-type", bool) |
| bool operator >=(num other) { |
| return (this == other) || (this > other); |
| } |
| |
| @pragma("vm:exact-result-type", bool) |
| bool operator <=(num other) { |
| return (this == other) || (this < other); |
| } |
| |
| @pragma("vm:exact-result-type", bool) |
| bool _greaterThanFromInteger(int other) |
| native "Integer_greaterThanFromInteger"; |
| |
| @pragma("vm:exact-result-type", bool) |
| bool operator ==(Object other) { |
| if (other is num) { |
| return other._equalToInteger(this); |
| } |
| return false; |
| } |
| |
| @pragma("vm:exact-result-type", bool) |
| bool _equalToInteger(int other) native "Integer_equalToInteger"; |
| int abs() { |
| return this < 0 ? -this : this; |
| } |
| |
| int get sign { |
| return (this > 0) ? 1 : (this < 0) ? -1 : 0; |
| } |
| |
| bool get isEven => ((this & 1) == 0); |
| bool get isOdd => !isEven; |
| bool get isNaN => false; |
| bool get isNegative => this < 0; |
| bool get isInfinite => false; |
| bool get isFinite => true; |
| |
| int toUnsigned(int width) { |
| return this & ((1 << width) - 1); |
| } |
| |
| int toSigned(int width) { |
| // The value of binary number weights each bit by a power of two. The |
| // twos-complement value weights the sign bit negatively. We compute the |
| // value of the negative weighting by isolating the sign bit with the |
| // correct power of two weighting and subtracting it from the value of the |
| // lower bits. |
| int signMask = 1 << (width - 1); |
| return (this & (signMask - 1)) - (this & signMask); |
| } |
| |
| int compareTo(num other) { |
| const int EQUAL = 0, LESS = -1, GREATER = 1; |
| if (other is double) { |
| const int MAX_EXACT_INT_TO_DOUBLE = 9007199254740992; // 2^53. |
| const int MIN_EXACT_INT_TO_DOUBLE = -MAX_EXACT_INT_TO_DOUBLE; |
| const bool limitIntsTo64Bits = ((1 << 64) == 0); |
| if (limitIntsTo64Bits) { |
| // With integers limited to 64 bits, double.toInt() clamps |
| // double value to fit into the MIN_INT64..MAX_INT64 range. |
| // Check if the double value is outside of this range. |
| // This check handles +/-infinity as well. |
| const double minInt64AsDouble = -9223372036854775808.0; |
| // MAX_INT64 is not precisely representable in doubles, so |
| // check against (MAX_INT64 + 1). |
| const double maxInt64Plus1AsDouble = 9223372036854775808.0; |
| if (other < minInt64AsDouble) { |
| return GREATER; |
| } else if (other >= maxInt64Plus1AsDouble) { |
| return LESS; |
| } |
| } else { |
| if (other.isInfinite) { |
| return other.isNegative ? GREATER : LESS; |
| } |
| } |
| if (other.isNaN) { |
| return LESS; |
| } |
| if (MIN_EXACT_INT_TO_DOUBLE <= this && this <= MAX_EXACT_INT_TO_DOUBLE) { |
| // Let the double implementation deal with -0.0. |
| return -(other.compareTo(this.toDouble())); |
| } else { |
| // If abs(other) > MAX_EXACT_INT_TO_DOUBLE, then other has an integer |
| // value (no bits below the decimal point). |
| other = other.toInt(); |
| } |
| } |
| if (this < other) { |
| return LESS; |
| } else if (this > other) { |
| return GREATER; |
| } else { |
| return EQUAL; |
| } |
| } |
| |
| int round() { |
| return this; |
| } |
| |
| int floor() { |
| return this; |
| } |
| |
| int ceil() { |
| return this; |
| } |
| |
| int truncate() { |
| return this; |
| } |
| |
| double roundToDouble() { |
| return this.toDouble(); |
| } |
| |
| double floorToDouble() { |
| return this.toDouble(); |
| } |
| |
| double ceilToDouble() { |
| return this.toDouble(); |
| } |
| |
| double truncateToDouble() { |
| return this.toDouble(); |
| } |
| |
| num clamp(num lowerLimit, num upperLimit) { |
| if (lowerLimit is! num) { |
| throw new ArgumentError.value(lowerLimit, "lowerLimit", "not a number"); |
| } |
| if (upperLimit is! num) { |
| throw new ArgumentError.value(upperLimit, "upperLimit", "not a number"); |
| } |
| |
| // Special case for integers. |
| if (lowerLimit is int && upperLimit is int && lowerLimit <= upperLimit) { |
| if (this < lowerLimit) return lowerLimit; |
| if (this > upperLimit) return upperLimit; |
| return this; |
| } |
| // Generic case involving doubles, and invalid integer ranges. |
| if (lowerLimit.compareTo(upperLimit) > 0) { |
| throw new ArgumentError(lowerLimit); |
| } |
| if (lowerLimit.isNaN) return lowerLimit; |
| // Note that we don't need to care for -0.0 for the lower limit. |
| if (this < lowerLimit) return lowerLimit; |
| if (this.compareTo(upperLimit) > 0) return upperLimit; |
| return this; |
| } |
| |
| int toInt() { |
| return this; |
| } |
| |
| @pragma("vm:exact-result-type", _Double) |
| double toDouble() { |
| return new _Double.fromInteger(this); |
| } |
| |
| String toStringAsFixed(int fractionDigits) { |
| return this.toDouble().toStringAsFixed(fractionDigits); |
| } |
| |
| String toStringAsExponential([int fractionDigits]) { |
| return this.toDouble().toStringAsExponential(fractionDigits); |
| } |
| |
| String toStringAsPrecision(int precision) { |
| return this.toDouble().toStringAsPrecision(precision); |
| } |
| |
| static const _digits = "0123456789abcdefghijklmnopqrstuvwxyz"; |
| |
| String toRadixString(int radix) { |
| if (radix < 2 || 36 < radix) { |
| throw new RangeError.range(radix, 2, 36, "radix"); |
| } |
| if (radix & (radix - 1) == 0) { |
| return _toPow2String(radix); |
| } |
| if (radix == 10) return this.toString(); |
| final bool isNegative = this < 0; |
| int value = isNegative ? -this : this; |
| if (value < 0) { |
| // With integers limited to 64 bits, the value |
| // MIN_INT64 = -0x8000000000000000 overflows at negation: |
| // -MIN_INT64 == MIN_INT64, so it requires special handling. |
| return _minInt64ToRadixString(radix); |
| } |
| List temp = new List(); |
| do { |
| int digit = value % radix; |
| value ~/= radix; |
| temp.add(_digits.codeUnitAt(digit)); |
| } while (value > 0); |
| if (isNegative) temp.add(0x2d); // '-'. |
| |
| _OneByteString string = _OneByteString._allocate(temp.length); |
| for (int i = 0, j = temp.length; j > 0; i++) { |
| string._setAt(i, temp[--j]); |
| } |
| return string; |
| } |
| |
| String _toPow2String(int radix) { |
| int value = this; |
| if (value == 0) return "0"; |
| assert(radix & (radix - 1) == 0); |
| var negative = value < 0; |
| var bitsPerDigit = radix.bitLength - 1; |
| var length = 0; |
| if (negative) { |
| value = -value; |
| length = 1; |
| if (value < 0) { |
| // With integers limited to 64 bits, the value |
| // MIN_INT64 = -0x8000000000000000 overflows at negation: |
| // -MIN_INT64 == MIN_INT64, so it requires special handling. |
| return _minInt64ToRadixString(radix); |
| } |
| } |
| // Integer division, rounding up, to find number of _digits. |
| length += (value.bitLength + bitsPerDigit - 1) ~/ bitsPerDigit; |
| _OneByteString string = _OneByteString._allocate(length); |
| string._setAt(0, 0x2d); // '-'. Is overwritten if not negative. |
| var mask = radix - 1; |
| do { |
| string._setAt(--length, _digits.codeUnitAt(value & mask)); |
| value >>= bitsPerDigit; |
| } while (value > 0); |
| return string; |
| } |
| |
| /// Converts negative value to radix string. |
| /// This method is only used to handle corner case of |
| /// MIN_INT64 = -0x8000000000000000. |
| String _minInt64ToRadixString(int radix) { |
| List temp = new List(); |
| int value = this; |
| assert(value < 0); |
| do { |
| int digit = -value.remainder(radix); |
| value ~/= radix; |
| temp.add(_digits.codeUnitAt(digit)); |
| } while (value != 0); |
| temp.add(0x2d); // '-'. |
| |
| _OneByteString string = _OneByteString._allocate(temp.length); |
| for (int i = 0, j = temp.length; j > 0; i++) { |
| string._setAt(i, temp[--j]); |
| } |
| return string; |
| } |
| |
| // Returns pow(this, e) % m. |
| int modPow(int e, int m) { |
| if (e is! int) { |
| throw new ArgumentError.value(e, "exponent", "not an integer"); |
| } |
| if (m is! int) { |
| throw new ArgumentError.value(m, "modulus", "not an integer"); |
| } |
| if (e < 0) throw new RangeError.range(e, 0, null, "exponent"); |
| if (m <= 0) throw new RangeError.range(m, 1, null, "modulus"); |
| if (e == 0) return 1; |
| int b = this; |
| if (b < 0 || b > m) { |
| b %= m; |
| } |
| int r = 1; |
| while (e > 0) { |
| if (e.isOdd) { |
| r = (r * b) % m; |
| } |
| e >>= 1; |
| b = (b * b) % m; |
| } |
| return r; |
| } |
| |
| // If inv is false, returns gcd(x, y). |
| // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1. |
| // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime"). |
| static int _binaryGcd(int x, int y, bool inv) { |
| int s = 0; |
| if (!inv) { |
| while (x.isEven && y.isEven) { |
| x >>= 1; |
| y >>= 1; |
| s++; |
| } |
| if (y.isOdd) { |
| var t = x; |
| x = y; |
| y = t; |
| } |
| } |
| final bool ac = x.isEven; |
| int u = x; |
| int v = y; |
| int a = 1, b = 0, c = 0, d = 1; |
| do { |
| while (u.isEven) { |
| u >>= 1; |
| if (ac) { |
| if (!a.isEven || !b.isEven) { |
| a += y; |
| b -= x; |
| } |
| a >>= 1; |
| } else if (!b.isEven) { |
| b -= x; |
| } |
| b >>= 1; |
| } |
| while (v.isEven) { |
| v >>= 1; |
| if (ac) { |
| if (!c.isEven || !d.isEven) { |
| c += y; |
| d -= x; |
| } |
| c >>= 1; |
| } else if (!d.isEven) { |
| d -= x; |
| } |
| d >>= 1; |
| } |
| if (u >= v) { |
| u -= v; |
| if (ac) a -= c; |
| b -= d; |
| } else { |
| v -= u; |
| if (ac) c -= a; |
| d -= b; |
| } |
| } while (u != 0); |
| if (!inv) return v << s; |
| if (v != 1) { |
| throw new Exception("Not coprime"); |
| } |
| if (d < 0) { |
| d += x; |
| if (d < 0) d += x; |
| } else if (d > x) { |
| d -= x; |
| if (d > x) d -= x; |
| } |
| return d; |
| } |
| |
| // Returns 1/this % m, with m > 0. |
| int modInverse(int m) { |
| if (m is! int) { |
| throw new ArgumentError.value(m, "modulus", "not an integer"); |
| } |
| if (m <= 0) throw new RangeError.range(m, 1, null, "modulus"); |
| if (m == 1) return 0; |
| int t = this; |
| if ((t < 0) || (t >= m)) t %= m; |
| if (t == 1) return 1; |
| if ((t == 0) || (t.isEven && m.isEven)) { |
| throw new Exception("Not coprime"); |
| } |
| return _binaryGcd(m, t, true); |
| } |
| |
| // Returns gcd of abs(this) and abs(other). |
| int gcd(int other) { |
| if (other is! int) { |
| throw new ArgumentError.value(other, "other", "not an integer"); |
| } |
| int x = this.abs(); |
| int y = other.abs(); |
| if (x == 0) return y; |
| if (y == 0) return x; |
| if ((x == 1) || (y == 1)) return 1; |
| return _binaryGcd(x, y, false); |
| } |
| } |
| |
| @pragma("vm:entry-point") |
| class _Smi extends _IntegerImplementation { |
| factory _Smi._uninstantiable() { |
| throw new UnsupportedError("_Smi can only be allocated by the VM"); |
| } |
| int get hashCode => this; |
| int get _identityHashCode => this; |
| @pragma("vm:exact-result-type", "dart:core#_Smi") |
| int operator ~() native "Smi_bitNegate"; |
| @pragma("vm:exact-result-type", "dart:core#_Smi") |
| int get bitLength native "Smi_bitLength"; |
| |
| int operator &(int other) => other._bitAndFromSmi(this); |
| |
| @pragma("vm:exact-result-type", "dart:core#_Smi") |
| int _bitAndFromSmi(_Smi other) native "Smi_bitAndFromSmi"; |
| |
| /** |
| * The digits of '00', '01', ... '99' as a single array. |
| * |
| * Get the digits of `n`, with `0 <= n < 100`, as |
| * `_digitTable[n * 2]` and `_digitTable[n * 2 + 1]`. |
| */ |
| static const _digitTable = const [ |
| 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, // |
| 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, // |
| 0x30, 0x38, 0x30, 0x39, 0x31, 0x30, 0x31, 0x31, // |
| 0x31, 0x32, 0x31, 0x33, 0x31, 0x34, 0x31, 0x35, // |
| 0x31, 0x36, 0x31, 0x37, 0x31, 0x38, 0x31, 0x39, // |
| 0x32, 0x30, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33, // |
| 0x32, 0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, // |
| 0x32, 0x38, 0x32, 0x39, 0x33, 0x30, 0x33, 0x31, // |
| 0x33, 0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35, // |
| 0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39, // |
| 0x34, 0x30, 0x34, 0x31, 0x34, 0x32, 0x34, 0x33, // |
| 0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x34, 0x37, // |
| 0x34, 0x38, 0x34, 0x39, 0x35, 0x30, 0x35, 0x31, // |
| 0x35, 0x32, 0x35, 0x33, 0x35, 0x34, 0x35, 0x35, // |
| 0x35, 0x36, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39, // |
| 0x36, 0x30, 0x36, 0x31, 0x36, 0x32, 0x36, 0x33, // |
| 0x36, 0x34, 0x36, 0x35, 0x36, 0x36, 0x36, 0x37, // |
| 0x36, 0x38, 0x36, 0x39, 0x37, 0x30, 0x37, 0x31, // |
| 0x37, 0x32, 0x37, 0x33, 0x37, 0x34, 0x37, 0x35, // |
| 0x37, 0x36, 0x37, 0x37, 0x37, 0x38, 0x37, 0x39, // |
| 0x38, 0x30, 0x38, 0x31, 0x38, 0x32, 0x38, 0x33, // |
| 0x38, 0x34, 0x38, 0x35, 0x38, 0x36, 0x38, 0x37, // |
| 0x38, 0x38, 0x38, 0x39, 0x39, 0x30, 0x39, 0x31, // |
| 0x39, 0x32, 0x39, 0x33, 0x39, 0x34, 0x39, 0x35, // |
| 0x39, 0x36, 0x39, 0x37, 0x39, 0x38, 0x39, 0x39, // |
| ]; |
| |
| /** |
| * Result of int.toString for -99, -98, ..., 98, 99. |
| */ |
| static const _smallLookupTable = const [ |
| "-99", "-98", "-97", "-96", "-95", "-94", "-93", "-92", "-91", "-90", // |
| "-89", "-88", "-87", "-86", "-85", "-84", "-83", "-82", "-81", "-80", // |
| "-79", "-78", "-77", "-76", "-75", "-74", "-73", "-72", "-71", "-70", // |
| "-69", "-68", "-67", "-66", "-65", "-64", "-63", "-62", "-61", "-60", // |
| "-59", "-58", "-57", "-56", "-55", "-54", "-53", "-52", "-51", "-50", // |
| "-49", "-48", "-47", "-46", "-45", "-44", "-43", "-42", "-41", "-40", // |
| "-39", "-38", "-37", "-36", "-35", "-34", "-33", "-32", "-31", "-30", // |
| "-29", "-28", "-27", "-26", "-25", "-24", "-23", "-22", "-21", "-20", // |
| "-19", "-18", "-17", "-16", "-15", "-14", "-13", "-12", "-11", "-10", // |
| "-9", "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", "0", // |
| "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", // |
| "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", // |
| "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", // |
| "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", // |
| "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", // |
| "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", // |
| "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", // |
| "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", // |
| "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", // |
| "91", "92", "93", "94", "95", "96", "97", "98", "99" // |
| ]; |
| |
| // Powers of 10 above 1000000 are indistinguishable by eye. |
| static const int _POW_10_7 = 10000000; |
| static const int _POW_10_8 = 100000000; |
| static const int _POW_10_9 = 1000000000; |
| |
| // Find the number of decimal digits in a positive smi. |
| // Never called with numbers < 100. These are handled before calling. |
| static int _positiveBase10Length(var smi) { |
| // A positive smi has length <= 19 if 63-bit, <=10 if 31-bit. |
| // Avoid comparing a 31-bit smi to a non-smi. |
| if (smi < 1000) return 3; |
| if (smi < 10000) return 4; |
| if (smi < _POW_10_7) { |
| if (smi < 100000) return 5; |
| if (smi < 1000000) return 6; |
| return 7; |
| } |
| if (smi < _POW_10_8) return 8; |
| if (smi < _POW_10_9) return 9; |
| smi = smi ~/ _POW_10_9; |
| // Handle numbers < 100 before calling recursively. |
| if (smi < 10) return 10; |
| if (smi < 100) return 11; |
| return 9 + _positiveBase10Length(smi); |
| } |
| |
| String toString() { |
| if (this < 100 && this > -100) return _smallLookupTable[this + 99]; |
| if (this < 0) return _negativeToString(this); |
| // Inspired by Andrei Alexandrescu: "Three Optimization Tips for C++" |
| // Avoid expensive remainder operation by doing it on more than |
| // one digit at a time. |
| const int DIGIT_ZERO = 0x30; |
| int length = _positiveBase10Length(this); |
| _OneByteString result = _OneByteString._allocate(length); |
| int index = length - 1; |
| var smi = this; |
| do { |
| // Two digits at a time. |
| var twoDigits = smi.remainder(100); |
| smi = smi ~/ 100; |
| int digitIndex = twoDigits * 2; |
| result._setAt(index, _digitTable[digitIndex + 1]); |
| result._setAt(index - 1, _digitTable[digitIndex]); |
| index -= 2; |
| } while (smi >= 100); |
| if (smi < 10) { |
| // Character code for '0'. |
| result._setAt(index, DIGIT_ZERO + smi); |
| } else { |
| // No remainder for this case. |
| int digitIndex = smi * 2; |
| result._setAt(index, _digitTable[digitIndex + 1]); |
| result._setAt(index - 1, _digitTable[digitIndex]); |
| } |
| return result; |
| } |
| |
| // Find the number of decimal digits in a negative smi. |
| // Never called with numbers > -100. These are handled before calling. |
| static int _negativeBase10Length(var negSmi) { |
| // A negative smi has length <= 19 if 63-bit, <=10 if 31-bit. |
| // Avoid comparing a 31-bit smi to a non-smi. |
| if (negSmi > -1000) return 3; |
| if (negSmi > -10000) return 4; |
| if (negSmi > -_POW_10_7) { |
| if (negSmi > -100000) return 5; |
| if (negSmi > -1000000) return 6; |
| return 7; |
| } |
| if (negSmi > -_POW_10_8) return 8; |
| if (negSmi > -_POW_10_9) return 9; |
| negSmi = negSmi ~/ _POW_10_9; |
| // Handle numbers > -100 before calling recursively. |
| if (negSmi > -10) return 10; |
| if (negSmi > -100) return 11; |
| return 9 + _negativeBase10Length(negSmi); |
| } |
| |
| // Convert a negative smi to a string. |
| // Doesn't negate the smi to avoid negating the most negative smi, which |
| // would become a non-smi. |
| static String _negativeToString(int negSmi) { |
| // Character code for '-' |
| const int MINUS_SIGN = 0x2d; |
| // Character code for '0'. |
| const int DIGIT_ZERO = 0x30; |
| if (negSmi > -10) { |
| return _OneByteString._allocate(2) |
| .._setAt(0, MINUS_SIGN) |
| .._setAt(1, DIGIT_ZERO - negSmi); |
| } |
| if (negSmi > -100) { |
| int digitIndex = 2 * -negSmi; |
| return _OneByteString._allocate(3) |
| .._setAt(0, MINUS_SIGN) |
| .._setAt(1, _digitTable[digitIndex]) |
| .._setAt(2, _digitTable[digitIndex + 1]); |
| } |
| // Number of digits, not including minus. |
| int digitCount = _negativeBase10Length(negSmi); |
| _OneByteString result = _OneByteString._allocate(digitCount + 1); |
| result._setAt(0, MINUS_SIGN); // '-'. |
| int index = digitCount; |
| do { |
| var twoDigits = negSmi.remainder(100); |
| negSmi = negSmi ~/ 100; |
| int digitIndex = -twoDigits * 2; |
| result._setAt(index, _digitTable[digitIndex + 1]); |
| result._setAt(index - 1, _digitTable[digitIndex]); |
| index -= 2; |
| } while (negSmi <= -100); |
| if (negSmi > -10) { |
| result._setAt(index, DIGIT_ZERO - negSmi); |
| } else { |
| // No remainder necessary for this case. |
| int digitIndex = -negSmi * 2; |
| result._setAt(index, _digitTable[digitIndex + 1]); |
| result._setAt(index - 1, _digitTable[digitIndex]); |
| } |
| return result; |
| } |
| } |
| |
| // Represents integers that cannot be represented by Smi but fit into 64bits. |
| @pragma("vm:entry-point") |
| class _Mint extends _IntegerImplementation { |
| factory _Mint._uninstantiable() { |
| throw new UnsupportedError("_Mint can only be allocated by the VM"); |
| } |
| int get hashCode => this; |
| int get _identityHashCode => this; |
| @pragma("vm:non-nullable-result-type") |
| int operator ~() native "Mint_bitNegate"; |
| @pragma("vm:exact-result-type", "dart:core#_Smi") |
| int get bitLength native "Mint_bitLength"; |
| |
| int _bitAndFromSmi(_Smi other) => _bitAndFromInteger(other); |
| } |