diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9cf81f3..407ce5b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
## 3.2.0
### Added
+- X10D: Added `RoundUpToPowerOf2()` for built-in integer types
- X10D: Added `Vector2.Deconstruct()`
- X10D: Added `Vector3.Deconstruct()`
- X10D: Added `Vector4.Deconstruct()`
diff --git a/X10D.Tests/src/Numerics/ByteTests.cs b/X10D.Tests/src/Numerics/ByteTests.cs
index d4890b2..c9cf215 100644
--- a/X10D.Tests/src/Numerics/ByteTests.cs
+++ b/X10D.Tests/src/Numerics/ByteTests.cs
@@ -39,4 +39,29 @@ public class ByteTests
const byte value = 181; // 10110101
Assert.AreEqual(value, value.RotateRight(8));
}
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnRoundedValue_GivenValue()
+ {
+ Assert.AreEqual(4, ((byte)3).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((byte)5).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((byte)6).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((byte)7).RoundUpToPowerOf2());
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnSameValue_GivenPowerOf2()
+ {
+ for (var i = 0; i < 8; i++)
+ {
+ var value = (byte)System.Math.Pow(2, i);
+ Assert.AreEqual(value, value.RoundUpToPowerOf2());
+ }
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturn0_Given0()
+ {
+ Assert.AreEqual(0, ((byte)0).RoundUpToPowerOf2());
+ }
}
diff --git a/X10D.Tests/src/Numerics/Int16Tests.cs b/X10D.Tests/src/Numerics/Int16Tests.cs
index 11a4a3d..5a40597 100644
--- a/X10D.Tests/src/Numerics/Int16Tests.cs
+++ b/X10D.Tests/src/Numerics/Int16Tests.cs
@@ -41,4 +41,29 @@ public class Int16Tests
const short value = 2896; // 00001011 01010000
Assert.AreEqual(value, value.RotateRight(16));
}
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnRoundedValue_GivenValue()
+ {
+ Assert.AreEqual(4, ((short)3).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((short)5).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((short)6).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((short)7).RoundUpToPowerOf2());
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnSameValue_GivenPowerOf2()
+ {
+ for (var i = 0; i < 8; i++)
+ {
+ var value = (short) System.Math.Pow(2, i);
+ Assert.AreEqual(value, value.RoundUpToPowerOf2());
+ }
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturn0_Given0()
+ {
+ Assert.AreEqual(0, ((short)0).RoundUpToPowerOf2());
+ }
}
diff --git a/X10D.Tests/src/Numerics/Int32Tests.cs b/X10D.Tests/src/Numerics/Int32Tests.cs
index 874b5af..40b8116 100644
--- a/X10D.Tests/src/Numerics/Int32Tests.cs
+++ b/X10D.Tests/src/Numerics/Int32Tests.cs
@@ -39,4 +39,29 @@ public class Int32Tests
const int value = 284719; // 00000000 00000100 01011000 00101111
Assert.AreEqual(value, value.RotateRight(32));
}
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnRoundedValue_GivenValue()
+ {
+ Assert.AreEqual(4, 3.RoundUpToPowerOf2());
+ Assert.AreEqual(8, 5.RoundUpToPowerOf2());
+ Assert.AreEqual(8, 6.RoundUpToPowerOf2());
+ Assert.AreEqual(8, 7.RoundUpToPowerOf2());
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnSameValue_GivenPowerOf2()
+ {
+ for (var i = 0; i < 8; i++)
+ {
+ var value = (int)System.Math.Pow(2, i);
+ Assert.AreEqual(value, value.RoundUpToPowerOf2());
+ }
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturn0_Given0()
+ {
+ Assert.AreEqual(0, 0.RoundUpToPowerOf2());
+ }
}
diff --git a/X10D.Tests/src/Numerics/Int64Tests.cs b/X10D.Tests/src/Numerics/Int64Tests.cs
index 2dff9cf..06bfe52 100644
--- a/X10D.Tests/src/Numerics/Int64Tests.cs
+++ b/X10D.Tests/src/Numerics/Int64Tests.cs
@@ -39,4 +39,29 @@ public class Int64Tests
const long value = 5972019251303316844; // 01010010 11100000 11011111 11011110 00110001 10111010 01111101 01101100
Assert.AreEqual(value, value.RotateRight(64));
}
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnRoundedValue_GivenValue()
+ {
+ Assert.AreEqual(4L, 3L.RoundUpToPowerOf2());
+ Assert.AreEqual(8L, 5L.RoundUpToPowerOf2());
+ Assert.AreEqual(8L, 6L.RoundUpToPowerOf2());
+ Assert.AreEqual(8L, 7L.RoundUpToPowerOf2());
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnSameValue_GivenPowerOf2()
+ {
+ for (var i = 0; i < 8; i++)
+ {
+ var value = (long)System.Math.Pow(2, i);
+ Assert.AreEqual(value, value.RoundUpToPowerOf2());
+ }
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturn0_Given0()
+ {
+ Assert.AreEqual(0L, 0L.RoundUpToPowerOf2());
+ }
}
diff --git a/X10D.Tests/src/Numerics/SByteTests.cs b/X10D.Tests/src/Numerics/SByteTests.cs
index c24ebcf..dafead3 100644
--- a/X10D.Tests/src/Numerics/SByteTests.cs
+++ b/X10D.Tests/src/Numerics/SByteTests.cs
@@ -40,4 +40,29 @@ public class SByteTests
const sbyte value = 117; // 01110101
Assert.AreEqual(value, value.RotateRight(8));
}
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnRoundedValue_GivenValue()
+ {
+ Assert.AreEqual(4, ((sbyte)3).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((sbyte)5).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((sbyte)6).RoundUpToPowerOf2());
+ Assert.AreEqual(8, ((sbyte)7).RoundUpToPowerOf2());
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnSameValue_GivenPowerOf2()
+ {
+ for (var i = 0; i < 7; i++)
+ {
+ var value = (sbyte)System.Math.Pow(2, i);
+ Assert.AreEqual(value, value.RoundUpToPowerOf2());
+ }
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturn0_Given0()
+ {
+ Assert.AreEqual(0, ((sbyte)0).RoundUpToPowerOf2());
+ }
}
diff --git a/X10D.Tests/src/Numerics/UInt16Tests.cs b/X10D.Tests/src/Numerics/UInt16Tests.cs
index 23a5d39..27448c2 100644
--- a/X10D.Tests/src/Numerics/UInt16Tests.cs
+++ b/X10D.Tests/src/Numerics/UInt16Tests.cs
@@ -42,4 +42,29 @@ public class UInt16Tests
const ushort value = 2896; // 00001011 01010000
Assert.AreEqual(value, value.RotateRight(16));
}
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnRoundedValue_GivenValue()
+ {
+ Assert.AreEqual(4U, ((ushort)3).RoundUpToPowerOf2());
+ Assert.AreEqual(8U, ((ushort)5).RoundUpToPowerOf2());
+ Assert.AreEqual(8U, ((ushort)6).RoundUpToPowerOf2());
+ Assert.AreEqual(8U, ((ushort)7).RoundUpToPowerOf2());
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnSameValue_GivenPowerOf2()
+ {
+ for (var i = 0; i < 8; i++)
+ {
+ var value = (ushort)System.Math.Pow(2, i);
+ Assert.AreEqual(value, value.RoundUpToPowerOf2());
+ }
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturn0_Given0()
+ {
+ Assert.AreEqual(0U, ((ushort)0).RoundUpToPowerOf2());
+ }
}
diff --git a/X10D.Tests/src/Numerics/UInt32Tests.cs b/X10D.Tests/src/Numerics/UInt32Tests.cs
index 5686953..6cc6c94 100644
--- a/X10D.Tests/src/Numerics/UInt32Tests.cs
+++ b/X10D.Tests/src/Numerics/UInt32Tests.cs
@@ -39,5 +39,28 @@ public class UInt32Tests
{
const uint value = 284719; // 00000000 00000100 01011000 00101111
Assert.AreEqual(value, value.RotateRight(32));
+ } [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnRoundedValue_GivenValue()
+ {
+ Assert.AreEqual(4U, 3U.RoundUpToPowerOf2());
+ Assert.AreEqual(8U, 5U.RoundUpToPowerOf2());
+ Assert.AreEqual(8U, 6U.RoundUpToPowerOf2());
+ Assert.AreEqual(8U, 7U.RoundUpToPowerOf2());
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnSameValue_GivenPowerOf2()
+ {
+ for (var i = 0; i < 8; i++)
+ {
+ var value = (uint)System.Math.Pow(2, i);
+ Assert.AreEqual(value, value.RoundUpToPowerOf2());
+ }
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturn0_Given0()
+ {
+ Assert.AreEqual(0U, 0U.RoundUpToPowerOf2());
}
}
diff --git a/X10D.Tests/src/Numerics/UInt64Tests.cs b/X10D.Tests/src/Numerics/UInt64Tests.cs
index 7d2f026..c2006f9 100644
--- a/X10D.Tests/src/Numerics/UInt64Tests.cs
+++ b/X10D.Tests/src/Numerics/UInt64Tests.cs
@@ -40,4 +40,29 @@ public class UInt64Tests
const ulong value = 5972019251303316844; // 01010010 11100000 11011111 11011110 00110001 10111010 01111101 01101100
Assert.AreEqual(value, value.RotateRight(64));
}
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnRoundedValue_GivenValue()
+ {
+ Assert.AreEqual(4UL, 3UL.RoundUpToPowerOf2());
+ Assert.AreEqual(8UL, 5UL.RoundUpToPowerOf2());
+ Assert.AreEqual(8UL, 6UL.RoundUpToPowerOf2());
+ Assert.AreEqual(8UL, 7UL.RoundUpToPowerOf2());
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturnSameValue_GivenPowerOf2()
+ {
+ for (var i = 0; i < 8; i++)
+ {
+ var value = (ulong)System.Math.Pow(2, i);
+ Assert.AreEqual(value, value.RoundUpToPowerOf2());
+ }
+ }
+
+ [TestMethod]
+ public void RoundUpToPowerOf2_ShouldReturn0_Given0()
+ {
+ Assert.AreEqual(0UL, 0UL.RoundUpToPowerOf2());
+ }
}
diff --git a/X10D/src/Numerics/ByteExtensions.cs b/X10D/src/Numerics/ByteExtensions.cs
index 02c6e74..6435be4 100644
--- a/X10D/src/Numerics/ByteExtensions.cs
+++ b/X10D/src/Numerics/ByteExtensions.cs
@@ -48,4 +48,23 @@ public static class ByteExtensions
count = count.Mod(8);
return (byte)((value >> count) | (value << (8 - count)));
}
+
+ ///
+ /// Rounds the current value up to a power of two.
+ ///
+ /// The value to round.
+ ///
+ /// The smallest power of two that's greater than or equal to , or 0 if
+ /// is 0 or the result overflows.
+ ///
+ [Pure]
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+#endif
+ public static byte RoundUpToPowerOf2(this byte value)
+ {
+ return (byte)((uint)value).RoundUpToPowerOf2();
+ }
}
diff --git a/X10D/src/Numerics/Int16Extensions.cs b/X10D/src/Numerics/Int16Extensions.cs
index 1a3656b..db48f91 100644
--- a/X10D/src/Numerics/Int16Extensions.cs
+++ b/X10D/src/Numerics/Int16Extensions.cs
@@ -47,4 +47,23 @@ public static class Int16Extensions
var unsigned = unchecked((ushort)value);
return unchecked((short)unsigned.RotateRight(count));
}
+
+ ///
+ /// Rounds the current value up to a power of two.
+ ///
+ /// The value to round.
+ ///
+ /// The smallest power of two that's greater than or equal to , or 0 if
+ /// is 0 or the result overflows.
+ ///
+ [Pure]
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+#endif
+ public static short RoundUpToPowerOf2(this short value)
+ {
+ return (short)((uint)value).RoundUpToPowerOf2();
+ }
}
diff --git a/X10D/src/Numerics/Int32Extensions.cs b/X10D/src/Numerics/Int32Extensions.cs
index 3bf74b9..74ebca4 100644
--- a/X10D/src/Numerics/Int32Extensions.cs
+++ b/X10D/src/Numerics/Int32Extensions.cs
@@ -47,4 +47,23 @@ public static class Int32Extensions
var unsigned = unchecked((uint)value);
return unchecked((int)unsigned.RotateRight(count));
}
+
+ ///
+ /// Rounds the current value up to a power of two.
+ ///
+ /// The value to round.
+ ///
+ /// The smallest power of two that's greater than or equal to , or 0 if
+ /// is 0 or the result overflows.
+ ///
+ [Pure]
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+#endif
+ public static int RoundUpToPowerOf2(this int value)
+ {
+ return (int)((uint)value).RoundUpToPowerOf2();
+ }
}
diff --git a/X10D/src/Numerics/Int64Extensions.cs b/X10D/src/Numerics/Int64Extensions.cs
index 695ed4b..f3a3283 100644
--- a/X10D/src/Numerics/Int64Extensions.cs
+++ b/X10D/src/Numerics/Int64Extensions.cs
@@ -47,4 +47,23 @@ public static class Int64Extensions
var unsigned = unchecked((ulong)value);
return unchecked((long)unsigned.RotateRight(count));
}
+
+ ///
+ /// Rounds the current value up to a power of two.
+ ///
+ /// The value to round.
+ ///
+ /// The smallest power of two that's greater than or equal to , or 0 if
+ /// is 0 or the result overflows.
+ ///
+ [Pure]
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+#endif
+ public static long RoundUpToPowerOf2(this long value)
+ {
+ return (long)((ulong)value).RoundUpToPowerOf2();
+ }
}
diff --git a/X10D/src/Numerics/SByteExtensions.cs b/X10D/src/Numerics/SByteExtensions.cs
index eb6ce07..85c393d 100644
--- a/X10D/src/Numerics/SByteExtensions.cs
+++ b/X10D/src/Numerics/SByteExtensions.cs
@@ -48,4 +48,23 @@ public static class SByteExtensions
var signed = unchecked((byte)value);
return unchecked((sbyte)signed.RotateRight(count));
}
+
+ ///
+ /// Rounds the current value up to a power of two.
+ ///
+ /// The value to round.
+ ///
+ /// The smallest power of two that's greater than or equal to , or 0 if
+ /// is 0 or the result overflows.
+ ///
+ [Pure]
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+#endif
+ public static sbyte RoundUpToPowerOf2(this sbyte value)
+ {
+ return (sbyte)((uint)value).RoundUpToPowerOf2();
+ }
}
diff --git a/X10D/src/Numerics/UInt16Extensions.cs b/X10D/src/Numerics/UInt16Extensions.cs
index 54403c9..af4e344 100644
--- a/X10D/src/Numerics/UInt16Extensions.cs
+++ b/X10D/src/Numerics/UInt16Extensions.cs
@@ -46,4 +46,23 @@ public static class UInt16Extensions
{
return (ushort)((ushort)(value >> count) | (ushort)(value << (16 - count)));
}
+
+ ///
+ /// Rounds the current value up to a power of two.
+ ///
+ /// The value to round.
+ ///
+ /// The smallest power of two that's greater than or equal to , or 0 if
+ /// is 0 or the result overflows.
+ ///
+ [Pure]
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+#endif
+ public static ushort RoundUpToPowerOf2(this ushort value)
+ {
+ return (ushort)((uint)value).RoundUpToPowerOf2();
+ }
}
diff --git a/X10D/src/Numerics/UInt32Extensions.cs b/X10D/src/Numerics/UInt32Extensions.cs
index 7381b1b..51940af 100644
--- a/X10D/src/Numerics/UInt32Extensions.cs
+++ b/X10D/src/Numerics/UInt32Extensions.cs
@@ -1,4 +1,5 @@
using System.Diagnostics.Contracts;
+using System.Numerics;
using System.Runtime.CompilerServices;
namespace X10D.Numerics;
@@ -46,4 +47,34 @@ public static class UInt32Extensions
{
return (value >> count) | (value << (32 - count));
}
+
+ ///
+ /// Rounds the current value up to a power of two.
+ ///
+ /// The value to round.
+ ///
+ /// The smallest power of two that's greater than or equal to , or 0 if
+ /// is 0 or the result overflows.
+ ///
+ [Pure]
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+#endif
+ public static uint RoundUpToPowerOf2(this uint value)
+ {
+#if NET6_0_OR_GREATER
+ return BitOperations.RoundUpToPowerOf2(value);
+#else
+ // Based on https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ --value;
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ return value + 1;
+#endif
+ }
}
diff --git a/X10D/src/Numerics/UInt64Extensions.cs b/X10D/src/Numerics/UInt64Extensions.cs
index 0f10aba..d97c1f7 100644
--- a/X10D/src/Numerics/UInt64Extensions.cs
+++ b/X10D/src/Numerics/UInt64Extensions.cs
@@ -1,4 +1,5 @@
using System.Diagnostics.Contracts;
+using System.Numerics;
using System.Runtime.CompilerServices;
namespace X10D.Numerics;
@@ -46,4 +47,35 @@ public static class UInt64Extensions
{
return (value >> count) | (value << (64 - count));
}
+
+ ///
+ /// Rounds the current value up to a power of two.
+ ///
+ /// The value to round.
+ ///
+ /// The smallest power of two that's greater than or equal to , or 0 if
+ /// is 0 or the result overflows.
+ ///
+ [Pure]
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+#endif
+ public static ulong RoundUpToPowerOf2(this ulong value)
+ {
+#if NET6_0_OR_GREATER
+ return BitOperations.RoundUpToPowerOf2(value);
+#else
+ // Based on https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ --value;
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ value |= value >> 32;
+ return value + 1;
+#endif
+ }
}