From a74a53f06b46d784cf51a793665b6a117037dc97 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 25 Nov 2023 12:44:07 -0800 Subject: [PATCH 1/4] add bitops --- BitFaster.Caching.UnitTests/BitOpsTests.cs | 36 ++++++++++++++ BitFaster.Caching/BitOps.cs | 56 ++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/BitFaster.Caching.UnitTests/BitOpsTests.cs b/BitFaster.Caching.UnitTests/BitOpsTests.cs index 51a37b96..ee2b184b 100644 --- a/BitFaster.Caching.UnitTests/BitOpsTests.cs +++ b/BitFaster.Caching.UnitTests/BitOpsTests.cs @@ -20,6 +20,16 @@ public void IntCeilingPowerOfTwo(int input, int power) BitOps.CeilingPowerOfTwo(input).Should().Be(power); } + [Theory] + [InlineData(3, 4)] + [InlineData(7, 8)] + [InlineData(15, 16)] + [InlineData(536870913, 1073741824)] + public void LongCeilingPowerOfTwo(long input, long power) + { + BitOps.CeilingPowerOfTwo(input).Should().Be(power); + } + [Theory] [InlineData(3, 4)] [InlineData(7, 8)] @@ -31,6 +41,32 @@ public void UIntCeilingPowerOfTwo(uint input, uint power) BitOps.CeilingPowerOfTwo(input).Should().Be(power); } + + [Theory] + [InlineData(3, 4)] + [InlineData(7, 8)] + [InlineData(15, 16)] + [InlineData(536870913, 1073741824)] + + public void UlongCeilingPowerOfTwo(ulong input, ulong power) + { + BitOps.CeilingPowerOfTwo(input).Should().Be(power); + } + + [Theory] + [InlineData(0, 64)] + [InlineData(1, 0)] + [InlineData(2, 1)] + [InlineData(1_000_000, 6)] + [InlineData(34359738368, 35)] + [InlineData(9223372036854775808, 63)] + [InlineData(ulong.MaxValue, 0)] + + public void LongTrailingZeroCount(ulong input, int count) + { + BitOps.TrailingZeroCount(input).Should().Be(count); + } + [Fact] public void IntBitCount() { diff --git a/BitFaster.Caching/BitOps.cs b/BitFaster.Caching/BitOps.cs index 27a4cee8..0d7285f3 100644 --- a/BitFaster.Caching/BitOps.cs +++ b/BitFaster.Caching/BitOps.cs @@ -17,6 +17,16 @@ public static int CeilingPowerOfTwo(int x) return (int)CeilingPowerOfTwo((uint)x); } + /// + /// Calculate the smallest power of 2 greater than the input parameter. + /// + /// The input parameter. + /// Smallest power of two greater than or equal to x. + internal static long CeilingPowerOfTwo(long x) + { + return (long)CeilingPowerOfTwo((ulong)x); + } + /// /// Calculate the smallest power of 2 greater than the input parameter. /// @@ -36,7 +46,53 @@ public static uint CeilingPowerOfTwo(uint x) #else return 1u << -BitOperations.LeadingZeroCount(x - 1); #endif + } + + /// + /// Calculate the smallest power of 2 greater than the input parameter. + /// + /// The input parameter. + /// Smallest power of two greater than or equal to x. + internal static ulong CeilingPowerOfTwo(ulong x) + { +#if NETSTANDARD2_0 + // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x |= x >> 32; + return x + 1; +#else + return 1u << -BitOperations.LeadingZeroCount(x - 1); +#endif + } + /// + /// Counts the number of trailing zero bits in the input parameter. + /// + /// The input parameter. + /// The number of trailing zero bits. + internal static int TrailingZeroCount(long x) + { + return TrailingZeroCount((ulong)x); + } + + /// + /// Counts the number of trailing zero bits in the input parameter. + /// + /// The input parameter. + /// The number of trailing zero bits. + internal static int TrailingZeroCount(ulong x) + { +#if NETSTANDARD2_0 + // https://codereview.stackexchange.com/questions/288007/c-bit-utility-functions-popcount-trailing-zeros-count-reverse-all-bits + return BitCount(~x & (x - 1)); +#else + return BitOperations.TrailingZeroCount(x); +#endif } /// From d378725e87987781d3a5928368547ce2759a7fd9 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 25 Nov 2023 12:47:33 -0800 Subject: [PATCH 2/4] 64bit test --- BitFaster.Caching.UnitTests/BitOpsTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/BitFaster.Caching.UnitTests/BitOpsTests.cs b/BitFaster.Caching.UnitTests/BitOpsTests.cs index ee2b184b..849637d8 100644 --- a/BitFaster.Caching.UnitTests/BitOpsTests.cs +++ b/BitFaster.Caching.UnitTests/BitOpsTests.cs @@ -25,6 +25,7 @@ public void IntCeilingPowerOfTwo(int input, int power) [InlineData(7, 8)] [InlineData(15, 16)] [InlineData(536870913, 1073741824)] + [InlineData(34359738368, 34359738368)] public void LongCeilingPowerOfTwo(long input, long power) { BitOps.CeilingPowerOfTwo(input).Should().Be(power); From 8e4b0b6617532c0e74818441558a32e5c2f35dc0 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 25 Nov 2023 13:57:41 -0800 Subject: [PATCH 3/4] fix long --- BitFaster.Caching.UnitTests/BitOpsTests.cs | 2 +- BitFaster.Caching/BitOps.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BitFaster.Caching.UnitTests/BitOpsTests.cs b/BitFaster.Caching.UnitTests/BitOpsTests.cs index 849637d8..af776f91 100644 --- a/BitFaster.Caching.UnitTests/BitOpsTests.cs +++ b/BitFaster.Caching.UnitTests/BitOpsTests.cs @@ -42,12 +42,12 @@ public void UIntCeilingPowerOfTwo(uint input, uint power) BitOps.CeilingPowerOfTwo(input).Should().Be(power); } - [Theory] [InlineData(3, 4)] [InlineData(7, 8)] [InlineData(15, 16)] [InlineData(536870913, 1073741824)] + [InlineData(34359738368, 34359738368)] public void UlongCeilingPowerOfTwo(ulong input, ulong power) { diff --git a/BitFaster.Caching/BitOps.cs b/BitFaster.Caching/BitOps.cs index 0d7285f3..9c35873e 100644 --- a/BitFaster.Caching/BitOps.cs +++ b/BitFaster.Caching/BitOps.cs @@ -66,7 +66,7 @@ internal static ulong CeilingPowerOfTwo(ulong x) x |= x >> 32; return x + 1; #else - return 1u << -BitOperations.LeadingZeroCount(x - 1); + return 1ul << -BitOperations.LeadingZeroCount(x - 1); #endif } From 68a9bba966b128b85f9aaaa0987cdceee0873810 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 25 Nov 2023 14:28:26 -0800 Subject: [PATCH 4/4] test long --- BitFaster.Caching.UnitTests/BitOpsTests.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/BitFaster.Caching.UnitTests/BitOpsTests.cs b/BitFaster.Caching.UnitTests/BitOpsTests.cs index af776f91..bfc956c2 100644 --- a/BitFaster.Caching.UnitTests/BitOpsTests.cs +++ b/BitFaster.Caching.UnitTests/BitOpsTests.cs @@ -54,6 +54,20 @@ public void UlongCeilingPowerOfTwo(ulong input, ulong power) BitOps.CeilingPowerOfTwo(input).Should().Be(power); } + [Theory] + [InlineData(0, 64)] + [InlineData(1, 0)] + [InlineData(2, 1)] + [InlineData(1_000_000, 6)] + [InlineData(34359738368, 35)] + [InlineData(4611686018427387904, 62)] + [InlineData(long.MaxValue, 0)] + + public void LongTrailingZeroCount(long input, int count) + { + BitOps.TrailingZeroCount(input).Should().Be(count); + } + [Theory] [InlineData(0, 64)] [InlineData(1, 0)] @@ -63,7 +77,7 @@ public void UlongCeilingPowerOfTwo(ulong input, ulong power) [InlineData(9223372036854775808, 63)] [InlineData(ulong.MaxValue, 0)] - public void LongTrailingZeroCount(ulong input, int count) + public void ULongTrailingZeroCount(ulong input, int count) { BitOps.TrailingZeroCount(input).Should().Be(count); }