瀏覽代碼

sparse_set/storage: make try_erase accept a range of entities

Michele Caini 4 年之前
父節點
當前提交
2e89b3b5b9
共有 2 個文件被更改,包括 52 次插入32 次删除
  1. 33 20
      src/entt/entity/sparse_set.hpp
  2. 19 12
      src/entt/entity/storage.hpp

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

@@ -234,23 +234,27 @@ protected:
 
     /**
      * @brief Erases an entity from a sparse set.
-     * @param it Iterator to the element to remove.
+     * @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 try_erase(const basic_iterator it) {
-        auto &ref = sparse_ref(*it);
+    virtual void try_erase(const basic_iterator first, const basic_iterator last) {
+        for(auto it = first; it != last; ++it) {
+            const auto pos = static_cast<size_type>(it.index());
+            auto &ref = sparse_ref(*it);
+
+            if(mode == deletion_policy::in_place) {
+                packed[pos] = std::exchange(free_list, entity_traits::combine(static_cast<typename entity_traits::entity_type>(pos), entity_traits::reserved));
+            } else {
+                packed[pos] = packed.back();
+                sparse_ref(packed.back()) = entity_traits::combine(static_cast<typename entity_traits::entity_type>(pos), entity_traits::to_integral(packed.back()));
+                // unnecessary but it helps to detect nasty bugs
+                ENTT_ASSERT((packed.back() = tombstone, true), "");
+                packed.pop_back();
+            }
 
-        if(const auto pos = static_cast<size_type>(it.index()); mode == deletion_policy::in_place) {
-            packed[pos] = std::exchange(free_list, entity_traits::combine(static_cast<typename entity_traits::entity_type>(pos), entity_traits::reserved));
-        } else {
-            packed[pos] = packed.back();
-            sparse_ref(packed.back()) = entity_traits::combine(static_cast<typename entity_traits::entity_type>(pos), entity_traits::to_integral(packed.back()));
-            // unnecessary but it helps to detect nasty bugs
-            ENTT_ASSERT((packed.back() = tombstone, true), "");
-            packed.pop_back();
+            // lazy self-assignment guard
+            ref = null;
         }
-
-        // lazy self-assignment guard
-        ref = null;
     }
 
     /**
@@ -692,7 +696,8 @@ public:
      * @param entt A valid identifier.
      */
     void erase(const entity_type entt) {
-        try_erase(--(end() - index(entt)));
+        const auto it = --(end() - index(entt));
+        try_erase(it, it + 1u);
     }
 
     /**
@@ -706,8 +711,12 @@ public:
      */
     template<typename It>
     void erase(It first, It last) {
-        for(; first != last; ++first) {
-            erase(*first);
+        if constexpr(std::is_same_v<It, basic_iterator>) {
+            try_erase(first, last);
+        } else {
+            for(; first != last; ++first) {
+                erase(*first);
+            }
         }
     }
 
@@ -894,9 +903,13 @@ public:
 
     /*! @brief Clears a sparse set. */
     void clear() {
-        for(auto &&entity: *this) {
-            // honor the modality and filter all tombstones
-            remove(entity);
+        if(mode == deletion_policy::in_place) {
+            for(auto &&entity: *this) {
+                // honor the modality and filter all tombstones
+                remove(entity);
+            }
+        } else {
+            try_erase(begin(), end());
         }
     }
 

+ 19 - 12
src/entt/entity/storage.hpp

@@ -277,7 +277,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
             alloc_traits::construct(packed.second(), to_address(elem), std::forward<Args>(args)...);
         }
         ENTT_CATCH {
-            base_type::try_erase(it);
+            base_type::try_erase(it, it + 1u);
             ENTT_THROW;
         }
 
@@ -326,14 +326,17 @@ private:
 protected:
     /**
      * @brief Erases an element from a storage.
-     * @param it Iterator to the element to remove.
+     * @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 try_erase(const typename underlying_type::basic_iterator it) override {
-        const auto pos = static_cast<size_type>(it.index());
-        auto &elem = element_at(comp_traits::in_place_delete ? pos : (base_type::size() - 1u));
-        [[maybe_unused]] auto unused = std::exchange(element_at(pos), std::move(elem));
-        std::destroy_at(std::addressof(elem));
-        base_type::try_erase(it);
+    void try_erase(const typename underlying_type::basic_iterator first, const typename underlying_type::basic_iterator last) override {
+        for(auto it = first; it != last; ++it) {
+            const auto pos = static_cast<size_type>(it.index());
+            auto &elem = element_at(comp_traits::in_place_delete ? pos : (base_type::size() - 1u));
+            [[maybe_unused]] auto unused = std::exchange(element_at(pos), std::move(elem));
+            std::destroy_at(std::addressof(elem));
+            base_type::try_erase(it, it + 1u);
+        }
     }
 
     /**
@@ -892,11 +895,15 @@ public:
  */
 template<typename Type>
 class sigh_storage_mixin final: public Type {
-    void try_erase(const typename Type::basic_iterator it) override {
+    void try_erase(const typename Type::basic_iterator first, const typename Type::basic_iterator last) override {
         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
-        const auto entt = *it;
-        destruction.publish(*owner, entt);
-        Type::try_erase(Type::find(entt));
+
+        for(auto it = first; it != last; ++it) {
+            const auto entt = *it;
+            destruction.publish(*owner, entt);
+            const auto curr = Type::find(entt);
+            Type::try_erase(curr, curr + 1u);
+        }
     }
 
     typename Type::basic_iterator try_emplace(const typename Type::entity_type entt, const bool force_back, const void *value) final {