Expose nint/nuint overloads for BitOperations (#58733)
authorRobin Lindner <robin.lindner1@t-online.de>
Fri, 17 Sep 2021 23:31:07 +0000 (01:31 +0200)
committerGitHub <noreply@github.com>
Fri, 17 Sep 2021 23:31:07 +0000 (16:31 -0700)
* Change access modifier of BitOperations.IsPow2

* Add CLSCompliant(false) attribute to BitOperations.IsPow2

* Add BitOperations.RoundUpToPowerOf2 method for nuint

* Add BitOperations.LeadingZeroCount method for nuint

* Add BitOperations.Log2 method for nuint

* Add BitOperations.PopCount method for nuint

* Add BitOperations.TrailingZeroCount for nint and nuint

* Add BitOperations.RotateLeft and BitOperations.RotateRight for nuint

* Replace Environment.Is64BitProcess check with preprocessor variable TARGET_64BIT and reimplement accidentally removed comment

* Fix formatting

* Remove last Environment.Is64BitProcess check

* Add tests

* Remove [CLSCompliant(false)] Attribute from BitOperations which use nint (not nuint)

* Add refs

* Add refs

* Fix RotateLeft and RotateRight test

* Add IgnoreOnArchitectureTheoryAttribute and remove checks for not existing preprocessor variable

* Replace custom TheoryAttribute with ConditionalTheory

* Add unchecked syntax due CS8778

* Fix parameter type in BitOperationsTests.BitOps_RoundUpToPow2_nuint_64

* Fix Test values

* Fix expectation parameter

* Fix 32-bit expectation

* Fix 32-bit test

src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
src/libraries/System.Runtime.Extensions/tests/System/Numerics/BitOperationsTests.cs
src/libraries/System.Runtime/ref/System.Runtime.cs

index b5ffd5e..6a7141c 100644 (file)
@@ -76,14 +76,15 @@ namespace System.Numerics
         /// </summary>
         /// <param name="value">The value.</param>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool IsPow2(nint value) => (value & (value - 1)) == 0 && value > 0;
+        public static bool IsPow2(nint value) => (value & (value - 1)) == 0 && value > 0;
 
         /// <summary>
         /// Evaluate whether a given integral value is a power of 2.
         /// </summary>
         /// <param name="value">The value.</param>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool IsPow2(nuint value) => (value & (value - 1)) == 0 && value != 0;
+        [CLSCompliant(false)]
+        public static bool IsPow2(nuint value) => (value & (value - 1)) == 0 && value != 0;
 
         /// <summary>Round the given integral value up to a power of 2.</summary>
         /// <param name="value">The value.</param>
@@ -115,7 +116,6 @@ namespace System.Numerics
             return value + 1;
         }
 
-
         /// <summary>
         /// Round the given integral value up to a power of 2.
         /// </summary>
@@ -146,6 +146,25 @@ namespace System.Numerics
         }
 
         /// <summary>
+        /// Round the given integral value up to a power of 2.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        /// <returns>
+        /// The smallest power of 2 which is greater than or equal to <paramref name="value"/>.
+        /// If <paramref name="value"/> is 0 or the result overflows, returns 0.
+        /// </returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static nuint RoundUpToPowerOf2(nuint value)
+        {
+#if TARGET_64BIT
+            return (nuint)RoundUpToPowerOf2((ulong)value);
+#else
+            return (nuint)RoundUpToPowerOf2((uint)value);
+#endif
+        }
+
+        /// <summary>
         /// Count the number of leading zero bits in a mask.
         /// Similar in behavior to the x86 instruction LZCNT.
         /// </summary>
@@ -219,6 +238,22 @@ namespace System.Numerics
         }
 
         /// <summary>
+        /// Count the number of leading zero bits in a mask.
+        /// Similar in behavior to the x86 instruction LZCNT.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static int LeadingZeroCount(nuint value)
+        {
+#if TARGET_64BIT
+            return LeadingZeroCount((ulong)value);
+#else
+            return LeadingZeroCount((uint)value);
+#endif
+        }
+
+        /// <summary>
         /// Returns the integer (floor) log of the specified value, base 2.
         /// Note that by convention, input value 0 returns 0 since log(0) is undefined.
         /// </summary>
@@ -296,6 +331,22 @@ namespace System.Numerics
 
         /// <summary>
         /// Returns the integer (floor) log of the specified value, base 2.
+        /// Note that by convention, input value 0 returns 0 since log(0) is undefined.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static int Log2(nuint value)
+        {
+#if TARGET_64BIT
+            return Log2((ulong)value);
+#else
+            return Log2((uint)value);
+#endif
+        }
+
+        /// <summary>
+        /// Returns the integer (floor) log of the specified value, base 2.
         /// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
         /// Does not directly use any hardware intrinsics, nor does it incur branching.
         /// </summary>
@@ -433,6 +484,22 @@ namespace System.Numerics
         }
 
         /// <summary>
+        /// Returns the population count (number of bits set) of a mask.
+        /// Similar in behavior to the x86 instruction POPCNT.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static int PopCount(nuint value)
+        {
+#if TARGET_64BIT
+            return PopCount((ulong)value);
+#else
+            return PopCount((uint)value);
+#endif
+        }
+
+        /// <summary>
         /// Count the number of trailing zero bits in an integer value.
         /// Similar in behavior to the x86 instruction TZCNT.
         /// </summary>
@@ -526,6 +593,31 @@ namespace System.Numerics
         }
 
         /// <summary>
+        /// Count the number of trailing zero bits in a mask.
+        /// Similar in behavior to the x86 instruction TZCNT.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int TrailingZeroCount(nint value)
+            => TrailingZeroCount((nuint)value);
+
+        /// <summary>
+        /// Count the number of trailing zero bits in a mask.
+        /// Similar in behavior to the x86 instruction TZCNT.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static int TrailingZeroCount(nuint value)
+        {
+#if TARGET_64BIT
+            return TrailingZeroCount((ulong)value);
+#else
+            return TrailingZeroCount((uint)value);
+#endif
+        }
+
+        /// <summary>
         /// Rotates the specified value left by the specified number of bits.
         /// Similar in behavior to the x86 instruction ROL.
         /// </summary>
@@ -552,6 +644,26 @@ namespace System.Numerics
             => (value << offset) | (value >> (64 - offset));
 
         /// <summary>
+        /// Rotates the specified value left by the specified number of bits.
+        /// Similar in behavior to the x86 instruction ROL.
+        /// </summary>
+        /// <param name="value">The value to rotate.</param>
+        /// <param name="offset">The number of bits to rotate by.
+        /// Any value outside the range [0..31] is treated as congruent mod 32 on a 32-bit process,
+        /// and any value outside the range [0..63] is treated as congruent mod 64 on a 64-bit process.</param>
+        /// <returns>The rotated value.</returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static nuint RotateLeft(nuint value, int offset)
+        {
+#if TARGET_64BIT
+            return (nuint)RotateLeft((ulong)value, offset);
+#else
+            return (nuint)RotateLeft((uint)value, offset);
+#endif
+        }
+
+        /// <summary>
         /// Rotates the specified value right by the specified number of bits.
         /// Similar in behavior to the x86 instruction ROR.
         /// </summary>
@@ -576,5 +688,25 @@ namespace System.Numerics
         [CLSCompliant(false)]
         public static ulong RotateRight(ulong value, int offset)
             => (value >> offset) | (value << (64 - offset));
+
+        /// <summary>
+        /// Rotates the specified value right by the specified number of bits.
+        /// Similar in behavior to the x86 instruction ROR.
+        /// </summary>
+        /// <param name="value">The value to rotate.</param>
+        /// <param name="offset">The number of bits to rotate by.
+        /// Any value outside the range [0..31] is treated as congruent mod 32 on a 32-bit process,
+        /// and any value outside the range [0..63] is treated as congruent mod 64 on a 64-bit process.</param>
+        /// <returns>The rotated value.</returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static nuint RotateRight(nuint value, int offset)
+        {
+#if TARGET_64BIT
+            return (nuint)RotateRight((ulong)value, offset);
+#else
+            return (nuint)RotateRight((uint)value, offset);
+#endif
+        }
     }
 }
index 3333157..10d77e4 100644 (file)
     <Compile Include="System\Runtime\ProfileOptimization.cs" />
     <Compile Include="System\Runtime\CompilerServices\SwitchExpressionExceptionTests.cs" />
 
-    <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetNodeName.cs" Condition="'$(TargetsUnix)' == 'true' or '$(TargetsBrowser)' == 'true'"
-             Link="Common\Interop\Unix\System.Native\Interop.GetNodeName.cs" />
-    <Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs"
-             Link="Common\Interop\Unix\Interop.Libraries.cs" />
-    <Compile Include="$(CommonTestPath)System\IO\PathFeatures.cs"
-             Link="Common\System\IO\PathFeatures.cs" />
-    <Compile Include="$(CommonTestPath)System\ShouldNotBeInvokedException.cs"
-             Link="Common\System\ShouldNotBeInvokedException.cs" />
-    <Compile Include="$(CommonTestPath)System\Security\Cryptography\ByteUtils.cs"
-             Link="Common\System\Security\Cryptography\ByteUtils.cs" />
+    <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetNodeName.cs" Condition="'$(TargetsUnix)' == 'true' or '$(TargetsBrowser)' == 'true'" Link="Common\Interop\Unix\System.Native\Interop.GetNodeName.cs" />
+    <Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs" Link="Common\Interop\Unix\Interop.Libraries.cs" />
+    <Compile Include="$(CommonTestPath)System\IO\PathFeatures.cs" Link="Common\System\IO\PathFeatures.cs" />
+    <Compile Include="$(CommonTestPath)System\ShouldNotBeInvokedException.cs" Link="Common\System\ShouldNotBeInvokedException.cs" />
+    <Compile Include="$(CommonTestPath)System\Security\Cryptography\ByteUtils.cs" Link="Common\System\Security\Cryptography\ByteUtils.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="AssemblyResolveTestApp\AssemblyResolveTestApp.csproj" />
index 7836538..2bfc0d2 100644 (file)
@@ -93,6 +93,90 @@ namespace System.Numerics.Tests
             Assert.Equal(expected, actual);
         }
 
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
+        [InlineData(0, false)]
+        [InlineData(0b1, true)]
+        [InlineData(0b10, true)]
+        [InlineData(0b100, true)]
+        [InlineData(0b1000, true)]
+        [InlineData(0b10000, true)]
+        [InlineData(0b100000, true)]
+        [InlineData(0b1000000, true)]
+        [InlineData(-0b1000000, false)]
+        [InlineData(0b1000001, false)]
+        [InlineData(0b1010001, false)]
+        [InlineData(0b1111111, false)]
+        [InlineData(-1, false)]
+        [InlineData(int.MaxValue, false)]
+        [InlineData(int.MinValue, false)]
+        public static void BitOps_IsPow2_nint_32(int n, bool expected)
+        {
+            bool actual = BitOperations.IsPow2((nint) n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+        [InlineData(0, false)]
+        [InlineData(0b1, true)]
+        [InlineData(0b10, true)]
+        [InlineData(0b100, true)]
+        [InlineData(0b1000, true)]
+        [InlineData(0b10000, true)]
+        [InlineData(0b100000, true)]
+        [InlineData(0b1000000, true)]
+        [InlineData(-0b1000000, false)]
+        [InlineData(0b1000001, false)]
+        [InlineData(0b1010001, false)]
+        [InlineData(0b1111111, false)]
+        [InlineData(-1, false)]
+        [InlineData(long.MaxValue, false)]
+        [InlineData(long.MinValue, false)]
+        public static void BitOps_IsPow2_nint_64(long n, bool expected)
+        {
+            bool actual = BitOperations.IsPow2((nint) n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
+        [InlineData(0u, false)]
+        [InlineData(0b1u, true)]
+        [InlineData(0b10u, true)]
+        [InlineData(0b100u, true)]
+        [InlineData(0b1000u, true)]
+        [InlineData(0b10000u, true)]
+        [InlineData(0b100000u, true)]
+        [InlineData(0b1000000u, true)]
+        [InlineData(0b1000001u, false)]
+        [InlineData(0b1010001u, false)]
+        [InlineData(0b1111111u, false)]
+        [InlineData(unchecked((uint)int.MinValue), true)]
+        [InlineData(uint.MaxValue, false)]
+        public static void BitOps_IsPow2_nuint_32(uint n, bool expected)
+        {
+            bool actual = BitOperations.IsPow2((nuint) n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+        [InlineData(0u, false)]
+        [InlineData(0b1u, true)]
+        [InlineData(0b10u, true)]
+        [InlineData(0b100u, true)]
+        [InlineData(0b1000u, true)]
+        [InlineData(0b10000u, true)]
+        [InlineData(0b100000u, true)]
+        [InlineData(0b1000000u, true)]
+        [InlineData(0b1000001u, false)]
+        [InlineData(0b1010001u, false)]
+        [InlineData(0b1111111u, false)]
+        [InlineData(unchecked((uint)int.MinValue), true)]
+        [InlineData(ulong.MaxValue, false)]
+        public static void BitOps_IsPow2_nuint_64(ulong n, bool expected)
+        {
+            bool actual = BitOperations.IsPow2((nuint) n);
+            Assert.Equal(expected, actual);
+        }
+
 
         [Theory]
         [InlineData(0u, 32)]
@@ -138,6 +222,51 @@ namespace System.Numerics.Tests
             Assert.Equal(expected, actual);
         }
 
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
+        [InlineData(0u, 32)]
+        [InlineData(0b1u, 31)]
+        [InlineData(0b10u, 30)]
+        [InlineData(0b100u, 29)]
+        [InlineData(0b1000u, 28)]
+        [InlineData(0b10000u, 27)]
+        [InlineData(0b100000u, 26)]
+        [InlineData(0b1000000u, 25)]
+        [InlineData(byte.MaxValue << 17, 32 - 8 - 17)]
+        [InlineData(byte.MaxValue << 9, 32 - 8 - 9)]
+        [InlineData(ushort.MaxValue << 11, 32 - 16 - 11)]
+        [InlineData(ushort.MaxValue << 2, 32 - 16 - 2)]
+        [InlineData(5 << 7, 32 - 3 - 7)]
+        [InlineData(uint.MaxValue, 0)]
+        public static void BitOps_LeadingZeroCount_nuint_32(uint n, int expected)
+        {
+            int actual = BitOperations.LeadingZeroCount(n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+        [InlineData(0ul, 64)]
+        [InlineData(0b1ul, 63)]
+        [InlineData(0b10ul, 62)]
+        [InlineData(0b100ul, 61)]
+        [InlineData(0b1000ul, 60)]
+        [InlineData(0b10000ul, 59)]
+        [InlineData(0b100000ul, 58)]
+        [InlineData(0b1000000ul, 57)]
+        [InlineData((ulong)byte.MaxValue << 41, 64 - 8 - 41)]
+        [InlineData((ulong)byte.MaxValue << 53, 64 - 8 - 53)]
+        [InlineData((ulong)ushort.MaxValue << 31, 64 - 16 - 31)]
+        [InlineData((ulong)ushort.MaxValue << 15, 64 - 16 - 15)]
+        [InlineData(ulong.MaxValue >> 5, 5)]
+        [InlineData(1ul << 63, 0)]
+        [InlineData(1ul << 62, 1)]
+        [InlineData(ulong.MaxValue, 0)]
+        public static void BitOps_LeadingZeroCount_nuint_64(ulong n, int expected)
+        {
+            int actual = BitOperations.LeadingZeroCount(n);
+            Assert.Equal(expected, actual);
+        }
+
         [Theory]
         [InlineData(0u, 32)]
         [InlineData(0b1u, 0)]
@@ -228,6 +357,96 @@ namespace System.Numerics.Tests
             Assert.Equal(expected, actual);
         }
 
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
+        [InlineData(0u, 32)]
+        [InlineData(0b1u, 0)]
+        [InlineData(0b10u, 1)]
+        [InlineData(0b100u, 2)]
+        [InlineData(0b1000u, 3)]
+        [InlineData(0b10000u, 4)]
+        [InlineData(0b100000u, 5)]
+        [InlineData(0b1000000u, 6)]
+        [InlineData((uint)byte.MaxValue << 24, 24)]
+        [InlineData((uint)byte.MaxValue << 22, 22)]
+        [InlineData((uint)ushort.MaxValue << 16, 16)]
+        [InlineData((uint)ushort.MaxValue << 19, 19)]
+        [InlineData(uint.MaxValue << 5, 5)]
+        [InlineData(3u << 27, 27)]
+        [InlineData(uint.MaxValue, 0)]
+        public static void BitOps_TrailingZeroCount_nuint_32(uint n, int expected)
+        {
+            int actual = BitOperations.TrailingZeroCount((nuint) n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+        [InlineData(0ul, 64)]
+        [InlineData(0b1ul, 0)]
+        [InlineData(0b10ul, 1)]
+        [InlineData(0b100ul, 2)]
+        [InlineData(0b1000ul, 3)]
+        [InlineData(0b10000ul, 4)]
+        [InlineData(0b100000ul, 5)]
+        [InlineData(0b1000000ul, 6)]
+        [InlineData((ulong)byte.MaxValue << 40, 40)]
+        [InlineData((ulong)byte.MaxValue << 57, 57)]
+        [InlineData((ulong)ushort.MaxValue << 31, 31)]
+        [InlineData((ulong)ushort.MaxValue << 15, 15)]
+        [InlineData(ulong.MaxValue << 5, 5)]
+        [InlineData(3ul << 59, 59)]
+        [InlineData(5ul << 63, 63)]
+        [InlineData(ulong.MaxValue, 0)]
+        public static void BitOps_TrailingZeroCount_nuint_64(ulong n, int expected)
+        {
+            int actual = BitOperations.TrailingZeroCount((nuint) n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
+        [InlineData(0, 32)]
+        [InlineData(0b1, 0)]
+        [InlineData(0b10, 1)]
+        [InlineData(0b100, 2)]
+        [InlineData(0b1000, 3)]
+        [InlineData(0b10000, 4)]
+        [InlineData(0b100000, 5)]
+        [InlineData(0b1000000, 6)]
+        [InlineData(byte.MaxValue << 24, 24)]
+        [InlineData(byte.MaxValue << 22, 22)]
+        [InlineData(ushort.MaxValue << 16, 16)]
+        [InlineData(ushort.MaxValue << 19, 19)]
+        [InlineData(int.MaxValue << 5, 5)]
+        [InlineData(3 << 27, 27)]
+        [InlineData(int.MaxValue, 0)]
+        public static void BitOps_TrailingZeroCount_nint_32(int n, int expected)
+        {
+            int actual = BitOperations.TrailingZeroCount((nint) n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+        [InlineData(0L, 64)]
+        [InlineData(0b1L, 0)]
+        [InlineData(0b10L, 1)]
+        [InlineData(0b100L, 2)]
+        [InlineData(0b1000L, 3)]
+        [InlineData(0b10000L, 4)]
+        [InlineData(0b100000L, 5)]
+        [InlineData(0b1000000L, 6)]
+        [InlineData((long)byte.MaxValue << 40, 40)]
+        [InlineData((long)byte.MaxValue << 57, 57)]
+        [InlineData((long)ushort.MaxValue << 31, 31)]
+        [InlineData((long)ushort.MaxValue << 15, 15)]
+        [InlineData(long.MaxValue << 5, 5)]
+        [InlineData(3L << 59, 59)]
+        [InlineData(5L << 63, 63)]
+        [InlineData(long.MaxValue, 0)]
+        public static void BitOps_TrailingZeroCount_nint_64(long n, int expected)
+        {
+            int actual = BitOperations.TrailingZeroCount((nint) n);
+            Assert.Equal(expected, actual);
+        }
+
         [Theory]
         [InlineData(0, 0)]
         [InlineData(1, 0)]
@@ -269,6 +488,47 @@ namespace System.Numerics.Tests
             Assert.Equal(expected, actual);
         }
 
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
+        [InlineData(0, 0)]
+        [InlineData(1, 0)]
+        [InlineData(2, 1)]
+        [InlineData(3, 2 - 1)]
+        [InlineData(4, 2)]
+        [InlineData(5, 3 - 1)]
+        [InlineData(6, 3 - 1)]
+        [InlineData(7, 3 - 1)]
+        [InlineData(8, 3)]
+        [InlineData(9, 4 - 1)]
+        [InlineData(byte.MaxValue, 8 - 1)]
+        [InlineData(ushort.MaxValue, 16 - 1)]
+        [InlineData(uint.MaxValue, 32 - 1)]
+        public static void BitOps_Log2_nuint_32(uint n, int expected)
+        {
+            int actual = BitOperations.Log2((nuint) n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+        [InlineData(0, 0)]
+        [InlineData(1, 0)]
+        [InlineData(2, 1)]
+        [InlineData(3, 2 - 1)]
+        [InlineData(4, 2)]
+        [InlineData(5, 3 - 1)]
+        [InlineData(6, 3 - 1)]
+        [InlineData(7, 3 - 1)]
+        [InlineData(8, 3)]
+        [InlineData(9, 4 - 1)]
+        [InlineData(byte.MaxValue, 8 - 1)]
+        [InlineData(ushort.MaxValue, 16 - 1)]
+        [InlineData(uint.MaxValue, 32 - 1)]
+        [InlineData(ulong.MaxValue, 64 - 1)]
+        public static void BitOps_Log2_nuint_64(ulong n, int expected)
+        {
+            int actual = BitOperations.Log2((nuint) n);
+            Assert.Equal(expected, actual);
+        }
+
         [Theory]
         [InlineData(0b001, 1)]
         [InlineData(0b010, 1)]
@@ -337,6 +597,61 @@ namespace System.Numerics.Tests
             Assert.Equal(expected, actual);
         }
 
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
+        [InlineData(0b001, 1)]
+        [InlineData(0b010, 1)]
+        [InlineData(0b011, 2)]
+        [InlineData(0b100, 1)]
+        [InlineData(0b101, 2)]
+        [InlineData(0b110, 2)]
+        [InlineData(0b111, 3)]
+        [InlineData(0b1101, 3)]
+        [InlineData(0b1111, 4)]
+        [InlineData(0b10111, 4)]
+        [InlineData(0b11111, 5)]
+        [InlineData(0b110111, 5)]
+        [InlineData(0b111111, 6)]
+        [InlineData(0b1111110, 6)]
+        public static void BitOps_PopCount_nuint_32(uint n, int expected)
+        {
+            int actual = BitOperations.PopCount((nuint) n);
+            Assert.Equal(expected, actual);
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+        [InlineData(0b001, 1)]
+        [InlineData(0b010, 1)]
+        [InlineData(0b011, 2)]
+        [InlineData(0b100, 1)]
+        [InlineData(0b101, 2)]
+        [InlineData(0b110, 2)]
+        [InlineData(0b111, 3)]
+        [InlineData(0b1101, 3)]
+        [InlineData(0b1111, 4)]
+        [InlineData(0b10111, 4)]
+        [InlineData(0b11111, 5)]
+        [InlineData(0b110111, 5)]
+        [InlineData(0b111111, 6)]
+        [InlineData(0b1111110, 6)]
+        [InlineData(0b1111111, 7)]
+        [InlineData(byte.MinValue, 0)] // 0
+        [InlineData(byte.MaxValue, 8)] // 255
+        [InlineData(unchecked((ulong)sbyte.MinValue), 57)] // 18446744073709551488
+        [InlineData(sbyte.MaxValue, 7)] // 127
+        [InlineData(ushort.MaxValue, 16)] // 65535
+        [InlineData(unchecked((ulong)short.MinValue), 49)] // 18446744073709518848
+        [InlineData(short.MaxValue, 15)] // 32767
+        [InlineData(unchecked((ulong)int.MinValue), 64 - 31)] // 18446744071562067968
+        [InlineData(int.MaxValue, 31)] // 2147483647
+        [InlineData(ulong.MaxValue >> 9, 64 - 9)] // 36028797018963967
+        [InlineData(ulong.MaxValue << 11, 64 - 11)] // 18446744073709549568
+        [InlineData(ulong.MaxValue, 64)]
+        public static void BitOps_PopCount_nuint_64(ulong n, int expected)
+        {
+            int actual = BitOperations.PopCount((nuint)n);
+            Assert.Equal(expected, actual);
+        }
+
         [Theory]
         [InlineData(0b00000000_00000000_00000000_00000001u, int.MaxValue, 0b10000000_00000000_00000000_00000000u)] // % 32 = 31
         [InlineData(0b01000000_00000001_00000000_00000001u, 3, 0b00000000_00001000_00000000_00001010u)]
@@ -353,6 +668,50 @@ namespace System.Numerics.Tests
         }
 
         [Fact]
+        public static void BitOps_RotateLeft_nuint()
+        {
+            unchecked
+            {
+                if (Environment.Is64BitProcess)
+                {
+                    nuint value = (nuint)0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101ul;
+                    Assert.Equal((nuint)0b10101010_10101010_10101010_10101010_10101010_10101010_10101010_10101010ul,
+                        BitOperations.RotateLeft(value, 1));
+                    Assert.Equal((nuint)0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101ul,
+                        BitOperations.RotateLeft(value, 2));
+                    Assert.Equal((nuint)0b10101010_10101010_10101010_10101010_10101010_10101010_10101010_10101010ul,
+                        BitOperations.RotateLeft(value, 3));
+                    Assert.Equal(value, BitOperations.RotateLeft(value, int.MinValue)); // % 64 = 0
+                    Assert.Equal(BitOperations.RotateLeft(value, 63),
+                        BitOperations.RotateLeft(value, int.MaxValue)); // % 64 = 63
+                }
+                else
+                {
+                    Assert.Equal((nuint)0b10000000_00000000_00000000_00000000u,
+                        BitOperations.RotateLeft((nuint)0b00000000_00000000_00000000_00000001u,
+                            int.MaxValue)); // % 32 = 31
+                    Assert.Equal((nuint)0b00000000_00001000_00000000_00001010u,
+                        BitOperations.RotateLeft((nuint)0b01000000_00000001_00000000_00000001u, 3));
+                    Assert.Equal((nuint)0b00000000_00000100_00000000_00000101u,
+                        BitOperations.RotateLeft((nuint)0b01000000_00000001_00000000_00000001u, 2));
+                    Assert.Equal((nuint)0b10101010_10101010_10101010_10101010u,
+                        BitOperations.RotateLeft((nuint)0b01010101_01010101_01010101_01010101u, 1));
+                    Assert.Equal((nuint)0b01010101_11111111_01010101_01010101u,
+                        BitOperations.RotateLeft((nuint)0b01010101_11111111_01010101_01010101u, 0));
+                    Assert.Equal((nuint)0b10000000_00000000_00000000_00000000u,
+                        BitOperations.RotateLeft((nuint)0b00000000_00000000_00000000_00000001u, -1));
+                    Assert.Equal((nuint)0b01000000_00000000_00000000_00000000u,
+                        BitOperations.RotateLeft((nuint)0b00000000_00000000_00000000_00000001u, -2));
+                    Assert.Equal((nuint)0b00100000_00000000_00000000_00000000u,
+                        BitOperations.RotateLeft((nuint)0b00000000_00000000_00000000_00000001u, -3));
+                    Assert.Equal((nuint)0b01010101_11111111_01010101_01010101u,
+                        BitOperations.RotateLeft((nuint)0b01010101_11111111_01010101_01010101u,
+                            int.MinValue)); // % 32 = 0
+                }
+            }
+        }
+
+        [Fact]
         public static void BitOps_RotateLeft_ulong()
         {
             ulong value = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101ul;
@@ -389,6 +748,50 @@ namespace System.Numerics.Tests
             Assert.Equal(BitOperations.RotateLeft(value, 63), BitOperations.RotateRight(value, int.MaxValue)); // % 64 = 63
         }
 
+        [Fact]
+        public static void BitOps_RotateRight_nuint()
+        {
+            unchecked
+            {
+                if (Environment.Is64BitProcess)
+                {
+                    const ulong value = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101ul;
+                    Assert.Equal(0b10101010_10101010_10101010_10101010_10101010_10101010_10101010_10101010ul,
+                        BitOperations.RotateRight(value, 1));
+                    Assert.Equal(0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101ul,
+                        BitOperations.RotateRight(value, 2));
+                    Assert.Equal(0b10101010_10101010_10101010_10101010_10101010_10101010_10101010_10101010ul,
+                        BitOperations.RotateRight(value, 3));
+                    Assert.Equal(value, BitOperations.RotateRight(value, int.MinValue)); // % 64 = 0
+                    Assert.Equal(BitOperations.RotateLeft(value, 63),
+                        BitOperations.RotateRight(value, int.MaxValue)); // % 64 = 63
+                }
+                else
+                {
+                    Assert.Equal((nuint)0b00000000_00000000_00000000_00000001u,
+                        BitOperations.RotateRight((nuint)0b10000000_00000000_00000000_00000000u,
+                            int.MaxValue)); // % 32 = 31
+                    Assert.Equal((nuint)0b01000000_00000001_00000000_00000001u,
+                        BitOperations.RotateRight((nuint)0b00000000_00001000_00000000_00001010u, 3));
+                    Assert.Equal((nuint)0b01000000_00000001_00000000_00000001u,
+                        BitOperations.RotateRight((nuint)0b00000000_00000100_00000000_00000101u, 2));
+                    Assert.Equal((nuint)0b10101010_10101010_10101010_10101010u,
+                        BitOperations.RotateRight((nuint)0b01010101_01010101_01010101_01010101u, 1));
+                    Assert.Equal((nuint)0b01010101_11111111_01010101_01010101u,
+                        BitOperations.RotateRight((nuint)0b01010101_11111111_01010101_01010101u, 0));
+                    Assert.Equal((nuint)0b00000000_00000000_00000000_00000001u,
+                        BitOperations.RotateRight((nuint)0b10000000_00000000_00000000_00000000u, -1));
+                    Assert.Equal((nuint)0b00000000_00000000_00000001_00000000u,
+                        BitOperations.RotateRight((nuint)0b00000000_00000000_00000000_01000000u, -2));
+                    Assert.Equal((nuint)0b00000000_00000000_00000000_00000010u,
+                        BitOperations.RotateRight((nuint)0b01000000_00000000_00000000_00000000u, -3));
+                    Assert.Equal((nuint)0b01010101_11111111_01010101_01010101u,
+                        BitOperations.RotateRight((nuint)0b01010101_11111111_01010101_01010101u,
+                            int.MinValue)); // % 32 = 0
+                }
+            }
+        }
+
         [Theory]
         [InlineData(0u, 0u)]
         [InlineData(1u, 1u)]
@@ -436,5 +839,53 @@ namespace System.Numerics.Tests
         {
             Assert.Equal(expected, BitOperations.RoundUpToPowerOf2(value));
         }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
+        [InlineData(0u, 0u)]
+        [InlineData(1u, 1u)]
+        [InlineData(2u, 2u)]
+        [InlineData(0x0096u, 0x0100u)]
+        [InlineData(0x05CDu, 0x0800u)]
+        [InlineData(0x0932u, 0x1000u)]
+        [InlineData(0x0004_C911u, 0x0008_0000u)]
+        [InlineData(0x00E0_A2E2u, 0x0100_0000u)]
+        [InlineData(0x0988_0713u, 0x1000_0000u)]
+        [InlineData(0x30A4_9649u, 0x4000_0000u)]
+        [InlineData(0x7FFF_FFFFu, 0x8000_0000u)]
+        [InlineData(0x8000_0000u, 0x8000_0000u)]
+        [InlineData(0x8000_0001u, 0ul)]
+        [InlineData(0xFFFF_FFFFu, 0ul)]
+        public static void BitOps_RoundUpToPow2_nuint_32(uint value, uint expected)
+        {
+            Assert.Equal(expected, BitOperations.RoundUpToPowerOf2((nuint) value));
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+        [InlineData(0ul, 0ul)]
+        [InlineData(1ul, 1ul)]
+        [InlineData(2ul, 2ul)]
+        [InlineData(0x0096ul, 0x0100ul)]
+        [InlineData(0x05cdul, 0x0800ul)]
+        [InlineData(0x0932ul, 0x1000ul)]
+        [InlineData(0x0004_c911ul, 0x0008_0000ul)]
+        [InlineData(0x00e0_a2b2ul, 0x0100_0000ul)]
+        [InlineData(0x0988_0713ul, 0x1000_0000ul)]
+        [InlineData(0x30a4_9649ul, 0x4000_0000ul)]
+        [InlineData(0x7FFF_FFFFul, 0x8000_0000ul)]
+        [InlineData(0x8000_0000ul, 0x8000_0000ul)]
+        [InlineData(0x8000_0001ul, 0x1_0000_0000ul)]
+        [InlineData(0xFFFF_FFFFul, 0x1_0000_0000ul)]
+        [InlineData(0x0000_0003_343B_0D81ul, 0x0000_0004_0000_0000ul)]
+        [InlineData(0x0000_0D87_5EE2_8F19ul, 0x0000_1000_0000_0000ul)]
+        [InlineData(0x0006_2A08_4A7A_3A2Dul, 0x0008_0000_0000_0000ul)]
+        [InlineData(0x0101_BF76_4398_F791ul, 0x0200_0000_0000_0000ul)]
+        [InlineData(0x7FFF_FFFF_FFFF_FFFFul, 0x8000_0000_0000_0000ul)]
+        [InlineData(0x8000_0000_0000_0000ul, 0x8000_0000_0000_0000ul)]
+        [InlineData(0x8000_0000_0000_0001ul, 0ul)]
+        [InlineData(0xFFFF_FFFF_FFFF_FFFFul, 0ul)]
+        public static void BitOps_RoundUpToPow2_nuint_64(ulong value, ulong expected)
+        {
+            Assert.Equal(expected, BitOperations.RoundUpToPowerOf2((nuint) value));
+        }
     }
 }
index 407ed6e..a7042b6 100644 (file)
@@ -11079,36 +11079,54 @@ namespace System.Numerics
         public static bool IsPow2(long value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static bool IsPow2(ulong value) { throw null; }
+        public static bool IsPow2(nint value) { throw null; }
+        [System.CLSCompliantAttribute(false)]
+        public static bool IsPow2(nuint value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static int LeadingZeroCount(uint value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static int LeadingZeroCount(ulong value) { throw null; }
         [System.CLSCompliantAttribute(false)]
+        public static int LeadingZeroCount(nuint value) { throw null; }
+        [System.CLSCompliantAttribute(false)]
         public static int Log2(uint value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static int Log2(ulong value) { throw null; }
         [System.CLSCompliantAttribute(false)]
+        public static int Log2(nuint value) { throw null; }
+        [System.CLSCompliantAttribute(false)]
         public static int PopCount(uint value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static int PopCount(ulong value) { throw null; }
         [System.CLSCompliantAttribute(false)]
+        public static int PopCount(nuint value) { throw null; }
+        [System.CLSCompliantAttribute(false)]
         public static uint RotateLeft(uint value, int offset) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static ulong RotateLeft(ulong value, int offset) { throw null; }
         [System.CLSCompliantAttribute(false)]
+        public static nuint RotateLeft(nuint value, int offset) { throw null; }
+        [System.CLSCompliantAttribute(false)]
         public static uint RotateRight(uint value, int offset) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static ulong RotateRight(ulong value, int offset) { throw null; }
         [System.CLSCompliantAttribute(false)]
+        public static nuint RotateRight(nuint value, int offset) { throw null; }
+        [System.CLSCompliantAttribute(false)]
         public static uint RoundUpToPowerOf2(uint value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static ulong RoundUpToPowerOf2(ulong value) { throw null; }
+        [System.CLSCompliantAttribute(false)]
+        public static nuint RoundUpToPowerOf2(nuint value) { throw null; }
         public static int TrailingZeroCount(int value) { throw null; }
         public static int TrailingZeroCount(long value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static int TrailingZeroCount(uint value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public static int TrailingZeroCount(ulong value) { throw null; }
+        public static int TrailingZeroCount(nint value) { throw null; }
+        [System.CLSCompliantAttribute(false)]
+        public static int TrailingZeroCount(nuint value) { throw null; }
     }
 }
 namespace System.Reflection