diff --git a/README.md b/README.md
index eb0478d66..7408cac30 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,6 @@
* [Multi component standard view](#multi-component-standard-view)
* [Persistent View](#persistent-view)
* [Give me everything](#give-me-everything)
- * [Spaces](#spaces)
* [Side notes](#side-notes)
* [Crash Course: core functionalities](#crash-course-core-functionalities)
* [Compile-time identifiers](#compile-time-identifiers)
@@ -947,119 +946,6 @@ In general, all these functions can result in poor performance.
entity. For similar reasons, `orphans` can be even slower. Both functions should
not be used frequently to avoid the risk of a performance hit.
-## Spaces
-
-Spaces are sort of partitions of a registry. They can be used to easily get a
-subset of the entities of a view or a registry without recurring to multiple
-registries to separate them explicitly.
-To learn more about their intended use,
-[here](https://gamedevelopment.tutsplus.com/tutorials/spaces-useful-game-object-containers--gamedev-14091)
-is an interesting article that goes deep into the topic.
-
-Spaces aren't for free. In most of the cases, the cost isn't relevant. However,
-keep in mind that they add an extra check during iterations and it could slow
-down a bit the whole thing.
-Alternatives to spaces exist, but they have their own problems:
-
-* Multiple registries: memory usage tends to grow up and some tasks are just
- more difficult to accomplish (as an example, putting an entity logically in
- more than one registry requires syncing them and it can quickly become a
- problem).
-
-* Dedicated components: memory usage tends to grow up and the number of spaces
- is fixed and defined at compile-time (at least, it ought to be for performance
- reasons), moreover the solution is much more error-prone.
-
-Another benefit of spaces defined as an external class is that users of a space
-do not have access to the whole registry, thus separation of responsibility is
-automatically enforced. In both the alternatives described above, systems have
-access to the whole set of entities instead and can easily break the contract
-with the callers.
-
-The `EnTT` framework offers support to spaces out of the box. Spaces are
-constructed using a registry to which they refer:
-
-```cpp
-entt::DefaultRegistry registry;
-entt::Space space{registry};
-```
-
-They offer the classical set of member functions to know the estimated number of
-entities and to check if a space has a given entity.
-Refer to the [official documentation](https://skypjack.github.io/entt/) for all
-the details.
-
-In addition, they expose two member functions to create an entity through a
-space or to assign to a space an already existent entity, other than member
-functions to remove entities from a space:
-
-```cpp
-// creates an entity using a space
-auto entity = space.create();
-
-// assigns an already existent entity to a space
-space.assign(registry.create());
-
-// removes an entity from the given space
-space.remove(entity);
-
-// removes all the entities from a space
-space.reset();
-```
-
-Entities returned through the `create` member function are created directly into
-the underlying registry and assigned immediately to the space.
-Removing an entity from a space doesn't mean that it's destroyed within the
-underlying registry in any case.
-
-Spaces and thus the entities they contain can be easily iterated in a range-for
-loop:
-
-```cpp
-for(auto entity: space) {
- // ...
-}
-```
-
-However, this isn't the best way to iterate entities in a space, mainly because
-this member function returns all the entities it contains, no matter what are
-their components. To iterate entities that have specific components, spaces
-expose two dedicated member functions that differ for the view they use under
-the hood:
-
-```cpp
-// uses a standard view internally
-space.view([](auto entity, auto &aComponent, auto &anotherComponent) {
- // ...
-});
-
-// uses a persistent view internally
-space.persisten([](auto entity, auto &aComponent, auto &anotherComponent) {
- // ...
-});
-```
-
-Spaces get rid of entities that are no longer in use during iterations. They
-aren't kept in sync with a registry each and every time an entity is destroyed
-so as to avoid penalties in terms of performance. Instead, spaces remove invalid
-entities as soon as they are detected during iterations.
-
-Because of the _lazy clean_ policy, the size of a space could grow up if
-destroyed entities are never detected for some reasons. To avoid it, spaces has
-a member function named `shrink` that forces a clean up and reduce the size to a
-minimum:
-
-```cpp
-// gets rid of all the invalid entities still tracked by a space
-space.shrink();
-```
-
-Note that the size of a space isn't a problem in terms of performance. Views
-rule during iterations, mainly because of the order which may have been imposed
-by the user for some reasons and must be respected. Therefore unused entities
-are never visited and thus they don't affect iterations. However, memory usage
-can be reduced by shrinking spaces every so often.
-
## Side notes
* Entity identifiers are numbers and nothing more. They are not classes and they
diff --git a/src/entt/entity/space.hpp b/src/entt/entity/space.hpp
deleted file mode 100644
index 909e17dae..000000000
--- a/src/entt/entity/space.hpp
+++ /dev/null
@@ -1,268 +0,0 @@
-#ifndef ENTT_ENTITY_SPACE_HPP
-#define ENTT_ENTITY_SPACE_HPP
-
-
-#include
-#include "sparse_set.hpp"
-#include "registry.hpp"
-
-
-namespace entt {
-
-
-/**
- * @brief A space is a sort of partition of a registry.
- *
- * Spaces can be used to create partitions of a registry. They can be useful for
- * logically separating menus, world and any other type of scene, while still
- * using only one registry.
- * Similar results are obtained either using multiple registries or using
- * dedicated components, even though in both cases the memory usage isn't the
- * same. On the other side, spaces can introduce performance hits that are
- * sometimes unacceptable (mainly if you are working on AAA games or kind of).
- *
- * For more details about spaces and their use, take a look at this article:
- * https://gamedevelopment.tutsplus.com/tutorials/spaces-useful-game-object-containers--gamedev-14091
- *
- * @tparam Entity A valid entity type (see entt_traits for more details).
- */
-template
-class Space: private SparseSet {
- using view_type = SparseSet;
-
- template
- inline void each(View view, Func func) {
- // use the view to iterate so as to respect order of components if any
- view.each([func = std::move(func), this](auto entity, auto &&... components) {
- if(this->has(entity)) {
- if(this->data()[this->get(entity)] == entity) {
- func(entity, std::forward(components)...);
- } else {
- // lazy destroy to avoid keeping a space in sync
- this->destroy(entity);
- }
- }
- });
- }
-
-public:
- /*! @brief Type of registry to which the space refers. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename registry_type::entity_type;
- /*! @brief Input iterator type. */
- using iterator_type = typename view_type::iterator_type;
- /*! @brief Unsigned integer type. */
- using size_type = typename view_type::size_type;
-
- /**
- * @brief Constructs a space by using the given registry.
- * @param registry An entity-component system properly initialized.
- */
- Space(registry_type ®istry)
- : registry{registry}
- {}
-
- /**
- * @brief Returns the number of entities tracked by a space.
- * @return Number of entities tracked by the space.
- */
- size_type size() const noexcept {
- return SparseSet::size();
- }
-
- /**
- * @brief Checks if there exists at least an entity tracked by a space.
- * @return True if the space tracks at least an entity, false otherwise.
- */
- bool empty() const noexcept {
- return SparseSet::empty();
- }
-
- /**
- * @brief Returns an iterator to the first entity tracked by a space.
- *
- * The returned iterator points to the first entity tracked by the space. If
- * the space is empty, the returned iterator will be equal to `end()`.
- *
- * @return An iterator to the first entity tracked by a space.
- */
- iterator_type begin() const noexcept {
- return SparseSet::begin();
- }
-
- /**
- * @brief Returns an iterator that is past the last entity tracked by a
- * space.
- *
- * The returned iterator points to the entity following the last entity
- * tracked by the space. Attempting to dereference the returned iterator
- * results in undefined behavior.
- *
- * @return An iterator to the entity following the last entity tracked by a
- * space.
- */
- iterator_type end() const noexcept {
- return SparseSet::end();
- }
-
- /**
- * @brief Checks if a space contains an entity.
- * @param entity A valid entity identifier.
- * @return True if the space contains the given entity, false otherwise.
- */
- bool contains(entity_type entity) const noexcept {
- return this->has(entity) && this->data()[this->get(entity)] == entity;
- }
-
- /**
- * @brief Creates a new entity and returns it.
- *
- * The space creates an entity from the underlying registry and registers it
- * immediately before to return the identifier. Use the `assign` member
- * function to register an already existent entity created at a different
- * time.
- *
- * The returned entity has no components assigned.
- *
- * @return A valid entity identifier.
- */
- entity_type create() {
- const auto entity = registry.create();
- assign(entity);
- return entity;
- }
-
- /**
- * @brief Assigns an entity to a space.
- *
- * The space starts tracking the given entity and will return it during
- * iterations whenever required.
- * Entities can be assigned to more than one space at the same time.
- *
- * @warning
- * Attempting to use an invalid entity or to assign an entity that doesn't
- * belong to the underlying registry results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of
- * invalid entity or if the registry doesn't own the entity.
- *
- * @param entity A valid entity identifier.
- */
- void assign(entity_type entity) {
- assert(registry.valid(entity));
-
- if(this->has(entity)) {
- this->destroy(entity);
- }
-
- this->construct(entity);
- }
-
- /**
- * @brief Removes an entity from a space.
- *
- * The space stops tracking the given entity and won't return it anymore
- * during iterations.
- * In case the entity belongs to more than one space, it won't be removed
- * automatically from all the other ones as a consequence of invoking this
- * function.
- *
- * @param entity A valid entity identifier.
- */
- void remove(entity_type entity) {
- if(this->has(entity)) {
- this->destroy(entity);
- }
- }
-
- /**
- * @brief Iterates entities using a standard view under the hood.
- *
- * A space does not return directly views to iterate entities because it
- * requires to apply a filter to those sets. Instead, it uses a view
- * internally and returns only those entities that are tracked by the space
- * itself.
- * This member function can be used to iterate a space by means of a
- * standard view. Naming the function the same as the type of view used to
- * perform the task proved to be a good choice so as not to tricky users.
- *
- * @note
- * Performance tend to degenerate when the number of components to iterate
- * grows up and the most of the entities have all the given components.
- * To get a performance boost, consider using the `persistent` member
- * function instead.
- *
- * @tparam Component Type of components used to construct the view.
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template
- void view(Func func) {
- each(registry.template view(), std::move(func));
- }
-
- /**
- * @brief Iterates entities using a persistent view under the hood.
- *
- * A space does not return directly views to iterate entities because it
- * requires to apply a filter to those sets. Instead, it uses a view
- * internally and returns only those entities that are tracked by the space
- * itself.
- * This member function can be used to iterate a space by means of a
- * persistent view. Naming the function the same as the type of view used to
- * perform the task proved to be a good choice so as not to tricky users.
- *
- * @tparam Component Type of components used to construct the view.
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template
- void persistent(Func func) {
- each(registry.template persistent(), std::move(func));
- }
-
- /**
- * @brief Performs a clean up step.
- *
- * Spaces do a lazy cleanup during iterations to avoid introducing
- * performance hits when entities are destroyed.
- * This function can be used to force a clean up step and to get rid of all
- * those entities that are still tracked by a space but have been destroyed
- * in the underlying registry.
- */
- void shrink() {
- for(auto entity: *this) {
- if(!registry.fast(entity)) {
- this->destroy(entity);
- }
- }
- }
-
- /**
- * @brief Resets a whole space.
- *
- * The space stops tracking all the entities assigned to it so far. After
- * calling this function, iterations won't return any entity.
- */
- void reset() {
- SparseSet::reset();
- }
-
-private:
- Registry ®istry;
-};
-
-
-/**
- * @brief Default space class.
- *
- * The default space is the best choice for almost all the applications.
- * Users should have a really good reason to choose something different.
- */
-using DefaultSpace = Space;
-
-
-}
-
-
-#endif // ENTT_ENTITY_SPACE_HPP
diff --git a/src/entt/entt.hpp b/src/entt/entt.hpp
index 3d40d9c17..b107aa1c5 100644
--- a/src/entt/entt.hpp
+++ b/src/entt/entt.hpp
@@ -4,7 +4,6 @@
#include "entity/actor.hpp"
#include "entity/entt_traits.hpp"
#include "entity/registry.hpp"
-#include "entity/space.hpp"
#include "entity/sparse_set.hpp"
#include "entity/view.hpp"
#include "locator/locator.hpp"
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index a56bd5b6d..32bd6d39b 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -55,7 +55,6 @@ add_executable(
$
entt/entity/actor.cpp
entt/entity/registry.cpp
- entt/entity/space.cpp
entt/entity/sparse_set.cpp
entt/entity/view.cpp
)
diff --git a/test/benchmark/benchmark.cpp b/test/benchmark/benchmark.cpp
index b703917cc..e545525a3 100644
--- a/test/benchmark/benchmark.cpp
+++ b/test/benchmark/benchmark.cpp
@@ -4,7 +4,6 @@
#include
#include
#include
-#include
struct Position {
std::uint64_t x;
@@ -315,152 +314,3 @@ TEST(Benchmark, SortMulti) {
timer.elapsed();
}
-
-TEST(Benchmark, SpaceConstruct) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- std::cout << "Constructing 1000000 entities" << std::endl;
-
- Timer timer;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- space.create();
- }
-
- timer.elapsed();
-}
-
-TEST(Benchmark, SpaceAssign) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- std::cout << "Assigning 1000000 entities" << std::endl;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- registry.create();
- }
-
- Timer timer;
-
- for(auto entity: registry.view()) {
- space.assign(entity);
- }
-
- timer.elapsed();
-}
-
-TEST(Benchmark, SpaceIterateSingleComponent1M) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- std::cout << "Iterating over 1000000 entities, one component" << std::endl;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- const auto entity = registry.create();
- space.assign(entity);
- }
-
- Timer timer;
- space.view([](auto, auto &) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, SpaceIterateTwoComponents1M) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- std::cout << "Iterating over 1000000 entities, two components" << std::endl;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- const auto entity = registry.create();
- space.assign(entity);
- }
-
- Timer timer;
- space.view([](auto, auto &...) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, SpaceIterateTwoComponentsPersistent1M) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
- registry.prepare();
-
- std::cout << "Iterating over 1000000 entities, two components, persistent view" << std::endl;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- const auto entity = registry.create();
- space.assign(entity);
- }
-
- Timer timer;
- space.persistent([](auto, auto &...) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, SpaceIterateFiveComponents1M) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- std::cout << "Iterating over 1000000 entities, five components" << std::endl;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- const auto entity = registry.create, Comp<2>, Comp<3>>();
- space.assign(entity);
- }
-
- Timer timer;
- space.view, Comp<2>, Comp<3>>([](auto, auto &...) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, SpaceIterateFiveComponentsPersistent1M) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
- registry.prepare, Comp<2>, Comp<3>>();
-
- std::cout << "Iterating over 1000000 entities, five components, persistent view" << std::endl;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- const auto entity = registry.create, Comp<2>, Comp<3>>();
- space.assign(entity);
- }
-
- Timer timer;
- space.persistent, Comp<2>, Comp<3>>([](auto, auto &...) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, SpaceIterateTenComponents1M) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- std::cout << "Iterating over 1000000 entities, ten components" << std::endl;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- const auto entity = registry.create, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
- space.assign(entity);
- }
-
- Timer timer;
- space.view, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>([](auto, auto &...) {});
- timer.elapsed();
-}
-
-TEST(Benchmark, SpaceIterateTenComponentsPersistent1M) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
- registry.prepare, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
-
- std::cout << "Iterating over 1000000 entities, ten components, persistent view" << std::endl;
-
- for(std::uint64_t i = 0; i < 1000000L; i++) {
- const auto entity = registry.create, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
- space.assign(entity);
- }
-
- Timer timer;
- space.persistent, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>([](auto, auto &...) {});
- timer.elapsed();
-}
diff --git a/test/entt/entity/space.cpp b/test/entt/entity/space.cpp
deleted file mode 100644
index 2a4a46a8a..000000000
--- a/test/entt/entity/space.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-#include
-#include
-#include
-
-TEST(Space, SpaceContainsView) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- auto e0 = space.create();
- auto e1 = registry.create();
-
- space.assign(e1);
- registry.assign(e1);
-
- ASSERT_TRUE(space.contains(e0));
- ASSERT_TRUE(space.contains(e1));
-
- space.view([e0, e1](auto entity, auto&&...) {
- ASSERT_NE(entity, e0);
- ASSERT_EQ(entity, e1);
- });
-
- space.view([e0, e1](auto, auto&&...) {
- FAIL();
- });
-
- auto count = 0;
-
- for(auto entity: space) {
- (void)entity;
- ++count;
- }
-
- ASSERT_EQ(count, 2);
-
- const auto view = registry.view();
-
- ASSERT_EQ(view.size(), typename decltype(view)::size_type{1});
- ASSERT_EQ(space.size(), entt::DefaultSpace::size_type{2});
- ASSERT_FALSE(space.empty());
-
- registry.reset();
- space.reset();
-
- ASSERT_TRUE(space.empty());
-
- for(auto i = 0; i < 5; ++i) {
- registry.destroy(space.create());
- registry.create();
- }
-
- ASSERT_EQ(space.size(), entt::DefaultSpace::size_type{5});
- ASSERT_FALSE(space.empty());
-
- space.view([](auto, auto&&...) {
- FAIL();
- });
-
- ASSERT_EQ(space.size(), entt::DefaultSpace::size_type{0});
- ASSERT_TRUE(space.empty());
-}
-
-TEST(Space, ViewContainsSpace) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- auto e0 = registry.create();
- auto e1 = space.create();
-
- registry.assign(e0);
- registry.assign(e1);
-
- ASSERT_FALSE(space.contains(e0));
- ASSERT_TRUE(space.contains(e1));
-
- space.view([e0, e1](auto entity, auto&&...) {
- ASSERT_NE(entity, e0);
- ASSERT_EQ(entity, e1);
- });
-
- space.view([e0, e1](auto, auto&&...) {
- FAIL();
- });
-
- auto count = 0;
-
- for(auto entity: space) {
- (void)entity;
- ++count;
- }
-
- ASSERT_EQ(count, 1);
-
- const auto view = registry.view();
-
- ASSERT_EQ(view.size(), typename decltype(view)::size_type{2});
- ASSERT_EQ(space.size(), entt::DefaultSpace::size_type{1});
- ASSERT_FALSE(space.empty());
-
- registry.reset();
- space.reset();
-
- ASSERT_TRUE(space.empty());
-
- for(auto i = 0; i < 5; ++i) {
- registry.destroy(space.create());
- registry.create();
- registry.create();
- }
-
- ASSERT_EQ(space.size(), entt::DefaultSpace::size_type{5});
- ASSERT_FALSE(space.empty());
-
- space.view([](auto, auto&&...) {
- FAIL();
- });
-
- ASSERT_EQ(space.size(), entt::DefaultSpace::size_type{0});
- ASSERT_TRUE(space.empty());
-}
-
-TEST(Space, AssignRemove) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- ASSERT_TRUE(space.empty());
-
- space.remove(space.create());
-
- ASSERT_TRUE(space.empty());
-}
-
-TEST(Space, Shrink) {
- entt::DefaultRegistry registry;
- entt::DefaultSpace space{registry};
-
- for(auto i = 0; i < 5; ++i) {
- space.create();
- }
-
- for(auto entity: space) {
- registry.destroy(entity);
- }
-
- space.create();
-
- ASSERT_EQ(space.size(), entt::DefaultSpace::size_type{5});
- ASSERT_FALSE(space.empty());
-
- space.shrink();
-
- ASSERT_EQ(space.size(), entt::DefaultSpace::size_type{1});
- ASSERT_FALSE(space.empty());
-}