sparse_set/storage: value type from base, if any

This commit is contained in:
Michele Caini
2021-11-19 23:37:33 +01:00
parent ad3fbe2052
commit 46e5d96ced
4 changed files with 55 additions and 7 deletions

View File

@@ -11,6 +11,7 @@
#include "../core/algorithm.hpp"
#include "../core/any.hpp"
#include "../core/memory.hpp"
#include "../core/type_info.hpp"
#include "entity.hpp"
#include "fwd.hpp"
@@ -282,14 +283,14 @@ public:
/*! @brief Default constructor. */
basic_sparse_set()
: basic_sparse_set{allocator_type{}} {}
: basic_sparse_set{type_id<void>()} {}
/**
* @brief Constructs an empty container with a given allocator.
* @param allocator The allocator to use.
*/
explicit basic_sparse_set(const allocator_type &allocator)
: basic_sparse_set{deletion_policy::swap_and_pop, allocator} {}
: basic_sparse_set{type_id<void>(), deletion_policy::swap_and_pop, allocator} {}
/**
* @brief Constructs an empty container with the given policy and allocator.
@@ -297,8 +298,18 @@ public:
* @param allocator The allocator to use (possibly default-constructed).
*/
explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {})
: basic_sparse_set{type_id<void>(), pol, allocator} {}
/**
* @brief Constructs an empty container with the given policy and allocator.
* @param value Returned value type, if any.
* @param pol Type of deletion policy.
* @param allocator The allocator to use (possibly default-constructed).
*/
explicit basic_sparse_set(const type_info &value, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {})
: sparse{allocator},
packed{allocator},
info{&value},
free_list{tombstone},
mode{pol} {}
@@ -309,6 +320,7 @@ public:
basic_sparse_set(basic_sparse_set &&other) ENTT_NOEXCEPT
: sparse{std::move(other.sparse)},
packed{std::move(other.packed)},
info{other.info},
free_list{std::exchange(other.free_list, tombstone)},
mode{other.mode} {}
@@ -320,6 +332,7 @@ public:
basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) ENTT_NOEXCEPT
: sparse{std::move(other.sparse), allocator},
packed{std::move(other.packed), allocator},
info{other.info},
free_list{std::exchange(other.free_list, tombstone)},
mode{other.mode} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
@@ -341,6 +354,7 @@ public:
release_sparse_pages();
sparse = std::move(other.sparse);
packed = std::move(other.packed);
info = other.info;
free_list = std::exchange(other.free_list, tombstone);
mode = other.mode;
return *this;
@@ -354,6 +368,7 @@ public:
using std::swap;
swap(sparse, other.sparse);
swap(packed, other.packed);
swap(info, other.info);
swap(free_list, other.free_list);
swap(mode, other.mode);
}
@@ -835,12 +850,21 @@ public:
}
}
/**
* @brief Returned value type, if any.
* @return Returned value type, if any.
*/
const type_info &type() const ENTT_NOEXCEPT {
return *info;
}
/*! @brief Forwards variables to mixins, if any. */
virtual void bind(any) ENTT_NOEXCEPT {}
private:
sparse_container_type sparse;
packed_container_type packed;
const type_info *info;
entity_type free_list;
deletion_policy mode;
};

View File

@@ -13,6 +13,7 @@
#include "../core/any.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/memory.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../signal/sigh.hpp"
#include "component.hpp"
@@ -390,15 +391,14 @@ public:
/*! @brief Default constructor. */
basic_storage()
: base_type{deletion_policy{comp_traits::in_place_delete::value}},
packed{} {}
: basic_storage{allocator_type{}} {}
/**
* @brief Constructs an empty storage with a given allocator.
* @param allocator The allocator to use.
*/
explicit basic_storage(const allocator_type &allocator)
: base_type{deletion_policy{comp_traits::in_place_delete::value}, allocator},
: base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete::value}, allocator},
packed{container_type{allocator}, allocator} {}
/**
@@ -743,14 +743,14 @@ public:
/*! @brief Default constructor. */
basic_storage()
: base_type{deletion_policy{comp_traits::in_place_delete::value}} {}
: basic_storage{allocator_type{}} {}
/**
* @brief Constructs an empty container with a given allocator.
* @param allocator The allocator to use.
*/
explicit basic_storage(const allocator_type &allocator)
: base_type{deletion_policy{comp_traits::in_place_delete::value}, allocator} {}
: base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete::value}, allocator} {}
/**
* @brief Move constructor.

View File

@@ -19,6 +19,7 @@ TEST(SparseSet, Functionalities) {
entt::sparse_set set;
ASSERT_NO_THROW([[maybe_unused]] auto alloc = set.get_allocator());
ASSERT_EQ(set.type(), entt::type_id<void>());
set.reserve(42);

View File

@@ -73,6 +73,7 @@ TEST(Storage, Functionalities) {
entt::storage<int> pool;
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<int>());
pool.reserve(42);
@@ -141,11 +142,13 @@ TEST(Storage, Move) {
ASSERT_TRUE(std::is_move_constructible_v<decltype(pool)>);
ASSERT_TRUE(std::is_move_assignable_v<decltype(pool)>);
ASSERT_EQ(pool.type(), entt::type_id<int>());
entt::storage<int> other{std::move(pool)};
ASSERT_TRUE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
ASSERT_EQ(other.at(0u), entt::entity{3});
ASSERT_EQ(other.get(entt::entity{3}), 3);
@@ -184,6 +187,9 @@ TEST(Storage, Swap) {
pool.swap(other);
ASSERT_EQ(pool.type(), entt::type_id<int>());
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(pool.size(), 1u);
ASSERT_EQ(other.size(), 1u);
@@ -209,6 +215,9 @@ TEST(Storage, StableSwap) {
pool.swap(other);
ASSERT_EQ(pool.type(), entt::type_id<stable_type>());
ASSERT_EQ(other.type(), entt::type_id<stable_type>());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(other.size(), 1u);
@@ -224,6 +233,8 @@ TEST(Storage, EmptyType) {
pool.emplace(entt::entity{99});
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<empty_stable_type>());
ASSERT_TRUE(pool.contains(entt::entity{99}));
ASSERT_DEATH(pool.get(entt::entity{}), "");
@@ -574,6 +585,9 @@ TEST(Storage, TypeFromBase) {
entt::sparse_set &base = pool;
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
ASSERT_EQ(pool.type(), entt::type_id<int>());
ASSERT_EQ(pool.type(), base.type());
ASSERT_FALSE(pool.contains(entities[0u]));
ASSERT_FALSE(pool.contains(entities[1u]));
@@ -602,6 +616,9 @@ TEST(Storage, EmptyTypeFromBase) {
entt::sparse_set &base = pool;
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
ASSERT_EQ(pool.type(), entt::type_id<empty_stable_type>());
ASSERT_EQ(pool.type(), base.type());
ASSERT_FALSE(pool.contains(entities[0u]));
ASSERT_FALSE(pool.contains(entities[1u]));
@@ -630,6 +647,9 @@ TEST(Storage, NonDefaultConstructibleTypeFromBase) {
entt::sparse_set &base = pool;
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
ASSERT_EQ(pool.type(), entt::type_id<non_default_constructible>());
ASSERT_EQ(pool.type(), base.type());
ASSERT_FALSE(pool.contains(entities[0u]));
ASSERT_FALSE(pool.contains(entities[1u]));
@@ -665,6 +685,9 @@ TEST(Storage, NonCopyConstructibleTypeFromBase) {
entt::sparse_set &base = pool;
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
ASSERT_EQ(pool.type(), entt::type_id<std::unique_ptr<int>>());
ASSERT_EQ(pool.type(), base.type());
ASSERT_FALSE(pool.contains(entities[0u]));
ASSERT_FALSE(pool.contains(entities[1u]));