From 9a1da4d9d0e669ce278ca98316200f193136b144 Mon Sep 17 00:00:00 2001 From: skyoxZ Date: Fri, 5 Apr 2024 02:33:05 +0800 Subject: [PATCH] Fix `Int128` checked-convert to signed IntX (#100342) * Fix Int128 checked-convert to signed IntX * Simplify implementation --- .../src/System/Int128.cs | 55 +++++-------------- .../System/Int128Tests.cs | 45 +++++++++++++++ 2 files changed, 60 insertions(+), 40 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index 12cc6c7dec562..c1e6c459f7b54 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -262,17 +262,12 @@ public static explicit operator Half(Int128 value) /// is not representable by . public static explicit operator checked short(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return checked((short)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((short)value._lower); + return checked((short)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -286,17 +281,12 @@ public static explicit operator checked short(Int128 value) /// is not representable by . public static explicit operator checked int(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return checked((int)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((int)value._lower); + return checked((int)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -310,17 +300,12 @@ public static explicit operator checked int(Int128 value) /// is not representable by . public static explicit operator checked long(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return lower; - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((long)value._lower); + return lower; } /// Explicitly converts a 128-bit signed integer to a value. @@ -334,17 +319,12 @@ public static explicit operator checked long(Int128 value) /// is not representable by . public static explicit operator checked nint(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return checked((nint)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((nint)value._lower); + return checked((nint)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -360,17 +340,12 @@ public static explicit operator checked nint(Int128 value) [CLSCompliant(false)] public static explicit operator checked sbyte(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return checked((sbyte)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((sbyte)value._lower); + return checked((sbyte)lower); } /// Explicitly converts a 128-bit signed integer to a value. diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs index 8c1910e2fbd8d..9b9103b56ec20 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs @@ -107,6 +107,51 @@ public static void EqualsTest(Int128 i1, object obj, bool expected) Assert.Equal(expected, i1.Equals(obj)); } + [Fact] + public static void CheckedConvertToInt64() + { + Assert.Equal(123L, checked((long)new Int128(0, 123))); + Assert.Equal(-123L, checked((long)(Int128)(-123))); + Assert.Throws(() => checked((long)new Int128(1, 1))); + Assert.Throws(() => checked((long)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToInt32() + { + Assert.Equal(123, checked((int)new Int128(0, 123))); + Assert.Equal(-123, checked((int)(Int128)(-123))); + Assert.Throws(() => checked((int)new Int128(1, 1))); + Assert.Throws(() => checked((int)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToInt16() + { + Assert.Equal((short)123, checked((short)new Int128(0, 123))); + Assert.Equal((short)(-123), checked((short)(Int128)(-123))); + Assert.Throws(() => checked((short)new Int128(1, 1))); + Assert.Throws(() => checked((short)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToSByte() + { + Assert.Equal((sbyte)123, checked((sbyte)new Int128(0, 123))); + Assert.Equal((sbyte)(-123), checked((sbyte)(Int128)(-123))); + Assert.Throws(() => checked((sbyte)new Int128(1, 1))); + Assert.Throws(() => checked((sbyte)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToIntPtr() + { + Assert.Equal((nint)123, checked((nint)new Int128(0, 123))); + Assert.Equal((nint)(-123), checked((nint)(Int128)(-123))); + Assert.Throws(() => checked((nint)new Int128(1, 1))); + Assert.Throws(() => checked((nint)new Int128(ulong.MaxValue, 42))); + } + public static IEnumerable ToString_TestData() { foreach (NumberFormatInfo defaultFormat in new[] { null, NumberFormatInfo.CurrentInfo })