Browse Source

memory: fast_mod no longer requires a compile-time modulus (but it's still a constexpr function)

Michele Caini 4 years ago
parent
commit
e4991d367e

+ 5 - 6
src/entt/core/memory.hpp

@@ -98,14 +98,13 @@ constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[ma
 
 
 /**
 /**
  * @brief Fast module utility function (powers of two only).
  * @brief Fast module utility function (powers of two only).
- * @tparam Value Compile-time page size, it must be a power of two.
  * @param value A value for which to calculate the modulus.
  * @param value A value for which to calculate the modulus.
- * @return Remainder of division.
+ * @param mod _Modulus_, it must be a power of two.
+ * @return The common remainder.
  */
  */
-template<std::size_t Value>
-[[nodiscard]] constexpr std::size_t fast_mod(const std::size_t value) ENTT_NOEXCEPT {
-    static_assert(is_power_of_two(Value), "Value must be a power of two");
-    return value & (Value - 1u);
+[[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) ENTT_NOEXCEPT {
+    ENTT_ASSERT(is_power_of_two(mod), "Value must be a power of two");
+    return value & (mod - 1u);
 }
 }
 
 
 } // namespace entt
 } // namespace entt

+ 3 - 3
src/entt/entity/sparse_set.hpp

@@ -171,13 +171,13 @@ class basic_sparse_set {
     [[nodiscard]] auto sparse_ptr(const Entity entt) const {
     [[nodiscard]] auto sparse_ptr(const Entity entt) const {
         const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));
         const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));
         const auto page = pos / sparse_page_v;
         const auto page = pos / sparse_page_v;
-        return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod<sparse_page_v>(pos)) : nullptr;
+        return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod(pos, sparse_page_v)) : nullptr;
     }
     }
 
 
     [[nodiscard]] auto &sparse_ref(const Entity entt) const {
     [[nodiscard]] auto &sparse_ref(const Entity entt) const {
         ENTT_ASSERT(sparse_ptr(entt), "Invalid element");
         ENTT_ASSERT(sparse_ptr(entt), "Invalid element");
         const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));
         const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));
-        return sparse[pos / sparse_page_v][fast_mod<sparse_page_v>(pos)];
+        return sparse[pos / sparse_page_v][fast_mod(pos, sparse_page_v)];
     }
     }
 
 
     void release_sparse_pages() {
     void release_sparse_pages() {
@@ -253,7 +253,7 @@ protected:
             std::uninitialized_fill(sparse[page], sparse[page] + sparse_page_v, null);
             std::uninitialized_fill(sparse[page], sparse[page] + sparse_page_v, null);
         }
         }
 
 
-        auto &elem = sparse[page][fast_mod<sparse_page_v>(pos)];
+        auto &elem = sparse[page][fast_mod(pos, sparse_page_v)];
         ENTT_ASSERT(entity_traits::to_version(elem) == entity_traits::to_version(tombstone), "Slot not available");
         ENTT_ASSERT(entity_traits::to_version(elem) == entity_traits::to_version(tombstone), "Slot not available");
 
 
         if(free_list == null) {
         if(free_list == null) {

+ 3 - 3
src/entt/entity/storage.hpp

@@ -123,7 +123,7 @@ public:
 
 
     [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
     [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
         const auto pos = index - 1;
         const auto pos = index - 1;
-        return (*packed)[pos / packed_page_v] + fast_mod<packed_page_v>(pos);
+        return (*packed)[pos / packed_page_v] + fast_mod(pos, packed_page_v);
     }
     }
 
 
     [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
     [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
@@ -182,7 +182,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
     using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
     using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
 
 
     [[nodiscard]] auto &element_at(const std::size_t pos) const {
     [[nodiscard]] auto &element_at(const std::size_t pos) const {
-        return packed.first()[pos / packed_page_v][fast_mod<packed_page_v>(pos)];
+        return packed.first()[pos / packed_page_v][fast_mod(pos, packed_page_v)];
     }
     }
 
 
     auto assure_at_least(const std::size_t pos) {
     auto assure_at_least(const std::size_t pos) {
@@ -204,7 +204,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
             }
             }
         }
         }
 
 
-        return container[idx] + fast_mod<packed_page_v>(pos);
+        return container[idx] + fast_mod(pos, packed_page_v);
     }
     }
 
 
     void release_unused_pages() {
     void release_unused_pages() {

+ 6 - 3
test/entt/core/memory.cpp

@@ -65,7 +65,10 @@ TEST(Memory, NextPowerOfTwo) {
 }
 }
 
 
 TEST(Memory, FastMod) {
 TEST(Memory, FastMod) {
-    ASSERT_EQ(entt::fast_mod<8u>(0u), 0u);
-    ASSERT_EQ(entt::fast_mod<8u>(7u), 7u);
-    ASSERT_EQ(entt::fast_mod<8u>(8u), 0u);
+    // constexpr-ness guaranteed
+    constexpr auto fast_mod_of_zero = entt::fast_mod(0u, 8u);
+
+    ASSERT_EQ(fast_mod_of_zero, 0u);
+    ASSERT_EQ(entt::fast_mod(7u, 8u), 7u);
+    ASSERT_EQ(entt::fast_mod(8u, 8u), 0u);
 }
 }