From 8713d0a90ddac0052bb583477a2aa4025eb398b8 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Sun, 25 Aug 2019 23:14:08 +0200 Subject: [PATCH] decoupling pools and components --- src/entt/entity/component.hpp | 37 +++++ .../{storage.hpp => default_storage.hpp} | 23 ++-- src/entt/entity/group.hpp | 10 +- src/entt/entity/observer.hpp | 4 +- src/entt/entity/registry.hpp | 20 +-- src/entt/entity/view.hpp | 8 +- src/entt/entt.hpp | 3 +- test/CMakeLists.txt | 2 +- .../{storage.cpp => default_storage.cpp} | 130 +++++++++--------- 9 files changed, 135 insertions(+), 102 deletions(-) create mode 100644 src/entt/entity/component.hpp rename src/entt/entity/{storage.hpp => default_storage.hpp} (97%) rename test/entt/entity/{storage.cpp => default_storage.cpp} (85%) diff --git a/src/entt/entity/component.hpp b/src/entt/entity/component.hpp new file mode 100644 index 0000000000..48a213f7ef --- /dev/null +++ b/src/entt/entity/component.hpp @@ -0,0 +1,37 @@ +#ifndef ENTT_ENTITY_COMPONENT_HPP +#define ENTT_ENTITY_COMPONENT_HPP + + +#include +#include "default_storage.hpp" + + +namespace entt { + + +template +struct component_traits; + + +template> +struct component_pool { + template + using type = default_storage; +}; + + +template +struct component_pool::pool_type>> { + template + using type = typename component_traits::pool_type; +}; + + +template +using component_pool_t = typename component_pool::template type; + + +} + + +#endif // ENTT_ENTITY_COMPONENT_HPP diff --git a/src/entt/entity/storage.hpp b/src/entt/entity/default_storage.hpp similarity index 97% rename from src/entt/entity/storage.hpp rename to src/entt/entity/default_storage.hpp index d27cc2123e..44d91cdf5e 100644 --- a/src/entt/entity/storage.hpp +++ b/src/entt/entity/default_storage.hpp @@ -1,5 +1,5 @@ -#ifndef ENTT_ENTITY_STORAGE_HPP -#define ENTT_ENTITY_STORAGE_HPP +#ifndef ENTT_ENTITY_DEFAULT_STORAGE_HPP +#define ENTT_ENTITY_DEFAULT_STORAGE_HPP #include @@ -19,7 +19,7 @@ namespace entt { /** - * @brief Basic storage implementation. + * @brief Default storage implementation. * * This class is a refinement of a sparse set that associates an object to an * entity. The main purpose of this class is to extend sparse sets to store @@ -48,13 +48,13 @@ namespace entt { * @tparam Type Type of objects assigned to the entities. */ template> -class basic_storage: public sparse_set { +class default_storage: public sparse_set { using underlying_type = sparse_set; using traits_type = entt_traits>; template class iterator { - friend class basic_storage; + friend class default_storage; using instance_type = std::conditional_t, std::vector>; using index_type = typename traits_type::difference_type; @@ -490,14 +490,14 @@ class basic_storage: public sparse_set { }; -/*! @copydoc basic_storage */ +/*! @copydoc default_storage */ template -class basic_storage>>: public sparse_set { +class default_storage>>: public sparse_set { using traits_type = entt_traits>; using underlying_type = sparse_set; class iterator { - friend class basic_storage; + friend class default_storage; using index_type = typename traits_type::difference_type; @@ -693,12 +693,7 @@ class basic_storage>>: publ } }; -/*! @copydoc basic_storage */ -template -struct storage: basic_storage {}; - - } -#endif // ENTT_ENTITY_STORAGE_HPP +#endif // ENTT_ENTITY_DEFAULT_STORAGE_HPP diff --git a/src/entt/entity/group.hpp b/src/entt/entity/group.hpp index d00a555c6d..c863fd9db3 100644 --- a/src/entt/entity/group.hpp +++ b/src/entt/entity/group.hpp @@ -8,7 +8,7 @@ #include "../config/config.h" #include "../core/type_traits.hpp" #include "sparse_set.hpp" -#include "storage.hpp" +#include "component.hpp" #include "utility.hpp" #include "fwd.hpp" @@ -72,10 +72,10 @@ class basic_group, get_t> { friend class basic_registry; template - using pool_type = std::conditional_t, const storage>, storage>; + using pool_type = std::conditional_t, const component_pool_t>, component_pool_t>; // we could use pool_type *..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug) - basic_group(sparse_set *ref, storage> *get, storage> *... other) ENTT_NOEXCEPT + basic_group(sparse_set *ref, pool_type *get, pool_type *... other) ENTT_NOEXCEPT : handler{ref}, pools{get, other...} {} @@ -492,13 +492,13 @@ class basic_group, get_t, Owned, Other...> friend class basic_registry; template - using pool_type = std::conditional_t, const storage>, storage>; + using pool_type = std::conditional_t, const component_pool_t>, component_pool_t>; template using component_iterator_type = decltype(std::declval>().begin()); // we could use pool_type *..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug) - basic_group(const typename basic_registry::size_type *sz, storage> *owned, storage> *... other, storage> *... get) ENTT_NOEXCEPT + basic_group(const typename basic_registry::size_type *sz, pool_type *owned, pool_type *... other, pool_type *... get) ENTT_NOEXCEPT : length{sz}, pools{owned, other..., get...} {} diff --git a/src/entt/entity/observer.hpp b/src/entt/entity/observer.hpp index 410464bd8d..c62dcc5365 100644 --- a/src/entt/entity/observer.hpp +++ b/src/entt/entity/observer.hpp @@ -10,8 +10,8 @@ #include #include "../config/config.h" #include "../core/type_traits.hpp" +#include "default_storage.hpp" #include "registry.hpp" -#include "storage.hpp" #include "entity.hpp" #include "fwd.hpp" @@ -428,7 +428,7 @@ class basic_observer { private: basic_registry *target; void(* release)(basic_observer &, basic_registry &); - storage view; + default_storage view; }; diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 1807de4328..2a63e70232 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -18,8 +18,8 @@ #include "../signal/sigh.hpp" #include "runtime_view.hpp" #include "sparse_set.hpp" +#include "component.hpp" #include "snapshot.hpp" -#include "storage.hpp" #include "utility.hpp" #include "entity.hpp" #include "group.hpp" @@ -51,13 +51,13 @@ class basic_registry { }; template - struct pool_handler: storage { + struct pool_handler: component_pool_t { group_type *group{}; pool_handler() ENTT_NOEXCEPT = default; - pool_handler(const storage &other) - : storage{other} + pool_handler(const component_pool_t &other) + : component_pool_t{other} {} auto on_construct() ENTT_NOEXCEPT { @@ -75,11 +75,11 @@ class basic_registry { template decltype(auto) assign(basic_registry ®istry, const Entity entt, Args &&... args) { if constexpr(std::is_empty_v) { - storage::construct(entt); + component_pool_t::construct(entt); construction.publish(entt, registry, Component{}); return Component{std::forward(args)...}; } else { - auto &component = storage::construct(entt, std::forward(args)...); + auto &component = component_pool_t::construct(entt, std::forward(args)...); construction.publish(entt, registry, component); return component; } @@ -87,7 +87,7 @@ class basic_registry { template auto batch(basic_registry ®istry, It first, It last, const Comp &... value) { - auto it = storage::batch(first, last, value...); + auto it = component_pool_t::batch(first, last, value...); if(!construction.empty()) { std::for_each(first, last, [this, ®istry, it](const auto entt) mutable { @@ -100,19 +100,19 @@ class basic_registry { void remove(basic_registry ®istry, const Entity entt) { destruction.publish(entt, registry); - storage::destroy(entt); + component_pool_t::destroy(entt); } template decltype(auto) replace(basic_registry ®istry, const Entity entt, Args &&... args) { if constexpr(std::is_empty_v) { - ENTT_ASSERT((storage::has(entt))); + ENTT_ASSERT((component_pool_t::has(entt))); update.publish(entt, registry, Component{}); return Component{std::forward(args)...}; } else { Component component{std::forward(args)...}; update.publish(entt, registry, component); - return (storage::get(entt) = std::move(component)); + return (component_pool_t::get(entt) = std::move(component)); } } diff --git a/src/entt/entity/view.hpp b/src/entt/entity/view.hpp index f7f1079927..f143266edf 100644 --- a/src/entt/entity/view.hpp +++ b/src/entt/entity/view.hpp @@ -11,7 +11,7 @@ #include "../config/config.h" #include "../core/type_traits.hpp" #include "sparse_set.hpp" -#include "storage.hpp" +#include "component.hpp" #include "entity.hpp" #include "fwd.hpp" @@ -64,7 +64,7 @@ class basic_view { friend class basic_registry; template - using pool_type = std::conditional_t, const storage>, storage>; + using pool_type = std::conditional_t, const component_pool_t>, component_pool_t>; template using component_iterator_type = decltype(std::declval>().begin()); @@ -145,7 +145,7 @@ class basic_view { }; // we could use pool_type *..., but vs complains about it and refuses to compile for unknown reasons (likely a bug) - basic_view(storage> *... ref) ENTT_NOEXCEPT + basic_view(pool_type *... ref) ENTT_NOEXCEPT : pools{ref...} {} @@ -541,7 +541,7 @@ class basic_view { /*! @brief A registry is allowed to create views. */ friend class basic_registry; - using pool_type = std::conditional_t, const storage>, storage>; + using pool_type = std::conditional_t, const component_pool_t>, component_pool_t>; basic_view(pool_type *ref) ENTT_NOEXCEPT : pool{ref} diff --git a/src/entt/entt.hpp b/src/entt/entt.hpp index 5705bb9d8a..04efe7e293 100644 --- a/src/entt/entt.hpp +++ b/src/entt/entt.hpp @@ -6,6 +6,8 @@ #include "core/type_traits.hpp" #include "core/utility.hpp" #include "entity/actor.hpp" +#include "entity/component.hpp" +#include "entity/default_storage.hpp" #include "entity/entity.hpp" #include "entity/group.hpp" #include "entity/helper.hpp" @@ -14,7 +16,6 @@ #include "entity/runtime_view.hpp" #include "entity/snapshot.hpp" #include "entity/sparse_set.hpp" -#include "entity/storage.hpp" #include "entity/utility.hpp" #include "entity/view.hpp" #include "locator/locator.hpp" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 33de7031a9..b4a1fdc1c3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -101,7 +101,7 @@ SETUP_AND_ADD_TEST(registry entt/entity/registry.cpp) SETUP_AND_ADD_TEST(runtime_view entt/entity/runtime_view.cpp) SETUP_AND_ADD_TEST(snapshot entt/entity/snapshot.cpp) SETUP_AND_ADD_TEST(sparse_set entt/entity/sparse_set.cpp) -SETUP_AND_ADD_TEST(storage entt/entity/storage.cpp) +SETUP_AND_ADD_TEST(default_storage entt/entity/default_storage.cpp) SETUP_AND_ADD_TEST(view entt/entity/view.cpp) # Test locator diff --git a/test/entt/entity/storage.cpp b/test/entt/entity/default_storage.cpp similarity index 85% rename from test/entt/entity/storage.cpp rename to test/entt/entity/default_storage.cpp index fdca85466c..29ef8c4440 100644 --- a/test/entt/entity/storage.cpp +++ b/test/entt/entity/default_storage.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include struct empty_type {}; @@ -20,8 +20,8 @@ struct throwing_component { int data; }; -TEST(Storage, Functionalities) { - entt::storage pool; +TEST(DefaultStorage, Functionalities) { + entt::default_storage pool; pool.reserve(42); @@ -75,13 +75,13 @@ TEST(Storage, Functionalities) { ASSERT_EQ(pool.capacity(), 0); - (void)entt::storage{std::move(pool)}; - entt::storage other; + (void)entt::default_storage{std::move(pool)}; + entt::default_storage other; other = std::move(pool); } -TEST(Storage, EmptyType) { - entt::storage pool; +TEST(DefaultStorage, EmptyType) { + entt::default_storage pool; pool.construct(entt::entity{42}); pool.construct(entt::entity{99}); @@ -94,8 +94,8 @@ TEST(Storage, EmptyType) { ASSERT_TRUE((std::is_same_v)); } -TEST(Storage, BatchAdd) { - entt::storage pool; +TEST(DefaultStorage, BatchAdd) { + entt::default_storage pool; entt::entity entities[2]; entities[0] = entt::entity{3}; @@ -117,8 +117,8 @@ TEST(Storage, BatchAdd) { ASSERT_EQ(pool.get(entities[1]), 2); } -TEST(Storage, BatchAddByCopy) { - entt::storage pool; +TEST(DefaultStorage, BatchAddByCopy) { + entt::default_storage pool; entt::entity entities[2]; entities[0] = entt::entity{3}; @@ -140,8 +140,8 @@ TEST(Storage, BatchAddByCopy) { ASSERT_EQ(pool.get(entities[1]), 2); } -TEST(Storage, BatchAddEmptyType) { - entt::storage pool; +TEST(DefaultStorage, BatchAddEmptyType) { + entt::default_storage pool; entt::entity entities[2]; entities[0] = entt::entity{3}; @@ -160,23 +160,23 @@ TEST(Storage, BatchAddEmptyType) { ASSERT_TRUE((std::is_same_v)); } -TEST(Storage, AggregatesMustWork) { +TEST(DefaultStorage, AggregatesMustWork) { struct aggregate_type { int value; }; // the goal of this test is to enforce the requirements for aggregate types - entt::storage{}.construct(entt::entity{0}, 42); + entt::default_storage{}.construct(entt::entity{0}, 42); } -TEST(Storage, TypesFromStandardTemplateLibraryMustWork) { +TEST(DefaultStorage, TypesFromStandardTemplateLibraryMustWork) { // see #37 - this test shouldn't crash, that's all - entt::storage> pool; + entt::default_storage> pool; pool.construct(entt::entity{0}).insert(42); pool.destroy(entt::entity{0}); } -TEST(Storage, Iterator) { - using iterator_type = typename entt::storage::iterator_type; +TEST(DefaultStorage, Iterator) { + using iterator_type = typename entt::default_storage::iterator_type; - entt::storage pool; + entt::default_storage pool; pool.construct(entt::entity{3}, 42); iterator_type end{pool.begin()}; @@ -215,10 +215,10 @@ TEST(Storage, Iterator) { ASSERT_GE(end, pool.end()); } -TEST(Storage, ConstIterator) { - using iterator_type = typename entt::storage::const_iterator_type; +TEST(DefaultStorage, ConstIterator) { + using iterator_type = typename entt::default_storage::const_iterator_type; - entt::storage pool; + entt::default_storage pool; pool.construct(entt::entity{3}, 42); iterator_type cend{pool.cbegin()}; @@ -257,9 +257,9 @@ TEST(Storage, ConstIterator) { ASSERT_GE(cend, pool.cend()); } -TEST(Storage, IteratorEmptyType) { - using iterator_type = typename entt::storage::iterator_type; - entt::storage pool; +TEST(DefaultStorage, IteratorEmptyType) { + using iterator_type = typename entt::default_storage::iterator_type; + entt::default_storage pool; pool.construct(entt::entity{3}); iterator_type end{pool.begin()}; @@ -303,8 +303,8 @@ TEST(Storage, IteratorEmptyType) { ASSERT_TRUE((std::is_same_v)); } -TEST(Storage, Raw) { - entt::storage pool; +TEST(DefaultStorage, Raw) { + entt::default_storage pool; pool.construct(entt::entity{3}, 3); pool.construct(entt::entity{12}, 6); @@ -319,8 +319,8 @@ TEST(Storage, Raw) { ASSERT_EQ(*(pool.raw() + 2u), 9); } -TEST(Storage, SortOrdered) { - entt::storage pool; +TEST(DefaultStorage, SortOrdered) { + entt::default_storage pool; pool.construct(entt::entity{12}, boxed_int{12}); pool.construct(entt::entity{42}, boxed_int{9}); @@ -355,8 +355,8 @@ TEST(Storage, SortOrdered) { ASSERT_EQ(begin, end); } -TEST(Storage, SortReverse) { - entt::storage pool; +TEST(DefaultStorage, SortReverse) { + entt::default_storage pool; pool.construct(entt::entity{12}, boxed_int{1}); pool.construct(entt::entity{42}, boxed_int{3}); @@ -391,8 +391,8 @@ TEST(Storage, SortReverse) { ASSERT_EQ(begin, end); } -TEST(Storage, SortUnordered) { - entt::storage pool; +TEST(DefaultStorage, SortUnordered) { + entt::default_storage pool; pool.construct(entt::entity{12}, boxed_int{6}); pool.construct(entt::entity{42}, boxed_int{3}); @@ -427,8 +427,8 @@ TEST(Storage, SortUnordered) { ASSERT_EQ(begin, end); } -TEST(Storage, SortRange) { - entt::storage pool; +TEST(DefaultStorage, SortRange) { + entt::default_storage pool; pool.construct(entt::entity{12}, boxed_int{6}); pool.construct(entt::entity{42}, boxed_int{3}); @@ -493,9 +493,9 @@ TEST(Storage, SortRange) { ASSERT_EQ(begin, end); } -TEST(Storage, RespectDisjoint) { - entt::storage lhs; - entt::storage rhs; +TEST(DefaultStorage, RespectDisjoint) { + entt::default_storage lhs; + entt::default_storage rhs; lhs.construct(entt::entity{3}, 3); lhs.construct(entt::entity{12}, 6); @@ -520,9 +520,9 @@ TEST(Storage, RespectDisjoint) { ASSERT_EQ(begin, end); } -TEST(Storage, RespectOverlap) { - entt::storage lhs; - entt::storage rhs; +TEST(DefaultStorage, RespectOverlap) { + entt::default_storage lhs; + entt::default_storage rhs; lhs.construct(entt::entity{3}, 3); lhs.construct(entt::entity{12}, 6); @@ -549,9 +549,9 @@ TEST(Storage, RespectOverlap) { ASSERT_EQ(begin, end); } -TEST(Storage, RespectOrdered) { - entt::storage lhs; - entt::storage rhs; +TEST(DefaultStorage, RespectOrdered) { + entt::default_storage lhs; + entt::default_storage rhs; lhs.construct(entt::entity{1}, 0); lhs.construct(entt::entity{2}, 0); @@ -595,9 +595,9 @@ TEST(Storage, RespectOrdered) { ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5}); } -TEST(Storage, RespectReverse) { - entt::storage lhs; - entt::storage rhs; +TEST(DefaultStorage, RespectReverse) { + entt::default_storage lhs; + entt::default_storage rhs; lhs.construct(entt::entity{1}, 0); lhs.construct(entt::entity{2}, 0); @@ -641,9 +641,9 @@ TEST(Storage, RespectReverse) { ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5}); } -TEST(Storage, RespectUnordered) { - entt::storage lhs; - entt::storage rhs; +TEST(DefaultStorage, RespectUnordered) { + entt::default_storage lhs; + entt::default_storage rhs; lhs.construct(entt::entity{1}, 0); lhs.construct(entt::entity{2}, 0); @@ -687,9 +687,9 @@ TEST(Storage, RespectUnordered) { ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5}); } -TEST(Storage, RespectOverlapEmptyType) { - entt::storage lhs; - entt::storage rhs; +TEST(DefaultStorage, RespectOverlapEmptyType) { + entt::default_storage lhs; + entt::default_storage rhs; lhs.construct(entt::entity{3}); lhs.construct(entt::entity{12}); @@ -708,24 +708,24 @@ TEST(Storage, RespectOverlapEmptyType) { ASSERT_EQ(std::as_const(lhs).sparse_set::get(entt::entity{42}), 1u); } -TEST(Storage, CanModifyDuringIteration) { - entt::storage pool; +TEST(DefaultStorage, CanModifyDuringIteration) { + entt::default_storage pool; pool.construct(entt::entity{0}, 42); - ASSERT_EQ(pool.capacity(), (entt::storage::size_type{1})); + ASSERT_EQ(pool.capacity(), (entt::default_storage::size_type{1})); const auto it = pool.cbegin(); - pool.reserve(entt::storage::size_type{2}); + pool.reserve(entt::default_storage::size_type{2}); - ASSERT_EQ(pool.capacity(), (entt::storage::size_type{2})); + ASSERT_EQ(pool.capacity(), (entt::default_storage::size_type{2})); // this should crash with asan enabled if we break the constraint const auto entity = *it; (void)entity; } -TEST(Storage, ReferencesGuaranteed) { - entt::storage pool; +TEST(DefaultStorage, ReferencesGuaranteed) { + entt::default_storage pool; pool.construct(entt::entity{0}, 0); pool.construct(entt::entity{1}, 1); @@ -752,14 +752,14 @@ TEST(Storage, ReferencesGuaranteed) { ASSERT_EQ(pool.get(entt::entity{1}).value, 3); } -TEST(Storage, MoveOnlyComponent) { +TEST(DefaultStorage, MoveOnlyComponent) { // the purpose is to ensure that move only components are always accepted - entt::storage> pool; + entt::default_storage> pool; (void)pool; } -TEST(Storage, ConstructorExceptionDoesNotAddToStorage) { - entt::storage pool; +TEST(DefaultStorage, ConstructorExceptionDoesNotAddToStorage) { + entt::default_storage pool; try { pool.construct(entt::entity{0});