ce4b15c0e9
- bit length
- truncate to signed fixed width integer
- truncate to unsigned fixed width integer
This change is motivated by a program that spends 20-30% of its time here:
// TODO(5828): Replace this with a bit-length method on int when available.
int n_bitLength = this.n.toRadixString(2).length;
See Also
https://code.google.com/p/dart/issues/detail?id=5828#c3
https://code.google.com/p/dart/issues/detail?id=6486#c2
https://code.google.com/p/dart/issues/detail?id=5798#c5
https://code.google.com/p/dart/issues/detail?id=12008
R=lrn@google.com, srdjan@google.com
Review URL: https://codereview.chromium.org//23645003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@27269 260f80e4-7a28-3924-810f-c04153c831b5
311 lines
9.3 KiB
Dart
311 lines
9.3 KiB
Dart
// 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.
|
|
|
|
// TODO(srdjan): fix limitations.
|
|
// - shift amount must be a Smi.
|
|
class _IntegerImplementation {
|
|
factory _IntegerImplementation._uninstantiable() {
|
|
throw new UnsupportedError(
|
|
"_IntegerImplementation can only be allocated by the VM");
|
|
}
|
|
num operator +(num other) {
|
|
return other._addFromInteger(this);
|
|
}
|
|
num operator -(num other) {
|
|
return other._subFromInteger(this);
|
|
}
|
|
num operator *(num other) {
|
|
return other._mulFromInteger(this);
|
|
}
|
|
num operator ~/(num other) {
|
|
if ((other is int) && (other == 0)) {
|
|
throw const IntegerDivisionByZeroException();
|
|
}
|
|
return other._truncDivFromInteger(this);
|
|
}
|
|
num operator /(num other) {
|
|
return this.toDouble() / other.toDouble();
|
|
}
|
|
num operator %(num other) {
|
|
if ((other is int) && (other == 0)) {
|
|
throw const IntegerDivisionByZeroException();
|
|
}
|
|
return other._moduloFromInteger(this);
|
|
}
|
|
int operator -() {
|
|
return 0 - this;
|
|
}
|
|
int operator &(int other) {
|
|
return other._bitAndFromInteger(this);
|
|
}
|
|
int operator |(int other) {
|
|
return other._bitOrFromInteger(this);
|
|
}
|
|
int operator ^(int other) {
|
|
return other._bitXorFromInteger(this);
|
|
}
|
|
num remainder(num other) {
|
|
return other._remainderFromInteger(this);
|
|
}
|
|
int _bitAndFromInteger(int other) native "Integer_bitAndFromInteger";
|
|
int _bitOrFromInteger(int other) native "Integer_bitOrFromInteger";
|
|
int _bitXorFromInteger(int other) native "Integer_bitXorFromInteger";
|
|
int _addFromInteger(int other) native "Integer_addFromInteger";
|
|
int _subFromInteger(int other) native "Integer_subFromInteger";
|
|
int _mulFromInteger(int other) native "Integer_mulFromInteger";
|
|
int _truncDivFromInteger(int other) native "Integer_truncDivFromInteger";
|
|
int _moduloFromInteger(int other) native "Integer_moduloFromInteger";
|
|
int _remainderFromInteger(int other) {
|
|
return other - (other ~/ this) * this;
|
|
}
|
|
int operator >>(int other) {
|
|
return other._shrFromInt(this);
|
|
}
|
|
int operator <<(int other) {
|
|
return other._shlFromInt(this);
|
|
}
|
|
bool operator <(num other) {
|
|
return other > this;
|
|
}
|
|
bool operator >(num other) {
|
|
return other._greaterThanFromInteger(this);
|
|
}
|
|
bool operator >=(num other) {
|
|
return (this == other) || (this > other);
|
|
}
|
|
bool operator <=(num other) {
|
|
return (this == other) || (this < other);
|
|
}
|
|
bool _greaterThanFromInteger(int other)
|
|
native "Integer_greaterThanFromInteger";
|
|
bool operator ==(other) {
|
|
if (other is num) {
|
|
return other._equalToInteger(this);
|
|
}
|
|
return false;
|
|
}
|
|
bool _equalToInteger(int other) native "Integer_equalToInteger";
|
|
int abs() {
|
|
return this < 0 ? -this : this;
|
|
}
|
|
bool get isEven => ((this & 1) == 0);
|
|
bool get isOdd => !isEven;
|
|
bool get isNaN => false;
|
|
bool get isNegative => this < 0;
|
|
bool get isInfinite => false;
|
|
|
|
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) {
|
|
final int EQUAL = 0, LESS = -1, GREATER = 1;
|
|
if (other is double) {
|
|
// TODO(floitsch): the following locals should be 'const'.
|
|
int MAX_EXACT_INT_TO_DOUBLE = 9007199254740992; // 2^53.
|
|
int MIN_EXACT_INT_TO_DOUBLE = -MAX_EXACT_INT_TO_DOUBLE;
|
|
double d = other;
|
|
if (d.isInfinite) {
|
|
return d == double.NEGATIVE_INFINITY ? GREATER : LESS;
|
|
}
|
|
if (d.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 -(d.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 = d.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(lowerLimit);
|
|
if (upperLimit is! num) throw new ArgumentError(upperLimit);
|
|
|
|
// Special case for integers.
|
|
if (lowerLimit is int && upperLimit is int) {
|
|
if (lowerLimit > upperLimit) {
|
|
throw new ArgumentError(lowerLimit);
|
|
}
|
|
if (this < lowerLimit) return lowerLimit;
|
|
if (this > upperLimit) return upperLimit;
|
|
return this;
|
|
}
|
|
// Generic case involving doubles.
|
|
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; }
|
|
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);
|
|
}
|
|
|
|
String toRadixString(int radix) {
|
|
final table = const ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
|
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
|
|
"k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
|
|
"u", "v", "w", "x", "y", "z"];
|
|
if (radix is! int || radix < 2 || radix > 36) {
|
|
throw new ArgumentError(radix);
|
|
}
|
|
final bool isNegative = this < 0;
|
|
int value = isNegative ? -this : this;
|
|
List temp = new List();
|
|
while (value > 0) {
|
|
int digit = value % radix;
|
|
value ~/= radix;
|
|
temp.add(digit);
|
|
}
|
|
if (temp.isEmpty) {
|
|
return "0";
|
|
}
|
|
StringBuffer buffer = new StringBuffer();
|
|
if (isNegative) buffer.write("-");
|
|
for (int i = temp.length - 1; i >= 0; i--) {
|
|
buffer.write(table[temp[i]]);
|
|
}
|
|
return buffer.toString();
|
|
}
|
|
|
|
_leftShiftWithMask32(count, mask) native "Integer_leftShiftWithMask32";
|
|
}
|
|
|
|
class _Smi extends _IntegerImplementation implements int {
|
|
factory _Smi._uninstantiable() {
|
|
throw new UnsupportedError(
|
|
"_Smi can only be allocated by the VM");
|
|
}
|
|
int get hashCode {
|
|
return this;
|
|
}
|
|
int operator ~() native "Smi_bitNegate";
|
|
int get bitLength native "Smi_bitLength";
|
|
|
|
int _shrFromInt(int other) native "Smi_shrFromInt";
|
|
int _shlFromInt(int other) native "Smi_shlFromInt";
|
|
|
|
String toString() {
|
|
if (this == 0) return "0";
|
|
var reversed = new List();
|
|
var val = this < 0 ? -this : this;
|
|
while (val > 0) {
|
|
reversed.add((val % 10) + 0x30);
|
|
val = val ~/ 10;
|
|
}
|
|
final int numDigits = reversed.length;
|
|
List digits;
|
|
int i;
|
|
if (this < 0) {
|
|
digits = new List(numDigits + 1);
|
|
digits[0] = 0x2D; // '-'.
|
|
i = 1;
|
|
} else {
|
|
digits = new List(numDigits);
|
|
i = 0;
|
|
}
|
|
int ri = reversed.length - 1;
|
|
for (; i < digits.length; i++, ri--) {
|
|
digits[i] = reversed[ri];
|
|
}
|
|
return _StringBase.createFromCharCodes(digits);
|
|
}
|
|
}
|
|
|
|
// Represents integers that cannot be represented by Smi but fit into 64bits.
|
|
class _Mint extends _IntegerImplementation implements int {
|
|
factory _Mint._uninstantiable() {
|
|
throw new UnsupportedError(
|
|
"_Mint can only be allocated by the VM");
|
|
}
|
|
int get hashCode {
|
|
return this;
|
|
}
|
|
int operator ~() native "Mint_bitNegate";
|
|
int get bitLength native "Mint_bitLength";
|
|
|
|
// Shift by mint exceeds range that can be handled by the VM.
|
|
int _shrFromInt(int other) {
|
|
if (other < 0) {
|
|
return -1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
int _shlFromInt(int other) native "Mint_shlFromInt";
|
|
}
|
|
|
|
// A number that can be represented as Smi or Mint will never be represented as
|
|
// Bigint.
|
|
class _Bigint extends _IntegerImplementation implements int {
|
|
factory _Bigint._uninstantiable() {
|
|
throw new UnsupportedError(
|
|
"_Bigint can only be allocated by the VM");
|
|
}
|
|
int get hashCode {
|
|
return this;
|
|
}
|
|
int operator ~() native "Bigint_bitNegate";
|
|
int get bitLength native "Bigint_bitLength";
|
|
|
|
// Shift by bigint exceeds range that can be handled by the VM.
|
|
int _shrFromInt(int other) {
|
|
if (other < 0) {
|
|
return -1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
int _shlFromInt(int other) native "Bigint_shlFromInt";
|
|
|
|
int pow(int exponent) {
|
|
throw "Bigint.pow not implemented";
|
|
}
|
|
}
|