diff --git a/src/entt/entity/group.hpp b/src/entt/entity/group.hpp index a658e191a..a6debf77c 100644 --- a/src/entt/entity/group.hpp +++ b/src/entt/entity/group.hpp @@ -114,18 +114,7 @@ class group_handler, get_t, exclude_t> fin std::apply([pos, entt](auto *...cpool) { (cpool->swap_elements(cpool->data()[pos], entt), ...); }, pools); } -public: - using entity_type = underlying_type; - - group_handler(Owned &...opool, Get &...gpool, Exclude &...epool) - : basic_group_handler{ - sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude), - +[](const id_type ctype) noexcept { return ((ctype == entt::type_hash::value()) || ...); }, - +[]([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == entt::type_hash::value()) || ...); }, - +[]([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == entt::type_hash::value()) || ...); }}, - pools{&opool..., &gpool...}, filter{&epool...}, len{} {} - - void push_on_construct(const entity_type entt) { + void push_on_construct(const underlying_type entt) { if(std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools) && std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter) && !(std::get<0>(pools)->index(entt) < len)) { @@ -133,7 +122,7 @@ public: } } - void push_on_destroy(const entity_type entt) { + void push_on_destroy(const underlying_type entt) { if(std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools) && std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter) && !(std::get<0>(pools)->index(entt) < len)) { @@ -141,12 +130,31 @@ public: } } - void remove_if(const entity_type entt) { + void remove_if(const underlying_type entt) { if(std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < len)) { swap_elements(--len, entt); } } +public: + using entity_type = underlying_type; + + group_handler(Owned &...opool, Get &...gpool, Exclude &...epool, const void *prev, const void *next) + : basic_group_handler{ + sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude), + +[](const id_type ctype) noexcept { return ((ctype == entt::type_hash::value()) || ...); }, + +[]([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == entt::type_hash::value()) || ...); }, + +[]([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == entt::type_hash::value()) || ...); }}, + pools{&opool..., &gpool...}, filter{&epool...}, len{} { + std::apply([this, prev, next](auto *...cpool) { ((cpool->on_construct().before(next).template connect<&group_handler::push_on_construct>(*this), cpool->on_destroy().before(prev).template connect<&group_handler::remove_if>(*this)), ...); }, pools); + std::apply([this, prev, next](auto *...cpool) { ((cpool->on_construct().before(prev).template connect<&group_handler::remove_if>(*this), cpool->on_destroy().before(next).template connect<&group_handler::push_on_destroy>(*this)), ...); }, filter); + + // we cannot iterate backwards because we want to leave behind valid entities in case of owned types + for(auto *first = std::get<0>(pools)->data(), *last = first + std::get<0>(pools)->size(); first != last; ++first) { + push_on_construct(*first); + } + } + [[nodiscard]] std::size_t length() const noexcept { return len; } diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 4aec84877..4fc11c730 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -1213,12 +1213,12 @@ public: if constexpr(sizeof...(Owned) == 0u) { handler = std::allocate_shared(get_allocator(), get_allocator(), assure>()..., assure>()...); } else { - handler = std::allocate_shared(get_allocator(), assure>()..., assure>()..., assure>()...); + constexpr auto hsize = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude); - ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [size = handler->size](const auto &data) { + ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [hsize](const auto &data) { const auto overlapping = (0u + ... + data.second->owned(type_hash>::value())); const auto sz = overlapping + (0u + ... + data.second->get(type_hash>::value())) + (0u + ... + data.second->exclude(type_hash>::value())); - return !overlapping || ((sz == size) || (sz == data.second->size)); + return !overlapping || ((sz == hsize) || (sz == data.second->size)); }), "Conflicting groups"); @@ -1227,30 +1227,17 @@ public: for(auto &&data: groups) { if((data.second->owned(type_hash>::value()) || ...)) { - if(const auto sz = data.second->size; sz < handler->size && (prev == nullptr || prev->size < sz)) { + if(const auto sz = data.second->size; sz < hsize && (prev == nullptr || prev->size < sz)) { prev = data.second.get(); } - if(const auto sz = data.second->size; sz > handler->size && (next == nullptr || next->size > sz)) { + if(const auto sz = data.second->size; sz > hsize && (next == nullptr || next->size > sz)) { next = data.second.get(); } } } - (on_construct>().before(*next).template connect<&handler_type::push_on_construct>(*handler), ...); - (on_construct>().before(*next).template connect<&handler_type::push_on_construct>(*handler), ...); - (on_destroy>().before(*next).template connect<&handler_type::push_on_destroy>(*handler), ...); - - (on_destroy>().before(*prev).template connect<&handler_type::remove_if>(*handler), ...); - (on_destroy>().before(*prev).template connect<&handler_type::remove_if>(*handler), ...); - (on_construct>().before(*prev).template connect<&handler_type::remove_if>(*handler), ...); - - auto &cpool = assure...>>>(); - - // we cannot iterate backwards because we want to leave behind valid entities in case of owned types - for(auto *first = cpool.data(), *last = first + cpool.size(); first != last; ++first) { - handler->push_on_construct(*first); - } + handler = std::allocate_shared(get_allocator(), assure>()..., assure>()..., assure>()..., prev, next); } groups.emplace(type_hash::value(), handler);