Browse Source

sparse_set/storage/sigh_storage_mixin:
* prepare to support non-movable, non-copyable types
* improve destroying entities

Michele Caini 3 years ago
parent
commit
e0ee35da61
3 changed files with 50 additions and 59 deletions
  1. 2 11
      src/entt/entity/sigh_storage_mixin.hpp
  2. 33 21
      src/entt/entity/sparse_set.hpp
  3. 15 27
      src/entt/entity/storage.hpp

+ 2 - 11
src/entt/entity/sigh_storage_mixin.hpp

@@ -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);

+ 33 - 21
src/entt/entity/sparse_set.hpp

@@ -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);
                 }
             }
         }

+ 15 - 27
src/entt/entity/storage.hpp

@@ -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.
-     */
-    void swap_and_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.
+     * @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 in_place_pop(basic_iterator first, basic_iterator last) override {
+    void 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);
+            }
         }
     }