From e0ef53d25e5cc77f04a1eb0a5e83867b631b04d9 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Fri, 9 Feb 2018 11:56:40 +0100 Subject: [PATCH] WIP: testing snapshots --- README.md | 15 ++++++---- src/entt/entity/registry.hpp | 43 ++++++++++++++++++++-------- src/entt/entity/snapshot.hpp | 32 ++++++++++++++++----- test/entt/entity/snapshot.cpp | 54 +++++++++++++++++++++++++++++++++-- 4 files changed, 118 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 8d3f780e9..05906e780 100644 --- a/README.md +++ b/README.md @@ -882,7 +882,8 @@ combining this function with a bunch of custom tests.
In all the other cases, this is the way to go. There exists also another member function to use to retrieve orphans. An orphan -is an entity that is still in use and has no assigned components.
+is an entity that is still in use and has neither assigned components nor +tags.
The signature of the function is the same of `each`: ```cpp @@ -891,10 +892,14 @@ registry.orphans([](auto entity) { }); ``` -In general, `each` is fairly slow because of some checks it performs on each and -every entity. For similar reasons, `orphans` can be even slower.
-Both functions should not be used frequently to avoid the risk of a performance -hit. +To test the _orphanity_ of a single entity, use the member function `orphan` +instead. It accepts a valid entity identifer as an argument and returns true in +case the entity is an orphan, false otherwise. + +In general, all these functions can result in poor performance.
+`each` is fairly slow because of some checks it performs on each and every +entity. For similar reasons, `orphans` can be even slower. Both functions should +not be used frequently to avoid the risk of a performance hit. ## Side notes diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 937b0b6ff..16ae2dcb8 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -923,7 +923,7 @@ class Registry { } /** - * @brief Iterate all the entities that have the given components. + * @brief Iterates all the entities that have the given components. * * The function object is invoked for each entity that is still in use and * has the given components assigned.
@@ -966,7 +966,7 @@ class Registry { } /** - * @brief Iterate all the entities that have the given components. + * @brief Iterates all the entities that have the given components. * * The function object is invoked for each entity that is still in use and * has the given components assigned.
@@ -1000,10 +1000,36 @@ class Registry { } /** - * @brief Iterate orphans and applies them the given function object. + * @brief Checks if an entity is an orphan. + * + * An orphan is an entity that has neither assigned components nor + * tags. + * + * @param entity A valid entity identifier. + * @return True if the entity is an orphan, false otherwise. + */ + bool orphan(entity_type entity) const { + assert(valid(entity)); + bool orphan = true; + + for(std::size_t i = 0; i < pools.size() && orphan; ++i) { + const auto &pool = pools[i]; + orphan = !(pool && pool->has(entity)); + } + + for(std::size_t i = 0; i < tags.size() && orphan; ++i) { + const auto &tag = tags[i]; + orphan = !(tag && (tag->entity == entity)); + } + + return orphan; + } + + /** + * @brief Iterates orphans and applies them the given function object. * * The function object is invoked for each entity that is still in use and - * has no assigned components.
+ * has neither assigned components nor tags.
* The signature of the function should be equivalent to the following: * * @code{.cpp} @@ -1018,14 +1044,7 @@ class Registry { template void orphans(Func func) const { each([func = std::move(func), this](auto entity) { - bool orphan = true; - - for(std::size_t i = 0; i < pools.size() && orphan; ++i) { - const auto &pool = pools[i]; - orphan = !(pool && pool->has(entity)); - } - - if(orphan) { + if(orphan(entity)) { func(entity); } }); diff --git a/src/entt/entity/snapshot.hpp b/src/entt/entity/snapshot.hpp index 90390a45a..1294905ca 100644 --- a/src/entt/entity/snapshot.hpp +++ b/src/entt/entity/snapshot.hpp @@ -148,12 +148,6 @@ class SnapshotDumpLoader final { } public: - ~SnapshotDumpLoader() { - registry.orphans([this](auto entity) { - registry.destroy(entity); - }); - } - template SnapshotDumpLoader entities(Archive &archive) && { each(archive, [this](auto entity) { @@ -190,6 +184,15 @@ class SnapshotDumpLoader final { return *this; } + + SnapshotDumpLoader orphans() { + registry.orphans([this](auto entity) { + registry.destroy(entity); + }); + + return *this; + } + private: Registry ®istry; func_type force_fn; @@ -358,18 +361,33 @@ class SnapshotProgressiveLoader { return *this; } - void shrink() { + SnapshotProgressiveLoader & shrink() { auto it = remloc.begin(); while(it != remloc.cend()) { + const auto local = it->second.first; bool &dirty = it->second.second; if(dirty) { dirty = false; } else { + if(registry.valid(local)) { + registry.destroy(local); + } + it = remloc.erase(it); } } + + return *this; + } + + SnapshotProgressiveLoader & orphans() { + registry.orphans([this](auto entity) { + registry.destroy(entity); + }); + + return *this; } private: diff --git a/test/entt/entity/snapshot.cpp b/test/entt/entity/snapshot.cpp index 2037114af..17e815047 100644 --- a/test/entt/entity/snapshot.cpp +++ b/test/entt/entity/snapshot.cpp @@ -42,6 +42,20 @@ struct Foo { }; TEST(Snapshot, Dump) { + entt::DefaultRegistry registry; + + auto e0 = registry.create(); + registry.assign(e0, 0); + + auto e1 = registry.create(); + registry.assign(e1, 0); + + auto e2 = registry.create(); + registry.assign(e2, 0); + + auto e3 = registry.create(); + registry.assign(e3, 0); + // TODO } @@ -95,6 +109,12 @@ TEST(Snapshot, Partial) { ASSERT_TRUE(registry.empty()); ASSERT_EQ(registry.capacity(), entt::DefaultRegistry::size_type{}); + ASSERT_FALSE(registry.valid(e0)); + ASSERT_FALSE(registry.valid(e1)); + ASSERT_FALSE(registry.valid(e2)); + ASSERT_FALSE(registry.valid(e3)); + ASSERT_FALSE(registry.valid(e4)); + registry.restore() .entities(input) .destroyed(input) @@ -106,21 +126,51 @@ TEST(Snapshot, Partial) { ASSERT_FALSE(registry.valid(e1)); ASSERT_TRUE(registry.valid(e2)); ASSERT_TRUE(registry.valid(e3)); - ASSERT_FALSE(registry.valid(e4)); + ASSERT_TRUE(registry.valid(e4)); ASSERT_EQ(registry.get(e0), 42); ASSERT_EQ(registry.get(e0), 'c'); ASSERT_FALSE(registry.has(e0)); ASSERT_EQ(registry.get(e2), 3); ASSERT_EQ(registry.get(e3), '0'); + ASSERT_TRUE(registry.orphan(e4)); ASSERT_TRUE(registry.has()); ASSERT_EQ(registry.attachee(), e3); ASSERT_EQ(registry.get(), .3f); - ASSERT_FALSE(registry.has()); ASSERT_EQ(registry.current(e1), v1); + + registry.snapshot() + .tag(output) + .destroyed(output) + .entities(output) + ; + + registry = {}; + + ASSERT_TRUE(registry.empty()); + ASSERT_EQ(registry.capacity(), entt::DefaultRegistry::size_type{}); + + ASSERT_FALSE(registry.valid(e0)); + ASSERT_FALSE(registry.valid(e1)); + ASSERT_FALSE(registry.valid(e2)); + ASSERT_FALSE(registry.valid(e3)); + ASSERT_FALSE(registry.valid(e4)); + + registry.restore() + .tag(input) + .destroyed(input) + .entities(input) + .orphans() + ; + + ASSERT_FALSE(registry.valid(e0)); + ASSERT_FALSE(registry.valid(e1)); + ASSERT_FALSE(registry.valid(e2)); + ASSERT_TRUE(registry.valid(e3)); + ASSERT_FALSE(registry.valid(e4)); } TEST(Snapshot, Progressive) {