Skip to content

Commit

Permalink
Fix Int128 checked-convert to signed IntX (dotnet#100342)
Browse files Browse the repository at this point in the history
* Fix Int128 checked-convert to signed IntX

* Simplify implementation
  • Loading branch information
skyoxZ committed Apr 4, 2024
1 parent cf38265 commit 9a1da4d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 40 deletions.
55 changes: 15 additions & 40 deletions src/libraries/System.Private.CoreLib/src/System/Int128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,17 +262,12 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
/// <exception cref="OverflowException"><paramref name="value" /> is not representable by <see cref="Int128" />.</exception>
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);
}

/// <summary>Explicitly converts a 128-bit signed integer to a <see cref="int" /> value.</summary>
Expand All @@ -286,17 +281,12 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
/// <exception cref="OverflowException"><paramref name="value" /> is not representable by <see cref="Int128" />.</exception>
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);
}

/// <summary>Explicitly converts a 128-bit signed integer to a <see cref="long" /> value.</summary>
Expand All @@ -310,17 +300,12 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
/// <exception cref="OverflowException"><paramref name="value" /> is not representable by <see cref="Int128" />.</exception>
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;
}

/// <summary>Explicitly converts a 128-bit signed integer to a <see cref="IntPtr" /> value.</summary>
Expand All @@ -334,17 +319,12 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
/// <exception cref="OverflowException"><paramref name="value" /> is not representable by <see cref="Int128" />.</exception>
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);
}

/// <summary>Explicitly converts a 128-bit signed integer to a <see cref="sbyte" /> value.</summary>
Expand All @@ -360,17 +340,12 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
[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);
}

/// <summary>Explicitly converts a 128-bit signed integer to a <see cref="float" /> value.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<OverflowException>(() => checked((long)new Int128(1, 1)));
Assert.Throws<OverflowException>(() => 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<OverflowException>(() => checked((int)new Int128(1, 1)));
Assert.Throws<OverflowException>(() => 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<OverflowException>(() => checked((short)new Int128(1, 1)));
Assert.Throws<OverflowException>(() => 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<OverflowException>(() => checked((sbyte)new Int128(1, 1)));
Assert.Throws<OverflowException>(() => 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<OverflowException>(() => checked((nint)new Int128(1, 1)));
Assert.Throws<OverflowException>(() => checked((nint)new Int128(ulong.MaxValue, 42)));
}

public static IEnumerable<object[]> ToString_TestData()
{
foreach (NumberFormatInfo defaultFormat in new[] { null, NumberFormatInfo.CurrentInfo })
Expand Down

0 comments on commit 9a1da4d

Please sign in to comment.