Make bitshifts work at bitwidth boundaries
Without this fix, new Int64(3) << 64 == Int64(3). This ensures that the result is 0 in such cases.
diff --git a/lib/src/int32.dart b/lib/src/int32.dart
index 562ff0c..db8ecd0 100644
--- a/lib/src/int32.dart
+++ b/lib/src/int32.dart
@@ -239,7 +239,9 @@
if (n < 0) {
throw new ArgumentError(n);
}
- n &= 31;
+ if (n >= 32) {
+ return ZERO;
+ }
return new Int32(_i << n);
}
@@ -247,7 +249,9 @@
if (n < 0) {
throw new ArgumentError(n);
}
- n &= 31;
+ if (n >= 32) {
+ return isNegative ? const Int32._internal(-1) : ZERO;
+ }
int value;
if (_i >= 0) {
value = _i >> n;
@@ -261,7 +265,9 @@
if (n < 0) {
throw new ArgumentError(n);
}
- n &= 31;
+ if (n >= 32) {
+ return ZERO;
+ }
int value;
if (_i >= 0) {
value = _i >> n;
diff --git a/lib/src/int64.dart b/lib/src/int64.dart
index c25b8fa..a84cbd9 100644
--- a/lib/src/int64.dart
+++ b/lib/src/int64.dart
@@ -343,7 +343,9 @@
if (n < 0) {
throw new ArgumentError.value(n);
}
- n &= 63;
+ if (n >= 64) {
+ return ZERO;
+ }
int res0, res1, res2;
if (n < _BITS) {
@@ -367,7 +369,9 @@
if (n < 0) {
throw new ArgumentError.value(n);
}
- n &= 63;
+ if (n >= 64) {
+ return isNegative ? const Int64._bits(_MASK, _MASK, _MASK2) : ZERO;
+ }
int res0, res1, res2;
@@ -410,7 +414,9 @@
if (n < 0) {
throw new ArgumentError.value(n);
}
- n &= 63;
+ if (n >= 64) {
+ return ZERO;
+ }
int res0, res1, res2;
int a2 = _MASK2 & _h; // Ensure a2 is positive.
diff --git a/test/int32_test.dart b/test/int32_test.dart
index 63149cf..afa7eeb 100644
--- a/test/int32_test.dart
+++ b/test/int32_test.dart
@@ -294,12 +294,18 @@
group("bitshift operators", () {
test("<<", () {
expect(new Int32(0x12345678) << 7, new Int32(0x12345678 << 7));
+ expect(new Int32(0x12345678) << 32, Int32.ZERO);
+ expect(new Int32(0x12345678) << 33, Int32.ZERO);
expect(() => new Int32(17) << -1, throwsArgumentError);
expect(() => new Int32(17) << null, throwsNoSuchMethodError);
});
test(">>", () {
expect(new Int32(0x12345678) >> 7, new Int32(0x12345678 >> 7));
+ expect(new Int32(0x12345678) >> 32, Int32.ZERO);
+ expect(new Int32(0x12345678) >> 33, Int32.ZERO);
+ expect(new Int32(-42) >> 32, new Int32(-1));
+ expect(new Int32(-42) >> 33, new Int32(-1));
expect(() => new Int32(17) >> -1, throwsArgumentError);
expect(() => new Int32(17) >> null, throwsNoSuchMethodError);
});
@@ -307,6 +313,10 @@
test("shiftRightUnsigned", () {
expect(new Int32(0x12345678).shiftRightUnsigned(7),
new Int32(0x12345678 >> 7));
+ expect(new Int32(0x12345678).shiftRightUnsigned(32), Int32.ZERO);
+ expect(new Int32(0x12345678).shiftRightUnsigned(33), Int32.ZERO);
+ expect(new Int32(-42).shiftRightUnsigned(32), Int32.ZERO);
+ expect(new Int32(-42).shiftRightUnsigned(33), Int32.ZERO);
expect(() => (new Int32(17).shiftRightUnsigned(-1)), throwsArgumentError);
expect(() => (new Int32(17).shiftRightUnsigned(null)),
throwsNoSuchMethodError);
diff --git a/test/int64_test.dart b/test/int64_test.dart
index fbd008d..8106c2e 100644
--- a/test/int64_test.dart
+++ b/test/int64_test.dart
@@ -494,6 +494,8 @@
new Int64.fromInts(0xd048d115, 0x9d159c00));
expect(new Int64(-1) << 5, new Int64(-32));
expect(new Int64(-1) << 0, new Int64(-1));
+ expect(new Int64(42) << 64, Int64.ZERO);
+ expect(new Int64(42) << 65, Int64.ZERO);
expect(() => new Int64(17) << -1, throwsArgumentError);
expect(() => new Int64(17) << null, throwsNoSuchMethodError);
});
@@ -506,6 +508,8 @@
new Int64.fromInts(0xffe48d04, 0x8d1159d1));
expect(
new Int64.fromInts(0xFFFFFFF, 0xFFFFFFFF) >> 34, new Int64(67108863));
+ expect(new Int64(42) >> 64, Int64.ZERO);
+ expect(new Int64(42) >> 65, Int64.ZERO);
for (int n = 0; n <= 66; n++) {
expect(new Int64(-1) >> n, new Int64(-1));
}
@@ -590,6 +594,8 @@
new Int64.fromInts(0x00000000, 0x00092345));
expect(new Int64.fromInts(0x00000000, 0x00009234),
new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(48));
+ expect(new Int64(-1).shiftRightUnsigned(64), Int64.ZERO);
+ expect(new Int64(1).shiftRightUnsigned(64), Int64.ZERO);
expect(() => new Int64(17).shiftRightUnsigned(-1), throwsArgumentError);
expect(() => new Int64(17).shiftRightUnsigned(null),
throwsNoSuchMethodError);