Просмотр исходного кода

snapshot: registry friendship is no longer required

Michele Caini 5 лет назад
Родитель
Сommit
4ac46bf19d
3 измененных файлов с 91 добавлено и 147 удалено
  1. 4 5
      TODO
  2. 4 39
      src/entt/entity/registry.hpp
  3. 83 103
      src/entt/entity/snapshot.hpp

+ 4 - 5
TODO

@@ -16,12 +16,11 @@ Next:
 * make it easier to hook into the type system and describe how to do that to eg auto-generate meta types on first use
 * review multi component views to reduce instantiations once empty types are gone...
 * add observer functions aside observer class
+* registry clear can use the range-destroy and run much, much faster!
 
 * WIP:
  - introduce the component iterators for non-contiguous collections of entities (multi component views, observers, user defined collections)
- - deprecate snapshot, loader, ...
- - provide documentation to describe alternatives
 
-* WIP: snapshot rework/deprecation
- - remove snapshot/loader from registry, make them external (faster) tools
- - deprecate snapshot classes, update documentation to describe alternatives
+* WIP: snapshot rework
+ - snapshot: use entity injection to load all entities at once
+ - update documentation to describe alternatives

+ 4 - 39
src/entt/entity/registry.hpp

@@ -1580,20 +1580,9 @@ public:
      *
      * @return A temporary object to use to take snasphosts.
      */
+    [[deprecated("basic_snapshot has now a constructor that accepts a reference to a registry")]]
     entt::basic_snapshot<Entity> snapshot() const {
-        using follow_fn_type = entity_type(const basic_registry &, const entity_type);
-
-        const auto head = to_integral(destroyed);
-        const entity_type seed = (destroyed == null) ? destroyed : entity_type{head | (to_integral(entities[head]) & (traits_type::version_mask << traits_type::entity_shift))};
-
-        follow_fn_type *follow = [](const basic_registry &reg, const entity_type entity) -> entity_type {
-            const auto &others = reg.entities;
-            const auto entt = to_integral(entity) & traits_type::entity_mask;
-            const auto curr = to_integral(others[entt]) & traits_type::entity_mask;
-            return entity_type{curr | (to_integral(others[curr]) & (traits_type::version_mask << traits_type::entity_shift))};
-        };
-
-        return { this, seed, follow };
+        return { *this };
     }
 
     /**
@@ -1611,33 +1600,9 @@ public:
      *
      * @return A temporary object to use to load snasphosts.
      */
+    [[deprecated("basic_snapshot_loader has now a constructor that accepts a reference to a registry")]]
     basic_snapshot_loader<Entity> loader() {
-        using force_fn_type = void(basic_registry &, const entity_type, const bool);
-
-        force_fn_type *force = [](basic_registry &reg, const entity_type entity, const bool drop) {
-            const auto entt = to_integral(entity) & traits_type::entity_mask;
-            auto &others = reg.entities;
-
-            if(!(entt < others.size())) {
-                auto curr = others.size();
-                others.resize(entt + 1);
-                std::generate(others.data() + curr, others.data() + entt, [&curr]() { return entity_type(curr++); });
-            }
-
-            others[entt] = entity;
-
-            if(drop) {
-                reg.destroy(entity);
-                const auto version = to_integral(entity) & (traits_type::version_mask << traits_type::entity_shift);
-                others[entt] = entity_type{(to_integral(others[entt]) & traits_type::entity_mask) | version};
-            }
-        };
-
-        clear();
-        entities.clear();
-        destroyed = null;
-
-        return { this, force };
+        return { *this };
     }
 
     /**

+ 83 - 103
src/entt/entity/snapshot.hpp

@@ -3,6 +3,7 @@
 
 
 #include <array>
+#include <vector>
 #include <cstddef>
 #include <utility>
 #include <iterator>
@@ -31,15 +32,8 @@ class basic_snapshot {
     /*! @brief A registry is allowed to create snapshots. */
     friend class basic_registry<Entity>;
 
-    using follow_fn_type = Entity(const basic_registry<Entity> &, const Entity);
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
-    basic_snapshot(const basic_registry<Entity> *source, Entity init, follow_fn_type *fn) ENTT_NOEXCEPT
-        : reg{source},
-          seed{init},
-          follow{fn}
-    {}
-
     template<typename Component, typename Archive, typename It>
     void get(Archive &archive, std::size_t sz, It first, It last) const {
         archive(typename traits_type::entity_type(sz));
@@ -71,6 +65,17 @@ class basic_snapshot {
     }
 
 public:
+    /*! @brief Underlying entity identifier. */
+    using entity_type = Entity;
+
+    /**
+     * @brief Constructs an instance that is bound to a given registry.
+     * @param source A valid reference to a registry.
+     */
+    basic_snapshot(const basic_registry<entity_type> &source) ENTT_NOEXCEPT
+        : reg{&source}
+    {}
+
     /*! @brief Default move constructor. */
     basic_snapshot(basic_snapshot &&) = default;
 
@@ -78,10 +83,10 @@ public:
     basic_snapshot & operator=(basic_snapshot &&) = default;
 
     /**
-     * @brief Puts aside all the entities that are still in use.
+     * @brief Puts aside all the entities from the underlying registry.
      *
      * Entities are serialized along with their versions. Destroyed entities are
-     * not taken in consideration by this function.
+     * taken in consideration as well by this function.
      *
      * @tparam Archive Type of output archive.
      * @param archive A valid reference to an output archive.
@@ -89,38 +94,27 @@ public:
      */
     template<typename Archive>
     const basic_snapshot & entities(Archive &archive) const {
-        archive(typename traits_type::entity_type(reg->alive()));
-        reg->each([&archive](const auto entt) { archive(entt); });
+        const auto sz = reg->size();
+        auto first = reg->data();
+        const auto last = first + sz;
+
+        archive(typename traits_type::entity_type(sz));
+
+        while(first != last) {
+            archive(*(first++));
+        }
+
         return *this;
     }
 
     /**
-     * @brief Puts aside destroyed entities.
-     *
-     * Entities are serialized along with their versions. Entities that are
-     * still in use are not taken in consideration by this function.
-     *
+     * @brief Deprecated function. Currently, it does nothing.
      * @tparam Archive Type of output archive.
-     * @param archive A valid reference to an output archive.
      * @return An object of this type to continue creating the snapshot.
      */
     template<typename Archive>
-    const basic_snapshot & destroyed(Archive &archive) const {
-        auto size = reg->size() - reg->alive();
-        archive(typename traits_type::entity_type(size));
-
-        if(size) {
-            auto curr = seed;
-            archive(curr);
-
-            for(--size; size; --size) {
-                curr = follow(*reg, curr);
-                archive(curr);
-            }
-        }
-
-        return *this;
-    }
+    [[deprecated("use ::entities instead, it exports now also destroyed entities")]]
+    const basic_snapshot & destroyed(Archive &) const { return *this; }
 
     /**
      * @brief Puts aside the given components.
@@ -160,9 +154,7 @@ public:
     }
 
 private:
-    const basic_registry<Entity> *reg;
-    const Entity seed;
-    follow_fn_type *follow;
+    const basic_registry<entity_type> *reg;
 };
 
 
@@ -181,36 +173,15 @@ class basic_snapshot_loader {
     /*! @brief A registry is allowed to create snapshot loaders. */
     friend class basic_registry<Entity>;
 
-    using force_fn_type = void(basic_registry<Entity> &, const Entity, const bool);
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
-    basic_snapshot_loader(basic_registry<Entity> *source, force_fn_type *fn) ENTT_NOEXCEPT
-        : reg{source},
-          force{fn}
-    {
-        // to restore a snapshot as a whole requires a clean registry
-        ENTT_ASSERT(reg->empty());
-    }
-
-    template<typename Archive>
-    void assure(Archive &archive, bool discard) const {
-        typename traits_type::entity_type length{};
-        archive(length);
-
-        while(length--) {
-            Entity entt{};
-            archive(entt);
-            force(*reg, entt, discard);
-        }
-    }
-
     template<typename Type, typename Archive, typename... Args>
     void assign(Archive &archive, Args... args) const {
         typename traits_type::entity_type length{};
         archive(length);
 
         while(length--) {
-            Entity entt{};
+            entity_type entt{};
 
             if constexpr(std::is_empty_v<Type>) {
                 archive(entt);
@@ -228,6 +199,20 @@ class basic_snapshot_loader {
     }
 
 public:
+    /*! @brief Underlying entity identifier. */
+    using entity_type = Entity;
+
+    /**
+     * @brief Constructs an instance that is bound to a given registry.
+     * @param source A valid reference to a registry.
+     */
+    basic_snapshot_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
+        : reg{&source}
+    {
+        // restoring a snapshot as a whole requires a clean registry
+        ENTT_ASSERT(reg->empty());
+    }
+
     /*! @brief Default move constructor. */
     basic_snapshot_loader(basic_snapshot_loader &&) = default;
 
@@ -246,27 +231,28 @@ public:
      */
     template<typename Archive>
     const basic_snapshot_loader & entities(Archive &archive) const {
-        static constexpr auto discard = false;
-        assure(archive, discard);
+        typename traits_type::entity_type length{};
+
+        archive(length);
+        std::vector<entity_type> entities(length);
+
+        for(decltype(length) pos{}; pos < length; ++pos) {
+            archive(entities[pos]);
+        }
+
+        reg->assign(entities.cbegin(), entities.cend());
+
         return *this;
     }
 
     /**
-     * @brief Restores entities that were destroyed during serialization.
-     *
-     * This function restores the entities that were destroyed during
-     * serialization and gives them the versions they originally had.
-     *
+     * @brief Deprecated function. Currently, it does nothing.
      * @tparam Archive Type of input archive.
-     * @param archive A valid reference to an input archive.
      * @return A valid loader to continue restoring data.
      */
     template<typename Archive>
-    const basic_snapshot_loader & destroyed(Archive &archive) const {
-        static constexpr auto discard = true;
-        assure(archive, discard);
-        return *this;
-    }
+    [[deprecated("use ::entities instead, it imports now also destroyed entities")]]
+    const basic_snapshot_loader & destroyed(Archive &) const { return *this; }
 
     /**
      * @brief Restores components and assigns them to the right entities.
@@ -306,8 +292,7 @@ public:
     }
 
 private:
-    basic_registry<Entity> *reg;
-    force_fn_type *force;
+    basic_registry<entity_type> *reg;
 };
 
 
@@ -364,12 +349,12 @@ class basic_continuous_loader {
             using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
             using second_type = typename std::decay_t<decltype(pair)>::second_type;
 
-            if constexpr(std::is_same_v<first_type, Entity> && std::is_same_v<second_type, Entity>) {
+            if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
                 other.emplace(map(pair.first), map(pair.second));
-            } else if constexpr(std::is_same_v<first_type, Entity>) {
+            } else if constexpr(std::is_same_v<first_type, entity_type>) {
                 other.emplace(map(pair.first), std::move(pair.second));
             } else {
-                static_assert(std::is_same_v<second_type, Entity>);
+                static_assert(std::is_same_v<second_type, entity_type>);
                 other.emplace(std::move(pair.first), map(pair.second));
             }
         }
@@ -381,7 +366,7 @@ class basic_continuous_loader {
     auto update(char, Container &container)
     -> decltype(typename Container::value_type{}, void()) {
         // vector like container
-        static_assert(std::is_same_v<typename Container::value_type, Entity>);
+        static_assert(std::is_same_v<typename Container::value_type, entity_type>);
 
         for(auto &&entt: container) {
             entt = map(entt);
@@ -392,7 +377,7 @@ class basic_continuous_loader {
     void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type:: *member) {
         if constexpr(!std::is_same_v<Other, Type>) {
             return;
-        } else if constexpr(std::is_same_v<Member, Entity>) {
+        } else if constexpr(std::is_same_v<Member, entity_type>) {
             instance.*member = map(instance.*member);
         } else {
             // maybe a container? let's try...
@@ -400,18 +385,6 @@ class basic_continuous_loader {
         }
     }
 
-    template<typename Archive>
-    void assure(Archive &archive, void(basic_continuous_loader:: *member)(Entity)) {
-        typename traits_type::entity_type length{};
-        archive(length);
-
-        while(length--) {
-            Entity entt{};
-            archive(entt);
-            (this->*member)(entt);
-        }
-    }
-
     template<typename Component>
     void remove_if_exists() {
         for(auto &&ref: remloc) {
@@ -429,7 +402,7 @@ class basic_continuous_loader {
         archive(length);
 
         while(length--) {
-            Entity entt{};
+            entity_type entt{};
 
             if constexpr(std::is_empty_v<Other>) {
                 archive(entt);
@@ -450,7 +423,7 @@ public:
     using entity_type = Entity;
 
     /**
-     * @brief Constructs a loader that is bound to a given registry.
+     * @brief Constructs an instance that is bound to a given registry.
      * @param source A valid reference to a registry.
      */
     basic_continuous_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
@@ -475,25 +448,32 @@ public:
      */
     template<typename Archive>
     basic_continuous_loader & entities(Archive &archive) {
-        assure(archive, &basic_continuous_loader::restore);
+        typename traits_type::entity_type length{};
+        entity_type entt{};
+
+        archive(length);
+
+        for(decltype(length) pos{}; pos < length; ++pos) {
+            archive(entt);
+
+            if(const auto entity = (to_integral(entt) & traits_type::entity_mask); entity == pos) {
+                restore(entt);
+            } else {
+                destroy(entt);
+            }
+        }
+
         return *this;
     }
 
     /**
-     * @brief Restores entities that were destroyed during serialization.
-     *
-     * This function restores the entities that were destroyed during
-     * serialization and creates local counterparts for them if required.
-     *
+     * @brief Deprecated function. Currently, it does nothing.
      * @tparam Archive Type of input archive.
-     * @param archive A valid reference to an input archive.
      * @return A non-const reference to this loader.
      */
     template<typename Archive>
-    basic_continuous_loader & destroyed(Archive &archive) {
-        assure(archive, &basic_continuous_loader::destroy);
-        return *this;
-    }
+    [[deprecated("use ::entities instead, it imports now also destroyed entities")]]
+    basic_continuous_loader & destroyed(Archive &) { return *this; }
 
     /**
      * @brief Restores components and assigns them to the right entities.