group: auto init for owning groups

This commit is contained in:
Michele Caini
2023-03-23 08:52:38 +01:00
parent 1a12dede6f
commit 6a16a8a20b
2 changed files with 28 additions and 33 deletions

View File

@@ -114,18 +114,7 @@ class group_handler<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> 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<typename Owned::value_type>::value()) || ...); },
+[]([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == entt::type_hash<typename Get::value_type>::value()) || ...); },
+[]([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == entt::type_hash<typename Exclude::value_type>::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<typename Owned::value_type>::value()) || ...); },
+[]([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == entt::type_hash<typename Get::value_type>::value()) || ...); },
+[]([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == entt::type_hash<typename Exclude::value_type>::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;
}

View File

@@ -1213,12 +1213,12 @@ public:
if constexpr(sizeof...(Owned) == 0u) {
handler = std::allocate_shared<handler_type>(get_allocator(), get_allocator(), assure<std::remove_const_t<Get>>()..., assure<std::remove_const_t<Exclude>>()...);
} else {
handler = std::allocate_shared<handler_type>(get_allocator(), assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()..., assure<std::remove_const_t<Exclude>>()...);
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<std::remove_const_t<Owned>>::value()));
const auto sz = overlapping + (0u + ... + data.second->get(type_hash<std::remove_const_t<Get>>::value())) + (0u + ... + data.second->exclude(type_hash<std::remove_const_t<Exclude>>::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<std::remove_const_t<Owned>>::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<std::remove_const_t<Owned>>().before(*next).template connect<&handler_type::push_on_construct>(*handler), ...);
(on_construct<std::remove_const_t<Get>>().before(*next).template connect<&handler_type::push_on_construct>(*handler), ...);
(on_destroy<std::remove_const_t<Exclude>>().before(*next).template connect<&handler_type::push_on_destroy>(*handler), ...);
(on_destroy<std::remove_const_t<Owned>>().before(*prev).template connect<&handler_type::remove_if>(*handler), ...);
(on_destroy<std::remove_const_t<Get>>().before(*prev).template connect<&handler_type::remove_if>(*handler), ...);
(on_construct<std::remove_const_t<Exclude>>().before(*prev).template connect<&handler_type::remove_if>(*handler), ...);
auto &cpool = assure<type_list_element_t<0u, type_list<std::remove_const_t<Owned>...>>>();
// 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<handler_type>(get_allocator(), assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()..., assure<std::remove_const_t<Exclude>>()..., prev, next);
}
groups.emplace(type_hash<handler_type>::value(), handler);