diff --git a/src/entt/core/memory.hpp b/src/entt/core/memory.hpp index 8c365ab8d..81b0533f3 100644 --- a/src/entt/core/memory.hpp +++ b/src/entt/core/memory.hpp @@ -11,6 +11,18 @@ namespace entt { +/** + * @brief Returns the number of set bits in a value (waiting for C++20 and + * `std::popcount`). + * @tparam Type Unsigned integer type. + * @param value A value of unsigned integer type. + * @return The number of set bits in the value. + */ +template +constexpr std::enable_if_t, int> popcount(Type value) noexcept { + return value ? (int(value & 1) + popcount(static_cast(value >> 1))) : 0; +} + /** * @brief Checks whether a value is a power of two or not (waiting for C++20 and * `std::has_single_bit`). diff --git a/src/entt/entity/entity.hpp b/src/entt/entity/entity.hpp index c6557189f..2d8e0cd17 100644 --- a/src/entt/entity/entity.hpp +++ b/src/entt/entity/entity.hpp @@ -5,6 +5,7 @@ #include #include #include "../config/config.h" +#include "../core/memory.hpp" #include "fwd.hpp" namespace entt { @@ -12,12 +13,6 @@ namespace entt { /*! @cond TURN_OFF_DOXYGEN */ namespace internal { -// waiting for C++20 and std::popcount -template -constexpr int popcount(Type value) noexcept { - return value ? (int(value & 1) + popcount(value >> 1)) : 0; -} - template struct entt_traits; @@ -64,7 +59,7 @@ struct entt_traits { */ template class basic_entt_traits { - static constexpr auto length = internal::popcount(Traits::entity_mask); + static constexpr auto length = popcount(Traits::entity_mask); static_assert(Traits::entity_mask && ((Traits::entity_mask & (Traits::entity_mask + 1)) == 0), "Invalid entity mask"); static_assert((Traits::version_mask & (Traits::version_mask + 1)) == 0, "Invalid version mask"); diff --git a/test/entt/core/memory.cpp b/test/entt/core/memory.cpp index 3074eb5ce..77d4dc9cc 100644 --- a/test/entt/core/memory.cpp +++ b/test/entt/core/memory.cpp @@ -15,32 +15,17 @@ #include "../../common/throwing_type.hpp" #include "../../common/tracked_memory_resource.hpp" -TEST(ToAddress, Functionalities) { - const std::shared_ptr shared = std::make_shared(); - auto *plain = std::addressof(*shared); +TEST(PopCount, Functionalities) { + // constexpr-ness guaranteed + constexpr auto zero_popcount = entt::popcount(0u); - ASSERT_EQ(entt::to_address(shared), plain); - ASSERT_EQ(entt::to_address(plain), plain); -} - -TEST(PoccaPocmaAndPocs, Functionalities) { - test::basic_test_allocator lhs, rhs; - test::basic_test_allocator no_pocs; - - // code coverage purposes - ASSERT_FALSE(lhs == rhs); - ASSERT_NO_THROW(entt::propagate_on_container_swap(no_pocs, no_pocs)); - - // honestly, I don't even know how one is supposed to test such a thing :) - entt::propagate_on_container_copy_assignment(lhs, rhs); - entt::propagate_on_container_move_assignment(lhs, rhs); - entt::propagate_on_container_swap(lhs, rhs); -} - -ENTT_DEBUG_TEST(PoccaPocmaAndPocsDeathTest, Functionalities) { - test::basic_test_allocator lhs, rhs; - - ASSERT_DEATH(entt::propagate_on_container_swap(lhs, rhs), ""); + ASSERT_EQ(zero_popcount, 0u); + ASSERT_EQ(entt::popcount(1u), 1u); + ASSERT_EQ(entt::popcount(2u), 1u); + ASSERT_EQ(entt::popcount(3u), 2u); + ASSERT_EQ(entt::popcount(7u), 3u); + ASSERT_EQ(entt::popcount(128u), 1u); + ASSERT_EQ(entt::popcount(201u), 4u); } TEST(IsPowerOfTwo, Functionalities) { @@ -84,6 +69,34 @@ TEST(FastMod, Functionalities) { ASSERT_EQ(entt::fast_mod(8u, 8u), 0u); } +TEST(ToAddress, Functionalities) { + const std::shared_ptr shared = std::make_shared(); + auto *plain = std::addressof(*shared); + + ASSERT_EQ(entt::to_address(shared), plain); + ASSERT_EQ(entt::to_address(plain), plain); +} + +TEST(PoccaPocmaAndPocs, Functionalities) { + test::basic_test_allocator lhs, rhs; + test::basic_test_allocator no_pocs; + + // code coverage purposes + ASSERT_FALSE(lhs == rhs); + ASSERT_NO_THROW(entt::propagate_on_container_swap(no_pocs, no_pocs)); + + // honestly, I don't even know how one is supposed to test such a thing :) + entt::propagate_on_container_copy_assignment(lhs, rhs); + entt::propagate_on_container_move_assignment(lhs, rhs); + entt::propagate_on_container_swap(lhs, rhs); +} + +ENTT_DEBUG_TEST(PoccaPocmaAndPocsDeathTest, Functionalities) { + test::basic_test_allocator lhs, rhs; + + ASSERT_DEATH(entt::propagate_on_container_swap(lhs, rhs), ""); +} + TEST(AllocateUnique, Functionalities) { test::throwing_allocator allocator{};