core: public popcount (waiting for C++20)

This commit is contained in:
Michele Caini
2024-06-10 18:32:28 +02:00
parent 3cec7c1065
commit fb47314d6f
3 changed files with 52 additions and 32 deletions

View File

@@ -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<typename Type>
constexpr std::enable_if_t<std::is_unsigned_v<Type>, int> popcount(Type value) noexcept {
return value ? (int(value & 1) + popcount(static_cast<Type>(value >> 1))) : 0;
}
/**
* @brief Checks whether a value is a power of two or not (waiting for C++20 and
* `std::has_single_bit`).

View File

@@ -5,6 +5,7 @@
#include <cstdint>
#include <type_traits>
#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<typename Type>
constexpr int popcount(Type value) noexcept {
return value ? (int(value & 1) + popcount(value >> 1)) : 0;
}
template<typename, typename = void>
struct entt_traits;
@@ -64,7 +59,7 @@ struct entt_traits<std::uint64_t> {
*/
template<typename Traits>
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");

View File

@@ -15,32 +15,17 @@
#include "../../common/throwing_type.hpp"
#include "../../common/tracked_memory_resource.hpp"
TEST(ToAddress, Functionalities) {
const std::shared_ptr<int> shared = std::make_shared<int>();
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<int> lhs, rhs;
test::basic_test_allocator<int, std::false_type> 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<int, std::false_type> 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<int> shared = std::make_shared<int>();
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<int> lhs, rhs;
test::basic_test_allocator<int, std::false_type> 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<int, std::false_type> lhs, rhs;
ASSERT_DEATH(entt::propagate_on_container_swap(lhs, rhs), "");
}
TEST(AllocateUnique, Functionalities) {
test::throwing_allocator<test::throwing_type> allocator{};