From 75ca22fb54e6d0481697ebf17670be7a758acd35 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Mon, 4 Apr 2022 00:12:59 +0300 Subject: [PATCH 01/27] started working on cleaner implementation --- CMakeLists.txt | 1 + src/entt/entity/polymorphic.hpp | 329 ++++++++++++++++++++++++++++++++ src/entt/entity/registry.hpp | 23 +++ test/CMakeLists.txt | 3 + test/playground.cpp | 64 +++++++ 5 files changed, 420 insertions(+) create mode 100644 src/entt/entity/polymorphic.hpp create mode 100644 test/playground.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fdd01a356b..4fd853cc52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,7 @@ if(ENTT_INCLUDE_HEADERS) $ $ $ + $ $ $ $ diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp new file mode 100644 index 0000000000..194667df15 --- /dev/null +++ b/src/entt/entity/polymorphic.hpp @@ -0,0 +1,329 @@ +#ifndef ENTT_ENTITY_POLYMORPHIC_HPP +#define ENTT_ENTITY_POLYMORPHIC_HPP + +#include "../core/type_info.hpp" +#include "../core/type_traits.hpp" + +namespace entt { + +/** + * @brief declares direct parent types of polymorphic component type. + * By default it uses the list from T::direct_parent_types, if it present, otherwise empty list is used. + * All parent types must be declared polymorphic. + * @code{.cpp} + * struct A {}; + * struct B : A {}; + * + * struct entt::poly_direct_parent_types { + * using parent_types = entt::type_list<>; // declares A as polymorphic type with no parents + * } + * struct entt::poly_direct_parent_types { + * using parent_types = entt::type_list; // declares B as polymorphic type with parent A + * } + * @endcode + * @tparam T polymorphic component type + */ +template +struct poly_direct_parent_types { + /** @brief entt::type_list of direct parent types */ + using parent_types = type_list<>; + + /** @brief used to detect, if this template was specialized for a type */ + using not_redefined_tag = void; +}; + +/** @copydoc poly_direct_parent_types */ +template +struct poly_direct_parent_types> { + using parent_types = typename T::direct_parent_types; +}; + +/** + * @brief for given polymorphic component type returns entt::type_list of direct parent types, + * for non polymorphic type will return empty list + * @tparam T type to get parents from + */ +template +using poly_direct_parent_types_t = typename poly_direct_parent_types::parent_types; + +/** + * @brief declares list of all parent types of polymorphic component type. + * By default will concatenates list of all direct parent types and all lists of all parents for each parent type. All parent + * types must be declared polymorphic. + * @tparam T + */ +template +struct poly_parent_types { +private: + template + struct all_parent_types; + + template + struct all_parent_types> { + using types = type_list_cat_t, typename poly_parent_types::parent_types...>; + }; + +public: + /** @brief entt::type_list of all parent types */ + using parent_types = typename all_parent_types>::types; + + /** @brief used to detect, if this template was specialized for a type */ + using not_redefined_tag = void; +}; + +/** @copydoc poly_parent_types */ +template +struct poly_parent_types> { + using parent_types = typename T::all_parent_types; +}; + +/** + * @brief for given polymorphic component type returns entt::type_list of all parent types, + * for non polymorphic type will return empty list + * @tparam T type to get parents from + */ +template +using poly_parent_types_t = typename poly_parent_types::parent_types; + + +/** + * @brief for given type, detects, if it was declared polymorphic. Type considered polymorphic, + * if it was either: + * - inherited from entt::inherit + * - declared types direct_parent_types or all_parent_types + * - for this type there is specialization of either entt::poly_direct_parent_types or entt::poly_parent_types + * @tparam T type to check + */ +template +struct is_poly_type { + static constexpr bool value = true; +}; + +/** @copydoc is_poly_type */ +template +struct is_poly_type::not_redefined_tag, typename poly_parent_types::not_redefined_tag>> { + static constexpr bool value = false; +}; + +/** @copydoc is_poly_type */ +template +static constexpr bool is_poly_type_v = is_poly_type::value; + +/** + * @brief used to inherit from all given parent types and declare inheriting type polymorphic with given direct parents. + * All parent types are required to be polymorphic + * @code{.cpp} + * struct A : public entt::inherit<> {}; // base polymorphic type with no parents + * struct B : public entt::inherit {}; // B inherits A, and declared as polymorphic component with direct parents {A} + * struct C : public entt::inherit {}; // C inherits B, and now has direct parents {B} and all parents {A, B} + * @endcode + * @tparam Parents list of parent types + */ +template +struct inherit : public Parents... { + static_assert((is_poly_type_v && ...), "entt::inherit must be used only with polymorphic types"); + using direct_parent_types = type_list; +}; + +/** + * @brief TODO + */ +template +struct poly_all { + static_assert(is_poly_type_v, "entt::poly_all must be used only with polymorphic types"); + using type = T; + using poly_all_tag = void; +}; + +/** + * @brief TODO + */ +template +struct poly_any { + static_assert(is_poly_type_v, "entt::poly_any must be used only with polymorphic types"); + using type = T; + using poly_any_tag = void; +}; + +/** + * @brief Holds runtime information about one polymorphic component type. + * @tparam Entity + */ +template +struct poly_type { + /** @brief Holds pointer to child type storage and a function to convert it into parent type */ + struct poly_pool_holder { + /** + * @brief gets child from a child pool as parent type reference by given entity + * @tparam Type parent type to convert into + * @param ptr pointer from the child type set + * @return Returns reference to Type, converted from a given pointer. Will return pointer instead of reference, if parent type is a pointer. + */ + template + inline decltype(auto) try_get(const Entity ent) ENTT_NOEXCEPT { + return static_cast*>(getter_ptr(pool_ptr, ent)); + } + + inline auto& pool() ENTT_NOEXCEPT { + return *pool_ptr; + } + + inline const auto& pool() const ENTT_NOEXCEPT { + return *pool_ptr; + } + + private: + inline poly_pool_holder(basic_sparse_set* pool, void* (*getter)(void*, Entity) ENTT_NOEXCEPT) : + pool_ptr(pool), getter_ptr(getter) {}; + + template + friend struct poly_type; + + private: + basic_sparse_set* pool_ptr; + void* (*getter_ptr)(void*, Entity) ENTT_NOEXCEPT; + }; + + /** + * @brief From a given set, makes a poly_storage_holder to hold child type and convert to parent type. + * @tparam SourceType source type to convert from = child type + * @tparam TargetType target type to convert to = parent type. + * @param pool_ptr child (source) type pool + * @return poly_storage_holder to hold SourceType set and access it as TargetType + */ + template::storage_type> + inline static poly_pool_holder make_pool_holder(StorageType* pool_ptr) ENTT_NOEXCEPT { + static_assert(std::is_pointer_v == std::is_pointer_v); + + void* (*get)(void*, Entity entity) ENTT_NOEXCEPT = +[](void* pool, const Entity entity) ENTT_NOEXCEPT -> void* { + if (static_cast(pool)->contains(entity)) { + // if entity is contained within the set + if constexpr(std::is_base_of_v, std::remove_pointer_t>) { + if constexpr(std::is_pointer_v) { + // TargetType and SourceType are pointers, dereference source pointer and do conversion + SourceType ptr = static_cast(pool)->get(entity); + return static_cast(ptr); + } else { + // TargetType is base of SourceType, do pointer conversion + return static_cast(std::addressof(static_cast(pool)->get(entity))); + } + } else { + // no inheritance - no conversion required + if constexpr(std::is_pointer_v) { + // in case of pointer type return it as it is + return static_cast(pool)->get(entity); + } else { + // + return std::addressof(static_cast(pool)->get(entity)); + } + } + } + // otherwise, return null + return nullptr; + }; + return poly_pool_holder(pool_ptr, get); + } + + inline auto& child_pools() ENTT_NOEXCEPT { + return child_pool_holders; + } + + inline const auto& child_pools() const ENTT_NOEXCEPT { + return child_pool_holders; + } + +private: + std::vector child_pool_holders{}; +}; + +/** + * @brief Holds all data of all poly types in this registry + * @tparam Entity + */ +template +struct poly_type_data { + /** + * @param id type id of polymorphic type + * @return poly_type for given type id + */ + inline auto& assure(const id_type id) { + return types[id]; + } + + /** + * @tparam Type polymorphic type + * @return poly_type for given type + */ + template + inline auto& assure() { + static_assert(is_poly_type_v); + return assure(type_id().hash()); + } +private: + dense_map, identity> types{}; +}; + + + +/** + * @brief Storage mixin for polymorphic component types + * @tparam Storage + */ +template +class poly_storage_mixin; + +/** @copydoc poly_storage_mixin */ +template +class poly_storage_mixin: public Storage { + using component_type = typename Storage::value_type; + using entity_type = typename Storage::entity_type; + + using Storage::Storage; + + void bind(any value) ENTT_NOEXCEPT override { + if(auto *reg = any_cast>(&value); reg) { + register_for_all_parent_types(*reg, poly_parent_types_t{}); + } + } + + template + void add_self_for_type(basic_registry& reg) { + auto& type = reg.poly_data().template assure(); + type.child_pools().push_back(poly_type::template make_pool_holder(this)); + } + + template + void register_for_all_parent_types(basic_registry& reg, [[maybe_unused]] type_list) { + (add_self_for_type(reg), ...); + add_self_for_type(reg); + } + + template + friend class poly_storage_mixin; +}; + +/** + * @brief storage_traits template specialization for polymorphic component types + * @tparam Entity entity type + * @tparam Type polymorphic component type + */ +template +struct storage_traits>> { + template + struct parent_guard; + + /** @brief used to assert, that all parent types of the component are polymorphic */ + template + struct parent_guard> { + static_assert((is_poly_type_v && ...), "all parents of polymorphic type must be also declared polymorphic"); + using type = T; + }; + + using guarded_type = typename parent_guard>::type; +public: + using storage_type = poly_storage_mixin>; +}; + +} // namespace entt + +#endif // ENTT_ENTITY_POLYMORPHIC_HPP diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index e8b01c3c61..9f72de80d4 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -22,6 +22,7 @@ #include "entity.hpp" #include "fwd.hpp" #include "group.hpp" +#include "polymorphic.hpp" #include "runtime_view.hpp" #include "sparse_set.hpp" #include "storage.hpp" @@ -1020,6 +1021,19 @@ class basic_registry { return view().template get(entity); } + /*! @copydoc get */ + template + [[nodiscard]] std::remove_pointer_t* poly_get([[maybe_unused]] const entity_type entity) { + ENTT_ASSERT(valid(entity), "Invalid entity"); + for (auto& pool : polymorphic_data.template assure().child_pools()) { + auto* component_ptr = pool.template try_get(entity); + if (component_ptr != nullptr) { + return component_ptr; + } + } + return nullptr; + } + /** * @brief Returns a reference to the given component for an entity. * @@ -1466,12 +1480,21 @@ class basic_registry { return vars; } + auto& poly_data() ENTT_NOEXCEPT { + return polymorphic_data; + } + + [[nodiscard]] const auto& poly_data() const ENTT_NOEXCEPT { + return polymorphic_data; + } + private: dense_map, identity> pools; std::vector groups; std::vector epool; entity_type free_list; context vars; + poly_type_data polymorphic_data; }; } // namespace entt diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a99436fc9b..32a89b2f09 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -86,6 +86,9 @@ endfunction() add_library(odr OBJECT odr.cpp) SETUP_TARGET(odr) +add_executable(playground playground.cpp) +SETUP_TARGET(playground) + function(SETUP_BASIC_TEST TEST_NAME TEST_SOURCES) add_executable(${TEST_NAME} $ ${TEST_SOURCES}) target_link_libraries(${TEST_NAME} PRIVATE GTest::Main Threads::Threads) diff --git a/test/playground.cpp b/test/playground.cpp new file mode 100644 index 0000000000..2fcf87457b --- /dev/null +++ b/test/playground.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include + + +struct shape { virtual void draw() const = 0; }; +template<> +struct entt::poly_parent_types { + using parent_types = type_list<>; +}; + +struct circle: public entt::inherit { void draw() const override { std::cout << "circle"; } }; +struct rectangle: public entt::inherit { void draw() const override { std::cout << "rectangle"; } }; + +struct animal: public entt::inherit<> { virtual void name() const = 0; }; +struct cat: public entt::inherit { void name() const override { std::cout << "cat"; } }; +struct dog: public entt::inherit { void name() const override { std::cout << "dog"; } }; + +template +void for_each_poly(entt::basic_registry& registry, Func func) { + auto& sets = registry.poly_data().template assure().child_pools(); + for (auto set_holder : sets) { + for (const auto ent : set_holder.pool()) { + auto* comp = set_holder.template try_get(ent); + func(ent, *comp); + } + } +} + +template +void for_each_poly(entt::basic_registry& registry, Entity ent, Func func) { + auto& sets = registry.poly_data().template assure().child_pools(); + for (auto set_holder : sets) { + auto* comp = set_holder.template get(ent); + func(ent, *comp); + } +} + + +int main() { + entt::registry registry; + const auto entity = registry.create(); + const auto other = registry.create(); + + registry.emplace(entity); + registry.emplace(entity); + registry.emplace(entity); + + registry.emplace(other); + registry.emplace(other); + + registry.poly_get(entity)->draw(); + std::cout << '\n'; + + for_each_poly(registry, []( const entt::entity& ent, shape& comp ) -> void { + std::cout << entt::to_entity(ent) << " -> "; + comp.draw(); + std::cout << '\n'; + }); + +// print_shapes(registry); +// print_animals(registry); +} \ No newline at end of file From d668113cdb151cfa3a649be9ff53be8e36bf8216 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Tue, 5 Apr 2022 17:04:56 +0300 Subject: [PATCH 02/27] cleanup & iterator implementation for single entity --- src/entt/entity/polymorphic.hpp | 282 +++++++++++++++++++++++++------- src/entt/entity/registry.hpp | 30 ++-- test/playground.cpp | 44 ++--- 3 files changed, 261 insertions(+), 95 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 194667df15..9d61f7901d 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -4,6 +4,136 @@ #include "../core/type_info.hpp" #include "../core/type_traits.hpp" + +namespace entt::internal { + +template +struct converting_iterator { + using value_type = std::decay_t()(*std::declval()))>; + using reference = value_type&; + using pointer = value_type*; + using difference_type = typename It::difference_type; + using iterator_category = std::bidirectional_iterator_tag; + + converting_iterator() ENTT_NOEXCEPT = default; + + converting_iterator(It it) ENTT_NOEXCEPT : + wrapped(it) {} + + converting_iterator &operator++() ENTT_NOEXCEPT { + wrapped++; + return *this; + } + + converting_iterator operator++(int) ENTT_NOEXCEPT { + converting_iterator orig = *this; + return ++(*this), orig; + } + + converting_iterator &operator--() ENTT_NOEXCEPT { + wrapped--; + return *this; + } + + converting_iterator operator--(int) ENTT_NOEXCEPT { + converting_iterator orig = *this; + return --(*this), orig; + } + + bool operator==(const converting_iterator& other) const ENTT_NOEXCEPT { + return wrapped == other.wrapped; + } + + bool operator!=(const converting_iterator& other) const ENTT_NOEXCEPT { + return wrapped != other.wrapped; + } + + reference operator*() ENTT_NOEXCEPT { + Convert convert{}; + return convert(*wrapped); + } + + pointer operator->() ENTT_NOEXCEPT { + return std::addressof(operator*()); + } + +private: + It wrapped; +}; + + +template +class poly_components_iterator { + using iterator_traits = typename std::iterator_traits; + using pool_holder_type = typename iterator_traits::value_type; + +public: + using entity_type = typename pool_holder_type::entity_type; + using value_type = typename pool_holder_type::value_type; + using pointer = typename pool_holder_type::pointer_type; + using reference = std::conditional_t, value_type, value_type&>; + using difference_type = typename iterator_traits::difference_type; + using iterator_category = std::forward_iterator_tag; + + poly_components_iterator() ENTT_NOEXCEPT = default; + + poly_components_iterator(entity_type e, PoolsIterator pos, PoolsIterator last) ENTT_NOEXCEPT : + ent(e), it(pos), end(last) { + if (it != end) { + current = it->template try_get(ent); + if(current == nullptr) { + ++(*this); + } + } + } + + poly_components_iterator &operator++() ENTT_NOEXCEPT { + ++it; + while (it != end) { + current = it->template try_get(ent); + if (current != nullptr) + break; + ++it; + } + return *this; + } + + poly_components_iterator operator++(int) ENTT_NOEXCEPT { + poly_components_iterator orig = *this; + return ++(*this), orig; + } + + bool operator==(const poly_components_iterator& other) const ENTT_NOEXCEPT { + return it == other.it; + } + + bool operator!=(const poly_components_iterator& other) const ENTT_NOEXCEPT { + return it != other.it; + } + + pointer operator->() ENTT_NOEXCEPT { + return current; + } + + reference operator*() ENTT_NOEXCEPT { + if constexpr(std::is_pointer_v) { + return operator->(); + } else { + return *operator->(); + } + } + +private: + entity_type ent; + PoolsIterator it; + PoolsIterator end; + pointer current = nullptr; +}; + + +} // namespace entt::internal + + namespace entt { /** @@ -145,75 +275,111 @@ struct poly_any { using poly_any_tag = void; }; + +/** @brief private base class for entt::poly_pool_holder */ +template +class poly_pool_holder_base { +public: + inline poly_pool_holder_base(basic_sparse_set* pool, void* (*getter)(void*, Entity) ENTT_NOEXCEPT) : + pool_ptr(pool), getter_ptr(getter) {} + +protected: + basic_sparse_set* pool_ptr; + void* (*getter_ptr)(void*, Entity) ENTT_NOEXCEPT; +}; + +/** @brief private base class for entt::poly_type */ +template +class poly_type_base { +protected: + using child_pools_container = std::vector>; + + child_pools_container child_pool_holders{}; +}; + /** - * @brief Holds runtime information about one polymorphic component type. - * @tparam Entity + * @brief Holds pointer to child type storage and a function to convert it into parent type + * @tparam Entity underlying entity type + * @tparam Type polymorphic component type to be converted into */ -template -struct poly_type { - /** @brief Holds pointer to child type storage and a function to convert it into parent type */ - struct poly_pool_holder { - /** - * @brief gets child from a child pool as parent type reference by given entity - * @tparam Type parent type to convert into - * @param ptr pointer from the child type set - * @return Returns reference to Type, converted from a given pointer. Will return pointer instead of reference, if parent type is a pointer. - */ - template - inline decltype(auto) try_get(const Entity ent) ENTT_NOEXCEPT { - return static_cast*>(getter_ptr(pool_ptr, ent)); - } +template +class poly_pool_holder : public poly_pool_holder_base { +public: + using poly_pool_holder_base::poly_pool_holder_base; - inline auto& pool() ENTT_NOEXCEPT { - return *pool_ptr; - } + using entity_type = Entity; + using value_type = Type; + using pointer_type = std::remove_pointer_t*; - inline const auto& pool() const ENTT_NOEXCEPT { - return *pool_ptr; - } + /** + * @brief gets child from a child pool as parent type reference by given entity + * @param ptr pointer from the child type set + * @return Returns reference to Type, converted from a given pointer. Will return pointer instead of reference, if parent type is a pointer. + */ + inline pointer_type try_get(const Entity ent) ENTT_NOEXCEPT { + return pointer_type(this->getter_ptr(this->pool_ptr, ent)); + } - private: - inline poly_pool_holder(basic_sparse_set* pool, void* (*getter)(void*, Entity) ENTT_NOEXCEPT) : - pool_ptr(pool), getter_ptr(getter) {}; + inline auto& pool() ENTT_NOEXCEPT { + return *this->pool_ptr; + } - template - friend struct poly_type; + inline const auto& pool() const ENTT_NOEXCEPT { + return *this->pool_ptr; + } +}; - private: - basic_sparse_set* pool_ptr; - void* (*getter_ptr)(void*, Entity) ENTT_NOEXCEPT; +/** + * @brief Holds runtime information about one polymorphic component type. + * @tparam Entity + */ +template +class poly_type : public poly_type_base { + struct cast_pool_holder { + poly_pool_holder& operator()(poly_pool_holder_base& holder) { + return static_cast&>(holder); + } }; +public: + using entity_type = Entity; + using value_type = Type; + using pools_container = typename poly_type_base::child_pools_container; + using pools_iterator = internal::converting_iterator; + using component_iterator = internal::poly_components_iterator; + /** * @brief From a given set, makes a poly_storage_holder to hold child type and convert to parent type. - * @tparam SourceType source type to convert from = child type - * @tparam TargetType target type to convert to = parent type. + * @tparam ChildType source type to convert from * @param pool_ptr child (source) type pool - * @return poly_storage_holder to hold SourceType set and access it as TargetType + * @return poly_storage_holder to hold ChildType set and access it as Type */ - template::storage_type> - inline static poly_pool_holder make_pool_holder(StorageType* pool_ptr) ENTT_NOEXCEPT { - static_assert(std::is_pointer_v == std::is_pointer_v); + template + inline static poly_pool_holder make_pool_holder(StorageType* pool_ptr) ENTT_NOEXCEPT { + using ChildType = typename StorageType::value_type; + static_assert(is_poly_type_v); + static_assert(type_list_contains_v, Type> || std::is_same_v); + static_assert(std::is_pointer_v == std::is_pointer_v); void* (*get)(void*, Entity entity) ENTT_NOEXCEPT = +[](void* pool, const Entity entity) ENTT_NOEXCEPT -> void* { if (static_cast(pool)->contains(entity)) { // if entity is contained within the set - if constexpr(std::is_base_of_v, std::remove_pointer_t>) { - if constexpr(std::is_pointer_v) { - // TargetType and SourceType are pointers, dereference source pointer and do conversion - SourceType ptr = static_cast(pool)->get(entity); - return static_cast(ptr); + if constexpr(std::is_base_of_v, std::remove_pointer_t>) { + if constexpr(std::is_pointer_v) { + // Type and ChildType are pointers, dereference source pointer and do conversion + ChildType ptr = static_cast(pool)->get(entity); + return static_cast(ptr); } else { - // TargetType is base of SourceType, do pointer conversion - return static_cast(std::addressof(static_cast(pool)->get(entity))); + // Type is base of ChildType, do pointer conversion + return static_cast(std::addressof(static_cast(pool)->get(entity))); } } else { // no inheritance - no conversion required - if constexpr(std::is_pointer_v) { + if constexpr(std::is_pointer_v) { // in case of pointer type return it as it is return static_cast(pool)->get(entity); } else { - // + // otherwise, get the address return std::addressof(static_cast(pool)->get(entity)); } } @@ -221,19 +387,24 @@ struct poly_type { // otherwise, return null return nullptr; }; - return poly_pool_holder(pool_ptr, get); + + return poly_pool_holder(pool_ptr, get); } - inline auto& child_pools() ENTT_NOEXCEPT { - return child_pool_holders; + template + void bind_child_storage(Storage* storage_ptr) { + this->child_pool_holders.emplace_back(make_pool_holder(storage_ptr)); } - inline const auto& child_pools() const ENTT_NOEXCEPT { - return child_pool_holders; + iterable_adaptor pools() { + return { pools_iterator(this->child_pool_holders.begin()), pools_iterator(this->child_pool_holders.end()) }; } -private: - std::vector child_pool_holders{}; + iterable_adaptor each(const entity_type ent) { + auto begin = pools_iterator(this->child_pool_holders.begin()); + auto end = pools_iterator(this->child_pool_holders.end()); + return { component_iterator(ent, begin, end), component_iterator(ent, end, end) }; + } }; /** @@ -257,10 +428,10 @@ struct poly_type_data { template inline auto& assure() { static_assert(is_poly_type_v); - return assure(type_id().hash()); + return static_cast&>(assure(type_id().hash())); } private: - dense_map, identity> types{}; + dense_map, identity> types{}; }; @@ -288,8 +459,7 @@ class poly_storage_mixin: public Storage { template void add_self_for_type(basic_registry& reg) { - auto& type = reg.poly_data().template assure(); - type.child_pools().push_back(poly_type::template make_pool_holder(this)); + reg.poly_data().template assure().bind_child_storage(this); } template diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 9f72de80d4..18e05aafe1 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -1021,17 +1021,27 @@ class basic_registry { return view().template get(entity); } - /*! @copydoc get */ + /** + * @brief For given polymorphic component type iterate over all child instances of it, attached to a given entity + * @tparam Component Polymorphic component type + * @param entity Entity, to get components from + * @return Iterable to iterate each component + */ template - [[nodiscard]] std::remove_pointer_t* poly_get([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - for (auto& pool : polymorphic_data.template assure().child_pools()) { - auto* component_ptr = pool.template try_get(entity); - if (component_ptr != nullptr) { - return component_ptr; - } - } - return nullptr; + [[nodiscard]] decltype(auto) poly_get_all([[maybe_unused]] const entity_type entity) { + return polymorphic_data.template assure().each(entity); + } + + /** + * @brief For given polymorphic component type find and return any child instance of this type, attached to a given entity + * @tparam Component Polymorphic component type + * @param entity Entity, to get components from + * @return Pointer to attached component or nullptr, if none attached. NOTE: will return pointer typed polymorphic components by value (as a single pointer) + */ + template + [[nodiscard]] decltype(auto) poly_get_any([[maybe_unused]] const entity_type entity) { + auto all = poly_get_all(entity); + return all.begin() != all.end() ? all.begin().operator->() : nullptr; } /** diff --git a/test/playground.cpp b/test/playground.cpp index 2fcf87457b..6845a032c3 100644 --- a/test/playground.cpp +++ b/test/playground.cpp @@ -17,26 +17,6 @@ struct animal: public entt::inherit<> { virtual void name() const = 0; }; struct cat: public entt::inherit { void name() const override { std::cout << "cat"; } }; struct dog: public entt::inherit { void name() const override { std::cout << "dog"; } }; -template -void for_each_poly(entt::basic_registry& registry, Func func) { - auto& sets = registry.poly_data().template assure().child_pools(); - for (auto set_holder : sets) { - for (const auto ent : set_holder.pool()) { - auto* comp = set_holder.template try_get(ent); - func(ent, *comp); - } - } -} - -template -void for_each_poly(entt::basic_registry& registry, Entity ent, Func func) { - auto& sets = registry.poly_data().template assure().child_pools(); - for (auto set_holder : sets) { - auto* comp = set_holder.template get(ent); - func(ent, *comp); - } -} - int main() { entt::registry registry; @@ -50,15 +30,21 @@ int main() { registry.emplace(other); registry.emplace(other); - registry.poly_get(entity)->draw(); - std::cout << '\n'; + for (auto& pool : registry.poly_data().assure().pools()) + { + for (auto ent : pool.pool()) { + std::cout << entt::to_entity(ent) << " -> "; + pool.try_get(ent)->draw(); + std::cout << '\n'; + } + } - for_each_poly(registry, []( const entt::entity& ent, shape& comp ) -> void { - std::cout << entt::to_entity(ent) << " -> "; - comp.draw(); + std::cout << "\nall shapes for entity " << entt::to_entity(entity) << "\n"; + for (shape& shape : registry.poly_get_all(entity)) { + shape.draw(); std::cout << '\n'; - }); - -// print_shapes(registry); -// print_animals(registry); + } + std::cout << "any shape for entity " << entt::to_entity(entity) << " "; + registry.poly_get_any(entity)->draw(); + std::cout << '\n'; } \ No newline at end of file From f4741c94a8764845ceacd971785fe0354e260e18 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Tue, 5 Apr 2022 17:33:22 +0300 Subject: [PATCH 03/27] each_poly method --- src/entt/entity/registry.hpp | 41 ++++++++++++++++++++++++- test/playground.cpp | 58 +++++++++++++++++++++++++----------- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 18e05aafe1..0dd4601b04 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -1029,6 +1029,7 @@ class basic_registry { */ template [[nodiscard]] decltype(auto) poly_get_all([[maybe_unused]] const entity_type entity) { + ENTT_ASSERT(valid(entity), "Invalid entity"); return polymorphic_data.template assure().each(entity); } @@ -1036,7 +1037,7 @@ class basic_registry { * @brief For given polymorphic component type find and return any child instance of this type, attached to a given entity * @tparam Component Polymorphic component type * @param entity Entity, to get components from - * @return Pointer to attached component or nullptr, if none attached. NOTE: will return pointer typed polymorphic components by value (as a single pointer) + * @return Pointer to attached component or nullptr, if none attached. NOTE: will return pointer type polymorphic components by value (as a single pointer) */ template [[nodiscard]] decltype(auto) poly_get_any([[maybe_unused]] const entity_type entity) { @@ -1044,6 +1045,39 @@ class basic_registry { return all.begin() != all.end() ? all.begin().operator->() : nullptr; } + /** + * @brief For a given component type applies given func to all child instances of this type in registry. + * @tparam Component polymorphic component type + * @tparam Func type of given function + * @param func function to call for each component, parameters are (entity, component&) or only one of them, or even none. Note: for pointer type components the component parameter is a value instead of value (single pointer) + */ + template + void each_poly(Func func) { + for (auto& pool : polymorphic_data.template assure().pools()) { + for (auto& ent : pool.pool()) { + if constexpr(std::is_invocable_v) { + auto ptr = pool.try_get(ent); + if constexpr(std::is_pointer_v) { + func(ent, ptr); + } else { + func(ent, *ptr); + } + } else if constexpr(std::is_invocable_v) { + auto ptr = pool.try_get(ent); + if constexpr(std::is_pointer_v) { + func(ptr); + } else { + func(*ptr); + } + } else if constexpr(std::is_invocable_v) { + func(ent); + } else { + func(); + } + } + } + } + /** * @brief Returns a reference to the given component for an entity. * @@ -1490,10 +1524,15 @@ class basic_registry { return vars; } + /** + * @brief Returns entt::poly_type_data object, that holds all information about polymorphic types in this registry + * @return object, that holds information about all polymorphic types in this registry + */ auto& poly_data() ENTT_NOEXCEPT { return polymorphic_data; } + /** @copydoc poly_data */ [[nodiscard]] const auto& poly_data() const ENTT_NOEXCEPT { return polymorphic_data; } diff --git a/test/playground.cpp b/test/playground.cpp index 6845a032c3..59cfb350c0 100644 --- a/test/playground.cpp +++ b/test/playground.cpp @@ -9,14 +9,26 @@ template<> struct entt::poly_parent_types { using parent_types = type_list<>; }; - struct circle: public entt::inherit { void draw() const override { std::cout << "circle"; } }; struct rectangle: public entt::inherit { void draw() const override { std::cout << "rectangle"; } }; -struct animal: public entt::inherit<> { virtual void name() const = 0; }; -struct cat: public entt::inherit { void name() const override { std::cout << "cat"; } }; -struct dog: public entt::inherit { void name() const override { std::cout << "dog"; } }; +struct animal { virtual void name() const = 0; }; +struct cat: public animal { void name() const override { std::cout << "cat"; } }; +struct dog: public animal { void name() const override { std::cout << "dog"; } }; + +template<> +struct entt::poly_parent_types { + using parent_types = type_list<>; +}; +template<> +struct entt::poly_parent_types { + using parent_types = type_list; +}; +template<> +struct entt::poly_parent_types { + using parent_types = type_list; +}; int main() { entt::registry registry; @@ -25,26 +37,38 @@ int main() { registry.emplace(entity); registry.emplace(entity); - registry.emplace(entity); + registry.emplace(entity, new cat); registry.emplace(other); - registry.emplace(other); - - for (auto& pool : registry.poly_data().assure().pools()) - { - for (auto ent : pool.pool()) { - std::cout << entt::to_entity(ent) << " -> "; - pool.try_get(ent)->draw(); - std::cout << '\n'; - } - } + registry.emplace(other, new dog); + + std::cout << "\nall shapes\n"; + registry.each_poly([](auto ent, auto& s) { + std::cout << entt::to_entity(ent) << " -> "; + s.draw(); + std::cout << '\n'; + }); std::cout << "\nall shapes for entity " << entt::to_entity(entity) << "\n"; - for (shape& shape : registry.poly_get_all(entity)) { - shape.draw(); + for (shape& s : registry.poly_get_all(entity)) { + s.draw(); std::cout << '\n'; } + std::cout << "any shape for entity " << entt::to_entity(entity) << " "; registry.poly_get_any(entity)->draw(); std::cout << '\n'; + + std::cout << "\nall animals\n"; + registry.each_poly([](auto ent, auto* a) { + std::cout << entt::to_entity(ent) << " -> "; + a->name(); + std::cout << '\n'; + }); + + std::cout << "\nall animals for entity " << entt::to_entity(entity) << "\n"; + for (animal* a : registry.poly_get_all(entity)) { + a->name(); + std::cout << '\n'; + } } \ No newline at end of file From 24b630673565b79c6a4030ce1dbbac98b0c97307 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Tue, 5 Apr 2022 17:39:59 +0300 Subject: [PATCH 04/27] comment adjustments --- src/entt/entity/polymorphic.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 9d61f7901d..f8c1a27217 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -276,7 +276,7 @@ struct poly_any { }; -/** @brief private base class for entt::poly_pool_holder */ +/** @brief base class for entt::poly_pool_holder */ template class poly_pool_holder_base { public: @@ -288,7 +288,7 @@ class poly_pool_holder_base { void* (*getter_ptr)(void*, Entity) ENTT_NOEXCEPT; }; -/** @brief private base class for entt::poly_type */ +/** @brief base class for entt::poly_type */ template class poly_type_base { protected: @@ -307,8 +307,11 @@ class poly_pool_holder : public poly_pool_holder_base { public: using poly_pool_holder_base::poly_pool_holder_base; + /** @brief entity type of the component pools */ using entity_type = Entity; + /** @brief component type */ using value_type = Type; + /** @brief pointer to the component, will be same as value_type, if component itself is a pointer */ using pointer_type = std::remove_pointer_t*; /** @@ -320,10 +323,12 @@ class poly_pool_holder : public poly_pool_holder_base { return pointer_type(this->getter_ptr(this->pool_ptr, ent)); } + /** @brief returns underlying pool */ inline auto& pool() ENTT_NOEXCEPT { return *this->pool_ptr; } + /** @copydoc pool */ inline const auto& pool() const ENTT_NOEXCEPT { return *this->pool_ptr; } @@ -342,10 +347,15 @@ class poly_type : public poly_type_base { }; public: + /** @brief entity type of the component pools */ using entity_type = Entity; + /** @brief component type */ using value_type = Type; + /** @brief type of the underlying pool container */ using pools_container = typename poly_type_base::child_pools_container; + /** @brief pool iterator type */ using pools_iterator = internal::converting_iterator; + /** @brief single entity component iterator type */ using component_iterator = internal::poly_components_iterator; /** From 3f3749e7bb59dba43c9dd4a1eb62284fcfa31f04 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Tue, 5 Apr 2022 17:59:47 +0300 Subject: [PATCH 05/27] poly_type_base -> poly_types_data --- src/entt/entity/polymorphic.hpp | 2 +- src/entt/entity/registry.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index f8c1a27217..941514b56d 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -422,7 +422,7 @@ class poly_type : public poly_type_base { * @tparam Entity */ template -struct poly_type_data { +struct poly_types_data { /** * @param id type id of polymorphic type * @return poly_type for given type id diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 0dd4601b04..126a2d2e33 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -1525,7 +1525,7 @@ class basic_registry { } /** - * @brief Returns entt::poly_type_data object, that holds all information about polymorphic types in this registry + * @brief Returns entt::poly_types_data object, that holds all information about polymorphic types in this registry * @return object, that holds information about all polymorphic types in this registry */ auto& poly_data() ENTT_NOEXCEPT { @@ -1543,7 +1543,7 @@ class basic_registry { std::vector epool; entity_type free_list; context vars; - poly_type_data polymorphic_data; + poly_types_data polymorphic_data; }; } // namespace entt From f943b9188f1ef01b15cc11a6e44f75fade3f5026 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Tue, 5 Apr 2022 22:52:47 +0300 Subject: [PATCH 06/27] correctly handling const qualifier for polymorphic components --- src/entt/entity/polymorphic.hpp | 65 +++++++++++++++++++++++++++++---- test/playground.cpp | 6 +-- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 941514b56d..784f9b02e4 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -5,6 +5,11 @@ #include "../core/type_traits.hpp" +/** + * @cond TURN_OFF_DOXYGEN + * Internal details not to be documented. + */ + namespace entt::internal { template @@ -62,7 +67,7 @@ struct converting_iterator { }; -template +template class poly_components_iterator { using iterator_traits = typename std::iterator_traits; using pool_holder_type = typename iterator_traits::value_type; @@ -130,9 +135,13 @@ class poly_components_iterator { pointer current = nullptr; }; - } // namespace entt::internal +/** + * Internal details not to be documented. + * @endcond + */ + namespace entt { @@ -340,10 +349,15 @@ class poly_pool_holder : public poly_pool_holder_base { */ template class poly_type : public poly_type_base { + /** @brief internally used to convert base_poly_pool_holder to a pool_poly_holder during the iteration */ struct cast_pool_holder { - poly_pool_holder& operator()(poly_pool_holder_base& holder) { + auto& operator()(poly_pool_holder_base& holder) { return static_cast&>(holder); } + + const auto& operator()(const poly_pool_holder_base& holder) const { + return static_cast&>(holder); + } }; public: @@ -355,8 +369,12 @@ class poly_type : public poly_type_base { using pools_container = typename poly_type_base::child_pools_container; /** @brief pool iterator type */ using pools_iterator = internal::converting_iterator; + /** @brief const pool iterator type */ + using const_pools_iterator = internal::converting_iterator; /** @brief single entity component iterator type */ - using component_iterator = internal::poly_components_iterator; + using component_iterator = internal::poly_components_iterator; + /** @brief const single entity component iterator type */ + using const_component_iterator = internal::poly_components_iterator; /** * @brief From a given set, makes a poly_storage_holder to hold child type and convert to parent type. @@ -401,20 +419,35 @@ class poly_type : public poly_type_base { return poly_pool_holder(pool_ptr, get); } + /** @brief adds given storage pointer as a child type pool to this polymorphic type */ template void bind_child_storage(Storage* storage_ptr) { this->child_pool_holders.emplace_back(make_pool_holder(storage_ptr)); } - iterable_adaptor pools() { + /** @brief returns an iterable to iterate through all pool holders */ + [[nodiscard]] iterable_adaptor pools() { return { pools_iterator(this->child_pool_holders.begin()), pools_iterator(this->child_pool_holders.end()) }; } - iterable_adaptor each(const entity_type ent) { + /** @copydoc pools */ + [[nodiscard]] iterable_adaptor pools() const { + return { const_pools_iterator(this->child_pool_holders.begin()), const_pools_iterator(this->child_pool_holders.end()) }; + } + + /** @brief returns an iterable to iterate through all polymorphic components, derived from this type, attached to a given entities */ + [[nodiscard]] iterable_adaptor each(const entity_type ent) { auto begin = pools_iterator(this->child_pool_holders.begin()); auto end = pools_iterator(this->child_pool_holders.end()); return { component_iterator(ent, begin, end), component_iterator(ent, end, end) }; } + + /** @copydoc each */ + [[nodiscard]] iterable_adaptor each(const entity_type ent) const { + auto begin = const_pools_iterator(this->child_pool_holders.begin()); + auto end = const_pools_iterator(this->child_pool_holders.end()); + return { const_component_iterator(ent, begin, end), const_component_iterator(ent, end, end) }; + } }; /** @@ -431,14 +464,30 @@ struct poly_types_data { return types[id]; } + /** @copydoc assure */ + inline const auto& assure(const id_type id) const { + if(const auto it = types.find(id); it != types.cend()) { + return static_cast &>(*it->second); + } + static poly_type_base placeholder{}; + return placeholder; + } + /** * @tparam Type polymorphic type * @return poly_type for given type */ template inline auto& assure() { - static_assert(is_poly_type_v); - return static_cast&>(assure(type_id().hash())); + static_assert(is_poly_type_v>); + return static_cast&>(assure(type_id>().hash())); + } + + /** @copydoc assure */ + template + inline const auto& assure() const { + static_assert(is_poly_type_v>); + return static_cast&>(assure(type_id>().hash())); } private: dense_map, identity> types{}; diff --git a/test/playground.cpp b/test/playground.cpp index 59cfb350c0..2119e5f7a5 100644 --- a/test/playground.cpp +++ b/test/playground.cpp @@ -4,13 +4,13 @@ #include -struct shape { virtual void draw() const = 0; }; +struct shape { virtual void draw() = 0; }; template<> struct entt::poly_parent_types { using parent_types = type_list<>; }; -struct circle: public entt::inherit { void draw() const override { std::cout << "circle"; } }; -struct rectangle: public entt::inherit { void draw() const override { std::cout << "rectangle"; } }; +struct circle: public entt::inherit { void draw() override { std::cout << "circle"; } }; +struct rectangle: public entt::inherit { void draw() override { std::cout << "rectangle"; } }; struct animal { virtual void name() const = 0; }; From 2c39cfcbdc5eacff57cf8fdbf6ce371cf416ed6b Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Tue, 5 Apr 2022 23:34:42 +0300 Subject: [PATCH 07/27] more correct const handling --- src/entt/entity/polymorphic.hpp | 57 ++++++++++++++++++++++----------- test/playground.cpp | 10 +++--- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 784f9b02e4..22d06d1647 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -14,7 +14,7 @@ namespace entt::internal { template struct converting_iterator { - using value_type = std::decay_t()(*std::declval()))>; + using value_type = std::remove_reference_t()(*std::declval()))>; using reference = value_type&; using pointer = value_type*; using difference_type = typename It::difference_type; @@ -74,9 +74,9 @@ class poly_components_iterator { public: using entity_type = typename pool_holder_type::entity_type; - using value_type = typename pool_holder_type::value_type; - using pointer = typename pool_holder_type::pointer_type; - using reference = std::conditional_t, value_type, value_type&>; + using pointer = std::conditional_t, typename pool_holder_type::const_pointer_type, typename pool_holder_type::pointer_type>; + using value_type = std::conditional_t, pointer, constness_as_t>; + using reference = std::conditional_t, pointer, value_type&>; using difference_type = typename iterator_traits::difference_type; using iterator_category = std::forward_iterator_tag; @@ -85,7 +85,7 @@ class poly_components_iterator { poly_components_iterator(entity_type e, PoolsIterator pos, PoolsIterator last) ENTT_NOEXCEPT : ent(e), it(pos), end(last) { if (it != end) { - current = it->template try_get(ent); + current = it->try_get(ent); if(current == nullptr) { ++(*this); } @@ -95,7 +95,7 @@ class poly_components_iterator { poly_components_iterator &operator++() ENTT_NOEXCEPT { ++it; while (it != end) { - current = it->template try_get(ent); + current = it->try_get(ent); if (current != nullptr) break; ++it; @@ -322,6 +322,8 @@ class poly_pool_holder : public poly_pool_holder_base { using value_type = Type; /** @brief pointer to the component, will be same as value_type, if component itself is a pointer */ using pointer_type = std::remove_pointer_t*; + /** @copydoc pointer_type */ + using const_pointer_type = const std::remove_pointer_t*; /** * @brief gets child from a child pool as parent type reference by given entity @@ -332,6 +334,11 @@ class poly_pool_holder : public poly_pool_holder_base { return pointer_type(this->getter_ptr(this->pool_ptr, ent)); } + /** @copydoc try_get */ + inline const_pointer_type try_get(const Entity ent) const ENTT_NOEXCEPT { + return const_cast*>(this)->try_get(ent); + } + /** @brief returns underlying pool */ inline auto& pool() ENTT_NOEXCEPT { return *this->pool_ptr; @@ -370,7 +377,7 @@ class poly_type : public poly_type_base { /** @brief pool iterator type */ using pools_iterator = internal::converting_iterator; /** @brief const pool iterator type */ - using const_pools_iterator = internal::converting_iterator; + using const_pools_iterator = internal::converting_iterator; /** @brief single entity component iterator type */ using component_iterator = internal::poly_components_iterator; /** @brief const single entity component iterator type */ @@ -432,7 +439,7 @@ class poly_type : public poly_type_base { /** @copydoc pools */ [[nodiscard]] iterable_adaptor pools() const { - return { const_pools_iterator(this->child_pool_holders.begin()), const_pools_iterator(this->child_pool_holders.end()) }; + return { const_pools_iterator(this->child_pool_holders.cbegin()), const_pools_iterator(this->child_pool_holders.cend()) }; } /** @brief returns an iterable to iterate through all polymorphic components, derived from this type, attached to a given entities */ @@ -444,8 +451,8 @@ class poly_type : public poly_type_base { /** @copydoc each */ [[nodiscard]] iterable_adaptor each(const entity_type ent) const { - auto begin = const_pools_iterator(this->child_pool_holders.begin()); - auto end = const_pools_iterator(this->child_pool_holders.end()); + auto begin = const_pools_iterator(this->child_pool_holders.cbegin()); + auto end = const_pools_iterator(this->child_pool_holders.cend()); return { const_component_iterator(ent, begin, end), const_component_iterator(ent, end, end) }; } }; @@ -455,7 +462,16 @@ class poly_type : public poly_type_base { * @tparam Entity */ template -struct poly_types_data { +class poly_types_data { + /** + * @brief converts const T* to T* const, used in assert, + * because first one looks much more intuitive, when the second is identical to const T for value types, but for pointers + */ + template + using sanitize_poly_type_t = std::conditional_t, + constness_as_t>*, std::remove_pointer_t>, T>; + +public: /** * @param id type id of polymorphic type * @return poly_type for given type id @@ -474,20 +490,23 @@ struct poly_types_data { } /** - * @tparam Type polymorphic type + * @tparam T polymorphic type * @return poly_type for given type */ - template - inline auto& assure() { - static_assert(is_poly_type_v>); - return static_cast&>(assure(type_id>().hash())); + template + inline decltype(auto) assure() { + using type = sanitize_poly_type_t; + using no_const_type = std::remove_const_t; + static_assert(is_poly_type_v); + return static_cast, type>&>(assure(type_id().hash())); } /** @copydoc assure */ - template + template inline const auto& assure() const { - static_assert(is_poly_type_v>); - return static_cast&>(assure(type_id>().hash())); + using no_const_type = std::remove_const_t>; + static_assert(is_poly_type_v); + return static_cast&>(assure(type_id().hash())); } private: dense_map, identity> types{}; diff --git a/test/playground.cpp b/test/playground.cpp index 2119e5f7a5..6ce7f7303a 100644 --- a/test/playground.cpp +++ b/test/playground.cpp @@ -43,14 +43,14 @@ int main() { registry.emplace(other, new dog); std::cout << "\nall shapes\n"; - registry.each_poly([](auto ent, auto& s) { + registry.each_poly([](auto ent, auto& s) { std::cout << entt::to_entity(ent) << " -> "; - s.draw(); + // s.draw(); std::cout << '\n'; }); std::cout << "\nall shapes for entity " << entt::to_entity(entity) << "\n"; - for (shape& s : registry.poly_get_all(entity)) { + for ( shape& s : registry.poly_get_all< shape>(entity)) { s.draw(); std::cout << '\n'; } @@ -60,14 +60,14 @@ int main() { std::cout << '\n'; std::cout << "\nall animals\n"; - registry.each_poly([](auto ent, auto* a) { + registry.each_poly([](auto ent, const animal* a) { std::cout << entt::to_entity(ent) << " -> "; a->name(); std::cout << '\n'; }); std::cout << "\nall animals for entity " << entt::to_entity(entity) << "\n"; - for (animal* a : registry.poly_get_all(entity)) { + for (const animal* a : registry.poly_get_all(entity)) { a->name(); std::cout << '\n'; } From 641478b80a0e8063463d316b67de091538c2e7ef Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sat, 9 Apr 2022 22:04:14 +0300 Subject: [PATCH 08/27] registry.poly_remove method --- src/entt/entity/polymorphic.hpp | 22 +++++++++++++++++++--- src/entt/entity/registry.hpp | 15 +++++++++++++++ test/playground.cpp | 4 ++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 22d06d1647..04199aced7 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -289,12 +289,15 @@ struct poly_any { template class poly_pool_holder_base { public: - inline poly_pool_holder_base(basic_sparse_set* pool, void* (*getter)(void*, Entity) ENTT_NOEXCEPT) : - pool_ptr(pool), getter_ptr(getter) {} + inline poly_pool_holder_base(basic_sparse_set* pool, + void* (*getter)(void*, Entity) ENTT_NOEXCEPT, + bool (*remover)(void*, Entity)) : + pool_ptr(pool), getter_ptr(getter), remover_ptr(remover) {} protected: basic_sparse_set* pool_ptr; void* (*getter_ptr)(void*, Entity) ENTT_NOEXCEPT; + bool (*remover_ptr)(void*, Entity); }; /** @brief base class for entt::poly_type */ @@ -339,6 +342,15 @@ class poly_pool_holder : public poly_pool_holder_base { return const_cast*>(this)->try_get(ent); } + /** + * @brief removes component from pool by entity + * @param ent entity + * @return true, if component was removed, false, if it didnt exist + */ + inline bool remove(const Entity ent) { + return this->remover_ptr(this->pool_ptr, ent); + } + /** @brief returns underlying pool */ inline auto& pool() ENTT_NOEXCEPT { return *this->pool_ptr; @@ -423,7 +435,11 @@ class poly_type : public poly_type_base { return nullptr; }; - return poly_pool_holder(pool_ptr, get); + bool (*remove)(void*, Entity entity) = +[](void* pool, const Entity entity) -> bool { + return static_cast(pool)->remove(entity); + }; + + return poly_pool_holder(pool_ptr, get, remove); } /** @brief adds given storage pointer as a child type pool to this polymorphic type */ diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 126a2d2e33..b4ecf65dd7 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -1044,6 +1044,21 @@ class basic_registry { auto all = poly_get_all(entity); return all.begin() != all.end() ? all.begin().operator->() : nullptr; } + /** + * @brief For given polymorphic component type remove all child instances of this type, attached to a given entity + * @tparam Component Polymorphic component type + * @param entity Entity, to remove components from + * @return count of removed components + */ + template + int poly_remove([[maybe_unused]] const entity_type entity) { + ENTT_ASSERT(valid(entity), "Invalid entity"); + int removed_count = 0; + for (auto& pool : polymorphic_data.template assure().pools()) { + removed_count += static_cast(pool.remove(entity)); + } + return removed_count; + } /** * @brief For a given component type applies given func to all child instances of this type in registry. diff --git a/test/playground.cpp b/test/playground.cpp index 6ce7f7303a..1c2b7928fb 100644 --- a/test/playground.cpp +++ b/test/playground.cpp @@ -43,9 +43,9 @@ int main() { registry.emplace(other, new dog); std::cout << "\nall shapes\n"; - registry.each_poly([](auto ent, auto& s) { + registry.each_poly([](auto ent, auto& s) { std::cout << entt::to_entity(ent) << " -> "; - // s.draw(); + s.draw(); std::cout << '\n'; }); From 07751cc8938a29f8ac2d0181ec49c6c49fbd0c49 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sun, 10 Apr 2022 22:21:35 +0300 Subject: [PATCH 09/27] sigh support for poly types --- src/entt/entity/poly_storage_mixin.hpp | 243 +++++++++++++++++++++++++ src/entt/entity/poly_type_traits.hpp | 151 +++++++++++++++ src/entt/entity/polymorphic.hpp | 184 +------------------ test/playground.cpp | 19 ++ 4 files changed, 418 insertions(+), 179 deletions(-) create mode 100644 src/entt/entity/poly_storage_mixin.hpp create mode 100644 src/entt/entity/poly_type_traits.hpp diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp new file mode 100644 index 0000000000..3bae2d2105 --- /dev/null +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -0,0 +1,243 @@ +#ifndef ENTT_ENTITY_POLY_STORAGE_MIXIN_HPP +#define ENTT_ENTITY_POLY_STORAGE_MIXIN_HPP + +#include "storage.hpp" + +namespace entt { + +/** + * @brief used to add signal support for polymorphic storages + * @tparam Entity storage entity type + * @tparam Type storage value type + */ +template +class poly_sigh_holder { +public: + /** + * @brief Returns a sink object. + * + * The sink returned by this function can be used to receive notifications + * whenever a new instance is created and assigned to an entity.
+ * Listeners are invoked after the object has been assigned to the entity. + * + * @sa sink + * + * @return A temporary sink object. + */ + [[nodiscard]] auto on_construct() ENTT_NOEXCEPT { + return sink{construction}; + } + + /** + * @brief Returns a sink object. + * + * The sink returned by this function can be used to receive notifications + * whenever an instance is explicitly updated.
+ * Listeners are invoked after the object has been updated. + * + * @sa sink + * + * @return A temporary sink object. + */ + [[nodiscard]] auto on_update() ENTT_NOEXCEPT { + return sink{update}; + } + + /** + * @brief Returns a sink object. + * + * The sink returned by this function can be used to receive notifications + * whenever an instance is removed from an entity and thus destroyed.
+ * Listeners are invoked before the object has been removed from the entity. + * + * @sa sink + * + * @return A temporary sink object. + */ + [[nodiscard]] auto on_destroy() ENTT_NOEXCEPT { + return sink{destruction}; + } + +private: + template + inline void publish_construction([[maybe_unused]] type_list, basic_registry& reg, const Entity ent) { + (reg.template storage().construction.publish(reg, ent), ...); + } + + inline void publish_construction(basic_registry& reg, const Entity ent) { + publish_construction(poly_parent_types_t{}, reg, ent); + publish_construction(type_list{}, reg, ent); + } + + template + inline void publish_update([[maybe_unused]] type_list, basic_registry& reg, const Entity ent) { + (reg.template storage().update.publish(reg, ent), ...); + } + + inline void publish_update(basic_registry& reg, const Entity ent) { + publish_update(poly_parent_types_t{}, reg, ent); + publish_update(type_list{}, reg, ent); + } + + template + inline void publish_destruction([[maybe_unused]] type_list, basic_registry& reg, const Entity ent) { + (reg.template storage().destruction.publish(reg, ent), ...); + } + + inline void publish_destruction(basic_registry& reg, const Entity ent) { + publish_destruction(poly_parent_types_t{}, reg, ent); + publish_destruction(type_list{}, reg, ent); + } + +private: + sigh&, const Entity)> construction{}; + sigh&, const Entity)> update{}; + sigh&, const Entity)> destruction{}; + + template + friend class poly_sigh_holder; + + template + friend class poly_storage_mixin; +}; + + +/** + * @brief Storage mixin for polymorphic component types + * @tparam Storage underlying storage type + * @tparam Entity entity type + * @tparam Type value type + */ +template +class poly_storage_mixin : public Storage, public poly_sigh_holder {template + void notify_destruction(typename Storage::basic_iterator first, typename Storage::basic_iterator last, Func func) { + ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); + for(; first != last; ++first) { + const auto entt = *first; + this->publish_destruction(*owner, entt); + const auto it = Storage::find(entt); + func(it, it + 1u); + } + } + + void swap_and_pop(typename Storage::basic_iterator first, typename Storage::basic_iterator last) final { + notify_destruction(std::move(first), std::move(last), [this](auto... args) { Storage::swap_and_pop(args...); }); + } + + void in_place_pop(typename Storage::basic_iterator first, typename Storage::basic_iterator last) final { + notify_destruction(std::move(first), std::move(last), [this](auto... args) { Storage::in_place_pop(args...); }); + } + + typename Storage::basic_iterator try_emplace(const typename Storage::entity_type entt, const bool force_back, const void *value) final { + ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); + Storage::try_emplace(entt, force_back, value); + this->publish_construction(*owner, entt); + return Storage::find(entt); + } + +public: + /*! @brief Underlying value type. */ + using value_type = typename Storage::value_type; + /*! @brief Underlying entity identifier. */ + using entity_type = typename Storage::entity_type; + + /*! @brief Inherited constructors. */ + using Storage::Storage; + + /** + * @brief Assigns entities to a storage. + * @tparam Args Types of arguments to use to construct the object. + * @param entt A valid identifier. + * @param args Parameters to use to initialize the object. + * @return A reference to the newly created object. + */ + template + decltype(auto) emplace(const entity_type entt, Args &&...args) { + ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); + Storage::emplace(entt, std::forward(args)...); + this->publish_construction(*owner, entt); + return this->get(entt); + } + + /** + * @brief Patches the given instance for an entity. + * @tparam Func Types of the function objects to invoke. + * @param entt A valid identifier. + * @param func Valid function objects. + * @return A reference to the patched instance. + */ + template + decltype(auto) patch(const entity_type entt, Func &&...func) { + ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); + Storage::patch(entt, std::forward(func)...); + this->publish_update(*owner, entt); + return this->get(entt); + } + + /** + * @brief Assigns entities to a storage. + * @tparam It Type of input iterator. + * @tparam Args Types of arguments to use to construct the objects assigned + * to the entities. + * @param first An iterator to the first element of the range of entities. + * @param last An iterator past the last element of the range of entities. + * @param args Parameters to use to initialize the objects assigned to the + * entities. + */ + template + void insert(It first, It last, Args &&...args) { + ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); + Storage::insert(first, last, std::forward(args)...); + + for(auto it = last; it != last; ++it) { + publish_construction(*owner, *it); + } + } + + /** + * @brief Forwards variables to mixins, if any. + * @param value A variable wrapped in an opaque container. + */ + void bind(any value) ENTT_NOEXCEPT override { + if(auto *reg = any_cast>(&value); reg) { + owner = reg; + register_for_all_parent_types(*reg, poly_parent_types_t{}); + } + Storage::bind(std::move(value)); + } + + template + void add_self_for_type(basic_registry& reg) { + reg.poly_data().template assure().bind_child_storage(this); + } + + template + void register_for_all_parent_types(basic_registry& reg, [[maybe_unused]] type_list) { + (add_self_for_type(reg), ...); + add_self_for_type(reg); + } + + template + friend class poly_storage_mixin; + +private: + basic_registry *owner{}; +}; + + +/** @copydoc poly_storage_mixin */ +template +class poly_storage_mixin && std::is_move_assignable_v)>>: + public basic_sparse_set, public poly_sigh_holder { + +public: + using base_type = basic_sparse_set; + using entity_type = Entity; + using value_type = Type; + + poly_storage_mixin() : base_type(type_id()) {}; +}; + +} // entt + +#endif // ENTT_ENTITY_POLY_STORAGE_MIXIN_HPP diff --git a/src/entt/entity/poly_type_traits.hpp b/src/entt/entity/poly_type_traits.hpp new file mode 100644 index 0000000000..d20d969746 --- /dev/null +++ b/src/entt/entity/poly_type_traits.hpp @@ -0,0 +1,151 @@ +#ifndef ENTT_ENTITY_POLY_TYPE_TRAITS_HPP +#define ENTT_ENTITY_POLY_TYPE_TRAITS_HPP + +#include "../core/type_info.hpp" +#include "../core/type_traits.hpp" + + +namespace entt { + +/** + * @brief declares direct parent types of polymorphic component type. + * By default it uses the list from T::direct_parent_types, if it present, otherwise empty list is used. + * All parent types must be declared polymorphic. + * @code{.cpp} + * struct A {}; + * struct B : A {}; + * + * struct entt::poly_direct_parent_types
{ + * using parent_types = entt::type_list<>; // declares A as polymorphic type with no parents + * } + * struct entt::poly_direct_parent_types { + * using parent_types = entt::type_list; // declares B as polymorphic type with parent A + * } + * @endcode + * @tparam T polymorphic component type + */ +template +struct poly_direct_parent_types { + /** @brief entt::type_list of direct parent types */ + using parent_types = type_list<>; + + /** @brief used to detect, if this template was specialized for a type */ + using not_redefined_tag = void; +}; + +/** @copydoc poly_direct_parent_types */ +template +struct poly_direct_parent_types> { + using parent_types = typename T::direct_parent_types; +}; + +/** + * @brief for given polymorphic component type returns entt::type_list of direct parent types, + * for non polymorphic type will return empty list + * @tparam T type to get parents from + */ +template +using poly_direct_parent_types_t = typename poly_direct_parent_types::parent_types; + +/** + * @brief declares list of all parent types of polymorphic component type. + * By default will concatenates list of all direct parent types and all lists of all parents for each parent type. All parent + * types must be declared polymorphic. + * @tparam T + */ +template +struct poly_parent_types { +private: + template + struct all_parent_types; + + template + struct all_parent_types> { + using types = type_list_cat_t, typename poly_parent_types::parent_types...>; + }; + +public: + /** @brief entt::type_list of all parent types */ + using parent_types = typename all_parent_types>::types; + + /** @brief used to detect, if this template was specialized for a type */ + using not_redefined_tag = void; +}; + +/** @copydoc poly_parent_types */ +template +struct poly_parent_types> { + using parent_types = typename T::all_parent_types; +}; + +/** + * @brief for given polymorphic component type returns entt::type_list of all parent types, + * for non polymorphic type will return empty list + * @tparam T type to get parents from + */ +template +using poly_parent_types_t = typename poly_parent_types::parent_types; + + +/** + * @brief for given type, detects, if it was declared polymorphic. Type considered polymorphic, + * if it was either: + * - inherited from entt::inherit + * - declared types direct_parent_types or all_parent_types + * - for this type there is specialization of either entt::poly_direct_parent_types or entt::poly_parent_types + * @tparam T type to check + */ +template +struct is_poly_type { + static constexpr bool value = true; +}; + +/** @copydoc is_poly_type */ +template +struct is_poly_type::not_redefined_tag, typename poly_parent_types::not_redefined_tag>> { + static constexpr bool value = false; +}; + +/** @copydoc is_poly_type */ +template +static constexpr bool is_poly_type_v = is_poly_type::value; + +/** + * @brief used to inherit from all given parent types and declare inheriting type polymorphic with given direct parents. + * All parent types are required to be polymorphic + * @code{.cpp} + * struct A : public entt::inherit<> {}; // base polymorphic type with no parents + * struct B : public entt::inherit {}; // B inherits A, and declared as polymorphic component with direct parents {A} + * struct C : public entt::inherit {}; // C inherits B, and now has direct parents {B} and all parents {A, B} + * @endcode + * @tparam Parents list of parent types + */ +template +struct inherit : public Parents... { + static_assert((is_poly_type_v && ...), "entt::inherit must be used only with polymorphic types"); + using direct_parent_types = type_list; +}; + +/** + * @brief TODO + */ +template +struct poly_all { + static_assert(is_poly_type_v, "entt::poly_all must be used only with polymorphic types"); + using type = T; + using poly_all_tag = void; +}; + +/** + * @brief TODO + */ +template +struct poly_any { + static_assert(is_poly_type_v, "entt::poly_any must be used only with polymorphic types"); + using type = T; + using poly_any_tag = void; +}; + +} // entt + +#endif // ENTT_ENTITY_POLY_TYPE_TRAITS_HPP diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 04199aced7..ea9e1b2bea 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -3,6 +3,9 @@ #include "../core/type_info.hpp" #include "../core/type_traits.hpp" +#include "fwd.hpp" +#include "poly_type_traits.hpp" +#include "poly_storage_mixin.hpp" /** @@ -142,149 +145,8 @@ class poly_components_iterator { * @endcond */ - namespace entt { -/** - * @brief declares direct parent types of polymorphic component type. - * By default it uses the list from T::direct_parent_types, if it present, otherwise empty list is used. - * All parent types must be declared polymorphic. - * @code{.cpp} - * struct A {}; - * struct B : A {}; - * - * struct entt::poly_direct_parent_types { - * using parent_types = entt::type_list<>; // declares A as polymorphic type with no parents - * } - * struct entt::poly_direct_parent_types { - * using parent_types = entt::type_list; // declares B as polymorphic type with parent A - * } - * @endcode - * @tparam T polymorphic component type - */ -template -struct poly_direct_parent_types { - /** @brief entt::type_list of direct parent types */ - using parent_types = type_list<>; - - /** @brief used to detect, if this template was specialized for a type */ - using not_redefined_tag = void; -}; - -/** @copydoc poly_direct_parent_types */ -template -struct poly_direct_parent_types> { - using parent_types = typename T::direct_parent_types; -}; - -/** - * @brief for given polymorphic component type returns entt::type_list of direct parent types, - * for non polymorphic type will return empty list - * @tparam T type to get parents from - */ -template -using poly_direct_parent_types_t = typename poly_direct_parent_types::parent_types; - -/** - * @brief declares list of all parent types of polymorphic component type. - * By default will concatenates list of all direct parent types and all lists of all parents for each parent type. All parent - * types must be declared polymorphic. - * @tparam T - */ -template -struct poly_parent_types { -private: - template - struct all_parent_types; - - template - struct all_parent_types> { - using types = type_list_cat_t, typename poly_parent_types::parent_types...>; - }; - -public: - /** @brief entt::type_list of all parent types */ - using parent_types = typename all_parent_types>::types; - - /** @brief used to detect, if this template was specialized for a type */ - using not_redefined_tag = void; -}; - -/** @copydoc poly_parent_types */ -template -struct poly_parent_types> { - using parent_types = typename T::all_parent_types; -}; - -/** - * @brief for given polymorphic component type returns entt::type_list of all parent types, - * for non polymorphic type will return empty list - * @tparam T type to get parents from - */ -template -using poly_parent_types_t = typename poly_parent_types::parent_types; - - -/** - * @brief for given type, detects, if it was declared polymorphic. Type considered polymorphic, - * if it was either: - * - inherited from entt::inherit - * - declared types direct_parent_types or all_parent_types - * - for this type there is specialization of either entt::poly_direct_parent_types or entt::poly_parent_types - * @tparam T type to check - */ -template -struct is_poly_type { - static constexpr bool value = true; -}; - -/** @copydoc is_poly_type */ -template -struct is_poly_type::not_redefined_tag, typename poly_parent_types::not_redefined_tag>> { - static constexpr bool value = false; -}; - -/** @copydoc is_poly_type */ -template -static constexpr bool is_poly_type_v = is_poly_type::value; - -/** - * @brief used to inherit from all given parent types and declare inheriting type polymorphic with given direct parents. - * All parent types are required to be polymorphic - * @code{.cpp} - * struct A : public entt::inherit<> {}; // base polymorphic type with no parents - * struct B : public entt::inherit {}; // B inherits A, and declared as polymorphic component with direct parents {A} - * struct C : public entt::inherit {}; // C inherits B, and now has direct parents {B} and all parents {A, B} - * @endcode - * @tparam Parents list of parent types - */ -template -struct inherit : public Parents... { - static_assert((is_poly_type_v && ...), "entt::inherit must be used only with polymorphic types"); - using direct_parent_types = type_list; -}; - -/** - * @brief TODO - */ -template -struct poly_all { - static_assert(is_poly_type_v, "entt::poly_all must be used only with polymorphic types"); - using type = T; - using poly_all_tag = void; -}; - -/** - * @brief TODO - */ -template -struct poly_any { - static_assert(is_poly_type_v, "entt::poly_any must be used only with polymorphic types"); - using type = T; - using poly_any_tag = void; -}; - - /** @brief base class for entt::poly_pool_holder */ template class poly_pool_holder_base { @@ -529,43 +391,6 @@ class poly_types_data { }; - -/** - * @brief Storage mixin for polymorphic component types - * @tparam Storage - */ -template -class poly_storage_mixin; - -/** @copydoc poly_storage_mixin */ -template -class poly_storage_mixin: public Storage { - using component_type = typename Storage::value_type; - using entity_type = typename Storage::entity_type; - - using Storage::Storage; - - void bind(any value) ENTT_NOEXCEPT override { - if(auto *reg = any_cast>(&value); reg) { - register_for_all_parent_types(*reg, poly_parent_types_t{}); - } - } - - template - void add_self_for_type(basic_registry& reg) { - reg.poly_data().template assure().bind_child_storage(this); - } - - template - void register_for_all_parent_types(basic_registry& reg, [[maybe_unused]] type_list) { - (add_self_for_type(reg), ...); - add_self_for_type(reg); - } - - template - friend class poly_storage_mixin; -}; - /** * @brief storage_traits template specialization for polymorphic component types * @tparam Entity entity type @@ -584,8 +409,9 @@ struct storage_traits>> { }; using guarded_type = typename parent_guard>::type; + public: - using storage_type = poly_storage_mixin>; + using storage_type = poly_storage_mixin, Entity, guarded_type>; }; } // namespace entt diff --git a/test/playground.cpp b/test/playground.cpp index 1c2b7928fb..22bb3a42c2 100644 --- a/test/playground.cpp +++ b/test/playground.cpp @@ -30,11 +30,27 @@ struct entt::poly_parent_types { using parent_types = type_list; }; +void on_construct(entt::registry&, entt::entity e) { + std::cout << "constructed " << entt::to_entity(e) << "\n"; +} + +void on_update(entt::registry&, entt::entity e) { + std::cout << "updated " << entt::to_entity(e) << "\n"; +} + +void on_destroy(entt::registry&, entt::entity e) { + std::cout << "destroyed " << entt::to_entity(e) << "\n"; +} + int main() { entt::registry registry; const auto entity = registry.create(); const auto other = registry.create(); + registry.on_construct().connect(); + registry.on_update().connect(); + registry.on_destroy().connect(); + registry.emplace(entity); registry.emplace(entity); registry.emplace(entity, new cat); @@ -71,4 +87,7 @@ int main() { a->name(); std::cout << '\n'; } + + registry.patch(entity); + registry.poly_remove(entity); } \ No newline at end of file From d08c3030779b8609869b15a8e493c75b26a4cb9a Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sun, 10 Apr 2022 22:26:17 +0300 Subject: [PATCH 10/27] added new header files to cmake --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fd853cc52..85dd1de45b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,8 @@ if(ENTT_INCLUDE_HEADERS) $ $ $ + $ + $ $ $ $ From 7fd0ad7b0eb554b70f53806c5ee2d4872e3d70f6 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sun, 10 Apr 2022 23:35:37 +0300 Subject: [PATCH 11/27] fixed includes --- src/entt/entity/poly_storage_mixin.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp index 3bae2d2105..fa198c358f 100644 --- a/src/entt/entity/poly_storage_mixin.hpp +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -2,6 +2,8 @@ #define ENTT_ENTITY_POLY_STORAGE_MIXIN_HPP #include "storage.hpp" +#include "poly_type_traits.hpp" + namespace entt { From df4271aae507275d908648fa9415be754a046b7b Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Thu, 14 Apr 2022 16:39:22 +0300 Subject: [PATCH 12/27] replaced poly_types_data with poly_types_accessor, moved poly algorithms out of the registry --- src/entt/entity/poly_storage_mixin.hpp | 5 +- src/entt/entity/polymorphic.hpp | 184 ++++++++++++++++++------- src/entt/entity/registry.hpp | 86 ------------ test/playground.cpp | 18 +-- 4 files changed, 144 insertions(+), 149 deletions(-) diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp index fa198c358f..21cfa00d7b 100644 --- a/src/entt/entity/poly_storage_mixin.hpp +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -7,6 +7,9 @@ namespace entt { +template +class poly_type; + /** * @brief used to add signal support for polymorphic storages * @tparam Entity storage entity type @@ -210,7 +213,7 @@ class poly_storage_mixin : public Storage, public poly_sigh_holder template void add_self_for_type(basic_registry& reg) { - reg.poly_data().template assure().bind_child_storage(this); + reg.ctx().template emplace>().bind_child_storage(this); } template diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index ea9e1b2bea..914e4f0029 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -145,6 +145,7 @@ class poly_components_iterator { * @endcond */ + namespace entt { /** @brief base class for entt::poly_pool_holder */ @@ -162,15 +163,6 @@ class poly_pool_holder_base { bool (*remover_ptr)(void*, Entity); }; -/** @brief base class for entt::poly_type */ -template -class poly_type_base { -protected: - using child_pools_container = std::vector>; - - child_pools_container child_pool_holders{}; -}; - /** * @brief Holds pointer to child type storage and a function to convert it into parent type * @tparam Entity underlying entity type @@ -229,7 +221,7 @@ class poly_pool_holder : public poly_pool_holder_base { * @tparam Entity */ template -class poly_type : public poly_type_base { +class poly_type { /** @brief internally used to convert base_poly_pool_holder to a pool_poly_holder during the iteration */ struct cast_pool_holder { auto& operator()(poly_pool_holder_base& holder) { @@ -247,7 +239,7 @@ class poly_type : public poly_type_base { /** @brief component type */ using value_type = Type; /** @brief type of the underlying pool container */ - using pools_container = typename poly_type_base::child_pools_container; + using pools_container = std::vector>; /** @brief pool iterator type */ using pools_iterator = internal::converting_iterator; /** @brief const pool iterator type */ @@ -333,62 +325,149 @@ class poly_type : public poly_type_base { auto end = const_pools_iterator(this->child_pool_holders.cend()); return { const_component_iterator(ent, begin, end), const_component_iterator(ent, end, end) }; } + +private: + pools_container child_pool_holders{}; }; + /** - * @brief Holds all data of all poly types in this registry + * @brief Provides access of runtime polymorphic type data. Allows user to create specializations + * to store polymorphic type data separately from the registry + * Must specialize assure() method, where Type is poly_type + * @tparam PolyTypesData underlying polymorphic types data storage type + */ +template +struct poly_types_accessor; + +/** + * poly_types_accessor specialisation to access runtime polymorphic type data, stored in the registry context * @tparam Entity */ template -class poly_types_data { +struct poly_types_accessor> { /** - * @brief converts const T* to T* const, used in assert, - * because first one looks much more intuitive, when the second is identical to const T for value types, but for pointers + * @tparam T polymorphic type + * @return poly_type for given type */ template - using sanitize_poly_type_t = std::conditional_t, - constness_as_t>*, std::remove_pointer_t>, T>; - -public: - /** - * @param id type id of polymorphic type - * @return poly_type for given type id - */ - inline auto& assure(const id_type id) { - return types[id]; + static inline decltype(auto) assure(basic_registry& reg) { + return reg.ctx().template emplace(); } +}; - /** @copydoc assure */ - inline const auto& assure(const id_type id) const { - if(const auto it = types.find(id); it != types.cend()) { - return static_cast &>(*it->second); - } - static poly_type_base placeholder{}; - return placeholder; +/** + * Converts const T* to T* const, used in assure_poly_type, because first one looks much more intuitive, + * when the second is identical to const T for value types, but for pointers + */ +template +using sanitize_poly_type_t = std::conditional_t && !std::is_const_v, + constness_as_t>*, std::remove_pointer_t>, T>; + +/** + * @brief Assures runtime polymorphic type data for a given entity and component types. + * @tparam Entity entity type + * @tparam Component polymorphic component type + * @tparam PolyTypesData underlying runtime polymorphic types data storage type + * @param data runtime polymorphic types data + * @return reference to poly_type, keeps const qualifiers both for Component and PolyData + */ +template +[[nodiscard]] decltype(auto) assure_poly_type(PolyTypesData& data) { + using type = sanitize_poly_type_t; + using no_const_type = std::remove_const_t; + static_assert(is_poly_type_v, "must be a polymorphic type"); + + using result_type = poly_type; + result_type& result = poly_types_accessor::template assure(const_cast&>(data)); + if constexpr(std::is_const_v || std::is_const_v) { + return const_cast(result); + } else { + return result; } +} - /** - * @tparam T polymorphic type - * @return poly_type for given type - */ - template - inline decltype(auto) assure() { - using type = sanitize_poly_type_t; - using no_const_type = std::remove_const_t; - static_assert(is_poly_type_v); - return static_cast, type>&>(assure(type_id().hash())); +} // namespace entt + + +namespace entt::algorithm { + +/** + * @brief For given polymorphic component type iterate over all child instances of it, attached to a given entity + * @tparam Component Polymorphic component type + * @param entity Entity, to get components from + * @return Iterable to iterate each component + */ +template +[[nodiscard]] decltype(auto) poly_get_all(basic_registry& reg, [[maybe_unused]] const Entity entity) { + ENTT_ASSERT(reg.valid(entity), "Invalid entity"); + return assure_poly_type(reg).each(entity); +} + +/** + * @brief For given polymorphic component type find and return any child instance of this type, attached to a given entity + * @tparam Component Polymorphic component type + * @param entity Entity, to get components from + * @return Pointer to attached component or nullptr, if none attached. NOTE: will return pointer type polymorphic components by value (as a single pointer) + */ +template +[[nodiscard]] decltype(auto) poly_get_any(basic_registry& reg, [[maybe_unused]] const Entity entity) { + auto all = poly_get_all(reg, entity); + return all.begin() != all.end() ? all.begin().operator->() : nullptr; +} + +/** + * @brief For given polymorphic component type remove all child instances of this type, attached to a given entity + * @tparam Component Polymorphic component type + * @param entity Entity, to remove components from + * @return count of removed components + */ +template +int poly_remove(basic_registry& reg, [[maybe_unused]] const Entity entity) { + ENTT_ASSERT(reg.valid(entity), "Invalid entity"); + int removed_count = 0; + for (auto& pool : assure_poly_type(reg).pools()) { + removed_count += static_cast(pool.remove(entity)); } + return removed_count; +} - /** @copydoc assure */ - template - inline const auto& assure() const { - using no_const_type = std::remove_const_t>; - static_assert(is_poly_type_v); - return static_cast&>(assure(type_id().hash())); +/** + * @brief For a given component type applies given func to all child instances of this type in registry. + * @tparam Component polymorphic component type + * @tparam Entity entity type of underlying registry + * @tparam Func type of given function + * @param reg registry to operate on + * @param func function to call for each component, parameters are (entity, component&) or only one of them, or even none. Note: for pointer type components the component parameter is a value instead of value (single pointer) + */ +template +void each_poly(basic_registry& reg, Func func) { + for (auto& pool : assure_poly_type(reg).pools()) { + for (auto& ent : pool.pool()) { + if constexpr(std::is_invocable_v) { + auto ptr = pool.try_get(ent); + if constexpr(std::is_pointer_v) { + func(ent, ptr); + } else { + func(ent, *ptr); + } + } else if constexpr(std::is_invocable_v) { + auto ptr = pool.try_get(ent); + if constexpr(std::is_pointer_v) { + func(ptr); + } else { + func(*ptr); + } + } else if constexpr(std::is_invocable_v) { + func(ent); + } else { + func(); + } + } } -private: - dense_map, identity> types{}; -}; +} + +} // namespace entt::algorithm /** @@ -397,7 +476,7 @@ class poly_types_data { * @tparam Type polymorphic component type */ template -struct storage_traits>> { +struct entt::storage_traits>> { template struct parent_guard; @@ -414,6 +493,5 @@ struct storage_traits>> { using storage_type = poly_storage_mixin, Entity, guarded_type>; }; -} // namespace entt #endif // ENTT_ENTITY_POLYMORPHIC_HPP diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index b4ecf65dd7..358bf14b4a 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -1021,78 +1021,6 @@ class basic_registry { return view().template get(entity); } - /** - * @brief For given polymorphic component type iterate over all child instances of it, attached to a given entity - * @tparam Component Polymorphic component type - * @param entity Entity, to get components from - * @return Iterable to iterate each component - */ - template - [[nodiscard]] decltype(auto) poly_get_all([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - return polymorphic_data.template assure().each(entity); - } - - /** - * @brief For given polymorphic component type find and return any child instance of this type, attached to a given entity - * @tparam Component Polymorphic component type - * @param entity Entity, to get components from - * @return Pointer to attached component or nullptr, if none attached. NOTE: will return pointer type polymorphic components by value (as a single pointer) - */ - template - [[nodiscard]] decltype(auto) poly_get_any([[maybe_unused]] const entity_type entity) { - auto all = poly_get_all(entity); - return all.begin() != all.end() ? all.begin().operator->() : nullptr; - } - /** - * @brief For given polymorphic component type remove all child instances of this type, attached to a given entity - * @tparam Component Polymorphic component type - * @param entity Entity, to remove components from - * @return count of removed components - */ - template - int poly_remove([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - int removed_count = 0; - for (auto& pool : polymorphic_data.template assure().pools()) { - removed_count += static_cast(pool.remove(entity)); - } - return removed_count; - } - - /** - * @brief For a given component type applies given func to all child instances of this type in registry. - * @tparam Component polymorphic component type - * @tparam Func type of given function - * @param func function to call for each component, parameters are (entity, component&) or only one of them, or even none. Note: for pointer type components the component parameter is a value instead of value (single pointer) - */ - template - void each_poly(Func func) { - for (auto& pool : polymorphic_data.template assure().pools()) { - for (auto& ent : pool.pool()) { - if constexpr(std::is_invocable_v) { - auto ptr = pool.try_get(ent); - if constexpr(std::is_pointer_v) { - func(ent, ptr); - } else { - func(ent, *ptr); - } - } else if constexpr(std::is_invocable_v) { - auto ptr = pool.try_get(ent); - if constexpr(std::is_pointer_v) { - func(ptr); - } else { - func(*ptr); - } - } else if constexpr(std::is_invocable_v) { - func(ent); - } else { - func(); - } - } - } - } - /** * @brief Returns a reference to the given component for an entity. * @@ -1539,26 +1467,12 @@ class basic_registry { return vars; } - /** - * @brief Returns entt::poly_types_data object, that holds all information about polymorphic types in this registry - * @return object, that holds information about all polymorphic types in this registry - */ - auto& poly_data() ENTT_NOEXCEPT { - return polymorphic_data; - } - - /** @copydoc poly_data */ - [[nodiscard]] const auto& poly_data() const ENTT_NOEXCEPT { - return polymorphic_data; - } - private: dense_map, identity> pools; std::vector groups; std::vector epool; entity_type free_list; context vars; - poly_types_data polymorphic_data; }; } // namespace entt diff --git a/test/playground.cpp b/test/playground.cpp index 22bb3a42c2..7abaff2d35 100644 --- a/test/playground.cpp +++ b/test/playground.cpp @@ -47,9 +47,9 @@ int main() { const auto entity = registry.create(); const auto other = registry.create(); - registry.on_construct().connect(); - registry.on_update().connect(); - registry.on_destroy().connect(); +// registry.on_construct().connect(); +// registry.on_update().connect(); +// registry.on_destroy().connect(); registry.emplace(entity); registry.emplace(entity); @@ -59,35 +59,35 @@ int main() { registry.emplace(other, new dog); std::cout << "\nall shapes\n"; - registry.each_poly([](auto ent, auto& s) { + entt::algorithm::each_poly(registry, [](auto ent, auto& s) { std::cout << entt::to_entity(ent) << " -> "; s.draw(); std::cout << '\n'; }); std::cout << "\nall shapes for entity " << entt::to_entity(entity) << "\n"; - for ( shape& s : registry.poly_get_all< shape>(entity)) { + for ( shape& s : entt::algorithm::poly_get_all< shape>(registry, entity)) { s.draw(); std::cout << '\n'; } std::cout << "any shape for entity " << entt::to_entity(entity) << " "; - registry.poly_get_any(entity)->draw(); + entt::algorithm::poly_get_any(registry, entity)->draw(); std::cout << '\n'; std::cout << "\nall animals\n"; - registry.each_poly([](auto ent, const animal* a) { + entt::algorithm::each_poly(registry, [](auto ent, const animal* a) { std::cout << entt::to_entity(ent) << " -> "; a->name(); std::cout << '\n'; }); std::cout << "\nall animals for entity " << entt::to_entity(entity) << "\n"; - for (const animal* a : registry.poly_get_all(entity)) { + for (const animal* a : entt::algorithm::poly_get_all(registry, entity)) { a->name(); std::cout << '\n'; } registry.patch(entity); - registry.poly_remove(entity); + entt::algorithm::poly_remove(registry, entity); } \ No newline at end of file From b77a527e13b1d9fa1b2bd5c86e40240d3388e59b Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Fri, 15 Apr 2022 11:22:55 +0300 Subject: [PATCH 13/27] separated poly algorithms from registry type, some cleanup and polishing --- src/entt/entity/polymorphic.hpp | 99 +++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 914e4f0029..44c6b10d12 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -332,32 +332,45 @@ class poly_type { /** - * @brief Provides access of runtime polymorphic type data. Allows user to create specializations - * to store polymorphic type data separately from the registry - * Must specialize assure() method, where Type is poly_type - * @tparam PolyTypesData underlying polymorphic types data storage type + * @brief Provides access of runtime polymorphic type data from the underlying pools holder type. + * Allows user to create specializations to store polymorphic type data separately from the registry. + * + * The poly_types_accessor specialization must define:
+ * - Type& assure(PolyPoolsHolder&) method, it must assure and return instance of @b Type stored given @b PolyPoolsHolder
+ * - holder_type - same as PolyPoolsHolder
+ * - entity_type - underlying entity type
+ * + * @tparam PolyPoolsHolder Underlying polymorphic types data holder */ -template +template struct poly_types_accessor; /** - * poly_types_accessor specialisation to access runtime polymorphic type data, stored in the registry context + * poly_types_accessor specialisation to access polymorphic data, stored in the registry context * @tparam Entity */ template struct poly_types_accessor> { + /** @brief Underlying polymorphic types data holder */ + using holder_type = basic_registry; + + /** @brief Underlying entity type */ + using entity_type = Entity; + /** - * @tparam T polymorphic type - * @return poly_type for given type + * @brief Assures and returns instance of some type stored given polymorphic types data holder + * @tparam Type Default-constructed type to assure in the underlying data holder and return + * @param holder Polymorphic types data holder reference + * @return */ - template - static inline decltype(auto) assure(basic_registry& reg) { - return reg.ctx().template emplace(); + template + static inline decltype(auto) assure(basic_registry& holder) { + return holder.ctx().template emplace(); } }; /** - * Converts const T* to T* const, used in assure_poly_type, because first one looks much more intuitive, + * @brief Converts const T* to T* const, used in assure_poly_type, because first one looks much more intuitive, * when the second is identical to const T for value types, but for pointers */ template @@ -365,22 +378,21 @@ using sanitize_poly_type_t = std::conditional_t && !std::is constness_as_t>*, std::remove_pointer_t>, T>; /** - * @brief Assures runtime polymorphic type data for a given entity and component types. - * @tparam Entity entity type - * @tparam Component polymorphic component type - * @tparam PolyTypesData underlying runtime polymorphic types data storage type - * @param data runtime polymorphic types data - * @return reference to poly_type, keeps const qualifiers both for Component and PolyData + * @brief Assures runtime polymorphic type data for a given component types in the given polymorphic data holder + * @tparam Component Polymorphic component type to assure + * @tparam PolyPoolsHolder Polymorphic types data holder type + * @param holder Polymorphic types data holder to operate on + * @return Reference to poly_type, keeps const qualifiers both for Component and PolyPoolsHolder */ -template -[[nodiscard]] decltype(auto) assure_poly_type(PolyTypesData& data) { +template +[[nodiscard]] decltype(auto) assure_poly_type(PolyPoolsHolder& holder) { using type = sanitize_poly_type_t; using no_const_type = std::remove_const_t; static_assert(is_poly_type_v, "must be a polymorphic type"); - using result_type = poly_type; - result_type& result = poly_types_accessor::template assure(const_cast&>(data)); - if constexpr(std::is_const_v || std::is_const_v) { + using result_type = poly_type; + result_type& result = poly_types_accessor::template assure(const_cast&>(holder)); + if constexpr(std::is_const_v || std::is_const_v) { return const_cast(result); } else { return result; @@ -395,23 +407,24 @@ namespace entt::algorithm { /** * @brief For given polymorphic component type iterate over all child instances of it, attached to a given entity * @tparam Component Polymorphic component type + * @param reg Registry, or any other polymorphic data holder to operate on * @param entity Entity, to get components from * @return Iterable to iterate each component */ -template -[[nodiscard]] decltype(auto) poly_get_all(basic_registry& reg, [[maybe_unused]] const Entity entity) { - ENTT_ASSERT(reg.valid(entity), "Invalid entity"); - return assure_poly_type(reg).each(entity); +template +[[nodiscard]] decltype(auto) poly_get_all(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { + return assure_poly_type(reg).each(entity); } /** * @brief For given polymorphic component type find and return any child instance of this type, attached to a given entity * @tparam Component Polymorphic component type + * @param reg Registry, or any other polymorphic data holder to operate on * @param entity Entity, to get components from * @return Pointer to attached component or nullptr, if none attached. NOTE: will return pointer type polymorphic components by value (as a single pointer) */ -template -[[nodiscard]] decltype(auto) poly_get_any(basic_registry& reg, [[maybe_unused]] const Entity entity) { +template +[[nodiscard]] decltype(auto) poly_get_any(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { auto all = poly_get_all(reg, entity); return all.begin() != all.end() ? all.begin().operator->() : nullptr; } @@ -419,14 +432,14 @@ template /** * @brief For given polymorphic component type remove all child instances of this type, attached to a given entity * @tparam Component Polymorphic component type + * @param reg Registry, or any other polymorphic data holder to operate on * @param entity Entity, to remove components from - * @return count of removed components + * @return Count of removed components */ -template -int poly_remove(basic_registry& reg, [[maybe_unused]] const Entity entity) { - ENTT_ASSERT(reg.valid(entity), "Invalid entity"); +template +int poly_remove(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { int removed_count = 0; - for (auto& pool : assure_poly_type(reg).pools()) { + for (auto& pool : assure_poly_type(reg).pools()) { removed_count += static_cast(pool.remove(entity)); } return removed_count; @@ -434,15 +447,17 @@ int poly_remove(basic_registry& reg, [[maybe_unused]] const Entity entit /** * @brief For a given component type applies given func to all child instances of this type in registry. - * @tparam Component polymorphic component type - * @tparam Entity entity type of underlying registry - * @tparam Func type of given function - * @param reg registry to operate on - * @param func function to call for each component, parameters are (entity, component&) or only one of them, or even none. Note: for pointer type components the component parameter is a value instead of value (single pointer) + * @tparam Component Polymorphic component type + * @tparam PolyPoolsHolder Entity type of underlying registry + * @tparam Entity Entity type of underlying registry + * @tparam Func Type of given function + * @param reg Registry, or any other polymorphic data holder to operate on + * @param func Function to call for each component, parameters are (entity, component&) or only one of them, or even none. + * Note: for pointer type components (T*) the component parameter is its value (T*) instead of pointer to value (T**) */ -template -void each_poly(basic_registry& reg, Func func) { - for (auto& pool : assure_poly_type(reg).pools()) { +template +void each_poly(PolyPoolsHolder& reg, Func func) { + for (auto& pool : assure_poly_type(reg).pools()) { for (auto& ent : pool.pool()) { if constexpr(std::is_invocable_v) { auto ptr = pool.try_get(ent); From 17d39b7f8ff4153aa5a4a4ffd68941a07a3291e3 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Fri, 15 Apr 2022 16:18:27 +0300 Subject: [PATCH 14/27] cleaned up poly_storage_mixin, using default poly_sigh_mixin for signal handling, template to validate poly types --- src/entt/entity/poly_storage_mixin.hpp | 207 +------------------------ src/entt/entity/poly_type_traits.hpp | 44 +++--- src/entt/entity/polymorphic.hpp | 21 +-- test/playground.cpp | 6 +- 4 files changed, 37 insertions(+), 241 deletions(-) diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp index 21cfa00d7b..a952be642e 100644 --- a/src/entt/entity/poly_storage_mixin.hpp +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -3,6 +3,7 @@ #include "storage.hpp" #include "poly_type_traits.hpp" +#include "sigh_storage_mixin.hpp" namespace entt { @@ -10,136 +11,14 @@ namespace entt { template class poly_type; -/** - * @brief used to add signal support for polymorphic storages - * @tparam Entity storage entity type - * @tparam Type storage value type - */ -template -class poly_sigh_holder { -public: - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever a new instance is created and assigned to an entity.
- * Listeners are invoked after the object has been assigned to the entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_construct() ENTT_NOEXCEPT { - return sink{construction}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is explicitly updated.
- * Listeners are invoked after the object has been updated. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_update() ENTT_NOEXCEPT { - return sink{update}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is removed from an entity and thus destroyed.
- * Listeners are invoked before the object has been removed from the entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_destroy() ENTT_NOEXCEPT { - return sink{destruction}; - } - -private: - template - inline void publish_construction([[maybe_unused]] type_list, basic_registry& reg, const Entity ent) { - (reg.template storage().construction.publish(reg, ent), ...); - } - - inline void publish_construction(basic_registry& reg, const Entity ent) { - publish_construction(poly_parent_types_t{}, reg, ent); - publish_construction(type_list{}, reg, ent); - } - - template - inline void publish_update([[maybe_unused]] type_list, basic_registry& reg, const Entity ent) { - (reg.template storage().update.publish(reg, ent), ...); - } - - inline void publish_update(basic_registry& reg, const Entity ent) { - publish_update(poly_parent_types_t{}, reg, ent); - publish_update(type_list{}, reg, ent); - } - - template - inline void publish_destruction([[maybe_unused]] type_list, basic_registry& reg, const Entity ent) { - (reg.template storage().destruction.publish(reg, ent), ...); - } - - inline void publish_destruction(basic_registry& reg, const Entity ent) { - publish_destruction(poly_parent_types_t{}, reg, ent); - publish_destruction(type_list{}, reg, ent); - } - -private: - sigh&, const Entity)> construction{}; - sigh&, const Entity)> update{}; - sigh&, const Entity)> destruction{}; - - template - friend class poly_sigh_holder; - - template - friend class poly_storage_mixin; -}; - - /** * @brief Storage mixin for polymorphic component types * @tparam Storage underlying storage type * @tparam Entity entity type * @tparam Type value type */ -template -class poly_storage_mixin : public Storage, public poly_sigh_holder {template - void notify_destruction(typename Storage::basic_iterator first, typename Storage::basic_iterator last, Func func) { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - for(; first != last; ++first) { - const auto entt = *first; - this->publish_destruction(*owner, entt); - const auto it = Storage::find(entt); - func(it, it + 1u); - } - } - - void swap_and_pop(typename Storage::basic_iterator first, typename Storage::basic_iterator last) final { - notify_destruction(std::move(first), std::move(last), [this](auto... args) { Storage::swap_and_pop(args...); }); - } - - void in_place_pop(typename Storage::basic_iterator first, typename Storage::basic_iterator last) final { - notify_destruction(std::move(first), std::move(last), [this](auto... args) { Storage::in_place_pop(args...); }); - } - - typename Storage::basic_iterator try_emplace(const typename Storage::entity_type entt, const bool force_back, const void *value) final { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - Storage::try_emplace(entt, force_back, value); - this->publish_construction(*owner, entt); - return Storage::find(entt); - } - +template +class poly_storage_mixin : public Storage { public: /*! @brief Underlying value type. */ using value_type = typename Storage::value_type; @@ -149,56 +28,6 @@ class poly_storage_mixin : public Storage, public poly_sigh_holder /*! @brief Inherited constructors. */ using Storage::Storage; - /** - * @brief Assigns entities to a storage. - * @tparam Args Types of arguments to use to construct the object. - * @param entt A valid identifier. - * @param args Parameters to use to initialize the object. - * @return A reference to the newly created object. - */ - template - decltype(auto) emplace(const entity_type entt, Args &&...args) { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - Storage::emplace(entt, std::forward(args)...); - this->publish_construction(*owner, entt); - return this->get(entt); - } - - /** - * @brief Patches the given instance for an entity. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid identifier. - * @param func Valid function objects. - * @return A reference to the patched instance. - */ - template - decltype(auto) patch(const entity_type entt, Func &&...func) { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - Storage::patch(entt, std::forward(func)...); - this->publish_update(*owner, entt); - return this->get(entt); - } - - /** - * @brief Assigns entities to a storage. - * @tparam It Type of input iterator. - * @tparam Args Types of arguments to use to construct the objects assigned - * to the entities. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param args Parameters to use to initialize the objects assigned to the - * entities. - */ - template - void insert(It first, It last, Args &&...args) { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - Storage::insert(first, last, std::forward(args)...); - - for(auto it = last; it != last; ++it) { - publish_construction(*owner, *it); - } - } - /** * @brief Forwards variables to mixins, if any. * @param value A variable wrapped in an opaque container. @@ -206,43 +35,23 @@ class poly_storage_mixin : public Storage, public poly_sigh_holder void bind(any value) ENTT_NOEXCEPT override { if(auto *reg = any_cast>(&value); reg) { owner = reg; - register_for_all_parent_types(*reg, poly_parent_types_t{}); + bind_all_parent_types(*reg, poly_parent_types_t{}); } Storage::bind(std::move(value)); } - template - void add_self_for_type(basic_registry& reg) { - reg.ctx().template emplace>().bind_child_storage(this); - } - +private: template - void register_for_all_parent_types(basic_registry& reg, [[maybe_unused]] type_list) { - (add_self_for_type(reg), ...); - add_self_for_type(reg); + void bind_all_parent_types(basic_registry& reg, [[maybe_unused]] type_list) { + (reg.ctx().template emplace>().bind_child_storage(this), ...); + reg.ctx().template emplace>().bind_child_storage(this); } - template - friend class poly_storage_mixin; - private: basic_registry *owner{}; }; -/** @copydoc poly_storage_mixin */ -template -class poly_storage_mixin && std::is_move_assignable_v)>>: - public basic_sparse_set, public poly_sigh_holder { - -public: - using base_type = basic_sparse_set; - using entity_type = Entity; - using value_type = Type; - - poly_storage_mixin() : base_type(type_id()) {}; -}; - } // entt #endif // ENTT_ENTITY_POLY_STORAGE_MIXIN_HPP diff --git a/src/entt/entity/poly_type_traits.hpp b/src/entt/entity/poly_type_traits.hpp index d20d969746..03f92a0a7c 100644 --- a/src/entt/entity/poly_type_traits.hpp +++ b/src/entt/entity/poly_type_traits.hpp @@ -7,6 +7,10 @@ namespace entt { +/** @brief Validates a polymorphic type and returns it unchanged */ +template +struct poly_type_validate; + /** * @brief declares direct parent types of polymorphic component type. * By default it uses the list from T::direct_parent_types, if it present, otherwise empty list is used. @@ -110,6 +114,23 @@ struct is_poly_type::not_red template static constexpr bool is_poly_type_v = is_poly_type::value; +/** @copydoc poly_type_validate */ +template +struct poly_type_validate> { + static_assert(std::is_same_v, T>, "only decayed types allowed to be declared as polymorphic"); + static_assert(is_poly_type_v, "validating non-polymorphic type (probably some polymorphic type inherits type, that was not declared polymorphic)"); + static_assert((is_poly_type_v && ...), "all parent types of a polymorphic type must be also polymorphic"); + static_assert((!std::is_pointer_v> && ... && !std::is_pointer_v>), "double pointers are not allowed as a polymorphic components"); + static_assert(((std::is_pointer_v == std::is_pointer_v) && ...), "you cannot mix pointer-based and value-based polymorphic components inside one hierarchy"); + + /** @brief same input type, but validated */ + using type = T; +}; + +/** @copydoc poly_type_validate */ +template +using poly_type_validate_t = typename poly_type_validate>::type; + /** * @brief used to inherit from all given parent types and declare inheriting type polymorphic with given direct parents. * All parent types are required to be polymorphic @@ -121,31 +142,10 @@ static constexpr bool is_poly_type_v = is_poly_type::value; * @tparam Parents list of parent types */ template -struct inherit : public Parents... { - static_assert((is_poly_type_v && ...), "entt::inherit must be used only with polymorphic types"); +struct inherit : public poly_type_validate_t... { using direct_parent_types = type_list; }; -/** - * @brief TODO - */ -template -struct poly_all { - static_assert(is_poly_type_v, "entt::poly_all must be used only with polymorphic types"); - using type = T; - using poly_all_tag = void; -}; - -/** - * @brief TODO - */ -template -struct poly_any { - static_assert(is_poly_type_v, "entt::poly_any must be used only with polymorphic types"); - using type = T; - using poly_any_tag = void; -}; - } // entt #endif // ENTT_ENTITY_POLY_TYPE_TRAITS_HPP diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 44c6b10d12..6be1a378ff 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -374,7 +374,7 @@ struct poly_types_accessor> { * when the second is identical to const T for value types, but for pointers */ template -using sanitize_poly_type_t = std::conditional_t && !std::is_const_v, +using poly_type_sanitize_t = std::conditional_t && !std::is_const_v, constness_as_t>*, std::remove_pointer_t>, T>; /** @@ -386,8 +386,8 @@ using sanitize_poly_type_t = std::conditional_t && !std::is */ template [[nodiscard]] decltype(auto) assure_poly_type(PolyPoolsHolder& holder) { - using type = sanitize_poly_type_t; - using no_const_type = std::remove_const_t; + using type = poly_type_sanitize_t; + using no_const_type = poly_type_validate_t>; static_assert(is_poly_type_v, "must be a polymorphic type"); using result_type = poly_type; @@ -492,20 +492,7 @@ void each_poly(PolyPoolsHolder& reg, Func func) { */ template struct entt::storage_traits>> { - template - struct parent_guard; - - /** @brief used to assert, that all parent types of the component are polymorphic */ - template - struct parent_guard> { - static_assert((is_poly_type_v && ...), "all parents of polymorphic type must be also declared polymorphic"); - using type = T; - }; - - using guarded_type = typename parent_guard>::type; - -public: - using storage_type = poly_storage_mixin, Entity, guarded_type>; + using storage_type = sigh_storage_mixin>>>; }; diff --git a/test/playground.cpp b/test/playground.cpp index 7abaff2d35..3b6c512c6d 100644 --- a/test/playground.cpp +++ b/test/playground.cpp @@ -47,9 +47,9 @@ int main() { const auto entity = registry.create(); const auto other = registry.create(); -// registry.on_construct().connect(); -// registry.on_update().connect(); -// registry.on_destroy().connect(); + registry.on_construct().connect(); + registry.on_update().connect(); + registry.on_destroy().connect(); registry.emplace(entity); registry.emplace(entity); From ca6f502519e87fd84c95394915b8ed4e7be00134 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sun, 17 Apr 2022 13:53:13 +0300 Subject: [PATCH 15/27] tests, cleanup and poly_count function --- src/entt/entity/poly_storage_mixin.hpp | 2 +- src/entt/entity/poly_type_traits.hpp | 30 +- src/entt/entity/polymorphic.hpp | 42 ++- src/entt/entity/registry.hpp | 1 - src/entt/entt.hpp | 1 + test/CMakeLists.txt | 5 +- test/entt/common/polymorphic_type.hpp | 72 ++++ test/entt/entity/poly_type_traits.cpp | 70 ++++ test/entt/entity/polymorphic.cpp | 441 +++++++++++++++++++++++++ test/playground.cpp | 93 ------ 10 files changed, 643 insertions(+), 114 deletions(-) create mode 100644 test/entt/common/polymorphic_type.hpp create mode 100644 test/entt/entity/poly_type_traits.cpp create mode 100644 test/entt/entity/polymorphic.cpp delete mode 100644 test/playground.cpp diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp index a952be642e..2ef5937d37 100644 --- a/src/entt/entity/poly_storage_mixin.hpp +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -54,4 +54,4 @@ class poly_storage_mixin : public Storage { } // entt -#endif // ENTT_ENTITY_POLY_STORAGE_MIXIN_HPP +#endif diff --git a/src/entt/entity/poly_type_traits.hpp b/src/entt/entity/poly_type_traits.hpp index 03f92a0a7c..3bd8ca4458 100644 --- a/src/entt/entity/poly_type_traits.hpp +++ b/src/entt/entity/poly_type_traits.hpp @@ -12,7 +12,7 @@ template struct poly_type_validate; /** - * @brief declares direct parent types of polymorphic component type. + * @brief Declares direct parent types of polymorphic component type. * By default it uses the list from T::direct_parent_types, if it present, otherwise empty list is used. * All parent types must be declared polymorphic. * @code{.cpp} @@ -44,7 +44,7 @@ struct poly_direct_parent_types> }; /** - * @brief for given polymorphic component type returns entt::type_list of direct parent types, + * @brief For given polymorphic component type returns entt::type_list of direct parent types, * for non polymorphic type will return empty list * @tparam T type to get parents from */ @@ -52,7 +52,7 @@ template using poly_direct_parent_types_t = typename poly_direct_parent_types::parent_types; /** - * @brief declares list of all parent types of polymorphic component type. + * @brief Declares list of all parent types of polymorphic component type. * By default will concatenates list of all direct parent types and all lists of all parents for each parent type. All parent * types must be declared polymorphic. * @tparam T @@ -83,20 +83,18 @@ struct poly_parent_types> { }; /** - * @brief for given polymorphic component type returns entt::type_list of all parent types, + * @brief For given polymorphic component type returns entt::type_list of all parent types, * for non polymorphic type will return empty list * @tparam T type to get parents from */ template using poly_parent_types_t = typename poly_parent_types::parent_types; - /** - * @brief for given type, detects, if it was declared polymorphic. Type considered polymorphic, - * if it was either: - * - inherited from entt::inherit - * - declared types direct_parent_types or all_parent_types - * - for this type there is specialization of either entt::poly_direct_parent_types or entt::poly_parent_types + * @brief For a given type, detects, if it was declared polymorphic. Type considered polymorphic, if it was either:
+ * - inherited from entt::inherit
+ * - declared types direct_parent_types or all_parent_types
+ * - for this type there is specialization of either entt::poly_direct_parent_types or entt::poly_parent_types
* @tparam T type to check */ template @@ -132,7 +130,15 @@ template using poly_type_validate_t = typename poly_type_validate>::type; /** - * @brief used to inherit from all given parent types and declare inheriting type polymorphic with given direct parents. + * @brief Returns if one polymorphic component type is same, or is declared as a parent of another polymorphic type + * @tparam Parent Parent type + * @tparam Type Child Type + */ +template +constexpr bool is_poly_parent_of_v = is_poly_type_v && (type_list_contains_v, Parent> || std::is_same_v); + +/** + * @brief Used to inherit from all given parent types and declare inheriting type polymorphic with given direct parents. * All parent types are required to be polymorphic * @code{.cpp} * struct A : public entt::inherit<> {}; // base polymorphic type with no parents @@ -148,4 +154,4 @@ struct inherit : public poly_type_validate_t... { } // entt -#endif // ENTT_ENTITY_POLY_TYPE_TRAITS_HPP +#endif diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 6be1a378ff..0439e3b56a 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -374,8 +374,11 @@ struct poly_types_accessor> { * when the second is identical to const T for value types, but for pointers */ template -using poly_type_sanitize_t = std::conditional_t && !std::is_const_v, - constness_as_t>*, std::remove_pointer_t>, T>; +using poly_type_sanitize_t = std::conditional_t, + std::conditional_t, + std::remove_const_t>* const, // (const?) T* const + constness_as_t>*, std::remove_pointer_t>> // (const?) T* + , T>; // (const?) T /** * @brief Assures runtime polymorphic type data for a given component types in the given polymorphic data holder @@ -445,6 +448,37 @@ int poly_remove(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { return removed_count; } +/** +* @brief For given polymorphic component type count all child instances of this type, attached to a given entity +* @tparam Component Polymorphic component type +* @param reg Registry, or any other polymorphic data holder to operate on +* @param entity Entity, to count attached components +* @return Count of components, attached to a given entity + */ +template +size_t poly_count(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { + size_t count = 0; + for ([[maybe_unused]] auto& component : poly_get_all(reg, entity)) { + count++; + } + return count; +} + +/** +* @brief For given polymorphic component type count all child instances of this type +* @tparam Component Polymorphic component type +* @param reg Registry, or any other polymorphic data holder to operate on +* @return Count of components + */ +template +size_t poly_count(PolyPoolsHolder& reg) { + size_t count = 0; + for (auto& pool : assure_poly_type(reg).pools()) { + count += pool.pool().size(); + } + return count; +} + /** * @brief For a given component type applies given func to all child instances of this type in registry. * @tparam Component Polymorphic component type @@ -456,7 +490,7 @@ int poly_remove(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { * Note: for pointer type components (T*) the component parameter is its value (T*) instead of pointer to value (T**) */ template -void each_poly(PolyPoolsHolder& reg, Func func) { +void poly_each(PolyPoolsHolder& reg, Func func) { for (auto& pool : assure_poly_type(reg).pools()) { for (auto& ent : pool.pool()) { if constexpr(std::is_invocable_v) { @@ -496,4 +530,4 @@ struct entt::storage_traits ${TEST_SOURCES}) target_link_libraries(${TEST_NAME} PRIVATE GTest::Main Threads::Threads) @@ -212,6 +209,8 @@ SETUP_BASIC_TEST(handle entt/entity/handle.cpp) SETUP_BASIC_TEST(helper entt/entity/helper.cpp) SETUP_BASIC_TEST(observer entt/entity/observer.cpp) SETUP_BASIC_TEST(organizer entt/entity/organizer.cpp) +SETUP_BASIC_TEST(poly_type_traits entt/entity/poly_type_traits.cpp) +SETUP_BASIC_TEST(polymorphic entt/entity/polymorphic.cpp) SETUP_BASIC_TEST(registry entt/entity/registry.cpp) SETUP_BASIC_TEST(runtime_view entt/entity/runtime_view.cpp) SETUP_BASIC_TEST(sigh_storage_mixin entt/entity/sigh_storage_mixin.cpp) diff --git a/test/entt/common/polymorphic_type.hpp b/test/entt/common/polymorphic_type.hpp new file mode 100644 index 0000000000..590cdf146f --- /dev/null +++ b/test/entt/common/polymorphic_type.hpp @@ -0,0 +1,72 @@ +#ifndef ENTT_COMMON_POLYMORPHIC_TYPE_HPP +#define ENTT_COMMON_POLYMORPHIC_TYPE_HPP + +#include + + +struct animal : public entt::inherit<> { virtual std::string name() = 0; int animal_payload{}; }; +struct dog : public entt::inherit { std::string name() override { return "dog"; }; }; +struct cat : public entt::inherit { std::string name() override { return "cat"; }; }; + +struct shape { virtual std::string draw() = 0; int shape_payload{}; }; +struct sphere : public shape { std::string draw() override { return "sphere"; } }; +struct cube : public shape { std::string draw() override { return "cube"; } }; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list<>; +}; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list; +}; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list; +}; + +struct fat_cat : public entt::inherit {}; + + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list<>; +}; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list; +}; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list; +}; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list<>; +}; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list; +}; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list; +}; + +template<> +struct entt::poly_direct_parent_types { + using parent_types = type_list; +}; + + +struct not_poly_type_base {}; +struct not_poly_type : public not_poly_type_base {}; + +#endif diff --git a/test/entt/entity/poly_type_traits.cpp b/test/entt/entity/poly_type_traits.cpp new file mode 100644 index 0000000000..502eb3821a --- /dev/null +++ b/test/entt/entity/poly_type_traits.cpp @@ -0,0 +1,70 @@ +#include +#include "../common/polymorphic_type.hpp" + + +TEST(IsPolyType, Functionalities) { + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + ASSERT_TRUE(entt::is_poly_type_v); + + ASSERT_FALSE(entt::is_poly_type_v); + ASSERT_FALSE(entt::is_poly_type_v); + ASSERT_FALSE(entt::is_poly_type_v); +} + +TEST(ValidatePolyType, Functionalities) { + ASSERT_TRUE((std::is_same_v, animal>)); + ASSERT_TRUE((std::is_same_v, dog>)); + ASSERT_TRUE((std::is_same_v, cat>)); + ASSERT_TRUE((std::is_same_v, shape>)); + ASSERT_TRUE((std::is_same_v, sphere>)); + ASSERT_TRUE((std::is_same_v, cube>)); + ASSERT_TRUE((std::is_same_v, fat_cat>)); +} + +TEST(IsPolyParentOf, Functionalities) { + ASSERT_TRUE((entt::is_poly_parent_of_v)); + ASSERT_TRUE((entt::is_poly_parent_of_v)); + ASSERT_TRUE((entt::is_poly_parent_of_v)); + ASSERT_TRUE((entt::is_poly_parent_of_v)); + ASSERT_TRUE((entt::is_poly_parent_of_v)); + ASSERT_TRUE((entt::is_poly_parent_of_v)); + ASSERT_TRUE((entt::is_poly_parent_of_v)); + ASSERT_TRUE((entt::is_poly_parent_of_v)); + + ASSERT_FALSE((entt::is_poly_parent_of_v)); + ASSERT_FALSE((entt::is_poly_parent_of_v)); + ASSERT_FALSE((entt::is_poly_parent_of_v)); + ASSERT_FALSE((entt::is_poly_parent_of_v)); + ASSERT_FALSE((entt::is_poly_parent_of_v)); + ASSERT_FALSE((entt::is_poly_parent_of_v)); +} + +TEST(ParentTypeList, Functionalities) { + ASSERT_TRUE((std::is_same_v, entt::type_list<>>)); + ASSERT_TRUE((std::is_same_v, entt::type_list>)); + ASSERT_TRUE((std::is_same_v, entt::type_list>)); + ASSERT_TRUE((std::is_same_v, entt::type_list<>>)); + ASSERT_TRUE((std::is_same_v, entt::type_list>)); + ASSERT_TRUE((std::is_same_v, entt::type_list>)); +} + +TEST(SanitizePolyType, Functionalities) { + ASSERT_TRUE((std::is_same_v, cat>)); + ASSERT_TRUE((std::is_same_v, const cat>)); + ASSERT_TRUE((std::is_same_v, cat*>)); + ASSERT_TRUE((std::is_same_v, cat* const>)); + ASSERT_TRUE((std::is_same_v, cat* const>)); + ASSERT_TRUE((std::is_same_v, cat* const>)); +} diff --git a/test/entt/entity/polymorphic.cpp b/test/entt/entity/polymorphic.cpp new file mode 100644 index 0000000000..27aab3cc30 --- /dev/null +++ b/test/entt/entity/polymorphic.cpp @@ -0,0 +1,441 @@ +#include +#include +#include "../common/polymorphic_type.hpp" + + +TEST(PolyGetAny, Functionalities) { + entt::registry reg; + + entt::entity entity1 = reg.create(); // components: cat, dog + entt::entity entity2 = reg.create(); // components: dog, sphere, cube + entt::entity entity3 = reg.create(); // components: fat_cat + reg.emplace(entity1); + reg.emplace(entity1); + reg.emplace(entity2); + reg.emplace(entity2); + reg.emplace(entity2); + reg.emplace(entity3); + + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), reg.try_get(entity1)); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity2), reg.try_get(entity2)); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity2), reg.try_get(entity2)); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3), reg.try_get(entity3)); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3)->draw(), "sphere"); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3)->name(), "cat"); + + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), nullptr); +} + + +TEST(PolyGetAnyPointer, Functionalities) { + entt::registry reg; + + cat cat1; + dog dog1; + dog dog2; + cube cube2; + sphere sphere2; + fat_cat fat_cat3; + + entt::entity entity1 = reg.create(); // components: cat, dog + entt::entity entity2 = reg.create(); // components: dog, sphere, cube + entt::entity entity3 = reg.create(); // components: fat_cat + reg.emplace(entity1, &cat1); + reg.emplace(entity1, &dog1); + reg.emplace(entity2, &dog2); + reg.emplace(entity2, &cube2); + reg.emplace(entity2, &sphere2); + reg.emplace(entity3, &fat_cat3); + + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), reg.get(entity1)); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity2), reg.get(entity2)); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity2), reg.get(entity2)); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3), reg.get(entity3)); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3)->draw(), "sphere"); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3)->name(), "cat"); + + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), nullptr); +} + + +TEST(PolyGetAll, Functionalities) { + entt::registry reg; + + entt::entity entity1 = reg.create(); // components: cat(payload=1), dog(payload=2) + entt::entity entity2 = reg.create(); // components: dog(payload=2), cube(payload=3), sphere(payload=4) + entt::entity entity3 = reg.create(); // components: fat_cat(both payloads = 5) + reg.emplace(entity1).animal_payload = 1; + reg.emplace(entity1).animal_payload = 2; + reg.emplace(entity2).animal_payload = 2; + reg.emplace(entity2).shape_payload = 3; + reg.emplace(entity2).shape_payload = 4; + auto& c = reg.emplace(entity3); + c.animal_payload = c.shape_payload = 5; + + { + int count = 0; + for(animal& a: entt::algorithm::poly_get_all(reg, entity1)) { + ASSERT_TRUE(a.animal_payload == 1 || a.animal_payload == 2); + ASSERT_TRUE(a.animal_payload != 1 || a.name() == "cat"); + ASSERT_TRUE(a.animal_payload != 2 || a.name() == "dog"); + count++; + } + ASSERT_EQ(count, 2); + } + + { + int count = 0; + for (cat& a: entt::algorithm::poly_get_all(reg, entity1)) { + ASSERT_TRUE(a.animal_payload == 1 && a.name() == "cat"); + count++; + } + ASSERT_EQ(count, 1); + } + + { + int count = 0; + for ([[maybe_unused]] shape& s: entt::algorithm::poly_get_all(reg, entity1)) { + count++; + } + ASSERT_EQ(count, 0); + } + + { + int count = 0; + for(shape& s: entt::algorithm::poly_get_all(reg, entity2)) { + ASSERT_TRUE(s.shape_payload == 3 || s.shape_payload == 4); + ASSERT_TRUE(s.shape_payload != 3 || s.draw() == "cube"); + ASSERT_TRUE(s.shape_payload != 4 || s.draw() == "sphere"); + count++; + } + ASSERT_EQ(count, 2); + } + + { + int animal_count = 0; + for(animal& a: entt::algorithm::poly_get_all(reg, entity3)) { + ASSERT_TRUE(a.animal_payload == 5 && a.name() == "cat"); + animal_count++; + } + ASSERT_EQ(animal_count, 1); + int shape_count = 0; + for(shape& s: entt::algorithm::poly_get_all(reg, entity3)) { + ASSERT_TRUE(s.shape_payload == 5 && s.draw() == "sphere"); + shape_count++; + } + ASSERT_EQ(shape_count, 1); + } +} + + +TEST(PolyGetAllPointers, Functionalities) { + entt::registry reg; + + cat cat1; + dog dog1; + dog dog2; + cube cube2; + sphere sphere2; + fat_cat fat_cat3; + + entt::entity entity1 = reg.create(); // components: cat(payload=1), dog(payload=2) + entt::entity entity2 = reg.create(); // components: dog(payload=2), cube(payload=3), sphere(payload=4) + entt::entity entity3 = reg.create(); // components: fat_cat(both payloads = 5) + reg.emplace(entity1, &cat1)->animal_payload = 1; + reg.emplace(entity1, &dog1)->animal_payload = 2; + reg.emplace(entity2, &dog2)->animal_payload = 2; + reg.emplace(entity2, &cube2)->shape_payload = 3; + reg.emplace(entity2, &sphere2)->shape_payload = 4; + auto* c = reg.emplace(entity3, &fat_cat3); + c->animal_payload = c->shape_payload = 5; + + { + int count = 0; + for(animal* a: entt::algorithm::poly_get_all(reg, entity1)) { + ASSERT_TRUE(a->animal_payload == 1 || a->animal_payload == 2); + ASSERT_TRUE(a->animal_payload != 1 || a->name() == "cat"); + ASSERT_TRUE(a->animal_payload != 2 || a->name() == "dog"); + count++; + } + ASSERT_EQ(count, 2); + } + + { + int count = 0; + for (cat* a: entt::algorithm::poly_get_all(reg, entity1)) { + ASSERT_TRUE(a->animal_payload == 1 && a->name() == "cat"); + count++; + } + ASSERT_EQ(count, 1); + } + + { + int count = 0; + for ([[maybe_unused]] shape* s: entt::algorithm::poly_get_all(reg, entity1)) { + count++; + } + ASSERT_EQ(count, 0); + } + + { + int count = 0; + for(shape* s: entt::algorithm::poly_get_all(reg, entity2)) { + ASSERT_TRUE(s->shape_payload == 3 || s->shape_payload == 4); + ASSERT_TRUE(s->shape_payload != 3 || s->draw() == "cube"); + ASSERT_TRUE(s->shape_payload != 4 || s->draw() == "sphere"); + count++; + } + ASSERT_EQ(count, 2); + } + + { + int animal_count = 0; + for(animal* a: entt::algorithm::poly_get_all(reg, entity3)) { + ASSERT_TRUE(a->animal_payload == 5 && a->name() == "cat"); + animal_count++; + } + ASSERT_EQ(animal_count, 1); + int shape_count = 0; + for(shape* s: entt::algorithm::poly_get_all(reg, entity3)) { + ASSERT_TRUE(s->shape_payload == 5 && s->draw() == "sphere"); + shape_count++; + } + ASSERT_EQ(shape_count, 1); + } +} + + +TEST(PolyCount, Functionalities) { + entt::registry reg; + + entt::entity entity1 = reg.create(); // components: cat, dog + entt::entity entity2 = reg.create(); // components: dog, sphere, cube + entt::entity entity3 = reg.create(); // components: fat_cat + reg.emplace(entity1); + reg.emplace(entity1); + reg.emplace(entity2); + reg.emplace(entity2); + reg.emplace(entity2); + reg.emplace(entity3); + + ASSERT_EQ(entt::algorithm::poly_count(reg, entity1), 1); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity1), 1); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity1), 2); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity1), 0); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity2), 0); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity2), 1); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity2), 2); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity3), 1); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity3), 1); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity3), 1); + + ASSERT_EQ(entt::algorithm::poly_count(reg), 1); + ASSERT_EQ(entt::algorithm::poly_count(reg), 2); + ASSERT_EQ(entt::algorithm::poly_count(reg), 2); + ASSERT_EQ(entt::algorithm::poly_count(reg), 2); + ASSERT_EQ(entt::algorithm::poly_count(reg), 4); + ASSERT_EQ(entt::algorithm::poly_count(reg), 3); + ASSERT_EQ(entt::algorithm::poly_count(reg), 1); +} + + +TEST(PolyEach, Functionalities) { + entt::registry reg; + + entt::entity entity1 = reg.create(); // components: cat(payload=1), dog(payload=2) + entt::entity entity2 = reg.create(); // components: dog(payload=2), cube(payload=3), sphere(payload=4) + entt::entity entity3 = reg.create(); // components: fat_cat(both payloads = 5) + reg.emplace(entity1).animal_payload = 1; + reg.emplace(entity1).animal_payload = 2; + reg.emplace(entity2).animal_payload = 2; + reg.emplace(entity2).shape_payload = 3; + reg.emplace(entity2).shape_payload = 4; + auto& c = reg.emplace(entity3); + c.animal_payload = c.shape_payload = 5; + + { + int count = 0; + entt::algorithm::poly_each(reg, [&] (entt::entity e, cube& s) -> void { + ASSERT_TRUE(e == entity2); + ASSERT_TRUE(s.shape_payload == 3); + count++; + }); + ASSERT_EQ(count, 1); + } + + { + int count = 0; + entt::algorithm::poly_each(reg, [&] (entt::entity e, animal& a) -> void { + ASSERT_TRUE(e == entity1 || e == entity2 || e == entity3); + if (e == entity1) { + ASSERT_TRUE(a.animal_payload == 1 || a.animal_payload == 2); + ASSERT_TRUE(a.animal_payload != 1 || a.name() == "cat"); + ASSERT_TRUE(a.animal_payload != 2 || a.name() == "dog"); + } else if (e == entity2) { + ASSERT_TRUE(a.animal_payload == 2 && a.name() == "dog"); + } else if (e == entity3) { + ASSERT_TRUE(a.animal_payload == 5 && a.name() == "cat"); + } + count++; + }); + ASSERT_EQ(count, 4); + } + + { + int count = 0; + entt::algorithm::poly_each(reg, [&] (entt::entity e, shape& s) -> void { + ASSERT_TRUE(e == entity2 || e == entity3); + if (e == entity2) { + ASSERT_TRUE(s.shape_payload == 3 || s.shape_payload == 4); + ASSERT_TRUE(s.shape_payload != 3 || s.draw() == "cube"); + ASSERT_TRUE(s.shape_payload != 4 || s.draw() == "sphere"); + } else if (e == entity3) { + ASSERT_TRUE(s.shape_payload == 5 && s.draw() == "sphere"); + } + count++; + }); + ASSERT_EQ(count, 3); + } + + { + int count = 0; + entt::algorithm::poly_each(reg, [&] (entt::entity e, [[maybe_unused]] animal* a) -> void { + count++; + }); + ASSERT_EQ(count, 0); + } +} + + +TEST(PolyEachPointer, Functionalities) { + entt::registry reg; + + cat cat1; + dog dog1; + dog dog2; + cube cube2; + sphere sphere2; + fat_cat fat_cat3; + + entt::entity entity1 = reg.create(); // components: cat(payload=1), dog(payload=2) + entt::entity entity2 = reg.create(); // components: dog(payload=2), cube(payload=3), sphere(payload=4) + entt::entity entity3 = reg.create(); // components: fat_cat(both payloads = 5) + reg.emplace(entity1, &cat1)->animal_payload = 1; + reg.emplace(entity1, &dog1)->animal_payload = 2; + reg.emplace(entity2, &dog2)->animal_payload = 2; + reg.emplace(entity2, &cube2)->shape_payload = 3; + reg.emplace(entity2, &sphere2)->shape_payload = 4; + auto* c = reg.emplace(entity3, &fat_cat3); + c->animal_payload = c->shape_payload = 5; + + { + int count = 0; + entt::algorithm::poly_each(reg, [&] (entt::entity e, cube* s) -> void { + ASSERT_TRUE(e == entity2); + ASSERT_TRUE(s->shape_payload == 3); + count++; + }); + ASSERT_EQ(count, 1); + } + + { + int count = 0; + entt::algorithm::poly_each(reg, [&] (entt::entity e, animal* a) -> void { + ASSERT_TRUE(e == entity1 || e == entity2 || e == entity3); + if (e == entity1) { + ASSERT_TRUE(a->animal_payload == 1 || a->animal_payload == 2); + ASSERT_TRUE(a->animal_payload != 1 || a->name() == "cat"); + ASSERT_TRUE(a->animal_payload != 2 || a->name() == "dog"); + } else if (e == entity2) { + ASSERT_TRUE(a->animal_payload == 2 && a->name() == "dog"); + } else if (e == entity3) { + ASSERT_TRUE(a->animal_payload == 5 && a->name() == "cat"); + } + count++; + }); + ASSERT_EQ(count, 4); + } + + { + int count = 0; + entt::algorithm::poly_each(reg, [&] (entt::entity e, shape* s) -> void { + ASSERT_TRUE(e == entity2 || e == entity3); + if (e == entity2) { + ASSERT_TRUE(s->shape_payload == 3 || s->shape_payload == 4); + ASSERT_TRUE(s->shape_payload != 3 || s->draw() == "cube"); + ASSERT_TRUE(s->shape_payload != 4 || s->draw() == "sphere"); + } else if (e == entity3) { + ASSERT_TRUE(s->shape_payload == 5 && s->draw() == "sphere"); + } + count++; + }); + ASSERT_EQ(count, 3); + } + + { + int count = 0; + entt::algorithm::poly_each(reg, [&] (entt::entity e, [[maybe_unused]] animal& a) -> void { + count++; + }); + ASSERT_EQ(count, 0); + } +} + + +TEST(PolyRemove, Functionalities) { + entt::registry reg; + + entt::entity entity1 = reg.create(); // components: cat, dog + entt::entity entity2 = reg.create(); // components: dog, sphere, cube + reg.emplace(entity1); + reg.emplace(entity1); + reg.emplace(entity2); + reg.emplace(entity2); + reg.emplace(entity2); + + ASSERT_NE(reg.try_get(entity1), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity1), nullptr); + ASSERT_NE(reg.try_get(entity1), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity1), nullptr); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity1), 2); + entt::algorithm::poly_remove(reg, entity1); + ASSERT_EQ(reg.try_get(entity1), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), nullptr); + ASSERT_EQ(reg.try_get(entity1), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), nullptr); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity1), 0); + + ASSERT_NE(reg.try_get(entity2), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity2), nullptr); + ASSERT_NE(reg.try_get(entity2), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity2), nullptr); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity2), 2); + entt::algorithm::poly_remove(reg, entity2); + ASSERT_EQ(reg.try_get(entity2), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity2), nullptr); + ASSERT_NE(reg.try_get(entity2), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity2), nullptr); + ASSERT_EQ(entt::algorithm::poly_count(reg, entity2), 1); + + entt::entity entity3 = reg.create(); // components: fat_cat + + reg.emplace(entity3); + ASSERT_NE(reg.try_get(entity3), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity3), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity3), nullptr); + entt::algorithm::poly_remove(reg, entity3); + ASSERT_EQ(reg.try_get(entity3), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3), nullptr); + + reg.emplace(entity3); + ASSERT_NE(reg.try_get(entity3), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity3), nullptr); + ASSERT_NE(entt::algorithm::poly_get_any(reg, entity3), nullptr); + entt::algorithm::poly_remove(reg, entity3); + ASSERT_EQ(reg.try_get(entity3), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3), nullptr); + ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity3), nullptr); +} \ No newline at end of file diff --git a/test/playground.cpp b/test/playground.cpp deleted file mode 100644 index 3b6c512c6d..0000000000 --- a/test/playground.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include -#include - - -struct shape { virtual void draw() = 0; }; -template<> -struct entt::poly_parent_types { - using parent_types = type_list<>; -}; -struct circle: public entt::inherit { void draw() override { std::cout << "circle"; } }; -struct rectangle: public entt::inherit { void draw() override { std::cout << "rectangle"; } }; - - -struct animal { virtual void name() const = 0; }; -struct cat: public animal { void name() const override { std::cout << "cat"; } }; -struct dog: public animal { void name() const override { std::cout << "dog"; } }; - -template<> -struct entt::poly_parent_types { - using parent_types = type_list<>; -}; -template<> -struct entt::poly_parent_types { - using parent_types = type_list; -}; -template<> -struct entt::poly_parent_types { - using parent_types = type_list; -}; - -void on_construct(entt::registry&, entt::entity e) { - std::cout << "constructed " << entt::to_entity(e) << "\n"; -} - -void on_update(entt::registry&, entt::entity e) { - std::cout << "updated " << entt::to_entity(e) << "\n"; -} - -void on_destroy(entt::registry&, entt::entity e) { - std::cout << "destroyed " << entt::to_entity(e) << "\n"; -} - -int main() { - entt::registry registry; - const auto entity = registry.create(); - const auto other = registry.create(); - - registry.on_construct().connect(); - registry.on_update().connect(); - registry.on_destroy().connect(); - - registry.emplace(entity); - registry.emplace(entity); - registry.emplace(entity, new cat); - - registry.emplace(other); - registry.emplace(other, new dog); - - std::cout << "\nall shapes\n"; - entt::algorithm::each_poly(registry, [](auto ent, auto& s) { - std::cout << entt::to_entity(ent) << " -> "; - s.draw(); - std::cout << '\n'; - }); - - std::cout << "\nall shapes for entity " << entt::to_entity(entity) << "\n"; - for ( shape& s : entt::algorithm::poly_get_all< shape>(registry, entity)) { - s.draw(); - std::cout << '\n'; - } - - std::cout << "any shape for entity " << entt::to_entity(entity) << " "; - entt::algorithm::poly_get_any(registry, entity)->draw(); - std::cout << '\n'; - - std::cout << "\nall animals\n"; - entt::algorithm::each_poly(registry, [](auto ent, const animal* a) { - std::cout << entt::to_entity(ent) << " -> "; - a->name(); - std::cout << '\n'; - }); - - std::cout << "\nall animals for entity " << entt::to_entity(entity) << "\n"; - for (const animal* a : entt::algorithm::poly_get_all(registry, entity)) { - a->name(); - std::cout << '\n'; - } - - registry.patch(entity); - entt::algorithm::poly_remove(registry, entity); -} \ No newline at end of file From 379722b9726699c7ed4fa3a679d036f52b09e7e6 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Tue, 19 Apr 2022 11:35:39 +0300 Subject: [PATCH 16/27] optimized poly_count --- src/entt/entity/polymorphic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 0439e3b56a..fcdd0d8ac8 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -458,8 +458,8 @@ int poly_remove(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { template size_t poly_count(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { size_t count = 0; - for ([[maybe_unused]] auto& component : poly_get_all(reg, entity)) { - count++; + for (auto& pool : assure_poly_type(reg).pools()) { + count += static_cast(pool.pool().contains(entity)); } return count; } From 7aed523beabc996dcfc07b9984632298759e9ca0 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Wed, 20 Apr 2022 12:46:01 +0300 Subject: [PATCH 17/27] fixed MSVC v141 build --- src/entt/entity/poly_type_traits.hpp | 10 ++--- src/entt/entity/polymorphic.hpp | 63 ++++++++++++++++++---------- test/entt/entity/polymorphic.cpp | 20 +++------ 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/entt/entity/poly_type_traits.hpp b/src/entt/entity/poly_type_traits.hpp index 3bd8ca4458..202799481f 100644 --- a/src/entt/entity/poly_type_traits.hpp +++ b/src/entt/entity/poly_type_traits.hpp @@ -110,16 +110,16 @@ struct is_poly_type::not_red /** @copydoc is_poly_type */ template -static constexpr bool is_poly_type_v = is_poly_type::value; +inline constexpr bool is_poly_type_v = is_poly_type::value; /** @copydoc poly_type_validate */ template struct poly_type_validate> { static_assert(std::is_same_v, T>, "only decayed types allowed to be declared as polymorphic"); static_assert(is_poly_type_v, "validating non-polymorphic type (probably some polymorphic type inherits type, that was not declared polymorphic)"); - static_assert((is_poly_type_v && ...), "all parent types of a polymorphic type must be also polymorphic"); - static_assert((!std::is_pointer_v> && ... && !std::is_pointer_v>), "double pointers are not allowed as a polymorphic components"); - static_assert(((std::is_pointer_v == std::is_pointer_v) && ...), "you cannot mix pointer-based and value-based polymorphic components inside one hierarchy"); + static_assert(std::bool_constant<(is_poly_type_v && ...)>::value, "all parent types of a polymorphic type must be also polymorphic"); + static_assert(std::bool_constant<(!std::is_pointer_v> && ... && !std::is_pointer_v>)>::value, "double pointers are not allowed as a polymorphic components"); + static_assert(std::bool_constant<((std::is_pointer_v == std::is_pointer_v) && ...)>::value, "you cannot mix pointer-based and value-based polymorphic components inside one hierarchy"); /** @brief same input type, but validated */ using type = T; @@ -135,7 +135,7 @@ using poly_type_validate_t = typename poly_type_validate -constexpr bool is_poly_parent_of_v = is_poly_type_v && (type_list_contains_v, Parent> || std::is_same_v); +inline constexpr bool is_poly_parent_of_v = is_poly_type_v && (type_list_contains_v, Parent> || std::is_same_v); /** * @brief Used to inherit from all given parent types and declare inheriting type polymorphic with given direct parents. diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index fcdd0d8ac8..646f029d9f 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -233,6 +233,38 @@ class poly_type { } }; + /** @brief derived value to base pointer conversion, workaround for if constexpr bug on some compilers */ + template + struct derived_to_base_ptr { + inline static Base* convert(Derived& ref) ENTT_NOEXCEPT { + return static_cast(std::addressof(ref)); + } + }; + + /** @copydoc derived_to_base_ptr */ + template + struct derived_to_base_ptr>> { + inline static Base convert(Derived ptr) ENTT_NOEXCEPT { + return static_cast(ptr); + } + }; + + /** @brief value to pointer conversion, workaround for if constexpr bug on some compilers */ + template + struct value_to_ptr { + inline static T* convert(T& ref) ENTT_NOEXCEPT { + return std::addressof(ref); + } + }; + + /** @copydoc value_to_ptr */ + template + struct value_to_ptr>> { + inline static T convert(T ptr) ENTT_NOEXCEPT { + return ptr; + } + }; + public: /** @brief entity type of the component pools */ using entity_type = Entity; @@ -257,32 +289,21 @@ class poly_type { */ template inline static poly_pool_holder make_pool_holder(StorageType* pool_ptr) ENTT_NOEXCEPT { - using ChildType = typename StorageType::value_type; - static_assert(is_poly_type_v); - static_assert(type_list_contains_v, Type> || std::is_same_v); - static_assert(std::is_pointer_v == std::is_pointer_v); + using BaseType = Type; + using DerivedType = typename StorageType::value_type; + static_assert(is_poly_type_v); + static_assert(type_list_contains_v, BaseType> || std::is_same_v); + static_assert(std::is_pointer_v == std::is_pointer_v); void* (*get)(void*, Entity entity) ENTT_NOEXCEPT = +[](void* pool, const Entity entity) ENTT_NOEXCEPT -> void* { if (static_cast(pool)->contains(entity)) { // if entity is contained within the set - if constexpr(std::is_base_of_v, std::remove_pointer_t>) { - if constexpr(std::is_pointer_v) { - // Type and ChildType are pointers, dereference source pointer and do conversion - ChildType ptr = static_cast(pool)->get(entity); - return static_cast(ptr); - } else { - // Type is base of ChildType, do pointer conversion - return static_cast(std::addressof(static_cast(pool)->get(entity))); - } + if constexpr(std::is_base_of_v, std::remove_pointer_t>) { + // if base type is inherited from derived type, do pointer conversion + return derived_to_base_ptr::convert(static_cast(pool)->get(entity)); } else { - // no inheritance - no conversion required - if constexpr(std::is_pointer_v) { - // in case of pointer type return it as it is - return static_cast(pool)->get(entity); - } else { - // otherwise, get the address - return std::addressof(static_cast(pool)->get(entity)); - } + // no inheritance - no conversion required, just get the pointer + return value_to_ptr::convert(static_cast(pool)->get(entity)); } } // otherwise, return null diff --git a/test/entt/entity/polymorphic.cpp b/test/entt/entity/polymorphic.cpp index 27aab3cc30..925fa70da0 100644 --- a/test/entt/entity/polymorphic.cpp +++ b/test/entt/entity/polymorphic.cpp @@ -95,11 +95,9 @@ TEST(PolyGetAll, Functionalities) { } { - int count = 0; - for ([[maybe_unused]] shape& s: entt::algorithm::poly_get_all(reg, entity1)) { - count++; + for (shape& s: entt::algorithm::poly_get_all(reg, entity1)) { + ASSERT_TRUE(false && std::addressof(s)); } - ASSERT_EQ(count, 0); } { @@ -172,11 +170,9 @@ TEST(PolyGetAllPointers, Functionalities) { } { - int count = 0; - for ([[maybe_unused]] shape* s: entt::algorithm::poly_get_all(reg, entity1)) { - count++; + for (shape* s: entt::algorithm::poly_get_all(reg, entity1)) { + ASSERT_TRUE(false && s); } - ASSERT_EQ(count, 0); } { @@ -300,11 +296,9 @@ TEST(PolyEach, Functionalities) { } { - int count = 0; entt::algorithm::poly_each(reg, [&] (entt::entity e, [[maybe_unused]] animal* a) -> void { - count++; + ASSERT_TRUE(false); }); - ASSERT_EQ(count, 0); } } @@ -375,11 +369,9 @@ TEST(PolyEachPointer, Functionalities) { } { - int count = 0; entt::algorithm::poly_each(reg, [&] (entt::entity e, [[maybe_unused]] animal& a) -> void { - count++; + ASSERT_TRUE(false); }); - ASSERT_EQ(count, 0); } } From cac84c791bb0bff6fa940271f5232993cb8b6d80 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Wed, 20 Apr 2022 15:52:36 +0300 Subject: [PATCH 18/27] code coverage trick for no-iterations tests --- test/entt/entity/polymorphic.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/test/entt/entity/polymorphic.cpp b/test/entt/entity/polymorphic.cpp index 925fa70da0..913670feac 100644 --- a/test/entt/entity/polymorphic.cpp +++ b/test/entt/entity/polymorphic.cpp @@ -95,9 +95,7 @@ TEST(PolyGetAll, Functionalities) { } { - for (shape& s: entt::algorithm::poly_get_all(reg, entity1)) { - ASSERT_TRUE(false && std::addressof(s)); - } + for (shape& s: entt::algorithm::poly_get_all(reg, entity1)) { FAIL() << std::addressof(s); } } { @@ -170,9 +168,7 @@ TEST(PolyGetAllPointers, Functionalities) { } { - for (shape* s: entt::algorithm::poly_get_all(reg, entity1)) { - ASSERT_TRUE(false && s); - } + for (shape* s: entt::algorithm::poly_get_all(reg, entity1)) { FAIL() << s; } } { @@ -296,9 +292,7 @@ TEST(PolyEach, Functionalities) { } { - entt::algorithm::poly_each(reg, [&] (entt::entity e, [[maybe_unused]] animal* a) -> void { - ASSERT_TRUE(false); - }); + entt::algorithm::poly_each(reg, [&] (entt::entity e, [[maybe_unused]] animal* a) -> void { FAIL(); }); } } @@ -369,9 +363,7 @@ TEST(PolyEachPointer, Functionalities) { } { - entt::algorithm::poly_each(reg, [&] (entt::entity e, [[maybe_unused]] animal& a) -> void { - ASSERT_TRUE(false); - }); + entt::algorithm::poly_each(reg, [&] (entt::entity e, [[maybe_unused]] animal& a) -> void { FAIL(); }); } } From cb811b0fd7142aba06aa92052bce7f1863376933 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Mon, 25 Apr 2022 15:02:04 +0300 Subject: [PATCH 19/27] * replaced converting_iterator + poly_type.pools() with poly_type.each_pool(f) * removed redundant remove virtualization * cleaned up poly_storage_mixin --- src/entt/entity/poly_storage_mixin.hpp | 7 +- src/entt/entity/polymorphic.hpp | 149 +++++++------------------ 2 files changed, 41 insertions(+), 115 deletions(-) diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp index 2ef5937d37..d578b0bf0c 100644 --- a/src/entt/entity/poly_storage_mixin.hpp +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -18,8 +18,7 @@ class poly_type; * @tparam Type value type */ template -class poly_storage_mixin : public Storage { -public: +struct poly_storage_mixin : Storage { /*! @brief Underlying value type. */ using value_type = typename Storage::value_type; /*! @brief Underlying entity identifier. */ @@ -34,7 +33,6 @@ class poly_storage_mixin : public Storage { */ void bind(any value) ENTT_NOEXCEPT override { if(auto *reg = any_cast>(&value); reg) { - owner = reg; bind_all_parent_types(*reg, poly_parent_types_t{}); } Storage::bind(std::move(value)); @@ -46,9 +44,6 @@ class poly_storage_mixin : public Storage { (reg.ctx().template emplace>().bind_child_storage(this), ...); reg.ctx().template emplace>().bind_child_storage(this); } - -private: - basic_registry *owner{}; }; diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 646f029d9f..91417b2d5d 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -15,71 +15,15 @@ namespace entt::internal { -template -struct converting_iterator { - using value_type = std::remove_reference_t()(*std::declval()))>; - using reference = value_type&; - using pointer = value_type*; - using difference_type = typename It::difference_type; - using iterator_category = std::bidirectional_iterator_tag; - - converting_iterator() ENTT_NOEXCEPT = default; - - converting_iterator(It it) ENTT_NOEXCEPT : - wrapped(it) {} - - converting_iterator &operator++() ENTT_NOEXCEPT { - wrapped++; - return *this; - } - - converting_iterator operator++(int) ENTT_NOEXCEPT { - converting_iterator orig = *this; - return ++(*this), orig; - } - - converting_iterator &operator--() ENTT_NOEXCEPT { - wrapped--; - return *this; - } - - converting_iterator operator--(int) ENTT_NOEXCEPT { - converting_iterator orig = *this; - return --(*this), orig; - } - - bool operator==(const converting_iterator& other) const ENTT_NOEXCEPT { - return wrapped == other.wrapped; - } - - bool operator!=(const converting_iterator& other) const ENTT_NOEXCEPT { - return wrapped != other.wrapped; - } - - reference operator*() ENTT_NOEXCEPT { - Convert convert{}; - return convert(*wrapped); - } - - pointer operator->() ENTT_NOEXCEPT { - return std::addressof(operator*()); - } - -private: - It wrapped; -}; - - -template +template class poly_components_iterator { using iterator_traits = typename std::iterator_traits; - using pool_holder_type = typename iterator_traits::value_type; public: - using entity_type = typename pool_holder_type::entity_type; - using pointer = std::conditional_t, typename pool_holder_type::const_pointer_type, typename pool_holder_type::pointer_type>; - using value_type = std::conditional_t, pointer, constness_as_t>; - using reference = std::conditional_t, pointer, value_type&>; + using entity_type = typename PoolHolderType::entity_type; + using pointer = std::conditional_t, typename PoolHolderType::const_pointer_type, typename PoolHolderType::pointer_type>; + using value_type = std::conditional_t, pointer, constness_as_t>; + using reference = std::conditional_t, pointer, value_type&>; using difference_type = typename iterator_traits::difference_type; using iterator_category = std::forward_iterator_tag; @@ -88,7 +32,7 @@ class poly_components_iterator { poly_components_iterator(entity_type e, PoolsIterator pos, PoolsIterator last) ENTT_NOEXCEPT : ent(e), it(pos), end(last) { if (it != end) { - current = it->try_get(ent); + current = static_cast(*it).try_get(ent); if(current == nullptr) { ++(*this); } @@ -98,7 +42,7 @@ class poly_components_iterator { poly_components_iterator &operator++() ENTT_NOEXCEPT { ++it; while (it != end) { - current = it->try_get(ent); + current = static_cast(*it).try_get(ent); if (current != nullptr) break; ++it; @@ -153,14 +97,12 @@ template class poly_pool_holder_base { public: inline poly_pool_holder_base(basic_sparse_set* pool, - void* (*getter)(void*, Entity) ENTT_NOEXCEPT, - bool (*remover)(void*, Entity)) : - pool_ptr(pool), getter_ptr(getter), remover_ptr(remover) {} + void* (*getter)(void*, Entity) ENTT_NOEXCEPT) : + pool_ptr(pool), getter_ptr(getter) {} protected: basic_sparse_set* pool_ptr; void* (*getter_ptr)(void*, Entity) ENTT_NOEXCEPT; - bool (*remover_ptr)(void*, Entity); }; /** @@ -202,7 +144,7 @@ class poly_pool_holder : public poly_pool_holder_base { * @return true, if component was removed, false, if it didnt exist */ inline bool remove(const Entity ent) { - return this->remover_ptr(this->pool_ptr, ent); + return this->pool_ptr->remove(ent); } /** @brief returns underlying pool */ @@ -222,17 +164,6 @@ class poly_pool_holder : public poly_pool_holder_base { */ template class poly_type { - /** @brief internally used to convert base_poly_pool_holder to a pool_poly_holder during the iteration */ - struct cast_pool_holder { - auto& operator()(poly_pool_holder_base& holder) { - return static_cast&>(holder); - } - - const auto& operator()(const poly_pool_holder_base& holder) const { - return static_cast&>(holder); - } - }; - /** @brief derived value to base pointer conversion, workaround for if constexpr bug on some compilers */ template struct derived_to_base_ptr { @@ -272,14 +203,12 @@ class poly_type { using value_type = Type; /** @brief type of the underlying pool container */ using pools_container = std::vector>; - /** @brief pool iterator type */ - using pools_iterator = internal::converting_iterator; - /** @brief const pool iterator type */ - using const_pools_iterator = internal::converting_iterator; + /** @brief type of the pool holder */ + using pool_holder = poly_pool_holder; /** @brief single entity component iterator type */ - using component_iterator = internal::poly_components_iterator; + using component_iterator = internal::poly_components_iterator; /** @brief const single entity component iterator type */ - using const_component_iterator = internal::poly_components_iterator; + using const_component_iterator = internal::poly_components_iterator; /** * @brief From a given set, makes a poly_storage_holder to hold child type and convert to parent type. @@ -288,7 +217,7 @@ class poly_type { * @return poly_storage_holder to hold ChildType set and access it as Type */ template - inline static poly_pool_holder make_pool_holder(StorageType* pool_ptr) ENTT_NOEXCEPT { + inline static pool_holder make_pool_holder(StorageType* pool_ptr) ENTT_NOEXCEPT { using BaseType = Type; using DerivedType = typename StorageType::value_type; static_assert(is_poly_type_v); @@ -310,11 +239,7 @@ class poly_type { return nullptr; }; - bool (*remove)(void*, Entity entity) = +[](void* pool, const Entity entity) -> bool { - return static_cast(pool)->remove(entity); - }; - - return poly_pool_holder(pool_ptr, get, remove); + return pool_holder(pool_ptr, get); } /** @brief adds given storage pointer as a child type pool to this polymorphic type */ @@ -323,27 +248,33 @@ class poly_type { this->child_pool_holders.emplace_back(make_pool_holder(storage_ptr)); } - /** @brief returns an iterable to iterate through all pool holders */ - [[nodiscard]] iterable_adaptor pools() { - return { pools_iterator(this->child_pool_holders.begin()), pools_iterator(this->child_pool_holders.end()) }; + /** @brief calls given function for all child pool holders */ + template + void each_pool(Func func) { + for (auto& pool : child_pool_holders) { + func(static_cast(pool)); + } } - /** @copydoc pools */ - [[nodiscard]] iterable_adaptor pools() const { - return { const_pools_iterator(this->child_pool_holders.cbegin()), const_pools_iterator(this->child_pool_holders.cend()) }; + /** @copydoc each_pool */ + template + void each_pool(Func func) const { + for (auto& pool : child_pool_holders) { + func(static_cast(pool)); + } } /** @brief returns an iterable to iterate through all polymorphic components, derived from this type, attached to a given entities */ [[nodiscard]] iterable_adaptor each(const entity_type ent) { - auto begin = pools_iterator(this->child_pool_holders.begin()); - auto end = pools_iterator(this->child_pool_holders.end()); + auto begin = this->child_pool_holders.begin(); + auto end = this->child_pool_holders.end(); return { component_iterator(ent, begin, end), component_iterator(ent, end, end) }; } /** @copydoc each */ [[nodiscard]] iterable_adaptor each(const entity_type ent) const { - auto begin = const_pools_iterator(this->child_pool_holders.cbegin()); - auto end = const_pools_iterator(this->child_pool_holders.cend()); + auto begin = this->child_pool_holders.cbegin(); + auto end = this->child_pool_holders.cend(); return { const_component_iterator(ent, begin, end), const_component_iterator(ent, end, end) }; } @@ -463,9 +394,9 @@ template template int poly_remove(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { int removed_count = 0; - for (auto& pool : assure_poly_type(reg).pools()) { + assure_poly_type(reg).each_pool([&](auto& pool){ removed_count += static_cast(pool.remove(entity)); - } + }); return removed_count; } @@ -479,9 +410,9 @@ int poly_remove(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { template size_t poly_count(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { size_t count = 0; - for (auto& pool : assure_poly_type(reg).pools()) { + assure_poly_type(reg).each_pool([&](auto& pool){ count += static_cast(pool.pool().contains(entity)); - } + }); return count; } @@ -494,9 +425,9 @@ size_t poly_count(PolyPoolsHolder& reg, [[maybe_unused]] const Entity entity) { template size_t poly_count(PolyPoolsHolder& reg) { size_t count = 0; - for (auto& pool : assure_poly_type(reg).pools()) { + assure_poly_type(reg).each_pool([&](auto& pool){ count += pool.pool().size(); - } + }); return count; } @@ -512,7 +443,7 @@ size_t poly_count(PolyPoolsHolder& reg) { */ template void poly_each(PolyPoolsHolder& reg, Func func) { - for (auto& pool : assure_poly_type(reg).pools()) { + assure_poly_type(reg).each_pool([&](auto& pool){ for (auto& ent : pool.pool()) { if constexpr(std::is_invocable_v) { auto ptr = pool.try_get(ent); @@ -534,7 +465,7 @@ void poly_each(PolyPoolsHolder& reg, Func func) { func(); } } - } + }); } } // namespace entt::algorithm From 1d15cb6a204135c0a039f6b39218bdac565ba6a7 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sat, 30 Apr 2022 13:47:01 +0300 Subject: [PATCH 20/27] Made polymorphic algorithms allocator aware * Added entt::poly_type_allocator to declare custom allocator types for components * Added Allocator parameter to poly_type and poly_type_holder * Added allocator_type type function to poly_type_accessor * Static assert to check, that pointer types, provided by allocators are same across one hierarchy --- src/entt/entity/poly_storage_mixin.hpp | 6 +-- src/entt/entity/poly_type_traits.hpp | 14 ++++++ src/entt/entity/polymorphic.hpp | 59 ++++++++++++++++---------- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp index d578b0bf0c..9e73b3943d 100644 --- a/src/entt/entity/poly_storage_mixin.hpp +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -8,7 +8,7 @@ namespace entt { -template +template class poly_type; /** @@ -41,8 +41,8 @@ struct poly_storage_mixin : Storage { private: template void bind_all_parent_types(basic_registry& reg, [[maybe_unused]] type_list) { - (reg.ctx().template emplace>().bind_child_storage(this), ...); - reg.ctx().template emplace>().bind_child_storage(this); + (reg.ctx().template emplace>>().bind_child_storage(this), ...); + reg.ctx().template emplace>>().bind_child_storage(this); } }; diff --git a/src/entt/entity/poly_type_traits.hpp b/src/entt/entity/poly_type_traits.hpp index 202799481f..9dc4fb5498 100644 --- a/src/entt/entity/poly_type_traits.hpp +++ b/src/entt/entity/poly_type_traits.hpp @@ -90,6 +90,20 @@ struct poly_parent_types> { template using poly_parent_types_t = typename poly_parent_types::parent_types; +/** + * Used to declare allocator type for polymorphic component type + * @tparam Type + */ +template +struct poly_type_allocator { + /** @brief allocator type */ + using type = std::allocator; +}; + +/** @copydoc poly_type_allocator */ +template +using poly_type_allocator_t = typename poly_type_allocator::type; + /** * @brief For a given type, detects, if it was declared polymorphic. Type considered polymorphic, if it was either:
* - inherited from entt::inherit
diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 91417b2d5d..d0eae15c83 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -96,21 +96,22 @@ namespace entt { template class poly_pool_holder_base { public: - inline poly_pool_holder_base(basic_sparse_set* pool, + inline poly_pool_holder_base(void* pool, void* (*getter)(void*, Entity) ENTT_NOEXCEPT) : pool_ptr(pool), getter_ptr(getter) {} protected: - basic_sparse_set* pool_ptr; + void* pool_ptr; void* (*getter_ptr)(void*, Entity) ENTT_NOEXCEPT; }; /** * @brief Holds pointer to child type storage and a function to convert it into parent type * @tparam Entity underlying entity type - * @tparam Type polymorphic component type to be converted into + * @tparam Type polymorphic component type to convert into + * @tparam Allocator allocator type of the pool */ -template +template class poly_pool_holder : public poly_pool_holder_base { public: using poly_pool_holder_base::poly_pool_holder_base; @@ -123,6 +124,8 @@ class poly_pool_holder : public poly_pool_holder_base { using pointer_type = std::remove_pointer_t*; /** @copydoc pointer_type */ using const_pointer_type = const std::remove_pointer_t*; + /** @brief type of hold sparse set */ + using sparse_set_type = basic_sparse_set::template rebind_alloc>; /** * @brief gets child from a child pool as parent type reference by given entity @@ -135,34 +138,36 @@ class poly_pool_holder : public poly_pool_holder_base { /** @copydoc try_get */ inline const_pointer_type try_get(const Entity ent) const ENTT_NOEXCEPT { - return const_cast*>(this)->try_get(ent); - } - - /** - * @brief removes component from pool by entity - * @param ent entity - * @return true, if component was removed, false, if it didnt exist - */ - inline bool remove(const Entity ent) { - return this->pool_ptr->remove(ent); + return const_cast*>(this)->try_get(ent); } /** @brief returns underlying pool */ inline auto& pool() ENTT_NOEXCEPT { - return *this->pool_ptr; + return *static_cast(this->pool_ptr); } /** @copydoc pool */ inline const auto& pool() const ENTT_NOEXCEPT { - return *this->pool_ptr; + return *static_cast(this->pool_ptr); + } + + /** + * @brief removes component from pool by entity + * @param ent entity + * @return true, if component was removed, false, if it didnt exist + */ + inline bool remove(const Entity ent) { + return pool().remove(ent); } }; /** * @brief Holds runtime information about one polymorphic component type. - * @tparam Entity + * @tparam Entity underlying entity type + * @tparam Type polymorphic component type +* @tparam Allocator allocator type for all bound contained pool holders */ -template +template class poly_type { /** @brief derived value to base pointer conversion, workaround for if constexpr bug on some compilers */ template @@ -201,10 +206,12 @@ class poly_type { using entity_type = Entity; /** @brief component type */ using value_type = Type; + /** @brief allocator type */ + using allocator_type = Allocator; /** @brief type of the underlying pool container */ using pools_container = std::vector>; /** @brief type of the pool holder */ - using pool_holder = poly_pool_holder; + using pool_holder = poly_pool_holder; /** @brief single entity component iterator type */ using component_iterator = internal::poly_components_iterator; /** @brief const single entity component iterator type */ @@ -223,6 +230,8 @@ class poly_type { static_assert(is_poly_type_v); static_assert(type_list_contains_v, BaseType> || std::is_same_v); static_assert(std::is_pointer_v == std::is_pointer_v); + static_assert(std::is_same_v::template rebind_alloc::pointer, typename StorageType::base_type::allocator_type::pointer>, + "Allocator pointer types dont match for polymorphic types in one hierarchy. Use std::poly_type_allocator to explicitly provide allocator type for each polymorphic component type."); void* (*get)(void*, Entity entity) ENTT_NOEXCEPT = +[](void* pool, const Entity entity) ENTT_NOEXCEPT -> void* { if (static_cast(pool)->contains(entity)) { @@ -291,6 +300,7 @@ class poly_type { * - Type& assure(PolyPoolsHolder&) method, it must assure and return instance of @b Type stored given @b PolyPoolsHolder
* - holder_type - same as PolyPoolsHolder
* - entity_type - underlying entity type
+ * - allocator_type - allocator type getter for given component type Type
* * @tparam PolyPoolsHolder Underlying polymorphic types data holder */ @@ -309,6 +319,10 @@ struct poly_types_accessor> { /** @brief Underlying entity type */ using entity_type = Entity; + /** @brief Returns allocator type for Type */ + template + using allocator_type = poly_type_allocator_t; + /** * @brief Assures and returns instance of some type stored given polymorphic types data holder * @tparam Type Default-constructed type to assure in the underlying data holder and return @@ -345,8 +359,9 @@ template using no_const_type = poly_type_validate_t>; static_assert(is_poly_type_v, "must be a polymorphic type"); - using result_type = poly_type; - result_type& result = poly_types_accessor::template assure(const_cast&>(holder)); + using accessor_type = poly_types_accessor; + using result_type = poly_type>; + result_type& result = accessor_type::template assure(const_cast&>(holder)); if constexpr(std::is_const_v || std::is_const_v) { return const_cast(result); } else { @@ -478,7 +493,7 @@ void poly_each(PolyPoolsHolder& reg, Func func) { */ template struct entt::storage_traits>> { - using storage_type = sigh_storage_mixin>>>; + using storage_type = sigh_storage_mixin, poly_type_allocator_t>>>; }; From bf764047b985a564620c291b9432863791540b70 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sun, 1 May 2022 13:39:09 +0300 Subject: [PATCH 21/27] using simple inlined vector for bound pools to avoid heap allocation for one element --- src/entt/entity/poly_storage_mixin.hpp | 4 +- src/entt/entity/polymorphic.hpp | 99 ++++++++++++++++++++++---- 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp index 9e73b3943d..c755aa6a7c 100644 --- a/src/entt/entity/poly_storage_mixin.hpp +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -41,8 +41,8 @@ struct poly_storage_mixin : Storage { private: template void bind_all_parent_types(basic_registry& reg, [[maybe_unused]] type_list) { - (reg.ctx().template emplace>>().bind_child_storage(this), ...); - reg.ctx().template emplace>>().bind_child_storage(this); + (reg.ctx().template emplace>>().bind_storage(this), ...); + reg.ctx().template emplace>>().bind_storage(this); } }; diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index d0eae15c83..221acb7364 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -1,6 +1,8 @@ #ifndef ENTT_ENTITY_POLYMORPHIC_HPP #define ENTT_ENTITY_POLYMORPHIC_HPP +#include +#include #include "../core/type_info.hpp" #include "../core/type_traits.hpp" #include "fwd.hpp" @@ -82,6 +84,69 @@ class poly_components_iterator { pointer current = nullptr; }; + +template +struct basic_inlined_vector { + using value_type = T; + using iterator = T*; + using const_iterator = const T*; + + iterator begin() { + return std::visit([&] (auto& payload) -> iterator { + using type = std::decay_t; + if constexpr(std::is_same_v) { + return nullptr; + } else if constexpr(std::is_same_v) { + return std::addressof(payload); + } else if constexpr(std::is_same_v>) { + return std::addressof(*payload.begin()); + } + }, storage); + } + + const_iterator begin() const { + return const_cast*>(this)->begin(); + } + + iterator end() { + return std::visit([&] (auto& payload) -> iterator { + using type = std::decay_t; + if constexpr(std::is_same_v) { + return nullptr; + } else if constexpr(std::is_same_v) { + return std::addressof(payload) + 1; + } else if constexpr(std::is_same_v>) { + return std::addressof(*payload.end()); + } + }, storage); + } + + const_iterator end() const { + return const_cast*>(this)->end(); + } + + template + void emplace_back(Args&& ...args) { + std::visit([&] (auto& payload) -> void { + using type = std::decay_t; + if constexpr(std::is_same_v) { + storage.template emplace(std::forward(args)...); + } else if constexpr(std::is_same_v) { + T tmp = std::move(payload); + auto& v = storage.template emplace>(); + v.reserve(2); + v.emplace_back(std::move(tmp)); + v.emplace_back(std::forward(args)...); + } else if constexpr(std::is_same_v>) { + payload.emplace_back(std::forward(args)...); + } + }, storage); + } + +private: + std::variant> storage; +}; + } // namespace entt::internal /** @@ -208,8 +273,8 @@ class poly_type { using value_type = Type; /** @brief allocator type */ using allocator_type = Allocator; - /** @brief type of the underlying pool container */ - using pools_container = std::vector>; + /** @brief type of underlying container for bound pools */ + using pools_container = internal::basic_inlined_vector>; /** @brief type of the pool holder */ using pool_holder = poly_pool_holder; /** @brief single entity component iterator type */ @@ -251,16 +316,26 @@ class poly_type { return pool_holder(pool_ptr, get); } - /** @brief adds given storage pointer as a child type pool to this polymorphic type */ + /** @brief binds given storage pointer as a child type pool to this polymorphic type */ template - void bind_child_storage(Storage* storage_ptr) { - this->child_pool_holders.emplace_back(make_pool_holder(storage_ptr)); + void bind_storage(Storage* storage_ptr) { + bound_pools.emplace_back(make_pool_holder(storage_ptr)); + } + + /** @brief returns all pools bound for this type */ + [[nodiscard]] auto& get_bound_pools() ENTT_NOEXCEPT { + return bound_pools; + } + + /** @copydoc get_bound_pools */ + [[nodiscard]] const auto& get_bound_pools() const ENTT_NOEXCEPT { + return bound_pools; } /** @brief calls given function for all child pool holders */ template void each_pool(Func func) { - for (auto& pool : child_pool_holders) { + for (auto& pool : bound_pools) { func(static_cast(pool)); } } @@ -268,27 +343,27 @@ class poly_type { /** @copydoc each_pool */ template void each_pool(Func func) const { - for (auto& pool : child_pool_holders) { + for (auto& pool : bound_pools) { func(static_cast(pool)); } } /** @brief returns an iterable to iterate through all polymorphic components, derived from this type, attached to a given entities */ [[nodiscard]] iterable_adaptor each(const entity_type ent) { - auto begin = this->child_pool_holders.begin(); - auto end = this->child_pool_holders.end(); + auto begin = bound_pools.begin(); + auto end = bound_pools.end(); return { component_iterator(ent, begin, end), component_iterator(ent, end, end) }; } /** @copydoc each */ [[nodiscard]] iterable_adaptor each(const entity_type ent) const { - auto begin = this->child_pool_holders.cbegin(); - auto end = this->child_pool_holders.cend(); + auto begin = bound_pools.begin(); + auto end = bound_pools.end(); return { const_component_iterator(ent, begin, end), const_component_iterator(ent, end, end) }; } private: - pools_container child_pool_holders{}; + pools_container bound_pools{}; }; From 1abb428e468a3ff1d8bdda56deceb269f1519538 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sun, 1 May 2022 15:20:11 +0300 Subject: [PATCH 22/27] virtual destructor for test poly types for clang --- test/entt/common/polymorphic_type.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/entt/common/polymorphic_type.hpp b/test/entt/common/polymorphic_type.hpp index 590cdf146f..e7483404c0 100644 --- a/test/entt/common/polymorphic_type.hpp +++ b/test/entt/common/polymorphic_type.hpp @@ -4,11 +4,11 @@ #include -struct animal : public entt::inherit<> { virtual std::string name() = 0; int animal_payload{}; }; +struct animal : public entt::inherit<> { virtual std::string name() = 0; int animal_payload{}; virtual ~animal() = default; }; struct dog : public entt::inherit { std::string name() override { return "dog"; }; }; struct cat : public entt::inherit { std::string name() override { return "cat"; }; }; -struct shape { virtual std::string draw() = 0; int shape_payload{}; }; +struct shape { virtual std::string draw() = 0; int shape_payload{}; virtual ~shape() = default; }; struct sphere : public shape { std::string draw() override { return "sphere"; } }; struct cube : public shape { std::string draw() override { return "cube"; } }; From da0d8e3f14f7168755749c2b78ef05cf94c75a34 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Sun, 1 May 2022 15:32:37 +0300 Subject: [PATCH 23/27] fixed extracting pointer type from allocator --- src/entt/entity/polymorphic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 221acb7364..6aceea0736 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -295,7 +295,7 @@ class poly_type { static_assert(is_poly_type_v); static_assert(type_list_contains_v, BaseType> || std::is_same_v); static_assert(std::is_pointer_v == std::is_pointer_v); - static_assert(std::is_same_v::template rebind_alloc::pointer, typename StorageType::base_type::allocator_type::pointer>, + static_assert(std::is_same_v::template rebind_traits::pointer, typename std::allocator_traits::pointer>, "Allocator pointer types dont match for polymorphic types in one hierarchy. Use std::poly_type_allocator to explicitly provide allocator type for each polymorphic component type."); void* (*get)(void*, Entity entity) ENTT_NOEXCEPT = +[](void* pool, const Entity entity) ENTT_NOEXCEPT -> void* { From 56dfa4d189e89a8a4a5115e748a57588b7620be9 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Mon, 2 May 2022 20:29:19 +0300 Subject: [PATCH 24/27] fixed msvc (I hope so) --- src/entt/entity/polymorphic.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 6aceea0736..ecded88749 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -116,7 +116,7 @@ struct basic_inlined_vector { } else if constexpr(std::is_same_v) { return std::addressof(payload) + 1; } else if constexpr(std::is_same_v>) { - return std::addressof(*payload.end()); + return std::addressof(*payload.begin()) + payload.size(); } }, storage); } @@ -127,16 +127,17 @@ struct basic_inlined_vector { template void emplace_back(Args&& ...args) { + auto& s = storage; std::visit([&] (auto& payload) -> void { using type = std::decay_t; if constexpr(std::is_same_v) { - storage.template emplace(std::forward(args)...); + s.template emplace(std::forward(args)...); } else if constexpr(std::is_same_v) { - T tmp = std::move(payload); - auto& v = storage.template emplace>(); + std::vector v; v.reserve(2); - v.emplace_back(std::move(tmp)); + v.emplace_back(std::move(payload)); v.emplace_back(std::forward(args)...); + s.template emplace>(std::move(v)); } else if constexpr(std::is_same_v>) { payload.emplace_back(std::forward(args)...); } From bfe466807456440d8f2152fd8eb51cb87051dde9 Mon Sep 17 00:00:00 2001 From: Evgeniy Smirnov Date: Wed, 11 May 2022 17:44:45 +0300 Subject: [PATCH 25/27] possible fix for codecov issue --- test/entt/entity/polymorphic.cpp | 72 ++++++++++++++++---------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/test/entt/entity/polymorphic.cpp b/test/entt/entity/polymorphic.cpp index 913670feac..e45bb8be0c 100644 --- a/test/entt/entity/polymorphic.cpp +++ b/test/entt/entity/polymorphic.cpp @@ -31,22 +31,22 @@ TEST(PolyGetAny, Functionalities) { TEST(PolyGetAnyPointer, Functionalities) { entt::registry reg; - cat cat1; - dog dog1; - dog dog2; - cube cube2; - sphere sphere2; - fat_cat fat_cat3; + auto cat1 = std::make_unique(); + auto dog1 = std::make_unique(); + auto dog2 = std::make_unique(); + auto cube2 = std::make_unique(); + auto sphere2 = std::make_unique(); + auto fat_cat3 = std::make_unique(); entt::entity entity1 = reg.create(); // components: cat, dog entt::entity entity2 = reg.create(); // components: dog, sphere, cube entt::entity entity3 = reg.create(); // components: fat_cat - reg.emplace(entity1, &cat1); - reg.emplace(entity1, &dog1); - reg.emplace(entity2, &dog2); - reg.emplace(entity2, &cube2); - reg.emplace(entity2, &sphere2); - reg.emplace(entity3, &fat_cat3); + reg.emplace(entity1, cat1.get()); + reg.emplace(entity1, dog1.get()); + reg.emplace(entity2, dog2.get()); + reg.emplace(entity2, cube2.get()); + reg.emplace(entity2, sphere2.get()); + reg.emplace(entity3, fat_cat3.get()); ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), nullptr); ASSERT_EQ(entt::algorithm::poly_get_any(reg, entity1), reg.get(entity1)); @@ -129,22 +129,22 @@ TEST(PolyGetAll, Functionalities) { TEST(PolyGetAllPointers, Functionalities) { entt::registry reg; - cat cat1; - dog dog1; - dog dog2; - cube cube2; - sphere sphere2; - fat_cat fat_cat3; + auto cat1 = std::make_unique(); + auto dog1 = std::make_unique(); + auto dog2 = std::make_unique(); + auto cube2 = std::make_unique(); + auto sphere2 = std::make_unique(); + auto fat_cat3 = std::make_unique(); entt::entity entity1 = reg.create(); // components: cat(payload=1), dog(payload=2) entt::entity entity2 = reg.create(); // components: dog(payload=2), cube(payload=3), sphere(payload=4) entt::entity entity3 = reg.create(); // components: fat_cat(both payloads = 5) - reg.emplace(entity1, &cat1)->animal_payload = 1; - reg.emplace(entity1, &dog1)->animal_payload = 2; - reg.emplace(entity2, &dog2)->animal_payload = 2; - reg.emplace(entity2, &cube2)->shape_payload = 3; - reg.emplace(entity2, &sphere2)->shape_payload = 4; - auto* c = reg.emplace(entity3, &fat_cat3); + reg.emplace(entity1, cat1.get())->animal_payload = 1; + reg.emplace(entity1, dog1.get())->animal_payload = 2; + reg.emplace(entity2, dog2.get())->animal_payload = 2; + reg.emplace(entity2, cube2.get())->shape_payload = 3; + reg.emplace(entity2, sphere2.get())->shape_payload = 4; + auto* c = reg.emplace(entity3, fat_cat3.get()); c->animal_payload = c->shape_payload = 5; { @@ -300,22 +300,22 @@ TEST(PolyEach, Functionalities) { TEST(PolyEachPointer, Functionalities) { entt::registry reg; - cat cat1; - dog dog1; - dog dog2; - cube cube2; - sphere sphere2; - fat_cat fat_cat3; + auto cat1 = std::make_unique(); + auto dog1 = std::make_unique(); + auto dog2 = std::make_unique(); + auto cube2 = std::make_unique(); + auto sphere2 = std::make_unique(); + auto fat_cat3 = std::make_unique(); entt::entity entity1 = reg.create(); // components: cat(payload=1), dog(payload=2) entt::entity entity2 = reg.create(); // components: dog(payload=2), cube(payload=3), sphere(payload=4) entt::entity entity3 = reg.create(); // components: fat_cat(both payloads = 5) - reg.emplace(entity1, &cat1)->animal_payload = 1; - reg.emplace(entity1, &dog1)->animal_payload = 2; - reg.emplace(entity2, &dog2)->animal_payload = 2; - reg.emplace(entity2, &cube2)->shape_payload = 3; - reg.emplace(entity2, &sphere2)->shape_payload = 4; - auto* c = reg.emplace(entity3, &fat_cat3); + reg.emplace(entity1, cat1.get())->animal_payload = 1; + reg.emplace(entity1, dog1.get())->animal_payload = 2; + reg.emplace(entity2, dog2.get())->animal_payload = 2; + reg.emplace(entity2, cube2.get())->shape_payload = 3; + reg.emplace(entity2, sphere2.get())->shape_payload = 4; + auto* c = reg.emplace(entity3, fat_cat3.get()); c->animal_payload = c->shape_payload = 5; { From e795dafa1f26289edb27c4ed30ff440927172cde Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Mon, 23 May 2022 20:43:33 +0300 Subject: [PATCH 26/27] fixes after rebase --- src/entt/entity/poly_storage_mixin.hpp | 2 +- src/entt/entity/polymorphic.hpp | 52 +++++++++++++------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/entt/entity/poly_storage_mixin.hpp b/src/entt/entity/poly_storage_mixin.hpp index c755aa6a7c..4d833d3471 100644 --- a/src/entt/entity/poly_storage_mixin.hpp +++ b/src/entt/entity/poly_storage_mixin.hpp @@ -31,7 +31,7 @@ struct poly_storage_mixin : Storage { * @brief Forwards variables to mixins, if any. * @param value A variable wrapped in an opaque container. */ - void bind(any value) ENTT_NOEXCEPT override { + void bind(any value) noexcept override { if(auto *reg = any_cast>(&value); reg) { bind_all_parent_types(*reg, poly_parent_types_t{}); } diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index ecded88749..33d0ab7305 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -29,9 +29,9 @@ class poly_components_iterator { using difference_type = typename iterator_traits::difference_type; using iterator_category = std::forward_iterator_tag; - poly_components_iterator() ENTT_NOEXCEPT = default; + poly_components_iterator() noexcept = default; - poly_components_iterator(entity_type e, PoolsIterator pos, PoolsIterator last) ENTT_NOEXCEPT : + poly_components_iterator(entity_type e, PoolsIterator pos, PoolsIterator last) noexcept : ent(e), it(pos), end(last) { if (it != end) { current = static_cast(*it).try_get(ent); @@ -41,7 +41,7 @@ class poly_components_iterator { } } - poly_components_iterator &operator++() ENTT_NOEXCEPT { + poly_components_iterator &operator++() noexcept { ++it; while (it != end) { current = static_cast(*it).try_get(ent); @@ -52,24 +52,24 @@ class poly_components_iterator { return *this; } - poly_components_iterator operator++(int) ENTT_NOEXCEPT { + poly_components_iterator operator++(int) noexcept { poly_components_iterator orig = *this; return ++(*this), orig; } - bool operator==(const poly_components_iterator& other) const ENTT_NOEXCEPT { + bool operator==(const poly_components_iterator& other) const noexcept { return it == other.it; } - bool operator!=(const poly_components_iterator& other) const ENTT_NOEXCEPT { + bool operator!=(const poly_components_iterator& other) const noexcept { return it != other.it; } - pointer operator->() ENTT_NOEXCEPT { + pointer operator->() noexcept { return current; } - reference operator*() ENTT_NOEXCEPT { + reference operator*() noexcept { if constexpr(std::is_pointer_v) { return operator->(); } else { @@ -163,12 +163,12 @@ template class poly_pool_holder_base { public: inline poly_pool_holder_base(void* pool, - void* (*getter)(void*, Entity) ENTT_NOEXCEPT) : + void* (*getter)(void*, Entity) noexcept) : pool_ptr(pool), getter_ptr(getter) {} protected: void* pool_ptr; - void* (*getter_ptr)(void*, Entity) ENTT_NOEXCEPT; + void* (*getter_ptr)(void*, Entity) noexcept; }; /** @@ -198,22 +198,22 @@ class poly_pool_holder : public poly_pool_holder_base { * @param ptr pointer from the child type set * @return Returns reference to Type, converted from a given pointer. Will return pointer instead of reference, if parent type is a pointer. */ - inline pointer_type try_get(const Entity ent) ENTT_NOEXCEPT { + inline pointer_type try_get(const Entity ent) noexcept { return pointer_type(this->getter_ptr(this->pool_ptr, ent)); } /** @copydoc try_get */ - inline const_pointer_type try_get(const Entity ent) const ENTT_NOEXCEPT { + inline const_pointer_type try_get(const Entity ent) const noexcept { return const_cast*>(this)->try_get(ent); } /** @brief returns underlying pool */ - inline auto& pool() ENTT_NOEXCEPT { + inline auto& pool() noexcept { return *static_cast(this->pool_ptr); } /** @copydoc pool */ - inline const auto& pool() const ENTT_NOEXCEPT { + inline const auto& pool() const noexcept { return *static_cast(this->pool_ptr); } @@ -238,7 +238,7 @@ class poly_type { /** @brief derived value to base pointer conversion, workaround for if constexpr bug on some compilers */ template struct derived_to_base_ptr { - inline static Base* convert(Derived& ref) ENTT_NOEXCEPT { + inline static Base* convert(Derived& ref) noexcept { return static_cast(std::addressof(ref)); } }; @@ -246,7 +246,7 @@ class poly_type { /** @copydoc derived_to_base_ptr */ template struct derived_to_base_ptr>> { - inline static Base convert(Derived ptr) ENTT_NOEXCEPT { + inline static Base convert(Derived ptr) noexcept { return static_cast(ptr); } }; @@ -254,7 +254,7 @@ class poly_type { /** @brief value to pointer conversion, workaround for if constexpr bug on some compilers */ template struct value_to_ptr { - inline static T* convert(T& ref) ENTT_NOEXCEPT { + inline static T* convert(T& ref) noexcept { return std::addressof(ref); } }; @@ -262,7 +262,7 @@ class poly_type { /** @copydoc value_to_ptr */ template struct value_to_ptr>> { - inline static T convert(T ptr) ENTT_NOEXCEPT { + inline static T convert(T ptr) noexcept { return ptr; } }; @@ -290,7 +290,7 @@ class poly_type { * @return poly_storage_holder to hold ChildType set and access it as Type */ template - inline static pool_holder make_pool_holder(StorageType* pool_ptr) ENTT_NOEXCEPT { + inline static pool_holder make_pool_holder(StorageType* pool_ptr) noexcept { using BaseType = Type; using DerivedType = typename StorageType::value_type; static_assert(is_poly_type_v); @@ -299,7 +299,7 @@ class poly_type { static_assert(std::is_same_v::template rebind_traits::pointer, typename std::allocator_traits::pointer>, "Allocator pointer types dont match for polymorphic types in one hierarchy. Use std::poly_type_allocator to explicitly provide allocator type for each polymorphic component type."); - void* (*get)(void*, Entity entity) ENTT_NOEXCEPT = +[](void* pool, const Entity entity) ENTT_NOEXCEPT -> void* { + void* (*get)(void*, Entity entity) noexcept = +[](void* pool, const Entity entity) noexcept -> void* { if (static_cast(pool)->contains(entity)) { // if entity is contained within the set if constexpr(std::is_base_of_v, std::remove_pointer_t>) { @@ -324,12 +324,12 @@ class poly_type { } /** @brief returns all pools bound for this type */ - [[nodiscard]] auto& get_bound_pools() ENTT_NOEXCEPT { + [[nodiscard]] auto& get_bound_pools() noexcept { return bound_pools; } /** @copydoc get_bound_pools */ - [[nodiscard]] const auto& get_bound_pools() const ENTT_NOEXCEPT { + [[nodiscard]] const auto& get_bound_pools() const noexcept { return bound_pools; } @@ -563,13 +563,13 @@ void poly_each(PolyPoolsHolder& reg, Func func) { /** - * @brief storage_traits template specialization for polymorphic component types + * @brief storage_type template specialization for polymorphic component types * @tparam Entity entity type * @tparam Type polymorphic component type */ -template -struct entt::storage_traits>> { - using storage_type = sigh_storage_mixin, poly_type_allocator_t>>>; +template +struct entt::storage_type>> { + using type = sigh_storage_mixin, Entity, poly_type_allocator_t>>>; }; From 6255e8b3411b1a848f51b6529ea3ef130c1a1204 Mon Sep 17 00:00:00 2001 From: Eugene Smirnov Date: Tue, 24 May 2022 10:53:16 +0300 Subject: [PATCH 27/27] handling empty polymorphic types correctly --- src/entt/entity/polymorphic.hpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/entt/entity/polymorphic.hpp b/src/entt/entity/polymorphic.hpp index 33d0ab7305..0ab91b73b0 100644 --- a/src/entt/entity/polymorphic.hpp +++ b/src/entt/entity/polymorphic.hpp @@ -300,14 +300,16 @@ class poly_type { "Allocator pointer types dont match for polymorphic types in one hierarchy. Use std::poly_type_allocator to explicitly provide allocator type for each polymorphic component type."); void* (*get)(void*, Entity entity) noexcept = +[](void* pool, const Entity entity) noexcept -> void* { - if (static_cast(pool)->contains(entity)) { - // if entity is contained within the set - if constexpr(std::is_base_of_v, std::remove_pointer_t>) { - // if base type is inherited from derived type, do pointer conversion - return derived_to_base_ptr::convert(static_cast(pool)->get(entity)); - } else { - // no inheritance - no conversion required, just get the pointer - return value_to_ptr::convert(static_cast(pool)->get(entity)); + if constexpr(!ignore_as_empty_v) { + if(static_cast(pool)->contains(entity)) { + // if entity is contained within the set + if constexpr(std::is_base_of_v, std::remove_pointer_t>) { + // if base type is inherited from derived type, do pointer conversion + return derived_to_base_ptr::convert(static_cast(pool)->get(entity)); + } else { + // no inheritance - no conversion required, just get the pointer + return value_to_ptr::convert(static_cast(pool)->get(entity)); + } } } // otherwise, return null