diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs index b5ffd5e777d984..6a7141cd01cd48 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs @@ -76,14 +76,15 @@ public static class BitOperations /// /// The value. [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; /// /// Evaluate whether a given integral value is a power of 2. /// /// The value. [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; /// Round the given integral value up to a power of 2. /// The value. @@ -115,7 +116,6 @@ public static uint RoundUpToPowerOf2(uint value) return value + 1; } - /// /// Round the given integral value up to a power of 2. /// @@ -145,6 +145,25 @@ public static ulong RoundUpToPowerOf2(ulong value) return value + 1; } + /// + /// Round the given integral value up to a power of 2. + /// + /// The value. + /// + /// The smallest power of 2 which is greater than or equal to . + /// If is 0 or the result overflows, returns 0. + /// + [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 + } + /// /// Count the number of leading zero bits in a mask. /// Similar in behavior to the x86 instruction LZCNT. @@ -218,6 +237,22 @@ public static int LeadingZeroCount(ulong value) return LeadingZeroCount(hi); } + /// + /// Count the number of leading zero bits in a mask. + /// Similar in behavior to the x86 instruction LZCNT. + /// + /// The value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [CLSCompliant(false)] + public static int LeadingZeroCount(nuint value) + { +#if TARGET_64BIT + return LeadingZeroCount((ulong)value); +#else + return LeadingZeroCount((uint)value); +#endif + } + /// /// 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. @@ -294,6 +329,22 @@ public static int Log2(ulong value) return 32 + Log2(hi); } + /// + /// 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. + /// + /// The value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [CLSCompliant(false)] + public static int Log2(nuint value) + { +#if TARGET_64BIT + return Log2((ulong)value); +#else + return Log2((uint)value); +#endif + } + /// /// 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. @@ -432,6 +483,22 @@ static int SoftwareFallback(ulong value) #endif } + /// + /// Returns the population count (number of bits set) of a mask. + /// Similar in behavior to the x86 instruction POPCNT. + /// + /// The value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [CLSCompliant(false)] + public static int PopCount(nuint value) + { +#if TARGET_64BIT + return PopCount((ulong)value); +#else + return PopCount((uint)value); +#endif + } + /// /// Count the number of trailing zero bits in an integer value. /// Similar in behavior to the x86 instruction TZCNT. @@ -525,6 +592,31 @@ public static int TrailingZeroCount(ulong value) return TrailingZeroCount(lo); } + /// + /// Count the number of trailing zero bits in a mask. + /// Similar in behavior to the x86 instruction TZCNT. + /// + /// The value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int TrailingZeroCount(nint value) + => TrailingZeroCount((nuint)value); + + /// + /// Count the number of trailing zero bits in a mask. + /// Similar in behavior to the x86 instruction TZCNT. + /// + /// The value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [CLSCompliant(false)] + public static int TrailingZeroCount(nuint value) + { +#if TARGET_64BIT + return TrailingZeroCount((ulong)value); +#else + return TrailingZeroCount((uint)value); +#endif + } + /// /// Rotates the specified value left by the specified number of bits. /// Similar in behavior to the x86 instruction ROL. @@ -551,6 +643,26 @@ public static uint RotateLeft(uint value, int offset) public static ulong RotateLeft(ulong value, int offset) => (value << offset) | (value >> (64 - offset)); + /// + /// Rotates the specified value left by the specified number of bits. + /// Similar in behavior to the x86 instruction ROL. + /// + /// The value to rotate. + /// 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. + /// The rotated value. + [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 + } + /// /// Rotates the specified value right by the specified number of bits. /// Similar in behavior to the x86 instruction ROR. @@ -576,5 +688,25 @@ public static uint RotateRight(uint value, int offset) [CLSCompliant(false)] public static ulong RotateRight(ulong value, int offset) => (value >> offset) | (value << (64 - offset)); + + /// + /// Rotates the specified value right by the specified number of bits. + /// Similar in behavior to the x86 instruction ROR. + /// + /// The value to rotate. + /// 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. + /// The rotated value. + [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 + } } } diff --git a/src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj b/src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj index 3333157e1ca028..10d77e4c9ec050 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj +++ b/src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj @@ -75,16 +75,11 @@ - - - - - + + + + + diff --git a/src/libraries/System.Runtime.Extensions/tests/System/Numerics/BitOperationsTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/Numerics/BitOperationsTests.cs index 7836538dbe7480..2bfc0d26ad6d29 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/Numerics/BitOperationsTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/Numerics/BitOperationsTests.cs @@ -93,6 +93,90 @@ public static void BitOps_IsPow2_ulong(ulong n, bool expected) 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 @@ public static void BitOps_LeadingZeroCount_ulong(ulong n, int expected) 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 @@ public static void BitOps_TrailingZeroCount_long(long n, int expected) 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 @@ public static void BitOps_Log2_ulong(ulong n, int expected) 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 @@ public static void BitOps_PopCount_ulong(ulong n, int expected) 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)] @@ -352,6 +667,50 @@ public static void BitOps_RotateLeft_uint(uint n, int offset, uint expected) Assert.Equal(expected, BitOperations.RotateLeft(n, offset)); } + [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() { @@ -389,6 +748,50 @@ public static void BitOps_RotateRight_ulong() 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 @@ public static void BitOps_RoundUpToPow2_ulong(ulong value, ulong expected) { 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)); + } } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 5de2f8d1c1605d..2d2f3ac15fbf05 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -11017,36 +11017,54 @@ public static partial class BitOperations 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