registry:
* prevent groups from being used with tombstones * support to compact one, several or all pools
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "component.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "group.hpp"
|
||||
@@ -58,6 +59,7 @@ class basic_registry {
|
||||
|
||||
template<typename... Exclude, typename... Get, typename... Owned>
|
||||
struct group_handler<exclude_t<Exclude...>, get_t<Get...>, Owned...> {
|
||||
static_assert(!std::disjunction_v<typename component_traits<Owned>::in_place_delete...>, "Groups do not support in-place delete");
|
||||
static_assert(std::conjunction_v<std::is_same<Owned, std::remove_const_t<Owned>>..., std::is_same<Get, std::remove_const_t<Get>>..., std::is_same<Exclude, std::remove_const_t<Exclude>>...>, "One or more component types are invalid");
|
||||
std::conditional_t<sizeof...(Owned) == 0, basic_sparse_set<Entity>, std::size_t> current{};
|
||||
|
||||
@@ -133,15 +135,14 @@ class basic_registry {
|
||||
auto recycle_identifier() ENTT_NOEXCEPT {
|
||||
ENTT_ASSERT(free_list != null, "No entities available");
|
||||
const auto curr = traits_type::to_entity(free_list);
|
||||
const auto version = traits_type::to_version(entities[curr]);
|
||||
free_list = entities[curr];
|
||||
return entities[curr] = traits_type::to_type(curr, version);
|
||||
free_list = traits_type::to_type(entities[curr], tombstone);
|
||||
return (entities[curr] = traits_type::to_type(curr, traits_type::to_version(entities[curr])));
|
||||
}
|
||||
|
||||
auto release_entity(const Entity entity, const typename traits_type::version_type version) {
|
||||
const auto entt = traits_type::to_entity(entity);
|
||||
entities[entt] = traits_type::to_type(traits_type::to_integral(free_list), version + (traits_type::to_type(null, version) == tombstone));
|
||||
free_list = traits_type::to_type(entt, {});
|
||||
free_list = traits_type::to_type(entt, traits_type::to_version(tombstone));
|
||||
return traits_type::to_version(entities[entt]);
|
||||
}
|
||||
|
||||
@@ -744,6 +745,24 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes all tombstones from a registry or only the pools for the
|
||||
* given components.
|
||||
* @tparam Component Types of components for which to clear all tombstones.
|
||||
*/
|
||||
template<typename... Component>
|
||||
void compact() {
|
||||
if constexpr(sizeof...(Component) == 0) {
|
||||
for(auto pos = pools.size(); pos; --pos) {
|
||||
if(auto &pdata = pools[pos-1]; pdata.pool) {
|
||||
pdata.pool->compact();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(assure<Component>()->compact(), ...);
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc remove */
|
||||
template<typename... Component>
|
||||
[[deprecated("Use ::remove instead")]]
|
||||
@@ -1619,7 +1638,7 @@ private:
|
||||
mutable std::vector<pool_data> pools{};
|
||||
std::vector<group_data> groups{};
|
||||
std::vector<entity_type> entities{};
|
||||
entity_type free_list{null};
|
||||
entity_type free_list{tombstone};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
#include <entt/entity/entity.hpp>
|
||||
|
||||
struct empty_type {};
|
||||
struct stable_type { int value; };
|
||||
|
||||
template<>
|
||||
struct entt::component_traits<stable_type> {
|
||||
using in_place_delete = std::true_type;
|
||||
using ignore_if_empty = std::true_type;
|
||||
};
|
||||
|
||||
struct non_default_constructible {
|
||||
non_default_constructible(int v): value{v} {}
|
||||
@@ -524,6 +531,93 @@ TEST(Registry, CreateDestroyCornerCase) {
|
||||
ASSERT_EQ(registry.current(e1), entt::registry::version_type{1});
|
||||
}
|
||||
|
||||
TEST(Registry, RangeDestroy) {
|
||||
entt::registry registry;
|
||||
const auto iview = registry.view<int>();
|
||||
const auto icview = registry.view<int, char>();
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<char>(e0);
|
||||
registry.emplace<double>(e0);
|
||||
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
ASSERT_TRUE(registry.valid(e0));
|
||||
ASSERT_TRUE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
|
||||
registry.destroy(icview.begin(), icview.end());
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 1u);
|
||||
ASSERT_EQ(registry.size<char>(), 0u);
|
||||
ASSERT_EQ(registry.size<double>(), 0u);
|
||||
|
||||
registry.destroy(iview.begin(), iview.end());
|
||||
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_NO_FATAL_FAILURE(registry.destroy(iview.begin(), iview.end()));
|
||||
ASSERT_EQ(iview.size(), 0u);
|
||||
ASSERT_EQ(icview.size_hint(), 0u);
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<char>(), 0u);
|
||||
ASSERT_EQ(registry.size<double>(), 0u);
|
||||
}
|
||||
|
||||
TEST(Registry, StableDestroy) {
|
||||
entt::registry registry;
|
||||
const auto iview = registry.view<int>();
|
||||
const auto icview = registry.view<int, stable_type>();
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<stable_type>(e0);
|
||||
registry.emplace<double>(e0);
|
||||
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<stable_type>(e1);
|
||||
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
ASSERT_TRUE(registry.valid(e0));
|
||||
ASSERT_TRUE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
|
||||
registry.destroy(icview.begin(), icview.end());
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 1u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
ASSERT_EQ(registry.size<double>(), 0u);
|
||||
|
||||
registry.destroy(iview.begin(), iview.end());
|
||||
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_EQ(iview.size(), 0u);
|
||||
ASSERT_EQ(icview.size_hint(), 0u);
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
ASSERT_EQ(registry.size<double>(), 0u);
|
||||
}
|
||||
|
||||
TEST(Registry, VersionOverflow) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
@@ -1221,40 +1315,6 @@ TEST(Registry, Signals) {
|
||||
ASSERT_EQ(listener.last, e0);
|
||||
}
|
||||
|
||||
TEST(Registry, RangeDestroy) {
|
||||
entt::registry registry;
|
||||
const auto iview = registry.view<int>();
|
||||
const auto icview = registry.view<int, char>();
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<char>(e0);
|
||||
registry.emplace<double>(e0);
|
||||
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
ASSERT_TRUE(registry.valid(e0));
|
||||
ASSERT_TRUE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
|
||||
registry.destroy(icview.begin(), icview.end());
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
|
||||
registry.destroy(iview.begin(), iview.end());
|
||||
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_NO_FATAL_FAILURE(registry.destroy(iview.begin(), iview.end()));
|
||||
}
|
||||
|
||||
TEST(Registry, Insert) {
|
||||
entt::registry registry;
|
||||
|
||||
@@ -1295,6 +1355,8 @@ TEST(Registry, Insert) {
|
||||
|
||||
TEST(Registry, Erase) {
|
||||
entt::registry registry;
|
||||
const auto iview = registry.view<int>();
|
||||
const auto icview = registry.view<int, char>();
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
@@ -1309,92 +1371,83 @@ TEST(Registry, Erase) {
|
||||
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<int>(e0));
|
||||
ASSERT_TRUE(registry.any_of<int>(e0));
|
||||
ASSERT_TRUE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.all_of<int>(e2));
|
||||
ASSERT_TRUE(registry.any_of<int>(e2));
|
||||
|
||||
const auto view = registry.view<int, char>();
|
||||
registry.erase<int, char>(e0);
|
||||
registry.erase<int, char>(icview.begin(), icview.end());
|
||||
registry.erase<int, char>(icview.begin(), icview.end());
|
||||
|
||||
registry.erase<int>(e0);
|
||||
registry.erase<int>(view.begin(), view.end());
|
||||
registry.erase<int>(view.begin(), view.end());
|
||||
ASSERT_FALSE(registry.any_of<int>(e0));
|
||||
ASSERT_FALSE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.any_of<int>(e2));
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 1u);
|
||||
ASSERT_EQ(registry.size<char>(), 0u);
|
||||
ASSERT_EQ(registry.size<double>(), 1u);
|
||||
|
||||
registry.erase<int>(iview.begin(), iview.end());
|
||||
|
||||
ASSERT_DEATH(registry.erase<int>(e0), "");
|
||||
ASSERT_DEATH(registry.erase<int>(e1), "");
|
||||
|
||||
ASSERT_FALSE(registry.all_of<int>(e0));
|
||||
ASSERT_FALSE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.all_of<int>(e2));
|
||||
ASSERT_FALSE(registry.any_of<int>(e2));
|
||||
ASSERT_NO_FATAL_FAILURE(registry.erase<int>(iview.begin(), iview.end()));
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<char>(), 0u);
|
||||
ASSERT_EQ(registry.size<double>(), 1u);
|
||||
}
|
||||
|
||||
TEST(Registry, RangeErase) {
|
||||
TEST(Registry, StableErase) {
|
||||
entt::registry registry;
|
||||
const auto iview = registry.view<int>();
|
||||
const auto icview = registry.view<int, char>();
|
||||
const auto icview = registry.view<int, stable_type>();
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<char>(e0);
|
||||
registry.emplace<stable_type>(e0);
|
||||
registry.emplace<double>(e0);
|
||||
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<char>(e1);
|
||||
registry.emplace<stable_type>(e1);
|
||||
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
ASSERT_TRUE(registry.any_of<int>(e0));
|
||||
ASSERT_TRUE(registry.any_of<int>(e1));
|
||||
ASSERT_TRUE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.any_of<int>(e2));
|
||||
|
||||
registry.erase<int, char>(icview.begin(), icview.end());
|
||||
registry.erase<int, stable_type>(e0);
|
||||
registry.erase<int, stable_type>(icview.begin(), icview.end());
|
||||
registry.erase<int, stable_type>(icview.begin(), icview.end());
|
||||
|
||||
ASSERT_FALSE(registry.any_of<int>(e0));
|
||||
ASSERT_FALSE(registry.any_of<int>(e1));
|
||||
ASSERT_FALSE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.any_of<int>(e2));
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 1u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
ASSERT_EQ(registry.size<double>(), 1u);
|
||||
|
||||
registry.erase<int>(iview.begin(), iview.end());
|
||||
|
||||
ASSERT_DEATH(registry.erase<int>(e0), "");
|
||||
ASSERT_DEATH(registry.erase<int>(e1), "");
|
||||
|
||||
ASSERT_FALSE(registry.any_of<int>(e2));
|
||||
ASSERT_NO_FATAL_FAILURE(registry.erase<int>(iview.begin(), iview.end()));
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
ASSERT_EQ(registry.size<double>(), 1u);
|
||||
}
|
||||
|
||||
TEST(Registry, Remove) {
|
||||
entt::registry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<char>(e0);
|
||||
registry.emplace<double>(e0);
|
||||
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<int>(e0));
|
||||
ASSERT_TRUE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.all_of<int>(e2));
|
||||
|
||||
const auto view = registry.view<int, char>();
|
||||
|
||||
ASSERT_EQ(registry.remove<int>(e0), 1u);
|
||||
ASSERT_EQ(registry.remove<int>(view.begin(), view.end()), 1u);
|
||||
ASSERT_EQ(registry.remove<int>(view.begin(), view.end()), 0u);
|
||||
ASSERT_EQ(registry.remove<int>(e1), 0u);
|
||||
|
||||
ASSERT_FALSE(registry.all_of<int>(e0));
|
||||
ASSERT_FALSE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.all_of<int>(e2));
|
||||
}
|
||||
|
||||
TEST(Registry, RangeRemove) {
|
||||
entt::registry registry;
|
||||
const auto iview = registry.view<int>();
|
||||
const auto icview = registry.view<int, char>();
|
||||
|
||||
@@ -1412,19 +1465,112 @@ TEST(Registry, RangeRemove) {
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
ASSERT_TRUE(registry.any_of<int>(e0));
|
||||
ASSERT_TRUE(registry.any_of<int>(e1));
|
||||
ASSERT_TRUE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.any_of<int>(e2));
|
||||
|
||||
registry.remove<int, char>(icview.begin(), icview.end());
|
||||
registry.remove<int, char>(e0);
|
||||
|
||||
ASSERT_EQ((registry.remove<int, char>(icview.begin(), icview.end())), 2u);
|
||||
ASSERT_EQ((registry.remove<int, char>(icview.begin(), icview.end())), 0u);
|
||||
|
||||
ASSERT_FALSE(registry.any_of<int>(e0));
|
||||
ASSERT_FALSE(registry.any_of<int>(e1));
|
||||
ASSERT_FALSE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.any_of<int>(e2));
|
||||
|
||||
registry.remove<int>(iview.begin(), iview.end());
|
||||
ASSERT_EQ(registry.size<int>(), 1u);
|
||||
ASSERT_EQ(registry.size<char>(), 0u);
|
||||
ASSERT_EQ(registry.size<double>(), 1u);
|
||||
|
||||
ASSERT_EQ((registry.remove<int>(iview.begin(), iview.end())), 1u);
|
||||
|
||||
ASSERT_EQ(registry.remove<int>(e0), 0u);
|
||||
ASSERT_EQ(registry.remove<int>(e1), 0u);
|
||||
|
||||
ASSERT_FALSE(registry.any_of<int>(e2));
|
||||
ASSERT_EQ(registry.remove<int>(iview.begin(), iview.end()), 0u);
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<char>(), 0u);
|
||||
ASSERT_EQ(registry.size<double>(), 1u);
|
||||
}
|
||||
|
||||
TEST(Registry, StableRemove) {
|
||||
entt::registry registry;
|
||||
const auto iview = registry.view<int>();
|
||||
const auto icview = registry.view<int, stable_type>();
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<stable_type>(e0);
|
||||
registry.emplace<double>(e0);
|
||||
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<stable_type>(e1);
|
||||
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
ASSERT_TRUE(registry.any_of<int>(e0));
|
||||
ASSERT_TRUE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.any_of<int>(e2));
|
||||
|
||||
registry.remove<int, stable_type>(e0);
|
||||
|
||||
ASSERT_EQ((registry.remove<int, stable_type>(icview.begin(), icview.end())), 2u);
|
||||
ASSERT_EQ((registry.remove<int, stable_type>(icview.begin(), icview.end())), 0u);
|
||||
|
||||
ASSERT_FALSE(registry.any_of<int>(e0));
|
||||
ASSERT_FALSE(registry.all_of<int>(e1));
|
||||
ASSERT_TRUE(registry.any_of<int>(e2));
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 1u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
ASSERT_EQ(registry.size<double>(), 1u);
|
||||
|
||||
ASSERT_EQ((registry.remove<int>(iview.begin(), iview.end())), 1u);
|
||||
|
||||
ASSERT_EQ(registry.remove<int>(e0), 0u);
|
||||
ASSERT_EQ(registry.remove<int>(e1), 0u);
|
||||
|
||||
ASSERT_FALSE(registry.any_of<int>(e2));
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
ASSERT_EQ(registry.size<double>(), 1u);
|
||||
}
|
||||
|
||||
TEST(Registry, Compact) {
|
||||
entt::registry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<stable_type>(e0);
|
||||
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<stable_type>(e1);
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 2u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
|
||||
registry.destroy(e0);
|
||||
registry.destroy(e1);
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
|
||||
registry.compact<int>();
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 2u);
|
||||
|
||||
registry.compact();
|
||||
|
||||
ASSERT_EQ(registry.size<int>(), 0u);
|
||||
ASSERT_EQ(registry.size<stable_type>(), 0u);
|
||||
}
|
||||
|
||||
TEST(Registry, NonOwningGroupInterleaved) {
|
||||
|
||||
Reference in New Issue
Block a user