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

registry: create with hint (close #303)

Michele Caini 6 лет назад
Родитель
Сommit
d202bd3e50
2 измененных файлов с 87 добавлено и 12 удалено
  1. 54 12
      src/entt/entity/registry.hpp
  2. 33 0
      test/entt/entity/registry.cpp

+ 54 - 12
src/entt/entity/registry.hpp

@@ -68,7 +68,7 @@ class basic_registry {
 
         template<typename... Args>
         decltype(auto) assign(basic_registry &owner, const Entity entt, Args &&... args) {
-            decltype(auto) component = storage<Entity, Component>::construct(entt, std::forward<Args>(args)...);
+            decltype(auto) component = storage<entity_type, Component>::construct(entt, std::forward<Args>(args)...);
             construction.publish(entt, owner, component);
             return component;
         }
@@ -76,7 +76,7 @@ class basic_registry {
         template<typename It, typename... Args>
         std::enable_if_t<std::is_same_v<typename std::iterator_traits<It>::value_type, Entity>, typename storage<Entity, Component>::reverse_iterator_type>
         assign(basic_registry &owner, It first, It last, Args &&... args) {
-            auto it = storage<Entity, Component>::construct(first, last, std::forward<Args>(args)...);
+            auto it = storage<entity_type, Component>::construct(first, last, std::forward<Args>(args)...);
             const auto end = it + (!construction.empty() * std::distance(first, last));
 
             std::for_each(it, end, [this, &owner, &first](decltype(*it) component) {
@@ -88,14 +88,14 @@ class basic_registry {
 
         void remove(basic_registry &owner, const Entity entt) {
             destruction.publish(entt, owner);
-            storage<Entity, Component>::destroy(entt);
+            storage<entity_type, Component>::destroy(entt);
         }
 
         template<typename... Args>
         decltype(auto) replace(basic_registry &owner, const Entity entt, Args &&... args) {
             Component component{std::forward<Args>(args)...};
             update.publish(entt, owner, component);
-            return (storage<Entity, Component>::get(entt) = std::move(component));
+            return (storage<entity_type, Component>::get(entt) = std::move(component));
         }
 
     private:
@@ -194,8 +194,7 @@ class basic_registry {
             const auto curr = to_integral(destroyed);
             const auto version = to_integral(entities[curr]) & (traits_type::version_mask << traits_type::entity_shift);
             destroyed = entity_type{to_integral(entities[curr]) & traits_type::entity_mask};
-            entt = entity_type{curr | version};
-            entities[curr] = entt;
+            entt = entities[curr] = entity_type{curr | version};
         }
 
         return entt;
@@ -205,9 +204,8 @@ class basic_registry {
         // lengthens the implicit list of destroyed entities
         const auto entt = to_integral(entity) & traits_type::entity_mask;
         const auto version = ((to_integral(entity) >> traits_type::entity_shift) + 1) << traits_type::entity_shift;
-        const auto node = to_integral(destroyed) | version;
-        entities[entt] = Entity{node};
-        destroyed = Entity{entt};
+        entities[entt] = entity_type{to_integral(destroyed) | version};
+        destroyed = entity_type{entt};
     }
 
     template<typename Component, typename... Args>
@@ -225,16 +223,16 @@ class basic_registry {
                 pdata.type_id = type_info<Component>::id();
                 pdata.pool = std::make_unique<pool_handler<Component>>(std::forward<Args>(args)...);
 
-                pdata.remove = [](sparse_set<Entity> &cpool, basic_registry &owner, const Entity entt) {
+                pdata.remove = [](sparse_set<entity_type> &cpool, basic_registry &owner, const entity_type entt) {
                     static_cast<pool_handler<Component> &>(cpool).remove(owner, entt);
                 };
 
                 if constexpr(std::is_copy_constructible_v<std::decay_t<Component>>) {
-                    pdata.assure = [](basic_registry &other, const sparse_set<Entity> &cpool) {
+                    pdata.assure = [](basic_registry &other, const sparse_set<entity_type> &cpool) {
                         other.assure<Component>(static_cast<const pool_handler<Component> &>(cpool));
                     };
 
-                    pdata.stamp = [](basic_registry &other, const Entity dst, const sparse_set<Entity> &cpool, const Entity src) {
+                    pdata.stamp = [](basic_registry &other, const entity_type dst, const sparse_set<entity_type> &cpool, const entity_type src) {
                         other.assign_or_replace<Component>(dst, static_cast<const pool_handler<Component> &>(cpool).get(src));
                     };
                 }
@@ -532,6 +530,50 @@ public:
         }
     }
 
+    /**
+     * @brief Creates a new entity and returns it.
+     *
+     * @sa create
+     *
+     * If the requested entity isn't in use, the suggested identifier is created
+     * and returned. Otherwise, a new one will be generated for this purpose.
+     *
+     * @tparam Component Types of components to assign to the entity.
+     * @param hint A desired entity identifier.
+     * @return A valid entity identifier if the component list is empty, a tuple
+     * containing the entity identifier and the references to the components
+     * just created otherwise.
+     */
+    template<typename... Component>
+    auto create(const entity_type hint) {
+        ENTT_ASSERT(hint != null);
+        entity_type entt;
+
+        if(const auto req = (to_integral(hint) & traits_type::entity_mask); !(req < entities.size())) {
+            entities.reserve(req + 1);
+
+            for(auto pos = entities.size(); pos < req; ++pos) {
+                entities.emplace_back(destroyed);
+                destroyed = entity_type(pos);
+            }
+
+            entt = entities.emplace_back(hint);
+        } else if(const auto curr = (to_integral(entities[req]) & traits_type::entity_mask); req == curr) {
+            entt = create();
+        } else {
+            auto *it = &destroyed;
+            for(; (to_integral(*it) & traits_type::entity_mask) != req; it = &entities[to_integral(*it) & traits_type::entity_mask]);
+            *it = entity_type{curr | (to_integral(*it) & (traits_type::version_mask << traits_type::entity_shift))};
+            entt = entities[req] = hint;
+        }
+
+        if constexpr(sizeof...(Component) == 0) {
+            return entt;
+        } else {
+            return std::tuple_cat(std::make_tuple(entt), std::forward_as_tuple(assign<Component>(entt)...));
+        }
+    }
+
     /**
      * @brief Destroys an entity and lets the registry recycle the identifier.
      *

+ 33 - 0
test/entt/entity/registry.cpp

@@ -1231,6 +1231,39 @@ TEST(Registry, CreateManyEntitiesWithComponentsAtOnceWithListener) {
     ASSERT_EQ(listener.counter, 6);
 }
 
+TEST(Registry, CreateWithHint) {
+    entt::registry registry;
+    auto e3 = registry.create(entt::entity{3});
+    auto e2 = registry.create(entt::entity{3});
+
+    ASSERT_EQ(e2, entt::entity{2});
+    ASSERT_FALSE(registry.valid(entt::entity{1}));
+    ASSERT_EQ(e3, entt::entity{3});
+
+    registry.destroy(e2);
+
+    ASSERT_EQ(registry.version(e2), 0);
+    ASSERT_EQ(registry.current(e2), 1);
+
+    e2 = registry.create();
+    auto e1 = registry.create(entt::entity{2});
+
+    ASSERT_EQ(registry.entity(e2), entt::entity{2});
+    ASSERT_EQ(registry.version(e2), 1);
+
+    ASSERT_EQ(registry.entity(e1), entt::entity{1});
+    ASSERT_EQ(registry.version(e1), 0);
+
+    registry.destroy(e1);
+    registry.destroy(e2);
+    auto e0 = std::get<0>(registry.create<int>(entt::entity{0}));
+
+    ASSERT_EQ(e0, entt::entity{0});
+    ASSERT_EQ(registry.version(e0), 0);
+    ASSERT_TRUE(registry.has<int>(e0));
+    ASSERT_FALSE(registry.has<char>(e0));
+}
+
 TEST(Registry, NonOwningGroupInterleaved) {
     entt::registry registry;
     typename entt::entity entity = entt::null;