diff --git a/README.md b/README.md
index c893410b5..12d7a26dd 100644
--- a/README.md
+++ b/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
Half of the entities have all the components | 0.0078s | **0.0072s** |
-| Standard view, 10M entities, two components
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
Half of the entities have all the components | **0.0090s** | 0.0407s |
-| Standard view, 10M entities, ten components
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
Half of the entities have all the components | 0.0009s | **0.0007s** |
+| Standard view, 1M entities, two components
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
Half of the entities have all the components | **0.0010s** | 0.0041s |
+| Standard view, 1M entities, ten components
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
Arrays are in reverse order | - | **0.0040s** |
| Sort 150k entities, enforce permutation
Arrays are in reverse order | - | **0.0006s** |
diff --git a/src/entt/entity/entt_traits.hpp b/src/entt/entity/entt_traits.hpp
index d07afa63d..241329fb2 100644
--- a/src/entt/entity/entt_traits.hpp
+++ b/src/entt/entity/entt_traits.hpp
@@ -58,11 +58,11 @@ struct entt_traits {
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;
};
diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp
index 9191c2fb6..1af8a6cad 100644
--- a/src/entt/entity/sparse_set.hpp
+++ b/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();
diff --git a/test/benchmark/benchmark.cpp b/test/benchmark/benchmark.cpp
index 0162ac24d..c075fa6ba 100644
--- a/test/benchmark/benchmark.cpp
+++ b/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 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();
}
@@ -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();
}
@@ -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();
if(i % 2) { registry.assign(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();
if(i == 5000000L) { registry.assign(entity); }
}
@@ -146,13 +146,13 @@ TEST(Benchmark, IterateTwoComponents10MOne) {
timer.elapsed();
}
-TEST(Benchmark, IterateTwoComponentsPersistent10M) {
+TEST(Benchmark, IterateTwoComponentsPersistent1M) {
entt::DefaultRegistry registry;
registry.prepare();
- 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();
}
@@ -161,44 +161,12 @@ TEST(Benchmark, IterateTwoComponentsPersistent10M) {
timer.elapsed();
}
-TEST(Benchmark, IterateTwoComponentsPersistent10MHalf) {
- entt::DefaultRegistry registry;
- registry.prepare();
-
- std::cout << "Iterating over 10000000 entities, two components, persistent view, half of the entities have all the components" << std::endl;
-
- for(std::uint64_t i = 0; i < 10000000L; i++) {
- auto entity = registry.create();
- if(i % 2) { registry.assign(entity); }
- }
-
- Timer timer;
- registry.persistent().each([](auto, auto &...) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, IterateTwoComponentsPersistent10MOne) {
- entt::DefaultRegistry registry;
- registry.prepare();
-
- std::cout << "Iterating over 10000000 entities, two components, persistent view, only one entity has all the components" << std::endl;
-
- for(std::uint64_t i = 0; i < 10000000L; i++) {
- auto entity = registry.create();
- if(i == 5000000L) { registry.assign(entity); }
- }
-
- Timer timer;
- registry.persistent().each([](auto, auto &...) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, IterateFiveComponents10M) {
+TEST(Benchmark, IterateFiveComponents1M) {
entt::DefaultRegistry registry;
- std::cout << "Iterating over 10000000 entities, five components" << std::endl;
+ std::cout << "Iterating over 1000000 entities, five components" << std::endl;
- for(std::uint64_t i = 0; i < 10000000L; i++) {
+ for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create, Comp<2>, Comp<3>>();
}
@@ -207,57 +175,43 @@ TEST(Benchmark, IterateFiveComponents10M) {
timer.elapsed();
}
-TEST(Benchmark, IterateTenComponents10M) {
+TEST(Benchmark, IterateFiveComponents1MHalf) {
entt::DefaultRegistry registry;
- std::cout << "Iterating over 10000000 entities, ten 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++) {
- registry.create, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
- }
-
- Timer timer;
- registry.view, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, IterateTenComponents10MHalf) {
- entt::DefaultRegistry registry;
-
- std::cout << "Iterating over 10000000 entities, ten components, half of the entities have all the components" << std::endl;
-
- for(std::uint64_t i = 0; i < 10000000L; i++) {
- auto entity = registry.create, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
+ for(std::uint64_t i = 0; i < 1000000L; i++) {
+ auto entity = registry.create, Comp<2>, Comp<3>>();
if(i % 2) { registry.assign(entity); }
}
Timer timer;
- registry.view, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
+ registry.view, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
timer.elapsed();
}
-TEST(Benchmark, IterateTenComponents10MOne) {
+TEST(Benchmark, IterateFiveComponents1MOne) {
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, five components, only one entity has all the components" << std::endl;
- for(std::uint64_t i = 0; i < 10000000L; i++) {
- auto entity = registry.create, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
+ for(std::uint64_t i = 0; i < 1000000L; i++) {
+ auto entity = registry.create, Comp<2>, Comp<3>>();
if(i == 5000000L) { registry.assign(entity); }
}
Timer timer;
- registry.view, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
+ registry.view, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
timer.elapsed();
}
-TEST(Benchmark, IterateFiveComponentsPersistent10M) {
+TEST(Benchmark, IterateFiveComponentsPersistent1M) {
entt::DefaultRegistry registry;
registry.prepare, Comp<2>, Comp<3>>();
- std::cout << "Iterating over 10000000 entities, five components, persistent view" << std::endl;
+ std::cout << "Iterating over 1000000 entities, five 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, Comp<2>, Comp<3>>();
}
@@ -266,46 +220,58 @@ TEST(Benchmark, IterateFiveComponentsPersistent10M) {
timer.elapsed();
}
-TEST(Benchmark, IterateTenComponentsPersistent10M) {
+TEST(Benchmark, IterateTenComponents1M) {
entt::DefaultRegistry registry;
- registry.prepare, 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;
+ std::cout << "Iterating over 1000000 entities, ten components" << std::endl;
- for(std::uint64_t i = 0; i < 10000000L; i++) {
+ for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
}
Timer timer;
- registry.persistent, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
+ registry.view, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
}
-TEST(Benchmark, IterateTenComponentsPersistent10MHalf) {
+TEST(Benchmark, IterateTenComponents1MHalf) {
entt::DefaultRegistry registry;
- registry.prepare, 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, 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, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
if(i % 2) { registry.assign(entity); }
}
Timer timer;
- registry.persistent, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
+ registry.view, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
}
-TEST(Benchmark, IterateTenComponentsPersistent10MOne) {
+TEST(Benchmark, IterateTenComponents1MOne) {
+ entt::DefaultRegistry registry;
+
+ std::cout << "Iterating over 1000000 entities, ten components, only one entity has all the components" << std::endl;
+
+ for(std::uint64_t i = 0; i < 1000000L; i++) {
+ auto entity = registry.create, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
+ if(i == 5000000L) { registry.assign(entity); }
+ }
+
+ Timer timer;
+ registry.view, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
+ timer.elapsed();
+}
+
+TEST(Benchmark, IterateTenComponentsPersistent1M) {
entt::DefaultRegistry registry;
registry.prepare, 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, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
- if(i == 5000000L) { registry.assign(entity); }
+ for(std::uint64_t i = 0; i < 1000000L; i++) {
+ registry.create, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
}
Timer timer;
diff --git a/test/entt/entity/registry.cpp b/test/entt/entity/registry.cpp
index f4f9289ce..9eaf4a215 100644
--- a/test/entt/entity/registry.cpp
+++ b/test/entt/entity/registry.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
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::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;