Kaynağa Gözat

sparse_set/storage:
* try_emplace returns a basic iterator
* try_erase accepts a basic iterator (prepare for an even faster remove/erase/clear/whatever)

Michele Caini 4 yıl önce
ebeveyn
işleme
518bbc651e
2 değiştirilmiş dosya ile 57 ekleme ve 44 silme
  1. 19 15
      src/entt/entity/sparse_set.hpp
  2. 38 29
      src/entt/entity/storage.hpp

+ 19 - 15
src/entt/entity/sparse_set.hpp

@@ -75,13 +75,11 @@ struct sparse_set_iterator final {
     }
 
     [[nodiscard]] reference operator[](const difference_type value) const {
-        const auto pos = offset - value - 1;
-        return packed->data()[pos];
+        return packed->data()[index() - value];
     }
 
     [[nodiscard]] pointer operator->() const {
-        const auto pos = offset - 1;
-        return packed->data() + pos;
+        return packed->data() + index();
     }
 
     [[nodiscard]] reference operator*() const {
@@ -231,14 +229,17 @@ private:
     virtual void move_element(const std::size_t, const std::size_t) {}
 
 protected:
+    /*! @brief Random access iterator type. */
+    using basic_iterator = internal::sparse_set_iterator<packed_container_type>;
+
     /**
      * @brief Erases an entity from a sparse set.
-     * @param entt A valid identifier.
+     * @param it Iterator to the element to remove.
      */
-    virtual void try_erase(const Entity entt) {
-        ENTT_ASSERT(contains(entt), "Set does not contain entity");
+    virtual void try_erase(const basic_iterator it) {
+        auto &ref = sparse_ref(*it);
 
-        if(const auto pos = index(entt); mode == deletion_policy::in_place) {
+        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();
@@ -249,23 +250,27 @@ protected:
         }
 
         // lazy self-assignment guard
-        sparse_ref(entt) = null;
+        ref = null;
     }
 
     /**
      * @brief Assigns an entity to a sparse set.
      * @param entt A valid identifier.
      * @param force_back Force back insertion.
+     * @return Iterator pointing to the emplaced element.
      */
-    virtual void try_emplace(const Entity entt, const bool force_back, const void * = nullptr) {
+    virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) {
         ENTT_ASSERT(!contains(entt), "Set already contains entity");
 
         if(auto &elem = assure_at_least(entt); free_list == null || force_back) {
             packed.push_back(entt);
             elem = entity_traits::combine(static_cast<typename entity_traits::entity_type>(packed.size() - 1u), entity_traits::to_integral(entt));
+            return begin();
         } else {
+            const auto pos = static_cast<size_type>(entity_traits::to_entity(free_list));
             elem = entity_traits::combine(entity_traits::to_integral(free_list), entity_traits::to_integral(entt));
-            free_list = std::exchange(packed[static_cast<size_type>(entity_traits::to_entity(free_list))], entt);
+            free_list = std::exchange(packed[pos], entt);
+            return --(end() - pos);
         }
     }
 
@@ -281,7 +286,7 @@ public:
     /*! @brief Pointer type to contained entities. */
     using pointer = typename packed_container_type::const_pointer;
     /*! @brief Random access iterator type. */
-    using iterator = internal::sparse_set_iterator<packed_container_type>;
+    using iterator = basic_iterator;
     /*! @brief Constant random access iterator type. */
     using const_iterator = iterator;
     /*! @brief Reverse iterator type. */
@@ -652,8 +657,7 @@ public:
      * `end()` iterator otherwise.
      */
     iterator emplace(const entity_type entt, const void *value = nullptr) {
-        try_emplace(entt, false, value);
-        return find(entt);
+        return try_emplace(entt, false, value);
     }
 
     /**
@@ -688,7 +692,7 @@ public:
      * @param entt A valid identifier.
      */
     void erase(const entity_type entt) {
-        try_erase(entt);
+        try_erase(--(end() - index(entt)));
     }
 
     /**

+ 38 - 29
src/entt/entity/storage.hpp

@@ -99,12 +99,12 @@ public:
     }
 
     [[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT {
-        const auto pos = offset - value - 1;
+        const auto pos = index() - value;
         return (*packed)[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)];
     }
 
     [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
-        const auto pos = offset - 1;
+        const auto pos = index();
         return (*packed)[pos / comp_traits::page_size] + fast_mod(pos, comp_traits::page_size);
     }
 
@@ -268,6 +268,22 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
         return container[idx] + fast_mod(pos, comp_traits::page_size);
     }
 
+    template<typename... Args>
+    auto emplace_element(const Entity entt, const bool force_back, Args &&...args) {
+        const auto it = base_type::try_emplace(entt, force_back);
+
+        ENTT_TRY {
+            auto elem = assure_at_least(static_cast<size_type>(it.index()));
+            alloc_traits::construct(packed.second(), to_address(elem), std::forward<Args>(args)...);
+        }
+        ENTT_CATCH {
+            base_type::try_erase(it);
+            ENTT_THROW;
+        }
+
+        return it;
+    }
+
     void shrink_to_size(const std::size_t sz) {
         if(const auto length = base_type::size(); base_type::slot() == length) {
             for(auto pos = sz; pos < length; ++pos) {
@@ -292,21 +308,6 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
         container.resize(from);
     }
 
-    template<typename... Args>
-    decltype(auto) emplace_element(const Entity entt, const bool force_back, Args &&...args) {
-        base_type::try_emplace(entt, force_back);
-
-        ENTT_TRY {
-            auto elem = assure_at_least(base_type::index(entt));
-            alloc_traits::construct(packed.second(), to_address(elem), std::forward<Args>(args)...);
-            return *elem;
-        }
-        ENTT_CATCH {
-            base_type::try_erase(entt);
-            ENTT_THROW;
-        }
-    }
-
 private:
     const void *get_at(const std::size_t pos) const final {
         return std::addressof(element_at(pos));
@@ -325,14 +326,14 @@ private:
 protected:
     /**
      * @brief Erases an element from a storage.
-     * @param entt A valid identifier.
+     * @param it Iterator to the element to remove.
      */
-    void try_erase(const Entity entt) override {
-        const auto pos = base_type::index(entt);
+    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(entt);
+        base_type::try_erase(it);
     }
 
     /**
@@ -341,14 +342,18 @@ protected:
      * @param value Optional opaque value.
      * @param force_back Force back insertion.
      */
-    void try_emplace([[maybe_unused]] const Entity entt, const bool force_back, const void *value) override {
+    typename underlying_type::basic_iterator try_emplace([[maybe_unused]] const Entity entt, const bool force_back, const void *value) override {
         if(value) {
             if constexpr(std::is_copy_constructible_v<value_type>) {
-                emplace_element(entt, force_back, *static_cast<const value_type *>(value));
+                return emplace_element(entt, force_back, *static_cast<const value_type *>(value));
+            } else {
+                return base_type::end();
             }
         } else {
             if constexpr(std::is_default_constructible_v<value_type>) {
-                emplace_element(entt, force_back);
+                return emplace_element(entt, force_back);
+            } else {
+                return base_type::end();
             }
         }
     }
@@ -637,9 +642,11 @@ public:
     template<typename... Args>
     value_type &emplace(const entity_type entt, Args &&...args) {
         if constexpr(std::is_aggregate_v<value_type>) {
-            return emplace_element(entt, false, Type{std::forward<Args>(args)...});
+            const auto it = emplace_element(entt, false, Type{std::forward<Args>(args)...});
+            return element_at(static_cast<size_type>(it.index()));
         } else {
-            return emplace_element(entt, false, std::forward<Args>(args)...);
+            const auto it = emplace_element(entt, false, std::forward<Args>(args)...);
+            return element_at(static_cast<size_type>(it.index()));
         }
     }
 
@@ -885,16 +892,18 @@ public:
  */
 template<typename Type>
 class sigh_storage_mixin final: public Type {
-    void try_erase(const typename Type::entity_type entt) final {
+    void try_erase(const typename Type::basic_iterator it) override {
         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
+        const auto entt = *it;
         destruction.publish(*owner, entt);
-        Type::try_erase(entt);
+        Type::try_erase(Type::find(entt));
     }
 
-    void try_emplace(const typename Type::entity_type entt, const bool force_back, const void *value) final {
+    typename Type::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);
         construction.publish(*owner, entt);
+        return Type::find(entt);
     }
 
 public: