group: decouple constructing and setting prev/next links

This commit is contained in:
Michele Caini
2023-03-29 17:35:53 +02:00
parent 61f28298c9
commit 645edfb2b8
2 changed files with 25 additions and 9 deletions

View File

@@ -136,7 +136,7 @@ class group_handler<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> fin
}
public:
group_handler(Owned &...opool, Get &...gpool, Exclude &...epool, const void *prev, const void *next)
group_handler(Owned &...opool, Get &...gpool, Exclude &...epool)
: owning_group_descriptor{
sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude),
+[](const id_type ctype) noexcept { return ((ctype == entt::type_hash<typename Owned::value_type>::value()) || ...); },
@@ -145,8 +145,8 @@ public:
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);
std::apply([this](auto *...cpool) { ((cpool->on_construct().template connect<&group_handler::push_on_construct>(*this), cpool->on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, pools);
std::apply([this](auto *...cpool) { ((cpool->on_construct().template connect<&group_handler::remove_if>(*this), cpool->on_destroy().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) {
@@ -154,6 +154,20 @@ public:
}
}
void previous(const void *elem) {
if(elem) {
std::apply([this, elem](auto *...cpool) { ((cpool->on_destroy().disconnect(this), cpool->on_destroy().before(elem).template connect<&group_handler::remove_if>(*this)), ...); }, pools);
std::apply([this, elem](auto *...cpool) { ((cpool->on_construct().disconnect(this), cpool->on_construct().before(elem).template connect<&group_handler::remove_if>(*this)), ...); }, filter);
}
}
void next(const void *elem) {
if(elem) {
std::apply([this, elem](auto *...cpool) { ((cpool->on_construct().disconnect(this), cpool->on_construct().before(elem).template connect<&group_handler::push_on_construct>(*this)), ...); }, pools);
std::apply([this, elem](auto *...cpool) { ((cpool->on_destroy().disconnect(this), cpool->on_destroy().before(elem).template connect<&group_handler::push_on_destroy>(*this)), ...); }, filter);
}
}
[[nodiscard]] std::size_t length() const noexcept {
return len;
}

View File

@@ -1222,9 +1222,10 @@ public:
return {*std::static_pointer_cast<handler_type>(it->second)};
}
constexpr auto hsize = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
auto 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>>()...);
owning_groups.emplace(type_hash<handler_type>::value(), handler);
ENTT_ASSERT(std::all_of(owning_groups.cbegin(), owning_groups.cend(), [hsize](const auto &data) {
ENTT_ASSERT(std::all_of(owning_groups.cbegin(), owning_groups.cend(), [hsize = handler->size](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 == hsize) || (sz == data.second->size));
@@ -1236,18 +1237,19 @@ public:
for(auto &&data: owning_groups) {
if((data.second->owned(type_hash<std::remove_const_t<Owned>>::value()) || ...)) {
if(const auto sz = data.second->size; sz < hsize && (prev == nullptr || prev->size < sz)) {
if(const auto sz = data.second->size; sz < handler->size && (prev == nullptr || prev->size < sz)) {
prev = data.second.get();
}
if(const auto sz = data.second->size; sz > hsize && (next == nullptr || next->size > sz)) {
if(const auto sz = data.second->size; sz > handler->size && (next == nullptr || next->size > sz)) {
next = data.second.get();
}
}
}
auto 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);
owning_groups.emplace(type_hash<handler_type>::value(), handler);
handler->previous(prev);
handler->next(next);
return {*handler};
}
}