1
0
Michele Caini 8 жил өмнө
parent
commit
7bf550a75f

+ 13 - 13
README.md

@@ -189,19 +189,19 @@ Dell XPS 13 out of the mid 2014):
 
 | Benchmark | EntityX (compile-time) | EnTT |
 |-----------|-------------|-------------|
-| Create 10M entities | 0.1289s | **0.0423s** |
-| Destroy 10M entities | 0.0531s | **0.0221s** |
-| Standard view, 10M entities, one component | 0.0107s | **7.8e-08s** |
-| Standard view, 10M entities, two components | **0.0113s** | 0.0142s |
-| Standard view, 10M entities, two components<br/>Half of the entities have all the components | 0.0078s | **0.0072s** |
-| Standard view, 10M entities, two components<br/>One of the entities has all the components | 0.0071s | **5.5e-07s** |
-| Persistent view, 10M entities, two components | 0.0113s | **1.1e-07s** |
-| Standard view, 10M entities, five components | **0.0091s** | 0.0352s |
-| Persistent view, 10M entities, five components | 0.0091s | **2.5e-07s** |
-| Standard view, 10M entities, ten components | **0.0105s** | 0.0780s |
-| Standard view, 10M entities, ten components<br/>Half of the entities have all the components | **0.0090s** | 0.0407s |
-| Standard view, 10M entities, ten components<br/>One of the entities has all the components | 0.0070s | **1.3e-06s** |
-| Persistent view, 10M entities, ten components | 0.0105s | **5.0e-07s** |
+| Create 1M entities | 0.0167s | **0.0076s** |
+| Destroy 1M entities | 0.0053s | **0.0031s** |
+| Standard view, 1M entities, one component | 0.0012s | **1.9e-07s** |
+| Standard view, 1M entities, two components | **0.0012s** | 0.0013s |
+| Standard view, 1M entities, two components<br/>Half of the entities have all the components | 0.0009s | **0.0007s** |
+| Standard view, 1M entities, two components<br/>One of the entities has all the components | 0.0008s | **1.3e-06s** |
+| Persistent view, 1M entities, two components | 0.0012s | **2.8e-07s** |
+| Standard view, 1M entities, five components | **0.0010s** | 0.0034s |
+| Persistent view, 1M entities, five components | 0.0010s | **2.8e-07s** |
+| Standard view, 1M entities, ten components | **0.0011s** | 0.0075s |
+| Standard view, 1M entities, ten components<br/>Half of the entities have all the components | **0.0010s** | 0.0041s |
+| Standard view, 1M entities, ten components<br/>One of the entities has all the components | 0.0008s | **1.7e-06s** |
+| Persistent view, 1M entities, ten components | 0.0011s | **3.0e-07s** |
 | Sort 150k entities, one component<br/>Arrays are in reverse order | - | **0.0040s** |
 | Sort 150k entities, enforce permutation<br/>Arrays are in reverse order | - | **0.0006s** |
 

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

@@ -58,11 +58,11 @@ struct entt_traits<std::uint32_t> {
     using version_type = std::uint16_t;
 
     /*! @brief Mask to use to get the entity number out of an identifier. */
-    static constexpr auto entity_mask = 0xFFFFFF;
+    static constexpr auto entity_mask = 0xFFFFF;
     /*! @brief Mask to use to get the version out of an identifier. */
-    static constexpr auto version_mask = 0xFF;
+    static constexpr auto version_mask = 0xFFF;
     /*! @brief Extent of the entity number within an identifier. */
-    static constexpr auto entity_shift = 24;
+    static constexpr auto entity_shift = 20;
 };
 
 

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

@@ -233,7 +233,7 @@ public:
         assert(has(entity));
         const auto entt = entity & traits_type::entity_mask;
         // we must get rid of the in-use bit for it's not part of the position
-        return reverse[entt] & ~in_use;
+        return reverse[entt] & traits_type::entity_mask;
     }
 
     /**
@@ -278,10 +278,9 @@ public:
         assert(has(entity));
         const auto entt = entity & traits_type::entity_mask;
         const auto back = direct.back() & traits_type::entity_mask;
-        const auto pos = reverse[entt] & ~in_use;
-        // the order matters: if back and entt are the same (for the sparse set
-        // has size 1), switching the two lines below doesn't work as expected
-        reverse[back] = pos | in_use;
+        // we must get rid of the in-use bit for it's not part of the position
+        const auto pos = reverse[entt] & traits_type::entity_mask;
+        reverse[back] = reverse[entt];
         reverse[entt] = pos;
         // swapping isn't required here, we are getting rid of the last element
         direct[pos] = direct.back();

+ 58 - 92
test/benchmark/benchmark.cpp

@@ -34,11 +34,11 @@ private:
 TEST(Benchmark, Construct) {
     entt::DefaultRegistry registry;
 
-    std::cout << "Constructing 10000000 entities" << std::endl;
+    std::cout << "Constructing 1000000 entities" << std::endl;
 
     Timer timer;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         registry.create();
     }
 
@@ -49,9 +49,9 @@ TEST(Benchmark, Destroy) {
     entt::DefaultRegistry registry;
     std::vector<entt::DefaultRegistry::entity_type> entities{};
 
-    std::cout << "Destroying 10000000 entities" << std::endl;
+    std::cout << "Destroying 1000000 entities" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         entities.push_back(registry.create());
     }
 
@@ -88,12 +88,12 @@ TEST(Benchmark, IterateCreateDeleteSingleComponent) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateSingleComponent10M) {
+TEST(Benchmark, IterateSingleComponent1M) {
     entt::DefaultRegistry registry;
 
-    std::cout << "Iterating over 10000000 entities, one component" << std::endl;
+    std::cout << "Iterating over 1000000 entities, one component" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         registry.create<Position>();
     }
 
@@ -102,12 +102,12 @@ TEST(Benchmark, IterateSingleComponent10M) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTwoComponents10M) {
+TEST(Benchmark, IterateTwoComponents1M) {
     entt::DefaultRegistry registry;
 
-    std::cout << "Iterating over 10000000 entities, two components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, two components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         registry.create<Position, Velocity>();
     }
 
@@ -116,12 +116,12 @@ TEST(Benchmark, IterateTwoComponents10M) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTwoComponents10MHalf) {
+TEST(Benchmark, IterateTwoComponents1MHalf) {
     entt::DefaultRegistry registry;
 
-    std::cout << "Iterating over 10000000 entities, two components, half of the entities have all the components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         auto entity = registry.create<Velocity>();
         if(i % 2) { registry.assign<Position>(entity); }
     }
@@ -131,12 +131,12 @@ TEST(Benchmark, IterateTwoComponents10MHalf) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTwoComponents10MOne) {
+TEST(Benchmark, IterateTwoComponents1MOne) {
     entt::DefaultRegistry registry;
 
-    std::cout << "Iterating over 10000000 entities, two components, only one entity has all the components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         auto entity = registry.create<Velocity>();
         if(i == 5000000L) { registry.assign<Position>(entity); }
     }
@@ -146,13 +146,13 @@ TEST(Benchmark, IterateTwoComponents10MOne) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTwoComponentsPersistent10M) {
+TEST(Benchmark, IterateTwoComponentsPersistent1M) {
     entt::DefaultRegistry registry;
     registry.prepare<Position, Velocity>();
 
-    std::cout << "Iterating over 10000000 entities, two components, persistent view" << std::endl;
+    std::cout << "Iterating over 1000000 entities, two components, persistent view" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         registry.create<Position, Velocity>();
     }
 
@@ -161,45 +161,43 @@ TEST(Benchmark, IterateTwoComponentsPersistent10M) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTwoComponentsPersistent10MHalf) {
+TEST(Benchmark, IterateFiveComponents1M) {
     entt::DefaultRegistry registry;
-    registry.prepare<Position, Velocity>();
 
-    std::cout << "Iterating over 10000000 entities, two components, persistent view, half of the entities have all the components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, five components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
-        auto entity = registry.create<Velocity>();
-        if(i % 2) { registry.assign<Position>(entity); }
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
     }
 
     Timer timer;
-    registry.persistent<Position, Velocity>().each([](auto, auto &...) {});
+    registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTwoComponentsPersistent10MOne) {
+TEST(Benchmark, IterateFiveComponents1MHalf) {
     entt::DefaultRegistry registry;
-    registry.prepare<Position, Velocity>();
 
-    std::cout << "Iterating over 10000000 entities, two components, persistent view, only one entity has all the components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
-        auto entity = registry.create<Velocity>();
-        if(i == 5000000L) { registry.assign<Position>(entity); }
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>>();
+        if(i % 2) { registry.assign<Position>(entity); }
     }
 
     Timer timer;
-    registry.persistent<Position, Velocity>().each([](auto, auto &...) {});
+    registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateFiveComponents10M) {
+TEST(Benchmark, IterateFiveComponents1MOne) {
     entt::DefaultRegistry registry;
 
-    std::cout << "Iterating over 10000000 entities, five components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
-        registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>>();
+        if(i == 5000000L) { registry.assign<Position>(entity); }
     }
 
     Timer timer;
@@ -207,28 +205,28 @@ TEST(Benchmark, IterateFiveComponents10M) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTenComponents10M) {
+TEST(Benchmark, IterateFiveComponentsPersistent1M) {
     entt::DefaultRegistry registry;
+    registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
 
-    std::cout << "Iterating over 10000000 entities, ten components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, five components, persistent view" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
-        registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
     }
 
     Timer timer;
-    registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
+    registry.persistent<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTenComponents10MHalf) {
+TEST(Benchmark, IterateTenComponents1M) {
     entt::DefaultRegistry registry;
 
-    std::cout << "Iterating over 10000000 entities, ten components, half of the entities have all the components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, ten components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
-        auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
-        if(i % 2) { registry.assign<Position>(entity); }
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
     }
 
     Timer timer;
@@ -236,14 +234,14 @@ TEST(Benchmark, IterateTenComponents10MHalf) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTenComponents10MOne) {
+TEST(Benchmark, IterateTenComponents1MHalf) {
     entt::DefaultRegistry registry;
 
-    std::cout << "Iterating over 10000000 entities, ten components, only one entity has all the components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, ten components, half of the entities have all the components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
-        if(i == 5000000L) { registry.assign<Position>(entity); }
+        if(i % 2) { registry.assign<Position>(entity); }
     }
 
     Timer timer;
@@ -251,61 +249,29 @@ TEST(Benchmark, IterateTenComponents10MOne) {
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateFiveComponentsPersistent10M) {
-    entt::DefaultRegistry registry;
-    registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
-
-    std::cout << "Iterating over 10000000 entities, five components, persistent view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
-        registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
-    }
-
-    Timer timer;
-    registry.persistent<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
-    timer.elapsed();
-}
-
-TEST(Benchmark, IterateTenComponentsPersistent10M) {
-    entt::DefaultRegistry registry;
-    registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
-
-    std::cout << "Iterating over 10000000 entities, ten components, persistent view" << std::endl;
-
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
-        registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
-    }
-
-    Timer timer;
-    registry.persistent<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
-    timer.elapsed();
-}
-
-TEST(Benchmark, IterateTenComponentsPersistent10MHalf) {
+TEST(Benchmark, IterateTenComponents1MOne) {
     entt::DefaultRegistry registry;
-    registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
 
-    std::cout << "Iterating over 10000000 entities, ten components, persistent view, half of the entities have all the components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, ten components, only one entity has all the components" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
         auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
-        if(i % 2) { registry.assign<Position>(entity); }
+        if(i == 5000000L) { registry.assign<Position>(entity); }
     }
 
     Timer timer;
-    registry.persistent<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
+    registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
     timer.elapsed();
 }
 
-TEST(Benchmark, IterateTenComponentsPersistent10MOne) {
+TEST(Benchmark, IterateTenComponentsPersistent1M) {
     entt::DefaultRegistry registry;
     registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
 
-    std::cout << "Iterating over 10000000 entities, ten components, persistent view, only one entity has all the components" << std::endl;
+    std::cout << "Iterating over 1000000 entities, ten components, persistent view" << std::endl;
 
-    for(std::uint64_t i = 0; i < 10000000L; i++) {
-        auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
-        if(i == 5000000L) { registry.assign<Position>(entity); }
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
     }
 
     Timer timer;

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

@@ -3,6 +3,7 @@
 #include <functional>
 #include <type_traits>
 #include <gtest/gtest.h>
+#include <entt/entity/entt_traits.hpp>
 #include <entt/entity/registry.hpp>
 
 TEST(DefaultRegistry, Functionalities) {
@@ -149,6 +150,22 @@ TEST(DefaultRegistry, CreateDestroyCornerCase) {
     ASSERT_EQ(registry.current(e1), entt::DefaultRegistry::version_type{1});
 }
 
+TEST(DefaultRegistry, VersionOverflow) {
+    entt::DefaultRegistry registry;
+
+    auto entity = registry.create();
+    registry.destroy(entity);
+
+    ASSERT_EQ(registry.version(entity), entt::DefaultRegistry::version_type{});
+
+    for(auto i = entt::entt_traits<entt::DefaultRegistry::entity_type>::version_mask; i; --i) {
+        ASSERT_NE(registry.current(entity), registry.version(entity));
+        registry.destroy(registry.create());
+    }
+
+    ASSERT_EQ(registry.current(entity), registry.version(entity));
+}
+
 TEST(DefaultRegistry, Each) {
     entt::DefaultRegistry registry;
     entt::DefaultRegistry::size_type tot;