瀏覽代碼

component_traits: entity based model

Michele Caini 1 年之前
父節點
當前提交
777ef5a0bd

+ 1 - 1
TODO

@@ -25,7 +25,6 @@ TODO:
   - documentation for reserved entities
 * storage entity: fast range-push from above
 * table: pop back to support swap and pop, single column access, empty type optimization
-* entity based component_traits
 * review cmake warning about FetchContent_Populate (need .28 and EXCLUDE_FROM_ALL for FetchContent)
 * suppress -Wself-move on CI with g++13
 * view specializations for multi, single and filtered elements
@@ -37,3 +36,4 @@ TODO:
 * any cdynamic to support const ownership construction
 * allow passing arguments to meta setter/getter (we can fallback on meta invoke for everything probably)
 * delegate/sigh: forward connect/disconnect from & to *
+* entity based component_traits, add tests for different entities

+ 8 - 5
src/entt/entity/component.hpp

@@ -36,14 +36,17 @@ struct page_size<Type, std::void_t<decltype(Type::page_size)>>
 
 /**
  * @brief Common way to access various properties of components.
- * @tparam Type Type of component.
+ * @tparam Type Element type.
+ * @tparam Entity A valid entity type.
  */
-template<typename Type, typename = void>
-struct component_traits_deprecated {
+template<typename Type, typename Entity, typename>
+struct component_traits {
     static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
 
-    /*! @brief Component type. */
-    using type = Type;
+    /*! @brief Element type. */
+    using element_type = Type;
+    /*! @brief Underlying entity identifier. */
+    using entity_type = Entity;
 
     /*! @brief Pointer stability, default is `false`. */
     static constexpr bool in_place_delete = internal::in_place_delete<Type>::value;

+ 3 - 0
src/entt/entity/fwd.hpp

@@ -25,6 +25,9 @@ enum class deletion_policy : std::uint8_t {
     unspecified = swap_and_pop
 };
 
+template<typename Type, typename Entity = entity, typename = void>
+struct component_traits;
+
 template<typename Entity = entity, typename = std::allocator<Entity>>
 class basic_sparse_set;
 

+ 1 - 1
src/entt/entity/helper.hpp

@@ -124,7 +124,7 @@ void invoke(Registry &reg, const typename Registry::entity_type entt) {
  */
 template<typename... Args>
 typename basic_storage<Args...>::entity_type to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) {
-    using traits_type = component_traits_deprecated<typename basic_storage<Args...>::value_type>;
+    using traits_type = component_traits<typename basic_storage<Args...>::value_type, typename basic_storage<Args...>::entity_type>;
     static_assert(traits_type::page_size != 0u, "Unexpected page size");
     const typename basic_storage<Args...>::base_type &base = storage;
     const auto *addr = std::addressof(instance);

+ 23 - 24
src/entt/entity/storage.hpp

@@ -23,9 +23,9 @@ namespace entt {
 /*! @cond TURN_OFF_DOXYGEN */
 namespace internal {
 
-template<typename Container>
+template<typename Container, auto Page>
 class storage_iterator final {
-    friend storage_iterator<const Container>;
+    friend storage_iterator<const Container, Page>;
 
     using container_type = std::remove_const_t<Container>;
     using alloc_traits = std::allocator_traits<typename container_type::allocator_type>;
@@ -49,7 +49,7 @@ public:
           offset{idx} {}
 
     template<bool Const = std::is_const_v<Container>, typename = std::enable_if_t<Const>>
-    constexpr storage_iterator(const storage_iterator<std::remove_const_t<Container>> &other) noexcept
+    constexpr storage_iterator(const storage_iterator<std::remove_const_t<Container>, Page> &other) noexcept
         : storage_iterator{other.payload, other.offset} {}
 
     constexpr storage_iterator &operator++() noexcept {
@@ -90,8 +90,7 @@ public:
 
     [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
         const auto pos = static_cast<typename Container::size_type>(index() - value);
-        constexpr auto page_size = component_traits_deprecated<value_type>::page_size;
-        return (*payload)[pos / page_size][fast_mod(static_cast<std::size_t>(pos), page_size)];
+        return (*payload)[pos / Page][fast_mod(static_cast<std::size_t>(pos), Page)];
     }
 
     [[nodiscard]] constexpr pointer operator->() const noexcept {
@@ -111,38 +110,38 @@ private:
     difference_type offset;
 };
 
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
+template<typename Lhs, typename Rhs, auto Page>
+[[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
     return rhs.index() - lhs.index();
 }
 
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator==(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
+template<typename Lhs, typename Rhs, auto Page>
+[[nodiscard]] constexpr bool operator==(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
     return lhs.index() == rhs.index();
 }
 
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator!=(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
+template<typename Lhs, typename Rhs, auto Page>
+[[nodiscard]] constexpr bool operator!=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
     return !(lhs == rhs);
 }
 
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator<(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
+template<typename Lhs, typename Rhs, auto Page>
+[[nodiscard]] constexpr bool operator<(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
     return lhs.index() > rhs.index();
 }
 
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator>(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
+template<typename Lhs, typename Rhs, auto Page>
+[[nodiscard]] constexpr bool operator>(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
     return rhs < lhs;
 }
 
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator<=(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
+template<typename Lhs, typename Rhs, auto Page>
+[[nodiscard]] constexpr bool operator<=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
     return !(lhs > rhs);
 }
 
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator>=(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
+template<typename Lhs, typename Rhs, auto Page>
+[[nodiscard]] constexpr bool operator>=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
     return !(lhs < rhs);
 }
 
@@ -233,7 +232,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
     using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
     using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
     using underlying_iterator = typename underlying_type::basic_iterator;
-    using traits_type = component_traits_deprecated<Type>;
+    using traits_type = component_traits<Type, Entity>;
 
     [[nodiscard]] auto &element_at(const std::size_t pos) const {
         return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
@@ -414,9 +413,9 @@ public:
     /*! @brief Constant pointer type to contained elements. */
     using const_pointer = typename alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
     /*! @brief Random access iterator type. */
-    using iterator = internal::storage_iterator<container_type>;
+    using iterator = internal::storage_iterator<container_type, traits_type::page_size>;
     /*! @brief Constant random access iterator type. */
-    using const_iterator = internal::storage_iterator<const container_type>;
+    using const_iterator = internal::storage_iterator<const container_type, traits_type::page_size>;
     /*! @brief Reverse iterator type. */
     using reverse_iterator = std::reverse_iterator<iterator>;
     /*! @brief Constant reverse iterator type. */
@@ -791,11 +790,11 @@ private:
 
 /*! @copydoc basic_storage */
 template<typename Type, typename Entity, typename Allocator>
-class basic_storage<Type, Entity, Allocator, std::enable_if_t<component_traits_deprecated<Type>::page_size == 0u>>
+class basic_storage<Type, Entity, Allocator, std::enable_if_t<component_traits<Type, Entity>::page_size == 0u>>
     : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
     using alloc_traits = std::allocator_traits<Allocator>;
     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
-    using traits_type = component_traits_deprecated<Type>;
+    using traits_type = component_traits<Type, Entity>;
 
 public:
     /*! @brief Allocator type. */

+ 7 - 7
test/entt/entity/component.cpp

@@ -13,49 +13,49 @@ struct self_contained {
 struct traits_based {};
 
 template<>
-struct entt::component_traits_deprecated<traits_based> {
+struct entt::component_traits<traits_based> {
     using type = traits_based;
     static constexpr auto in_place_delete = false;
     static constexpr auto page_size = 8u;
 };
 
 TEST(Component, VoidType) {
-    using traits_type = entt::component_traits_deprecated<void>;
+    using traits_type = entt::component_traits<void>;
 
     ASSERT_FALSE(traits_type::in_place_delete);
     ASSERT_EQ(traits_type::page_size, 0u);
 }
 
 TEST(Component, Empty) {
-    using traits_type = entt::component_traits_deprecated<test::empty>;
+    using traits_type = entt::component_traits<test::empty>;
 
     ASSERT_FALSE(traits_type::in_place_delete);
     ASSERT_EQ(traits_type::page_size, 0u);
 }
 
 TEST(Component, NonEmpty) {
-    using traits_type = entt::component_traits_deprecated<test::boxed_int>;
+    using traits_type = entt::component_traits<test::boxed_int>;
 
     ASSERT_FALSE(traits_type::in_place_delete);
     ASSERT_EQ(traits_type::page_size, ENTT_PACKED_PAGE);
 }
 
 TEST(Component, NonMovable) {
-    using traits_type = entt::component_traits_deprecated<test::non_movable>;
+    using traits_type = entt::component_traits<test::non_movable>;
 
     ASSERT_TRUE(traits_type::in_place_delete);
     ASSERT_EQ(traits_type::page_size, ENTT_PACKED_PAGE);
 }
 
 TEST(Component, SelfContained) {
-    using traits_type = entt::component_traits_deprecated<self_contained>;
+    using traits_type = entt::component_traits<self_contained>;
 
     ASSERT_TRUE(traits_type::in_place_delete);
     ASSERT_EQ(traits_type::page_size, 4u);
 }
 
 TEST(Component, TraitsBased) {
-    using traits_type = entt::component_traits_deprecated<traits_based>;
+    using traits_type = entt::component_traits<traits_based>;
 
     ASSERT_TRUE(!traits_type::in_place_delete);
     ASSERT_EQ(traits_type::page_size, 8u);

+ 1 - 1
test/entt/entity/helper.cpp

@@ -62,7 +62,7 @@ TEST(Invoke, Functionalities) {
 
 TYPED_TEST(ToEntity, Functionalities) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::registry registry;
     const entt::entity null = entt::null;

+ 1 - 1
test/entt/entity/reactive_mixin.cpp

@@ -49,7 +49,7 @@ TYPED_TEST_SUITE(ReactiveMixinDeathTest, ReactiveMixinTypes, );
 
 TYPED_TEST(ReactiveMixin, Constructors) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::reactive_mixin<entt::storage<value_type>> pool;
 

+ 3 - 3
test/entt/entity/sigh_mixin.cpp

@@ -68,7 +68,7 @@ TYPED_TEST_SUITE(SighMixinDeathTest, SighMixinTypes, );
 
 TYPED_TEST(SighMixin, Functionalities) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::registry registry;
     auto &pool = registry.storage<value_type>();
@@ -384,7 +384,7 @@ TYPED_TEST(SighMixin, Move) {
 
 TYPED_TEST(SighMixin, Swap) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::sigh_mixin<entt::storage<value_type>> pool;
     entt::sigh_mixin<entt::storage<value_type>> other;
@@ -594,7 +594,7 @@ TYPED_TEST(SighMixin, ThrowingAllocator) {
     typename storage_type::base_type &base = pool;
     registry_type registry;
 
-    constexpr auto packed_page_size = entt::component_traits_deprecated<value_type>::page_size;
+    constexpr auto packed_page_size = entt::component_traits<value_type>::page_size;
     constexpr auto sparse_page_size = entt::entt_traits<entt::entity>::page_size;
 
     std::size_t on_construct{};

+ 18 - 18
test/entt/entity/storage.cpp

@@ -62,20 +62,20 @@ struct create_from_constructor {
 };
 
 template<>
-struct entt::component_traits_deprecated<std::unordered_set<char>> {
+struct entt::component_traits<std::unordered_set<char>> {
     static constexpr auto in_place_delete = true;
     static constexpr auto page_size = 4u;
 };
 
 template<>
-struct entt::component_traits_deprecated<int> {
+struct entt::component_traits<int> {
     static constexpr auto in_place_delete = false;
     static constexpr auto page_size = 128u;
 };
 
 template<typename Type>
 struct Storage: testing::Test {
-    static_assert(entt::component_traits_deprecated<Type>::page_size != 0u, "Empty type not allowed");
+    static_assert(entt::component_traits<Type>::page_size != 0u, "Empty type not allowed");
 
     using type = Type;
 };
@@ -90,7 +90,7 @@ TYPED_TEST_SUITE(StorageDeathTest, StorageTypes, );
 
 TYPED_TEST(Storage, Constructors) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
 
@@ -164,7 +164,7 @@ TYPED_TEST(Storage, Move) {
 
 TYPED_TEST(Storage, Swap) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
     entt::storage<value_type> other;
@@ -198,7 +198,7 @@ TYPED_TEST(Storage, Swap) {
 
 TYPED_TEST(Storage, Capacity) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
 
@@ -215,7 +215,7 @@ TYPED_TEST(Storage, Capacity) {
 
 TYPED_TEST(Storage, ShrinkToFit) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
 
@@ -544,11 +544,11 @@ TYPED_TEST(Storage, IteratorConversion) {
 
 TYPED_TEST(Storage, IteratorPageSizeAwareness) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
 
-    static_assert(!std::is_same_v<value_type, int> || (traits_type::page_size != entt::component_traits_deprecated<value_type *>::page_size), "Different page size required");
+    static_assert(!std::is_same_v<value_type, int> || (traits_type::page_size != entt::component_traits<value_type *>::page_size), "Different page size required");
 
     for(unsigned int next{}; next < traits_type::page_size; ++next) {
         pool.emplace(entt::entity{next});
@@ -664,7 +664,7 @@ TEST(Storage, EmplaceSelfMoveSupportInPlaceDelete) {
 
 TYPED_TEST(Storage, TryEmplace) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
     entt::sparse_set &base = pool;
@@ -833,7 +833,7 @@ ENTT_DEBUG_TYPED_TEST(StorageDeathTest, Patch) {
 
 TYPED_TEST(Storage, Insert) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
     const std::array entity{entt::entity{1}, entt::entity{3}};
@@ -878,7 +878,7 @@ TYPED_TEST(Storage, Insert) {
 
 TYPED_TEST(Storage, Erase) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
     const std::array entity{entt::entity{1}, entt::entity{3}, entt::entity{2}};
@@ -935,7 +935,7 @@ TYPED_TEST(Storage, CrossErase) {
 
 TYPED_TEST(Storage, Remove) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
     const std::array entity{entt::entity{1}, entt::entity{3}, entt::entity{2}};
@@ -995,7 +995,7 @@ TYPED_TEST(Storage, CrossRemove) {
 
 TYPED_TEST(Storage, Clear) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
     const std::array entity{entt::entity{1}, entt::entity{3}, entt::entity{2}};
@@ -1020,7 +1020,7 @@ TYPED_TEST(Storage, Clear) {
 
 TYPED_TEST(Storage, Compact) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
 
@@ -1066,7 +1066,7 @@ TYPED_TEST(Storage, Compact) {
 
 TYPED_TEST(Storage, SwapElements) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
 
@@ -1635,7 +1635,7 @@ ENTT_DEBUG_TEST(StorageDeathTest, NonMovableComponent) {
 
 TYPED_TEST(Storage, CanModifyDuringIteration) {
     using value_type = typename TestFixture::type;
-    using traits_type = entt::component_traits_deprecated<value_type>;
+    using traits_type = entt::component_traits<value_type>;
 
     entt::storage<value_type> pool;
     auto *ptr = &pool.emplace(entt::entity{0}, 2);
@@ -1783,7 +1783,7 @@ TYPED_TEST(Storage, ThrowingAllocator) {
     entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>> pool{};
     typename std::decay_t<decltype(pool)>::base_type &base = pool;
 
-    constexpr auto packed_page_size = entt::component_traits_deprecated<value_type>::page_size;
+    constexpr auto packed_page_size = entt::component_traits<value_type>::page_size;
     constexpr auto sparse_page_size = entt::entt_traits<entt::entity>::page_size;
 
     pool.get_allocator().template throw_counter<value_type>(0u);

+ 1 - 1
test/entt/entity/storage_no_instance.cpp

@@ -17,7 +17,7 @@
 
 template<typename Type>
 struct StorageNoInstance: testing::Test {
-    static_assert(entt::component_traits_deprecated<Type>::page_size == 0u, "Non-empty type not allowed");
+    static_assert(entt::component_traits<Type>::page_size == 0u, "Non-empty type not allowed");
 
     using type = Type;