Bläddra i källkod

added registry::create overload to create multiple entities at once

Michele Caini 7 år sedan
förälder
incheckning
6f0cdc864f
4 ändrade filer med 81 tillägg och 2 borttagningar
  1. 3 0
      docs/entity.md
  2. 39 2
      src/entt/entity/registry.hpp
  3. 11 0
      test/benchmark/benchmark.cpp
  4. 28 0
      test/entt/entity/registry.cpp

+ 3 - 0
docs/entity.md

@@ -134,6 +134,9 @@ auto entity = registry.create();
 registry.destroy(entity);
 ```
 
+There exists another overload of the `create` member function that accepts two
+iterators, that is a range to assign. It can be used to create multiple entities
+at once.<br/>
 Entities can also be destroyed _by type_, that is by specifying the types of the
 components that identify them:
 

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

@@ -435,8 +435,7 @@ public:
             entities[entt] = entity;
             --available;
         } else {
-            entity = entity_type(entities.size());
-            entities.push_back(entity);
+            entity = entities.emplace_back(entity_type(entities.size()));
             // traits_type::entity_mask is reserved to allow for null identifiers
             assert(entity < traits_type::entity_mask);
         }
@@ -444,6 +443,44 @@ public:
         return entity;
     }
 
+    /**
+     * @brief Assigns each element in a range an entity.
+     *
+     * There are two kinds of entity identifiers:
+     *
+     * * Newly created ones in case no entities have been previously destroyed.
+     * * Recycled ones with updated versions.
+     *
+     * Users should not care about the type of the returned entity identifier.
+     * In case entity identifers are stored around, the `valid` member
+     * function can be used to know if they are still valid or the entity has
+     * been destroyed and potentially recycled.
+     *
+     * The generated entities have no components assigned.
+     *
+     * @tparam It Type of forward iterator.
+     * @param first An iterator to the first element of the range to generate.
+     * @param last An iterator past the last element of the range to generate.
+     */
+    template<typename It>
+    void create(It first, It last) {
+        const auto length = size_type(last - first);
+        const auto sz = std::min(available, length);
+
+        available -= sz;
+
+        std::generate_n(first, sz, [this]() {
+            const auto entt = next;
+            const auto version = entities[entt] & (traits_type::version_mask << traits_type::entity_shift);
+            next = entities[entt] & traits_type::entity_mask;
+            return (entities[entt] = entt | version);
+        });
+
+        std::generate_n((first + sz), (length - sz), [this]() {
+            return entities.emplace_back(entity_type(entities.size()));
+        });
+    }
+
     /**
      * @brief Destroys an entity and lets the registry recycle the identifier.
      *

+ 11 - 0
test/benchmark/benchmark.cpp

@@ -45,6 +45,17 @@ TEST(Benchmark, Construct) {
     timer.elapsed();
 }
 
+TEST(Benchmark, ConstructMany) {
+    entt::registry<> registry;
+    std::vector<entt::registry<>::entity_type> entities(1000000);
+
+    std::cout << "Constructing 1000000 entities at once" << std::endl;
+
+    timer timer;
+    registry.create(entities.begin(), entities.end());
+    timer.elapsed();
+}
+
 TEST(Benchmark, Destroy) {
     entt::registry<> registry;
 

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

@@ -1,6 +1,7 @@
 #include <unordered_map>
 #include <unordered_set>
 #include <functional>
+#include <iterator>
 #include <type_traits>
 #include <gtest/gtest.h>
 #include <entt/entity/entt_traits.hpp>
@@ -704,3 +705,30 @@ TEST(Registry, SignalsOnAccommodate) {
 
     ASSERT_FALSE((registry.persistent_view<int, char>().empty()));
 }
+
+TEST(Registry, CreateManyEntitiesAtOnce) {
+    entt::registry<> registry;
+    entt::registry<>::entity_type entities[3];
+
+    const auto entity = registry.create();
+    registry.destroy(registry.create());
+    registry.destroy(entity);
+    registry.destroy(registry.create());
+
+    registry.create(std::begin(entities), std::end(entities));
+
+    ASSERT_TRUE(registry.valid(entities[0]));
+    ASSERT_TRUE(registry.valid(entities[1]));
+    ASSERT_TRUE(registry.valid(entities[2]));
+
+    ASSERT_EQ(registry.entity(entities[0]), entt::registry<>::entity_type{0});
+    ASSERT_EQ(registry.version(entities[0]), entt::registry<>::version_type{2});
+
+    ASSERT_EQ(registry.entity(entities[1]), entt::registry<>::entity_type{1});
+    ASSERT_EQ(registry.version(entities[1]), entt::registry<>::version_type{1});
+
+    ASSERT_EQ(registry.entity(entities[2]), entt::registry<>::entity_type{2});
+    ASSERT_EQ(registry.version(entities[2]), entt::registry<>::version_type{0});
+
+    // TODO
+}