From 3b50672b70b945b1d4c9ee7d1fda0092c23ef0c0 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Wed, 28 Dec 2022 17:32:05 +0100 Subject: [PATCH] storage: restore storage_for/storage_type duality, it turned out to be very useful in practice --- src/entt/entity/fwd.hpp | 32 ++++++++++++++++++++++---------- src/entt/entity/registry.hpp | 32 ++++++++++++++++---------------- test/entt/entity/storage.cpp | 10 ++++++++-- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/entt/entity/fwd.hpp b/src/entt/entity/fwd.hpp index 7f9607d88..18e71c078 100644 --- a/src/entt/entity/fwd.hpp +++ b/src/entt/entity/fwd.hpp @@ -26,19 +26,12 @@ class sigh_mixin; * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ -template>, typename = void> +template, typename = void> struct storage_type { /*! @brief Type-to-storage conversion result. */ using type = sigh_mixin>; }; -/*! @copydoc storage_type */ -template -struct storage_type { - /*! @brief Type-to-storage conversion result. */ - using type = const typename storage_type::type; -}; - /** * @brief Helper type. * @tparam Args Arguments to forward. @@ -46,6 +39,25 @@ struct storage_type { template using storage_type_t = typename storage_type::type; +/** + * Type-to-storage conversion utility that preserves constness. + * @tparam Type Storage value type, eventually const. + * @tparam Entity A valid entity type. + * @tparam Allocator Type of allocator used to manage memory and elements. + */ +template>> +struct storage_for { + /*! @brief Type-to-storage conversion result. */ + using type = constness_as_t, Entity, Allocator>, Type>; +}; + +/** + * @brief Helper type. + * @tparam Args Arguments to forward. + */ +template +using storage_for_t = typename storage_for::type; + template> class basic_registry; @@ -172,7 +184,7 @@ using continuous_loader = basic_continuous_loader; * @tparam Exclude Types of storage used to filter the view. */ template> -using view = basic_view, type_list_transform_t>; +using view = basic_view, type_list_transform_t>; /*! @brief Alias declaration for the most common use case. */ using runtime_view = basic_runtime_view; @@ -187,7 +199,7 @@ using const_runtime_view = basic_runtime_view; * @tparam Exclude Types of storage used to filter the group. */ template -using group = basic_group, type_list_transform_t, type_list_transform_t>; +using group = basic_group, type_list_transform_t, type_list_transform_t>; } // namespace entt diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 0c2c7d9fc..1727c60df 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -243,7 +243,7 @@ class basic_registry { using basic_common_type = basic_sparse_set; template - using storage_for = typename storage_type>>::type; + using storage_for_type = typename storage_for>>::type; template struct group_handler; @@ -251,7 +251,7 @@ class basic_registry { template struct group_handler, get_t, Owned...> { // nasty workaround for an issue with the toolset v141 that doesn't accept a fold expression here - static_assert(!std::disjunction_v::traits_type::in_place_delete>...>, "Groups do not support in-place delete"); + static_assert(!std::disjunction_v::traits_type::in_place_delete>...>, "Groups do not support in-place delete"); using value_type = std::conditional_t; value_type current{}; @@ -263,7 +263,7 @@ class basic_registry { void maybe_valid_if(basic_registry &owner, const Entity entt) { [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.assure()...); - const auto is_valid = ((std::is_same_v || std::get &>(cpools).contains(entt)) && ...) + const auto is_valid = ((std::is_same_v || std::get &>(cpools).contains(entt)) && ...) && ((std::is_same_v || owner.assure().contains(entt)) && ...) && ((std::is_same_v || !owner.assure().contains(entt)) && ...); @@ -274,7 +274,7 @@ class basic_registry { } else { if(is_valid && !(std::get<0>(cpools).index(entt) < current)) { const auto pos = current++; - (std::get &>(cpools).swap_elements(std::get &>(cpools).data()[pos], entt), ...); + (std::get &>(cpools).swap_elements(std::get &>(cpools).data()[pos], entt), ...); } } } @@ -285,7 +285,7 @@ class basic_registry { } else { if(const auto cpools = std::forward_as_tuple(owner.assure()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) { const auto pos = --current; - (std::get &>(cpools).swap_elements(std::get &>(cpools).data()[pos], entt), ...); + (std::get &>(cpools).swap_elements(std::get &>(cpools).data()[pos], entt), ...); } } } @@ -305,20 +305,20 @@ class basic_registry { auto &cpool = pools[id]; if(!cpool) { - using alloc_type = typename storage_for>::allocator_type; + using alloc_type = typename storage_for_type>::allocator_type; if constexpr(std::is_same_v && !std::is_constructible_v) { // std::allocator has no cross constructors (waiting for C++20) - cpool = std::allocate_shared>>(get_allocator(), alloc_type{}); + cpool = std::allocate_shared>>(get_allocator(), alloc_type{}); } else { - cpool = std::allocate_shared>>(get_allocator(), get_allocator()); + cpool = std::allocate_shared>>(get_allocator(), get_allocator()); } cpool->bind(forward_as_any(*this)); } ENTT_ASSERT(cpool->type() == type_id(), "Unexpected type"); - return static_cast &>(*cpool); + return static_cast &>(*cpool); } template @@ -327,10 +327,10 @@ class basic_registry { if(const auto it = pools.find(id); it != pools.cend()) { ENTT_ASSERT(it->second->type() == type_id(), "Unexpected type"); - return static_cast &>(*it->second); + return static_cast &>(*it->second); } - static storage_for placeholder{}; + static storage_for_type placeholder{}; return placeholder; } @@ -1268,14 +1268,14 @@ public: * @return A newly created view. */ template - [[nodiscard]] basic_view, storage_for...>, exclude_t...>> + [[nodiscard]] basic_view, storage_for_type...>, exclude_t...>> view(exclude_t = {}) const { return {assure>(), assure>()..., assure>()...}; } /*! @copydoc view */ template - [[nodiscard]] basic_view, storage_for...>, exclude_t...>> + [[nodiscard]] basic_view, storage_for_type...>, exclude_t...>> view(exclude_t = {}) { return {assure>(), assure>()..., assure>()...}; } @@ -1305,7 +1305,7 @@ public: * @return A newly created group. */ template - [[nodiscard]] basic_group...>, get_t...>, exclude_t...>> + [[nodiscard]] basic_group...>, get_t...>, exclude_t...>> group(get_t = {}, exclude_t = {}) { static_assert(sizeof...(Owned) + sizeof...(Get) > 0, "Exclusion-only groups are not supported"); static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1, "Single component groups are not allowed"); @@ -1383,12 +1383,12 @@ public: } } - return {handler->current, std::get> &>(cpools)..., std::get> &>(cpools)..., assure>()...}; + return {handler->current, std::get> &>(cpools)..., std::get> &>(cpools)..., assure>()...}; } /*! @copydoc group */ template - [[nodiscard]] basic_group...>, get_t...>, exclude_t...>> + [[nodiscard]] basic_group...>, get_t...>, exclude_t...>> group_if_exists(get_t = {}, exclude_t = {}) const { auto it = std::find_if(groups.cbegin(), groups.cend(), [](const auto &gdata) { return gdata.size == (sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude)) diff --git a/test/entt/entity/storage.cpp b/test/entt/entity/storage.cpp index 80f7dfa9d..81a3933e7 100644 --- a/test/entt/entity/storage.cpp +++ b/test/entt/entity/storage.cpp @@ -1962,10 +1962,16 @@ TEST(Storage, UsesAllocatorConstruction) { TEST(Storage, StorageType) { // just a bunch of static asserts to avoid regressions - static_assert(std::is_same_v, const entt::sigh_mixin>>); static_assert(std::is_same_v, entt::sigh_mixin>>); - static_assert(std::is_same_v, const entt::sigh_mixin>>); static_assert(std::is_same_v, entt::sigh_mixin>>); } +TEST(Storage, StorageFor) { + // just a bunch of static asserts to avoid regressions + static_assert(std::is_same_v, const entt::sigh_mixin>>); + static_assert(std::is_same_v, entt::sigh_mixin>>); + static_assert(std::is_same_v, const entt::sigh_mixin>>); + static_assert(std::is_same_v, entt::sigh_mixin>>); +} + #endif