1 #include <cstddef>
2 #include <gtest/gtest.h>
3 #include <entt/core/utility.hpp>
4 #include <entt/entity/poly_storage.hpp>
5 #include <entt/entity/registry.hpp>
6
7 template<typename... Type>
8 entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &);
9
10 template<typename Entity>
11 struct PolyStorage: entt::type_list_cat_t<
12 decltype(as_type_list(std::declval<entt::Storage<Entity>>())),
13 entt::type_list<
14 void(const Entity *, const Entity *, void *),
15 void(entt::basic_registry<Entity> &, const Entity, const void *),
16 const void *(const Entity) const,
17 void(entt::basic_registry<Entity> &) const
18 >
19 > {
20 using entity_type = Entity;
21 using size_type = std::size_t;
22
23 template<typename Base>
24 struct type: entt::Storage<Entity>::template type<Base> {
25 static constexpr auto base = decltype(as_type_list(std::declval<entt::Storage<Entity>>()))::size;
26
erasePolyStorage::type27 void erase(entt::basic_registry<Entity> &owner, const entity_type *first, const entity_type *last) {
28 entt::poly_call<base + 0>(*this, first, last, &owner);
29 }
30
emplacePolyStorage::type31 void emplace(entt::basic_registry<Entity> &owner, const entity_type entity, const void *instance) {
32 entt::poly_call<base + 1>(*this, owner, entity, instance);
33 }
34
getPolyStorage::type35 const void * get(const entity_type entity) const {
36 return entt::poly_call<base + 2>(*this, entity);
37 }
38
copy_toPolyStorage::type39 void copy_to(entt::basic_registry<Entity> &other) const {
40 entt::poly_call<base + 3>(*this, other);
41 }
42 };
43
44 template<typename Type>
45 struct members {
emplacePolyStorage::members46 static void emplace(Type &self, entt::basic_registry<Entity> &owner, const entity_type entity, const void *instance) {
47 self.emplace(owner, entity, *static_cast<const typename Type::value_type *>(instance));
48 }
49
getPolyStorage::members50 static const typename Type::value_type * get(const Type &self, const entity_type entity) {
51 return &self.get(entity);
52 }
53
copy_toPolyStorage::members54 static void copy_to(const Type &self, entt::basic_registry<entity_type> &other) {
55 const entt::sparse_set &base = self;
56 other.template insert<typename Type::value_type>(base.rbegin(), base.rend(), self.rbegin());
57 }
58 };
59
60 template<typename Type>
61 using impl = entt::value_list_cat_t<
62 typename entt::Storage<Entity>::template impl<Type>,
63 entt::value_list<
64 &Type::template erase<const entity_type *>,
65 &members<Type>::emplace,
66 &members<Type>::get,
67 &members<Type>::copy_to
68 >
69 >;
70 };
71
72 template<typename Entity>
73 struct entt::poly_storage_traits<Entity> {
74 using storage_type = entt::poly<PolyStorage<Entity>>;
75 };
76
TEST(PolyStorage,CopyEntity)77 TEST(PolyStorage, CopyEntity) {
78 entt::registry registry;
79 const auto entity = registry.create();
80 const auto other = registry.create();
81
82 registry.emplace<int>(entity, 42);
83 registry.emplace<char>(entity, 'c');
84
85 ASSERT_TRUE((registry.all_of<int, char>(entity)));
86 ASSERT_FALSE((registry.any_of<int, char>(other)));
87
88 registry.visit(entity, [&](const auto info) {
89 auto &&storage = registry.storage(info);
90 storage->emplace(registry, other, storage->get(entity));
91 });
92
93 ASSERT_TRUE((registry.all_of<int, char>(entity)));
94 ASSERT_TRUE((registry.all_of<int, char>(other)));
95
96 ASSERT_EQ(registry.get<int>(entity), registry.get<int>(other));
97 ASSERT_EQ(registry.get<char>(entity), registry.get<char>(other));
98 }
99
TEST(PolyStorage,CopyRegistry)100 TEST(PolyStorage, CopyRegistry) {
101 entt::registry registry;
102 entt::registry other;
103 entt::entity entities[10u];
104
105 registry.create(std::begin(entities), std::end(entities));
106 registry.insert<int>(std::begin(entities), std::end(entities), 42);
107 registry.insert<char>(std::begin(entities), std::end(entities), 'c');
108
109 ASSERT_EQ(registry.size(), 10u);
110 ASSERT_EQ(other.size(), 0u);
111
112 other.assign(registry.data(), registry.data() + registry.size(), registry.released());
113 registry.visit([&](const auto info) { std::as_const(registry).storage(info)->copy_to(other); });
114
115 ASSERT_EQ(registry.size(), other.size());
116 ASSERT_EQ((registry.view<int, char>().size_hint()), (other.view<int, char>().size_hint()));
117 ASSERT_NE((other.view<int, char>().size_hint()), 0u);
118
119 for(const auto entity: registry.view<int, char>()) {
120 ASSERT_EQ((registry.get<int, char>(entity)), (other.get<int, char>(entity)));
121 }
122 }
123
TEST(PolyStorage,Constness)124 TEST(PolyStorage, Constness) {
125 entt::registry registry;
126 const auto &cregistry = registry;
127
128 entt::entity entity[1];
129 entity[0] = registry.create();
130 registry.emplace<int>(entity[0], 42);
131
132 // cannot invoke erase on a const storage, let's copy the returned value
133 auto cstorage = cregistry.storage(entt::type_id<int>());
134
135 ASSERT_DEATH(cstorage->erase(registry, std::begin(entity), std::end(entity)), "");
136 ASSERT_TRUE(registry.all_of<int>(entity[0]));
137
138 auto &&storage = registry.storage(entt::type_id<int>());
139 storage->erase(registry, std::begin(entity), std::end(entity));
140
141 ASSERT_FALSE(registry.all_of<int>(entity[0]));
142 }
143