Browse Source

memory: added constexpr function next_power_of_two

Michele Caini 4 years ago
parent
commit
3144cfafd5
2 changed files with 44 additions and 1 deletions
  1. 21 0
      src/entt/core/memory.hpp
  2. 23 1
      test/entt/core/memory.cpp

+ 21 - 0
src/entt/core/memory.hpp

@@ -75,6 +75,27 @@ constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[ma
     return value && ((value & (value - 1)) == 0);
 }
 
+/**
+ * @brief Computes the smallest power of two greater than or equal to a value.
+ * @param value The value to use.
+ * @return The smallest power of two greater than or equal to the given value.
+ */
+[[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
+    std::size_t curr = value;
+
+    curr |= curr >> 1;
+    curr |= curr >> 2;
+    curr |= curr >> 4;
+    curr |= curr >> 8;
+    curr |= curr >> 16;
+
+    if constexpr(sizeof(value) > sizeof(std::uint32_t)) {
+        curr |= curr >> 32;
+    }
+
+    return ++curr;
+}
+
 /**
  * @brief Fast module utility function (powers of two only).
  * @tparam Value Compile-time page size, it must be a power of two.

+ 23 - 1
test/entt/core/memory.cpp

@@ -1,3 +1,4 @@
+#include <cmath>
 #include <memory>
 #include <gtest/gtest.h>
 #include <entt/core/memory.hpp>
@@ -33,7 +34,10 @@ TEST(Memory, PoccaPocmaAndPocs) {
 }
 
 TEST(Memory, IsPowerOfTwo) {
-    ASSERT_FALSE(entt::is_power_of_two(0u));
+    // constexpr-ness guaranteed
+    constexpr auto zero_is_power_of_two = entt::is_power_of_two(0u);
+
+    ASSERT_FALSE(zero_is_power_of_two);
     ASSERT_TRUE(entt::is_power_of_two(1u));
     ASSERT_TRUE(entt::is_power_of_two(2u));
     ASSERT_TRUE(entt::is_power_of_two(4u));
@@ -42,6 +46,24 @@ TEST(Memory, IsPowerOfTwo) {
     ASSERT_FALSE(entt::is_power_of_two(200u));
 }
 
+TEST(Memory, NextPowerOfTwo) {
+    // constexpr-ness guaranteed
+    constexpr auto next_power_of_two_of_zero = entt::next_power_of_two(0u);
+
+    ASSERT_EQ(next_power_of_two_of_zero, 1u);
+    ASSERT_EQ(entt::next_power_of_two(1u), 2u);
+    ASSERT_EQ(entt::next_power_of_two(17u), 32u);
+    ASSERT_EQ(entt::next_power_of_two(32u), 64u);
+    ASSERT_EQ(entt::next_power_of_two(32u), 64u);
+
+    if constexpr(sizeof(std::size_t) > sizeof(std::uint32_t)) {
+        ASSERT_EQ(entt::next_power_of_two(std::pow(2, 32)), std::pow(2, 33));
+        ASSERT_EQ(entt::next_power_of_two(std::pow(2, 64)), 0u);
+    } else {
+        ASSERT_EQ(entt::next_power_of_two(std::pow(2, 32)), 0u);
+    }
+}
+
 TEST(Memory, FastMod) {
     ASSERT_EQ(entt::fast_mod<8u>(0u), 0u);
     ASSERT_EQ(entt::fast_mod<8u>(7u), 7u);