From 7e0bd92593283737b9e558c002b2561fded9e674 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Sun, 10 Feb 2019 22:51:20 +0100 Subject: [PATCH] fix #184 - conflicts between partial-owning groups aren't correctly detected --- src/entt/entity/registry.hpp | 161 ++++++++++++++++------------------- test/entt/entity/group.cpp | 2 +- 2 files changed, 74 insertions(+), 89 deletions(-) diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index f66b8403b..56ba5cbc4 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -59,7 +59,6 @@ constexpr exclude_t exclude{}; template class registry { using component_family = family; - using handler_family = family; using group_family = family; using signal_type = sigh; using traits_type = entt_traits; @@ -71,53 +70,61 @@ class registry { struct basic_descriptor { virtual ~basic_descriptor() = default; - virtual bool contains(typename component_family::family_type) = 0; - typename sparse_set::size_type last; + virtual bool owns(typename component_family::family_type) = 0; }; - template - struct descriptor: basic_descriptor { - bool contains(typename component_family::family_type ctype) override { + template + struct descriptor; + + template + struct descriptor, get_t, Owned...>: basic_descriptor { + typename sparse_set::size_type data; + + template + void induce_if(registry ®, const Entity entity) { + if(reg.has(entity) && (0 + ... + reg.has(entity)) == Accepted) { + const auto curr = data++; + (std::swap(reg.pool().get(entity), reg.pool().raw()[curr]), ...); + (reg.pool().swap(reg.pools[reg.type()]->get(entity), curr), ...); + } + } + + void discard_if(registry ®, const Entity entity) { + const auto ctype = type>>(); + + if(reg.pools[ctype]->has(entity) && reg.pools[ctype]->get(entity) < data) { + const auto curr = --data; + (std::swap(reg.pool().get(entity), reg.pool().raw()[curr]), ...); + (reg.pool().swap(reg.pools[reg.type()]->get(entity), curr), ...); + } + } + + bool owns(typename component_family::family_type ctype) override { return ((ctype == type()) || ...); } }; - template - static void induce_if(registry ®, const Entity entity) { - if((reg.*Has)(entity) && (reg.*Accept)(entity)) { - const auto curr = reg.groups[group_family::type]->last++; - (std::swap(reg.pool().get(entity), reg.pool().raw()[curr]), ...); - (reg.pool().swap(reg.pools[reg.type()]->get(entity), curr), ...); + template + struct descriptor, get_t>: basic_descriptor { + sparse_set data; + + template + void construct_if(registry ®, const Entity entity) { + if(reg.has(entity) && (0 + ... + reg.has(entity)) == Accepted) { + data.construct(entity); + } } - } - template - static void discard_if(registry ®, const Entity entity) { - const auto ctype = type>>(); - const auto gtype = group_family::type; - - if(reg.pools[ctype]->has(entity) && reg.pools[ctype]->get(entity) < reg.groups[gtype]->last) { - const auto curr = --reg.groups[gtype]->last; - (std::swap(reg.pool().get(entity), reg.pool().raw()[curr]), ...); - (reg.pool().swap(reg.pools[reg.type()]->get(entity), curr), ...); + void destroy_if(registry &, const Entity entity) { + if(data.has(entity)) { + data.destroy(entity); + } } - } - template - static void construct_if(registry ®, const Entity entity) { - if((reg.*Has)(entity) && (reg.*Accept)(entity)) { - reg.handlers[handler_family::type]->construct(entity); + bool owns(typename component_family::family_type) override { + return false; } - } - - template - static void destroy_if(registry ®, const Entity entity) { - auto &handler = reg.handlers[handler_family::type]; - - if(handler->has(entity)) { - handler->destroy(entity); - } - } + }; template inline const auto & pool() const ENTT_NOEXCEPT { @@ -149,13 +156,6 @@ class registry { return const_cast> &>(std::as_const(*this).template assure()); } - template - bool accept(const Entity entity) const ENTT_NOEXCEPT { - assert(valid(entity)); - // internal function, pools are guaranteed to exist - return (0 + ... + pool().has(entity)) == Auth; - } - public: /*! @brief Underlying entity identifier. */ using entity_type = typename traits_type::entity_type; @@ -1148,8 +1148,8 @@ public: */ template bool owned() const ENTT_NOEXCEPT { - return std::any_of(groups.cbegin(), groups.cend(), [](const auto &descriptor) { - return descriptor && descriptor->contains(type()); + return std::any_of(groups.cbegin(), groups.cend(), [](const auto &curr) { + return curr && curr->owns(type()); }); } @@ -1185,66 +1185,52 @@ public: static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1); static_assert(sizeof...(Owned) + sizeof...(Get)); + using descriptor_type = descriptor...>, get_t...>, std::decay_t...>; + const auto gtype = group_family::type...>, get_t...>, std::decay_t...>; + (assure(), ...); (assure(), ...); (assure(), ...); - if constexpr(sizeof...(Owned) == 0) { - using handler_type = type_list>; - const auto htype = handler_family::type; + if(!(gtype < groups.size())) { + groups.resize(gtype + 1); + } - if(!(htype < handlers.size())) { - handlers.resize(htype + 1); - } + if(!groups[gtype]) { + assert((!owned() && ...)); + groups[gtype] = std::make_unique(); + auto *curr = static_cast(groups[gtype].get()); - if(!handlers[htype]) { - handlers[htype] = std::make_unique>(); - auto *direct = handlers[htype].get(); - - ((sighs[type()].destruction.sink().template connect<®istry::destroy_if>()), ...); - ((sighs[type()].construction.sink().template connect<&construct_if<®istry::has, ®istry::accept<0, Exclude...>, handler_type>>()), ...); - ((sighs[type()].destruction.sink().template connect<&construct_if<®istry::has, ®istry::accept<1, Exclude...>, handler_type>>()), ...); - ((sighs[type()].construction.sink().template connect<®istry::destroy_if>()), ...); + if constexpr(sizeof...(Owned) == 0) { + ((sighs[type()].destruction.sink().template connect<&descriptor_type::destroy_if>(curr)), ...); + ((sighs[type()].construction.sink().template connect<&descriptor_type::template construct_if<0>>(curr)), ...); + ((sighs[type()].destruction.sink().template connect<&descriptor_type::template construct_if<1>>(curr)), ...); + ((sighs[type()].construction.sink().template connect<&descriptor_type::destroy_if>(curr)), ...); for(const auto entity: view()) { - if(accept<0, Exclude...>(entity)) { - direct->construct(entity); - } + curr->template construct_if<0>(*this, entity); } - } + } else { + (sighs[type()].construction.sink().template connect<&descriptor_type::template induce_if<0>>(curr), ...); + (sighs[type()].construction.sink().template connect<&descriptor_type::template induce_if<0>>(curr), ...); - return { handlers[htype].get(), &pool()... }; - } else { - const auto gtype = group_family::type; + (sighs[type()].destruction.sink().template connect<&descriptor_type::discard_if>(curr), ...); + (sighs[type()].destruction.sink().template connect<&descriptor_type::discard_if>(curr), ...); - if(!(gtype < groups.size())) { - groups.resize(gtype + 1); - } - - if(!groups[gtype]) { - assert((!owned() && ...)); - groups[gtype] = std::make_unique>(); - - (sighs[type()].construction.sink().template connect<&induce_if<®istry::has, ®istry::accept<0, Exclude...>, Owned...>>(), ...); - (sighs[type()].construction.sink().template connect<&induce_if<®istry::has, ®istry::accept<0, Exclude...>, Owned...>>(), ...); - - (sighs[type()].destruction.sink().template connect<&discard_if>(), ...); - (sighs[type()].destruction.sink().template connect<&discard_if>(), ...); - - (sighs[type()].destruction.sink().template connect<&induce_if<®istry::has, ®istry::accept<1, Exclude...>, Owned...>>(), ...); - (sighs[type()].construction.sink().template connect<&discard_if>(), ...); + (sighs[type()].destruction.sink().template connect<&descriptor_type::template induce_if<1>>(curr), ...); + (sighs[type()].construction.sink().template connect<&descriptor_type::discard_if>(curr), ...); const auto *cpool = std::min({ pools[type()].get()... }, [](const auto *lhs, const auto *rhs) { return lhs->size() < rhs->size(); }); - std::for_each(cpool->data(), cpool->data() + cpool->size(), [this](const auto entity) { - induce_if<®istry::has, ®istry::accept<0, Exclude...>, Owned...>(*this, entity); + std::for_each(cpool->data(), cpool->data() + cpool->size(), [curr, this](const auto entity) { + curr->template induce_if<0>(*this, entity); }); } - - return { &groups[gtype]->last, &pool()..., &pool()... }; } + + return { &static_cast(*groups[gtype]).data, &pool()..., &pool()... }; } /*! @copydoc group */ @@ -1423,7 +1409,6 @@ public: private: std::vector> groups; - std::vector>> handlers; mutable std::vector>> pools; mutable std::vector sighs; std::vector entities; diff --git a/test/entt/entity/group.cpp b/test/entt/entity/group.cpp index fc4504dd1..81a50a510 100644 --- a/test/entt/entity/group.cpp +++ b/test/entt/entity/group.cpp @@ -222,7 +222,7 @@ TEST(OwningGroup, Empty) { FAIL(); } - for(auto entity: registry.group(entt::get)) { + for(auto entity: registry.group(entt::get)) { (void)entity; FAIL(); }