diff --git a/BitFaster.Caching.UnitTests/BitOpsTests.cs b/BitFaster.Caching.UnitTests/BitOpsTests.cs
index 51a37b96..bfc956c2 100644
--- a/BitFaster.Caching.UnitTests/BitOpsTests.cs
+++ b/BitFaster.Caching.UnitTests/BitOpsTests.cs
@@ -20,6 +20,17 @@ 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)]
+ [InlineData(34359738368, 34359738368)]
+ public void LongCeilingPowerOfTwo(long input, long power)
+ {
+ BitOps.CeilingPowerOfTwo(input).Should().Be(power);
+ }
+
[Theory]
[InlineData(3, 4)]
[InlineData(7, 8)]
@@ -31,6 +42,46 @@ 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)
+ {
+ 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)]
+ [InlineData(2, 1)]
+ [InlineData(1_000_000, 6)]
+ [InlineData(34359738368, 35)]
+ [InlineData(9223372036854775808, 63)]
+ [InlineData(ulong.MaxValue, 0)]
+
+ public void ULongTrailingZeroCount(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..9c35873e 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 1ul << -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
}
///