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