Adding System.Math overloads for nint/nuint (#46647)
authorTanner Gooding <tagoo@outlook.com>
Fri, 8 Jan 2021 18:27:22 +0000 (10:27 -0800)
committerGitHub <noreply@github.com>
Fri, 8 Jan 2021 18:27:22 +0000 (10:27 -0800)
* Adding System.Math overloads for nint/nuint

* Adding a missing cast

* Fixing the Clamp_NInt and Clamp_NUInt tests to work with the provided MemberData

src/libraries/System.Private.CoreLib/src/System/Math.cs
src/libraries/System.Runtime.Extensions/tests/System/Math.cs
src/libraries/System.Runtime/ref/System.Runtime.cs

index 335a3cc..5ca23b8 100644 (file)
@@ -85,6 +85,23 @@ namespace System
             return value;
         }
 
+        /// <summary>Returns the absolute value of a native signed integer.</summary>
+        /// <param name="value">A number that is greater than <see cref="IntPtr.MinValue" />, but less than or equal to <see cref="IntPtr.MaxValue" />.</param>
+        /// <returns>A native signed integer, x, such that 0 ≤ x ≤ <see cref="IntPtr.MaxValue" />.</returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static nint Abs(nint value)
+        {
+            if (value < 0)
+            {
+                value = -value;
+                if (value < 0)
+                {
+                    ThrowAbsOverflow();
+                }
+            }
+            return value;
+        }
+
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [CLSCompliant(false)]
         public static sbyte Abs(sbyte value)
@@ -522,6 +539,41 @@ namespace System
             return value;
         }
 
+        /// <summary>Returns <paramref name="value" /> clamped to the inclusive range of <paramref name="min" /> and <paramref name="max" />.</summary>
+        /// <param name="value">The value to be clamped.</param>
+        /// <param name="min">The lower bound of the result.</param>
+        /// <param name="max">The upper bound of the result.</param>
+        /// <returns>
+        ///   <paramref name="value" /> if <paramref name="min" /> ≤ <paramref name="value" /> ≤ <paramref name="max" />.
+        ///
+        ///   -or-
+        ///
+        ///   <paramref name="min" /> if <paramref name="value" /> &lt; <paramref name="min" />.
+        ///
+        ///   -or-
+        ///
+        ///   <paramref name="max" /> if <paramref name="max" /> &lt; <paramref name="value" />.
+        /// </returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static nint Clamp(nint value, nint min, nint max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
         [CLSCompliant(false)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static sbyte Clamp(sbyte value, sbyte min, sbyte max)
@@ -626,6 +678,42 @@ namespace System
             return value;
         }
 
+        /// <summary>Returns <paramref name="value" /> clamped to the inclusive range of <paramref name="min" /> and <paramref name="max" />.</summary>
+        /// <param name="value">The value to be clamped.</param>
+        /// <param name="min">The lower bound of the result.</param>
+        /// <param name="max">The upper bound of the result.</param>
+        /// <returns>
+        ///   <paramref name="value" /> if <paramref name="min" /> ≤ <paramref name="value" /> ≤ <paramref name="max" />.
+        ///
+        ///   -or-
+        ///
+        ///   <paramref name="min" /> if <paramref name="value" /> &lt; <paramref name="min" />.
+        ///
+        ///   -or-
+        ///
+        ///   <paramref name="max" /> if <paramref name="max" /> &lt; <paramref name="value" />.
+        /// </returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static nuint Clamp(nuint value, nuint min, nuint max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static decimal Floor(decimal d)
         {
@@ -760,6 +848,16 @@ namespace System
             return (val1 >= val2) ? val1 : val2;
         }
 
+        /// <summary>Returns the larger of two native signed integers.</summary>
+        /// <param name="val1">The first of two native signed integers to compare.</param>
+        /// <param name="val2">The second of two native signed integers to compare.</param>
+        /// <returns>Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is larger.</returns>
+        [NonVersionable]
+        public static nint Max(nint val1, nint val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
         [CLSCompliant(false)]
         [NonVersionable]
         public static sbyte Max(sbyte val1, sbyte val2)
@@ -810,6 +908,17 @@ namespace System
             return (val1 >= val2) ? val1 : val2;
         }
 
+        /// <summary>Returns the larger of two native unsigned integers.</summary>
+        /// <param name="val1">The first of two native unsigned integers to compare.</param>
+        /// <param name="val2">The second of two native unsigned integers to compare.</param>
+        /// <returns>Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is larger.</returns>
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static nuint Max(nuint val1, nuint val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
         public static double MaxMagnitude(double x, double y)
         {
             // This matches the IEEE 754:2019 `maximumMagnitude` function
@@ -881,6 +990,16 @@ namespace System
             return (val1 <= val2) ? val1 : val2;
         }
 
+        /// <summary>Returns the smaller of two native signed integers.</summary>
+        /// <param name="val1">The first of two native signed integers to compare.</param>
+        /// <param name="val2">The second of two native signed integers to compare.</param>
+        /// <returns>Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is smaller.</returns>
+        [NonVersionable]
+        public static nint Min(nint val1, nint val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
         [CLSCompliant(false)]
         [NonVersionable]
         public static sbyte Min(sbyte val1, sbyte val2)
@@ -926,6 +1045,17 @@ namespace System
             return (val1 <= val2) ? val1 : val2;
         }
 
+        /// <summary>Returns the smaller of two native unsigned integers.</summary>
+        /// <param name="val1">The first of two native unsigned integers to compare.</param>
+        /// <param name="val2">The second of two native unsigned integers to compare.</param>
+        /// <returns>Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is smaller.</returns>
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static nuint Min(nuint val1, nuint val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
         public static double MinMagnitude(double x, double y)
         {
             // This matches the IEEE 754:2019 `minimumMagnitude` function
@@ -1165,6 +1295,15 @@ namespace System
             return unchecked((int)(value >> 63 | (long)((ulong)-value >> 63)));
         }
 
+        public static int Sign(nint value)
+        {
+#if TARGET_64BIT
+            return unchecked((int)(value >> 63 | (long)((ulong)-value >> 63)));
+#else
+            return unchecked((int)(value >> 31) | (int)((uint)-value >> 31));
+#endif
+        }
+
         [CLSCompliant(false)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static int Sign(sbyte value)
index a774266..2fc59ef 100644 (file)
@@ -441,6 +441,15 @@ namespace System.Tests
         }
 
         [Fact]
+        public static void Abs_NInt()
+        {
+            Assert.Equal((nint)3, Math.Abs((nint)3));
+            Assert.Equal((nint)0, Math.Abs((nint)0));
+            Assert.Equal((nint)3, Math.Abs((nint)(-3)));
+            Assert.Throws<OverflowException>(() => Math.Abs(nint.MinValue));
+        }
+
+        [Fact]
         public static void Abs_SByte()
         {
             Assert.Equal((sbyte)3, Math.Abs((sbyte)3));
@@ -1113,6 +1122,13 @@ namespace System.Tests
         }
 
         [Fact]
+        public static void Max_NInt()
+        {
+            Assert.Equal((nint)3, Math.Max((nint)(-2), (nint)3));
+            Assert.Equal(nint.MaxValue, Math.Max(nint.MinValue, nint.MaxValue));
+        }
+
+        [Fact]
         public static void Max_SByte()
         {
             Assert.Equal((sbyte)3, Math.Max((sbyte)(-2), (sbyte)3));
@@ -1164,6 +1180,13 @@ namespace System.Tests
         }
 
         [Fact]
+        public static void Max_NUInt()
+        {
+            Assert.Equal((nuint)3, Math.Max((nuint)2, (nuint)3));
+            Assert.Equal(nuint.MaxValue, Math.Max(nuint.MinValue, nuint.MaxValue));
+        }
+
+        [Fact]
         public static void Min_Byte()
         {
             Assert.Equal((byte)2, Math.Min((byte)3, (byte)2));
@@ -1222,6 +1245,13 @@ namespace System.Tests
         }
 
         [Fact]
+        public static void Min_NInt()
+        {
+            Assert.Equal((nint)(-2), Math.Min((nint)3, (nint)(-2)));
+            Assert.Equal(nint.MinValue, Math.Min(nint.MinValue, nint.MaxValue));
+        }
+
+        [Fact]
         public static void Min_SByte()
         {
             Assert.Equal((sbyte)(-2), Math.Min((sbyte)3, (sbyte)(-2)));
@@ -1272,6 +1302,13 @@ namespace System.Tests
             Assert.Equal(ulong.MinValue, Math.Min(ulong.MinValue, ulong.MaxValue));
         }
 
+        [Fact]
+        public static void Min_NUInt()
+        {
+            Assert.Equal((nuint)2, Math.Min((nuint)3, (nuint)2));
+            Assert.Equal(nuint.MinValue, Math.Min(nuint.MinValue, nuint.MaxValue));
+        }
+
         public static IEnumerable<object[]> Pow_TestData
         {
             get
@@ -1524,6 +1561,14 @@ namespace System.Tests
         }
 
         [Fact]
+        public static void Sign_NInt()
+        {
+            Assert.Equal(0, Math.Sign((nint)0));
+            Assert.Equal(-1, Math.Sign((nint)(-3)));
+            Assert.Equal(1, Math.Sign((nint)3));
+        }
+
+        [Fact]
         public static void Sign_SByte()
         {
             Assert.Equal(0, Math.Sign((sbyte)0));
@@ -2388,6 +2433,21 @@ namespace System.Tests
             Assert.Equal(expected, Math.Clamp(value, min, max));
         }
 
+
+        [Theory]
+        [MemberData(nameof(Clamp_SignedInt_TestData))]
+        public static void Clamp_NInt(int value, int min, int max, int expected)
+        {
+            Assert.Equal((nint)expected, Math.Clamp((nint)value, (nint)min, (nint)max));
+        }
+
+        [Theory]
+        [MemberData(nameof(Clamp_UnsignedInt_TestData))]
+        public static void Clamp_NUInt(uint value, uint min, uint max, uint expected)
+        {
+            Assert.Equal((nuint)expected, Math.Clamp((nuint)value, (nuint)min, (nuint)max));
+        }
+
         [Theory]
         [MemberData(nameof(Clamp_SignedInt_TestData))]
         [InlineData(double.NegativeInfinity, double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity)]
@@ -2876,7 +2936,7 @@ namespace System.Tests
             Assert.Equal(-3, Math.Round(-3.0));
             Assert.Equal( 4, Math.Round( 3.5));
             Assert.Equal(-4, Math.Round(-3.5));
-            
+
             Assert.Equal( 0, Math.Round( 0.5, MidpointRounding.ToZero));
             Assert.Equal( 0, Math.Round( 0.5, MidpointRounding.ToZero));
             Assert.Equal( 1, Math.Round( 1.0, MidpointRounding.ToZero));
@@ -2925,7 +2985,7 @@ namespace System.Tests
             Assert.Equal(-3, MathF.Round(-3.0f));
             Assert.Equal( 4, MathF.Round( 3.5f));
             Assert.Equal(-4, MathF.Round(-3.5f));
-            
+
             Assert.Equal( 0, MathF.Round( 0.5f, MidpointRounding.ToZero));
             Assert.Equal( 0, MathF.Round( 0.5f, MidpointRounding.ToZero));
             Assert.Equal( 1, MathF.Round( 1.0f, MidpointRounding.ToZero));
index 2282fe5..2691568 100644 (file)
@@ -2655,6 +2655,7 @@ namespace System
         public static short Abs(short value) { throw null; }
         public static int Abs(int value) { throw null; }
         public static long Abs(long value) { throw null; }
+        public static nint Abs(nint value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static sbyte Abs(sbyte value) { throw null; }
         public static float Abs(float value) { throw null; }
@@ -2680,6 +2681,7 @@ namespace System
         public static short Clamp(short value, short min, short max) { throw null; }
         public static int Clamp(int value, int min, int max) { throw null; }
         public static long Clamp(long value, long min, long max) { throw null; }
+        public static nint Clamp(nint value, nint min, nint max) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static sbyte Clamp(sbyte value, sbyte min, sbyte max) { throw null; }
         public static float Clamp(float value, float min, float max) { throw null; }
@@ -2689,24 +2691,26 @@ namespace System
         public static uint Clamp(uint value, uint min, uint max) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static ulong Clamp(ulong value, ulong min, ulong max) { throw null; }
+        [System.CLSCompliantAttribute(false)]
+        public static nuint Clamp(nuint value, nuint min, nuint max) { throw null; }
         public static double CopySign(double x, double y) { throw null; }
         public static double Cos(double d) { throw null; }
         public static double Cosh(double value) { throw null; }
         public static int DivRem(int a, int b, out int result) { throw null; }
         public static long DivRem(long a, long b, out long result) { throw null; }
         public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) { throw null; }
+        public static (short Quotient, short Remainder) DivRem(short left, short right) { throw null; }
+        public static (int Quotient, int Remainder) DivRem(int left, int right) { throw null; }
+        public static (long Quotient, long Remainder) DivRem(long left, long right) { throw null; }
+        public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) { throw null; }
-        public static (short Quotient, short Remainder) DivRem(short left, short right) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) { throw null; }
-        public static (int Quotient, int Remainder) DivRem(int left, int right) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) { throw null; }
-        public static (long Quotient, long Remainder) DivRem(long left, long right) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) { throw null; }
-        public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) { throw null; }
         public static double Exp(double d) { throw null; }
@@ -2725,6 +2729,7 @@ namespace System
         public static short Max(short val1, short val2) { throw null; }
         public static int Max(int val1, int val2) { throw null; }
         public static long Max(long val1, long val2) { throw null; }
+        public static nint Max(nint val1, nint val2) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static sbyte Max(sbyte val1, sbyte val2) { throw null; }
         public static float Max(float val1, float val2) { throw null; }
@@ -2734,6 +2739,8 @@ namespace System
         public static uint Max(uint val1, uint val2) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static ulong Max(ulong val1, ulong val2) { throw null; }
+        [System.CLSCompliantAttribute(false)]
+        public static nuint Max(nuint val1, nuint val2) { throw null; }
         public static double MaxMagnitude(double x, double y) { throw null; }
         public static byte Min(byte val1, byte val2) { throw null; }
         public static decimal Min(decimal val1, decimal val2) { throw null; }
@@ -2741,6 +2748,7 @@ namespace System
         public static short Min(short val1, short val2) { throw null; }
         public static int Min(int val1, int val2) { throw null; }
         public static long Min(long val1, long val2) { throw null; }
+        public static nint Min(nint val1, nint val2) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static sbyte Min(sbyte val1, sbyte val2) { throw null; }
         public static float Min(float val1, float val2) { throw null; }
@@ -2750,6 +2758,8 @@ namespace System
         public static uint Min(uint val1, uint val2) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static ulong Min(ulong val1, ulong val2) { throw null; }
+        [System.CLSCompliantAttribute(false)]
+        public static nuint Min(nuint val1, nuint val2) { throw null; }
         public static double MinMagnitude(double x, double y) { throw null; }
         public static double Pow(double x, double y) { throw null; }
         public static decimal Round(decimal d) { throw null; }
@@ -2766,6 +2776,7 @@ namespace System
         public static int Sign(short value) { throw null; }
         public static int Sign(int value) { throw null; }
         public static int Sign(long value) { throw null; }
+        public static int Sign(nint value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static int Sign(sbyte value) { throw null; }
         public static int Sign(float value) { throw null; }