sparse_set/storage/sigh_storage_mixin:
* prepare to support non-movable, non-copyable types * improve destroying entities
This commit is contained in:
@@ -27,26 +27,17 @@ class sigh_storage_mixin final: public Type {
|
||||
using sigh_type = sigh<void(basic_registry<typename Type::entity_type> &, const typename Type::entity_type), typename Type::allocator_type>;
|
||||
using basic_iterator = typename Type::basic_iterator;
|
||||
|
||||
template<typename Func>
|
||||
void notify_destruction(basic_iterator first, basic_iterator last, Func func) {
|
||||
void pop(basic_iterator first, basic_iterator last) override {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
|
||||
for(; first != last; ++first) {
|
||||
const auto entt = *first;
|
||||
destruction.publish(*owner, entt);
|
||||
const auto it = Type::find(entt);
|
||||
func(it, it + 1u);
|
||||
Type::pop(it, it + 1u);
|
||||
}
|
||||
}
|
||||
|
||||
void swap_and_pop(basic_iterator first, basic_iterator last) final {
|
||||
notify_destruction(std::move(first), std::move(last), [this](auto... args) { Type::swap_and_pop(args...); });
|
||||
}
|
||||
|
||||
void in_place_pop(basic_iterator first, basic_iterator last) final {
|
||||
notify_destruction(std::move(first), std::move(last), [this](auto... args) { Type::in_place_pop(args...); });
|
||||
}
|
||||
|
||||
basic_iterator try_emplace(const typename Type::entity_type entt, const bool force_back, const void *value) final {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
Type::try_emplace(entt, force_back, value);
|
||||
|
||||
@@ -234,31 +234,43 @@ protected:
|
||||
using basic_iterator = internal::sparse_set_iterator<packed_container_type>;
|
||||
|
||||
/**
|
||||
* @brief Erases entities from a sparse set.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @brief Erases an entity from a sparse set.
|
||||
* @param it An iterator to the element to pop.
|
||||
*/
|
||||
virtual void swap_and_pop(basic_iterator first, basic_iterator last) {
|
||||
for(; first != last; ++first) {
|
||||
sparse_ref(packed.back()) = entity_traits::combine(static_cast<typename entity_traits::entity_type>(first.index()), entity_traits::to_integral(packed.back()));
|
||||
const auto entt = std::exchange(packed[first.index()], packed.back());
|
||||
// unnecessary but it helps to detect nasty bugs
|
||||
ENTT_ASSERT((packed.back() = null, true), "");
|
||||
// lazy self-assignment guard
|
||||
sparse_ref(entt) = null;
|
||||
packed.pop_back();
|
||||
}
|
||||
void swap_and_pop(const basic_iterator it) {
|
||||
sparse_ref(packed.back()) = entity_traits::combine(static_cast<typename entity_traits::entity_type>(it.index()), entity_traits::to_integral(packed.back()));
|
||||
const auto entt = std::exchange(packed[it.index()], packed.back());
|
||||
// unnecessary but it helps to detect nasty bugs
|
||||
ENTT_ASSERT((packed.back() = null, true), "");
|
||||
// lazy self-assignment guard
|
||||
sparse_ref(entt) = null;
|
||||
packed.pop_back();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases an entity from a sparse set.
|
||||
* @param it An iterator to the element to pop.
|
||||
*/
|
||||
void in_place_pop(const basic_iterator it) {
|
||||
sparse_ref(*it) = null;
|
||||
packed[it.index()] = std::exchange(free_list, entity_traits::combine(static_cast<typename entity_traits::entity_type>(it.index()), entity_traits::reserved));
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Erases entities from a sparse set.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
*/
|
||||
virtual void in_place_pop(basic_iterator first, basic_iterator last) {
|
||||
for(; first != last; ++first) {
|
||||
sparse_ref(*first) = null;
|
||||
packed[first.index()] = std::exchange(free_list, entity_traits::combine(static_cast<typename entity_traits::entity_type>(first.index()), entity_traits::reserved));
|
||||
virtual void pop(basic_iterator first, basic_iterator last) {
|
||||
if(mode == deletion_policy::in_place) {
|
||||
for(; first != last; ++first) {
|
||||
in_place_pop(first);
|
||||
}
|
||||
} else {
|
||||
for(; first != last; ++first) {
|
||||
swap_and_pop(first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,7 +722,7 @@ public:
|
||||
*/
|
||||
void erase(const entity_type entt) {
|
||||
const auto it = --(end() - index(entt));
|
||||
(mode == deletion_policy::in_place) ? in_place_pop(it, it + 1u) : swap_and_pop(it, it + 1u);
|
||||
pop(it, it + 1u);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -725,7 +737,7 @@ public:
|
||||
template<typename It>
|
||||
void erase(It first, It last) {
|
||||
if constexpr(std::is_same_v<It, basic_iterator>) {
|
||||
(mode == deletion_policy::in_place) ? in_place_pop(first, last) : swap_and_pop(first, last);
|
||||
pop(first, last);
|
||||
} else {
|
||||
for(; first != last; ++first) {
|
||||
erase(*first);
|
||||
@@ -922,12 +934,12 @@ public:
|
||||
/*! @brief Clears a sparse set. */
|
||||
void clear() {
|
||||
if(const auto last = end(); free_list == null) {
|
||||
in_place_pop(begin(), last);
|
||||
pop(begin(), last);
|
||||
} else {
|
||||
for(auto &&entity: *this) {
|
||||
// tombstone filter on itself
|
||||
if(const auto it = find(entity); it != last) {
|
||||
in_place_pop(it, it + 1u);
|
||||
pop(it, it + 1u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,12 +275,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
|
||||
entt::uninitialized_construct_using_allocator(to_address(elem), packed.second(), std::forward<Args>(args)...);
|
||||
}
|
||||
ENTT_CATCH {
|
||||
if constexpr(comp_traits::in_place_delete) {
|
||||
base_type::in_place_pop(it, it + 1u);
|
||||
} else {
|
||||
base_type::swap_and_pop(it, it + 1u);
|
||||
}
|
||||
|
||||
base_type::pop(it, it + 1u);
|
||||
ENTT_THROW;
|
||||
}
|
||||
|
||||
@@ -330,29 +325,22 @@ protected:
|
||||
using basic_iterator = typename underlying_type::basic_iterator;
|
||||
|
||||
/**
|
||||
* @brief Erases elements from a storage.
|
||||
* @param first An iterator to the first element to erase.
|
||||
* @param last An iterator past the last element to erase.
|
||||
* @brief Erases entities from a sparse set.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
*/
|
||||
void swap_and_pop(basic_iterator first, basic_iterator last) override {
|
||||
void pop(basic_iterator first, basic_iterator last) override {
|
||||
for(; first != last; ++first) {
|
||||
auto &elem = element_at(base_type::size() - 1u);
|
||||
// destroying on exit allows reentrant destructors
|
||||
[[maybe_unused]] auto unused = std::exchange(element_at(static_cast<size_type>(first.index())), std::move(elem));
|
||||
std::destroy_at(std::addressof(elem));
|
||||
base_type::swap_and_pop(first, first + 1u);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases elements from a storage.
|
||||
* @param first An iterator to the first element to erase.
|
||||
* @param last An iterator past the last element to erase.
|
||||
*/
|
||||
void in_place_pop(basic_iterator first, basic_iterator last) override {
|
||||
for(; first != last; ++first) {
|
||||
base_type::in_place_pop(first, first + 1u);
|
||||
std::destroy_at(std::addressof(element_at(static_cast<size_type>(first.index()))));
|
||||
if constexpr(comp_traits::in_place_delete) {
|
||||
base_type::in_place_pop(first);
|
||||
std::destroy_at(std::addressof(element_at(static_cast<size_type>(first.index()))));
|
||||
} else {
|
||||
auto &elem = element_at(base_type::size() - 1u);
|
||||
// destroying on exit allows reentrant destructors
|
||||
[[maybe_unused]] auto unused = std::exchange(element_at(static_cast<size_type>(first.index())), std::move(elem));
|
||||
std::destroy_at(std::addressof(elem));
|
||||
base_type::swap_and_pop(first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user