Browse Source

allows setting a continuous loader as registry context (close #224)

Michele Caini 7 years ago
parent
commit
3109928dcd
2 changed files with 56 additions and 94 deletions
  1. 23 57
      src/entt/entity/registry.hpp
  2. 33 37
      src/entt/entity/snapshot.hpp

+ 23 - 57
src/entt/entity/registry.hpp

@@ -191,16 +191,11 @@ class basic_registry {
         bool(* const is_same)(const ENTT_ID_TYPE *);
     };
 
-    struct ctx_wrapper {
-        virtual ~ctx_wrapper() = default;
+    struct ctx_variable {
+        std::unique_ptr<void, void(*)(void *)> value;
         ENTT_ID_TYPE runtime_type;
     };
 
-    template<typename Type>
-    struct type_wrapper: ctx_wrapper {
-        Type value;
-    };
-
     template<typename Type, typename Family>
     static ENTT_ID_TYPE runtime_type() ENTT_NOEXCEPT {
         if constexpr(is_named_type_v<Type>) {
@@ -1491,7 +1486,7 @@ public:
             return (curr | (others[curr] & (traits_type::version_mask << traits_type::entity_shift)));
         };
 
-        return { *this, seed, follow };
+        return { this, seed, follow };
     }
 
     /**
@@ -1537,7 +1532,7 @@ public:
         entities.clear();
         available = {};
 
-        return { *this, force };
+        return { this, force };
     }
 
     /**
@@ -1554,35 +1549,22 @@ public:
     template<typename Type, typename... Args>
     Type & set(Args &&... args) {
         const auto ctype = runtime_type<Type, context_family>();
-        ctx_wrapper *wrapper = nullptr;
+        auto it = std::find_if(vars.begin(), vars.end(), [ctype](const auto &candidate) {
+            return candidate.runtime_type == ctype;
+        });
 
-        if constexpr(is_named_type_v<Type>) {
-            const auto it = std::find_if(vars.begin()+skip_family_vars, vars.end(), [ctype](const auto &candidate) {
-                return candidate->runtime_type == ctype;
+        if(it == vars.cend()) {
+            vars.push_back({
+                decltype(ctx_variable::value){new Type{std::forward<Args>(args)...}, +[](void *ptr) { delete static_cast<Type *>(ptr); }},
+                ctype
             });
 
-            wrapper = (it == vars.cend()) ? vars.emplace_back(std::make_unique<type_wrapper<Type>>()).get() : it->get();
+            it = std::prev(vars.end());
         } else {
-            if(!(ctype < skip_family_vars)) {
-                vars.reserve(vars.size()+ctype-skip_family_vars+1);
-
-                while(!(ctype < skip_family_vars)) {
-                    vars.emplace(vars.begin()+(skip_family_vars++), nullptr);
-                }
-            }
-
-            if(!vars[ctype]) {
-                vars[ctype] = std::make_unique<type_wrapper<Type>>();
-            }
-
-            wrapper = vars[ctype].get();
+            it->value.reset(new Type{std::forward<Args>(args)...});
         }
 
-        auto &value = static_cast<type_wrapper<Type> *>(wrapper)->value;
-        value = Type{std::forward<Args>(args)...};
-        wrapper->runtime_type = ctype;
-
-        return value;
+        return *static_cast<Type *>(it->value.get());
     }
 
     /**
@@ -1591,17 +1573,9 @@ public:
      */
     template<typename Type>
     void unset() {
-        const auto ctype = runtime_type<Type, context_family>();
-
-        if constexpr(is_named_type_v<Type>) {
-            vars.erase(std::remove_if(vars.begin()+skip_family_vars, vars.end(), [ctype](auto &wrapper) {
-                return wrapper->runtime_type == ctype;
-            }), vars.end());
-        } else {
-            if(ctype < skip_family_vars) {
-                vars[ctype].reset();
-            }
-        }
+        vars.erase(std::remove_if(vars.begin(), vars.end(), [](auto &var) {
+            return var.runtime_type == runtime_type<Type, context_family>();
+        }), vars.end());
     }
 
     /**
@@ -1612,18 +1586,11 @@ public:
      */
     template<typename Type>
     const Type * try_ctx() const ENTT_NOEXCEPT {
-        const auto ctype = runtime_type<Type, context_family>();
-
-        if constexpr(is_named_type_v<Type>) {
-            const auto it = std::find_if(vars.begin()+skip_family_vars, vars.end(), [ctype](const auto &candidate) {
-                return candidate->runtime_type == ctype;
-            });
+        const auto it = std::find_if(vars.begin(), vars.end(), [](const auto &var) {
+            return var.runtime_type == runtime_type<Type, context_family>();
+        });
 
-            return (it == vars.cend()) ? nullptr : &static_cast<const type_wrapper<Type> &>(**it).value;
-        } else {
-            const bool valid = ctype < skip_family_vars && vars[ctype];
-            return valid ? &static_cast<const type_wrapper<Type> &>(*vars[ctype]).value : nullptr;
-        }
+        return (it == vars.cend()) ? nullptr : static_cast<const Type *>(it->value.get());
     }
 
     /*! @copydoc try_ctx */
@@ -1658,11 +1625,10 @@ public:
     }
 
 private:
-    std::vector<pool_data> pools;
     std::size_t skip_family_pools{};
+    std::vector<pool_data> pools;
     std::vector<group_data> groups;
-    std::vector<std::unique_ptr<ctx_wrapper>> vars;
-    std::size_t skip_family_vars{};
+    std::vector<ctx_variable> vars;
     std::vector<entity_type> entities;
     size_type available{};
     entity_type next{};

+ 33 - 37
src/entt/entity/snapshot.hpp

@@ -33,7 +33,7 @@ class basic_snapshot {
 
     using follow_fn_type = Entity(const basic_registry<Entity> &, const Entity);
 
-    basic_snapshot(const basic_registry<Entity> &source, Entity init, follow_fn_type *fn) ENTT_NOEXCEPT
+    basic_snapshot(const basic_registry<Entity> *source, Entity init, follow_fn_type *fn) ENTT_NOEXCEPT
         : reg{source},
           seed{init},
           follow{fn}
@@ -46,11 +46,11 @@ class basic_snapshot {
         while(first != last) {
             const auto entt = *(first++);
 
-            if(reg.template has<Component>(entt)) {
+            if(reg->template has<Component>(entt)) {
                 if constexpr(std::is_empty_v<Component>) {
                     archive(entt);
                 } else {
-                    archive(entt, reg.template get<Component>(entt));
+                    archive(entt, reg->template get<Component>(entt));
                 }
             }
         }
@@ -63,7 +63,7 @@ class basic_snapshot {
 
         while(begin != last) {
             const auto entt = *(begin++);
-            ((reg.template has<Component>(entt) ? ++size[Indexes] : size[Indexes]), ...);
+            ((reg->template has<Component>(entt) ? ++size[Indexes] : size[Indexes]), ...);
         }
 
         (get<Component>(archive, size[Indexes], first, last), ...);
@@ -88,8 +88,8 @@ public:
      */
     template<typename Archive>
     const basic_snapshot & entities(Archive &archive) const {
-        archive(static_cast<Entity>(reg.alive()));
-        reg.each([&archive](const auto entt) { archive(entt); });
+        archive(static_cast<Entity>(reg->alive()));
+        reg->each([&archive](const auto entt) { archive(entt); });
         return *this;
     }
 
@@ -105,7 +105,7 @@ public:
      */
     template<typename Archive>
     const basic_snapshot & destroyed(Archive &archive) const {
-        auto size = reg.size() - reg.alive();
+        auto size = reg->size() - reg->alive();
         archive(static_cast<Entity>(size));
 
         if(size) {
@@ -113,7 +113,7 @@ public:
             archive(curr);
 
             for(--size; size; --size) {
-                curr = follow(reg, curr);
+                curr = follow(*reg, curr);
                 archive(curr);
             }
         }
@@ -135,8 +135,8 @@ public:
     template<typename... Component, typename Archive>
     const basic_snapshot & component(Archive &archive) const {
         if constexpr(sizeof...(Component) == 1) {
-            const auto sz = reg.template size<Component...>();
-            const auto *entities = reg.template data<Component...>();
+            const auto sz = reg->template size<Component...>();
+            const auto *entities = reg->template data<Component...>();
 
             archive(static_cast<Entity>(sz));
 
@@ -146,7 +146,7 @@ public:
                 if constexpr(std::is_empty_v<Component...>) {
                     archive(entt);
                 } else {
-                    archive(entt, reg.template get<Component...>(entt));
+                    archive(entt, reg->template get<Component...>(entt));
                 }
             };
         } else {
@@ -177,7 +177,7 @@ public:
     }
 
 private:
-    const basic_registry<Entity> &reg;
+    const basic_registry<Entity> *reg;
     const Entity seed;
     follow_fn_type *follow;
 };
@@ -200,12 +200,12 @@ class basic_snapshot_loader {
 
     using force_fn_type = void(basic_registry<Entity> &, const Entity, const bool);
 
-    basic_snapshot_loader(basic_registry<Entity> &source, force_fn_type *fn) ENTT_NOEXCEPT
+    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());
+        ENTT_ASSERT(reg->empty());
     }
 
     template<typename Archive>
@@ -216,7 +216,7 @@ class basic_snapshot_loader {
         while(length--) {
             Entity entt{};
             archive(entt);
-            force(reg, entt, destroyed);
+            force(*reg, entt, destroyed);
         }
     }
 
@@ -236,8 +236,8 @@ class basic_snapshot_loader {
             }
 
             static constexpr auto destroyed = false;
-            force(reg, entt, destroyed);
-            reg.template assign<Type>(args..., entt, std::as_const(instance));
+            force(*reg, entt, destroyed);
+            reg->template assign<Type>(args..., entt, std::as_const(instance));
         }
     }
 
@@ -312,15 +312,15 @@ public:
      * @return A valid loader to continue restoring data.
      */
     const basic_snapshot_loader & orphans() const {
-        reg.orphans([this](const auto entt) {
-            reg.destroy(entt);
+        reg->orphans([this](const auto entt) {
+            reg->destroy(entt);
         });
 
         return *this;
     }
 
 private:
-    basic_registry<Entity> &reg;
+    basic_registry<Entity> *reg;
     force_fn_type *force;
 };
 
@@ -349,9 +349,9 @@ class basic_continuous_loader {
         const auto it = remloc.find(entt);
 
         if(it == remloc.cend()) {
-            const auto local = reg.create();
+            const auto local = reg->create();
             remloc.emplace(entt, std::make_pair(local, true));
-            reg.destroy(local);
+            reg->destroy(local);
         }
     }
 
@@ -359,14 +359,10 @@ class basic_continuous_loader {
         const auto it = remloc.find(entt);
 
         if(it == remloc.cend()) {
-            const auto local = reg.create();
+            const auto local = reg->create();
             remloc.emplace(entt, std::make_pair(local, true));
         } else {
-            remloc[entt].first =
-                    reg.valid(remloc[entt].first)
-                    ? remloc[entt].first
-                    : reg.create();
-
+            remloc[entt].first = reg->valid(remloc[entt].first) ? remloc[entt].first : reg->create();
             // set the dirty flag
             remloc[entt].second = true;
         }
@@ -403,8 +399,8 @@ class basic_continuous_loader {
         for(auto &&ref: remloc) {
             const auto local = ref.second.first;
 
-            if(reg.valid(local)) {
-                reg.template reset<Component>(local);
+            if(reg->valid(local)) {
+                reg->template reset<Component>(local);
             }
         }
     }
@@ -439,7 +435,7 @@ public:
      * @param source A valid reference to a registry.
      */
     basic_continuous_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
-        : reg{source}
+        : reg{&source}
     {}
 
     /*! @brief Default move constructor. */
@@ -502,7 +498,7 @@ public:
     template<typename... Component, typename Archive, typename... Type, typename... Member>
     basic_continuous_loader & component(Archive &archive, Member Type:: *... member) {
         auto apply = [this](const auto entt, const auto &component) {
-            reg.template assign_or_replace<std::decay_t<decltype(component)>>(entt, component);
+            reg->template assign_or_replace<std::decay_t<decltype(component)>>(entt, component);
         };
 
         (reset<Component>(), ...);
@@ -529,8 +525,8 @@ public:
                 dirty = false;
                 ++it;
             } else {
-                if(reg.valid(local)) {
-                    reg.destroy(local);
+                if(reg->valid(local)) {
+                    reg->destroy(local);
                 }
 
                 it = remloc.erase(it);
@@ -551,8 +547,8 @@ public:
      * @return A non-const reference to this loader.
      */
     basic_continuous_loader & orphans() {
-        reg.orphans([this](const auto entt) {
-            reg.destroy(entt);
+        reg->orphans([this](const auto entt) {
+            reg->destroy(entt);
         });
 
         return *this;
@@ -585,7 +581,7 @@ public:
 
 private:
     std::unordered_map<Entity, std::pair<Entity, bool>> remloc;
-    basic_registry<Entity> &reg;
+    basic_registry<Entity> *reg;
 };