Sfoglia il codice sorgente

entity:
* sparse_set: stable virtual remove
* basic_storage: fake get for empty types,
* sigh_storage_mixin: use swap_and_pop, drop ::remove, ignore emptiness
* poly_storage: ::remove is no longer part of its interface by default

Michele Caini 5 anni fa
parent
commit
169b816613

+ 4 - 1
TODO

@@ -18,10 +18,13 @@
   - ...
 
 WIP:
+* HP: as_ref should be a qualified function, not a global one (no breaking change, ADL makes it work anyway)
+* HP: remove storage category and get_as_tuple, make storage classes return tuple (+ view generator detect shared storage in future)?
 * HP: remove non-const registry::storage function?
+* HP: review registry::get, registry::try_get
 * HP: weak reference wrapper example with custom storage.
 * HP: review ENTT_PAGE_SIZE, seems "wrong" (see sparse_set)
-* HP: as_ref should be a qualified function, not a global one (no breaking change, ADL makes it work anyway)
+* HP: virtual sparse_set::poly_storage (and sparse_set * only in the registry)
 * HP: merge view and view pack
 * HP: invalid view auto-refresh
 * HP: paginate pools

+ 2 - 24
src/entt/entity/poly_storage.hpp

@@ -18,15 +18,7 @@ namespace entt {
  * @tparam Entity A valid entity type (see entt_traits for more details).
  */
 template<typename Entity>
-struct Storage: type_list<
-    type_info() const ENTT_NOEXCEPT,
-    void(const Entity *, const Entity *)
-> {
-    /*! @brief Underlying entity identifier. */
-    using entity_type = Entity;
-    /*! @brief Unsigned integer type. */
-    using size_type = std::size_t;
-
+struct Storage: type_list<type_info() const ENTT_NOEXCEPT> {
     /**
      * @brief Concept definition.
      * @tparam Base Opaque base class from which to inherit.
@@ -40,17 +32,6 @@ struct Storage: type_list<
         type_info value_type() const ENTT_NOEXCEPT {
             return poly_call<0>(*this);
         }
-
-        /**
-         * @brief Removes entities from a storage.
-         * @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 remove(const entity_type *first, const entity_type *last) {
-            poly_call<1>(*this, first, last);
-        }
     };
 
     /**
@@ -58,10 +39,7 @@ struct Storage: type_list<
      * @tparam Type Type for which to generate an implementation.
      */
     template<typename Type>
-    using impl = value_list<
-        &type_id<typename Type::value_type>,
-        &Type::template remove<const entity_type *>
-    >;
+    using impl = value_list<&type_id<typename Type::value_type>>;
 };
 
 

+ 3 - 3
src/entt/entity/registry.hpp

@@ -639,7 +639,7 @@ public:
         auto *cpool = assure<Component>();
 
         return cpool->contains(entity)
-            ? cpool->patch(entity, [&args...](auto &curr) { curr = Component{std::forward<Args>(args)...}; })
+            ? cpool->patch(entity, [&args...](auto &... curr) { ((curr = Component{std::forward<Args>(args)...}), ...); })
             : cpool->emplace(entity, std::forward<Args>(args)...);
     }
 
@@ -692,7 +692,7 @@ public:
      */
     template<typename Component, typename... Args>
     decltype(auto) replace(const entity_type entity, Args &&... args) {
-        return assure<Component>()->patch(entity, [&args...](auto &curr) { curr = Component{std::forward<Args>(args)...}; });
+        return assure<Component>()->patch(entity, [&args...](auto &... curr) { ((curr = Component{std::forward<Args>(args)...}), ...); });
     }
 
     /**
@@ -776,7 +776,7 @@ public:
 
         for(auto pos = pools.size(); pos; --pos) {
             if(auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->contains(entity)) {
-                pdata.poly->remove(std::begin(wrap), std::end(wrap));
+                pdata.pool->remove(std::begin(wrap), std::end(wrap));
             }
         }
     }

+ 6 - 5
src/entt/entity/sparse_set.hpp

@@ -433,17 +433,18 @@ public:
     void remove(const entity_type entt) {
         ENTT_ASSERT(contains(entt));
         auto &ref = sparse[page(entt)][offset(entt)];
-        const auto pos = size_type{to_integral(ref)};
-        const auto other = packed.back();
 
+        // last chance to use the entity for derived classes and mixins, if any
+        swap_and_pop(size_type{to_integral(ref)});
+
+        const auto other = packed.back();
         sparse[page(other)][offset(other)] = ref;
-        // If it looks weird, imagine what the subtle bugs it prevents are
+        // if it looks weird, imagine what the subtle bugs it prevents are
         ENTT_ASSERT((packed.back() = entt, true));
-        packed[pos] = other;
+        packed[size_type{to_integral(ref)}] = other;
         ref = null;
 
         packed.pop_back();
-        swap_and_pop(pos);
     }
 
     /**

+ 23 - 37
src/entt/entity/storage.hpp

@@ -512,6 +512,19 @@ public:
     /*! @brief Storage category. */
     using storage_category = empty_storage_tag;
 
+    /**
+     * @brief Fake get function.
+     *
+     * @warning
+     * Attempting to use an entity that doesn't belong to the storage results in
+     * undefined behavior.
+     *
+     * @param entt A valid entity identifier.
+     */
+    void get([[maybe_unused]] const entity_type entt) const {
+        ENTT_ASSERT(contains(entt));
+    }
+
     /**
      * @brief Assigns an entity to a storage and constructs its object.
      *
@@ -570,6 +583,12 @@ class sigh_storage_mixin: public Type {
         return *static_cast<Owner *>(payload());
     }
 
+protected:
+    void swap_and_pop(const std::size_t pos) {
+        destruction.publish(owner(), data()[pos]);
+        Type::swap_and_pop(pos);
+    }
+
 public:
     /*! @brief Underlying value type. */
     using value_type = typename Type::value_type;
@@ -654,10 +673,7 @@ public:
     decltype(auto) emplace(const entity_type entity, Args &&... args) {
         Type::emplace(entity, std::forward<Args>(args)...);
         construction.publish(owner(), entity);
-
-        if constexpr(!std::is_same_v<storage_category, empty_storage_tag>) {
-            return this->get(entity);
-        }
+        return get(entity);
     }
 
     /**
@@ -681,32 +697,6 @@ public:
         }
     }
 
-    /**
-     * @copybrief storage_adapter_mixin::remove
-     * @param entity A valid entity identifier.
-     */
-    void remove(const entity_type entity) {
-        destruction.publish(owner(), entity);
-        Type::remove(entity);
-    }
-
-    /**
-     * @copybrief storage_adapter_mixin::remove
-     * @tparam It Type of input iterator.
-     * @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.
-     */
-    template<typename It>
-    void remove(It first, It last) {
-        if(!destruction.empty()) {
-            for(auto it = first; it != last; ++it) {
-                destruction.publish(owner(), *it);
-            }
-        }
-
-        Type::remove(first, last);
-    }
-
     /**
      * @copybrief storage_adapter_mixin::patch
      * @tparam Func Types of the function objects to invoke.
@@ -716,13 +706,9 @@ public:
      */
     template<typename... Func>
     decltype(auto) patch(const entity_type entity, [[maybe_unused]] Func &&... func) {
-        if constexpr(std::is_same_v<storage_category, empty_storage_tag>) {
-            update.publish(owner(), entity);
-        } else {
-            Type::patch(entity, std::forward<Func>(func)...);
-            update.publish(owner(), entity);
-            return this->get(entity);
-        }
+        Type::patch(entity, std::forward<Func>(func)...);
+        update.publish(owner(), entity);
+        return get(entity);
     }
 
 private:

+ 9 - 3
test/entt/entity/poly_storage.cpp

@@ -11,6 +11,7 @@ template<typename Entity>
 struct PolyStorage: entt::type_list_cat_t<
     decltype(as_type_list(std::declval<entt::Storage<Entity>>())),
     entt::type_list<
+        void(const Entity *, const Entity *),
         void(const Entity, const void *),
         const void *(const Entity) const,
         void(entt::basic_registry<Entity> &) const
@@ -23,16 +24,20 @@ struct PolyStorage: entt::type_list_cat_t<
     struct type: entt::Storage<Entity>::template type<Base> {
         static constexpr auto base = std::tuple_size_v<typename entt::poly_vtable<entt::Storage<Entity>>::type>;
 
+        void remove(const entity_type *first, const entity_type *last) {
+            entt::poly_call<base + 0>(*this, first, last);
+        }
+
         void emplace(const entity_type entity, const void *instance) {
-            entt::poly_call<base + 0>(*this, entity, instance);
+            entt::poly_call<base + 1>(*this, entity, instance);
         }
 
         const void * get(const entity_type entity) const {
-            return entt::poly_call<base + 1>(*this, entity);
+            return entt::poly_call<base + 2>(*this, entity);
         }
 
         void copy_to(entt::basic_registry<Entity> &other) const {
-            entt::poly_call<base + 2>(*this, other);
+            entt::poly_call<base + 3>(*this, other);
         }
     };
 
@@ -55,6 +60,7 @@ struct PolyStorage: entt::type_list_cat_t<
     using impl = entt::value_list_cat_t<
         typename entt::Storage<Entity>::template impl<Type>,
         entt::value_list<
+            &Type::template remove<const entity_type *>,
             &members<Type>::emplace,
             &members<Type>::get,
             &members<Type>::copy_to