core: public popcount (waiting for C++20)
This commit is contained in:
@@ -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`).
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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{};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user