1 #include <iterator>
2 #include <algorithm>
3 #include <gtest/gtest.h>
4 #include <entt/core/type_info.hpp>
5 #include <entt/entity/component.hpp>
6 #include <entt/entity/registry.hpp>
7 #include <entt/entity/runtime_view.hpp>
8
9 struct stable_type { int value; };
10
11 template<>
12 struct entt::component_traits<stable_type>: basic_component_traits {
13 using in_place_delete = std::true_type;
14 };
15
TEST(RuntimeView,Functionalities)16 TEST(RuntimeView, Functionalities) {
17 entt::registry registry;
18
19 // forces the creation of the pools
20 registry.reserve<int>(0);
21 registry.reserve<char>(0);
22
23 entt::id_type types[] = { entt::type_hash<int>::value(), entt::type_hash<char>::value() };
24 auto view = registry.runtime_view(std::begin(types), std::end(types));
25
26 ASSERT_EQ(view.size_hint(), 0u);
27
28 const auto e0 = registry.create();
29 registry.emplace<char>(e0);
30
31 const auto e1 = registry.create();
32 registry.emplace<int>(e1);
33
34 ASSERT_NE(view.size_hint(), 0u);
35
36 registry.emplace<char>(e1);
37
38 auto it = view.begin();
39
40 ASSERT_EQ(*it, e1);
41 ASSERT_EQ(++it, (view.end()));
42
43 ASSERT_NO_FATAL_FAILURE((view.begin()++));
44 ASSERT_NO_FATAL_FAILURE((++view.begin()));
45
46 ASSERT_NE(view.begin(), view.end());
47 ASSERT_EQ(view.size_hint(), 1u);
48
49 registry.get<char>(e0) = '1';
50 registry.get<char>(e1) = '2';
51 registry.get<int>(e1) = 42;
52
53 for(auto entity: view) {
54 ASSERT_EQ(registry.get<int>(entity), 42);
55 ASSERT_EQ(registry.get<char>(entity), '2');
56 }
57
58 entt::runtime_view empty{};
59
60 ASSERT_EQ(empty.size_hint(), 0u);
61 ASSERT_EQ(empty.begin(), empty.end());
62 }
63
TEST(RuntimeView,Iterator)64 TEST(RuntimeView, Iterator) {
65 entt::registry registry;
66
67 const auto entity = registry.create();
68 registry.emplace<int>(entity);
69 registry.emplace<char>(entity);
70
71 entt::id_type types[] = { entt::type_hash<int>::value(), entt::type_hash<char>::value() };
72 auto view = registry.runtime_view(std::begin(types), std::end(types));
73 using iterator = typename decltype(view)::iterator;
74
75 iterator end{view.begin()};
76 iterator begin{};
77 begin = view.end();
78 std::swap(begin, end);
79
80 ASSERT_EQ(begin, view.begin());
81 ASSERT_EQ(end, view.end());
82 ASSERT_NE(begin, end);
83
84 ASSERT_EQ(begin++, view.begin());
85 ASSERT_EQ(begin--, view.end());
86
87 ASSERT_EQ(++begin, view.end());
88 ASSERT_EQ(--begin, view.begin());
89
90 ASSERT_EQ(*begin, entity);
91 ASSERT_EQ(*begin.operator->(), entity);
92 }
93
TEST(RuntimeView,Contains)94 TEST(RuntimeView, Contains) {
95 entt::registry registry;
96
97 const auto e0 = registry.create();
98 registry.emplace<int>(e0);
99 registry.emplace<char>(e0);
100
101 const auto e1 = registry.create();
102 registry.emplace<int>(e1);
103 registry.emplace<char>(e1);
104
105 registry.destroy(e0);
106
107 entt::id_type types[] = { entt::type_hash<int>::value(), entt::type_hash<char>::value() };
108 auto view = registry.runtime_view(std::begin(types), std::end(types));
109
110 ASSERT_FALSE(view.contains(e0));
111 ASSERT_TRUE(view.contains(e1));
112 }
113
TEST(RuntimeView,Empty)114 TEST(RuntimeView, Empty) {
115 entt::registry registry;
116
117 const auto e0 = registry.create();
118 registry.emplace<double>(e0);
119 registry.emplace<int>(e0);
120 registry.emplace<float>(e0);
121
122 const auto e1 = registry.create();
123 registry.emplace<char>(e1);
124 registry.emplace<float>(e1);
125
126 entt::id_type types[] = { entt::type_hash<int>::value(), entt::type_hash<char>::value(), entt::type_hash<float>::value() };
127 auto view = registry.runtime_view(std::begin(types), std::end(types));
128
129 view.each([](auto) { FAIL(); });
130
131 ASSERT_EQ((std::find(view.begin(), view.end(), e0)), view.end());
132 ASSERT_EQ((std::find(view.begin(), view.end(), e1)), view.end());
133 }
134
TEST(RuntimeView,Each)135 TEST(RuntimeView, Each) {
136 entt::registry registry;
137
138 const auto e0 = registry.create();
139 registry.emplace<int>(e0);
140 registry.emplace<char>(e0);
141
142 const auto e1 = registry.create();
143 registry.emplace<int>(e1);
144 registry.emplace<char>(e1);
145
146 entt::id_type types[] = { entt::type_hash<int>::value(), entt::type_hash<char>::value() };
147 auto view = registry.runtime_view(std::begin(types), std::end(types));
148 std::size_t cnt = 0;
149
150 view.each([&cnt](auto) { ++cnt; });
151
152 ASSERT_EQ(cnt, std::size_t{2});
153 }
154
TEST(RuntimeView,EachWithHoles)155 TEST(RuntimeView, EachWithHoles) {
156 entt::registry registry;
157
158 const auto e0 = registry.create();
159 const auto e1 = registry.create();
160 const auto e2 = registry.create();
161
162 registry.emplace<char>(e0, '0');
163 registry.emplace<char>(e1, '1');
164
165 registry.emplace<int>(e0, 0);
166 registry.emplace<int>(e2, 2);
167
168 entt::id_type types[] = { entt::type_hash<int>::value(), entt::type_hash<char>::value() };
169 auto view = registry.runtime_view(std::begin(types), std::end(types));
170
171 view.each([e0](auto entity) {
172 ASSERT_EQ(e0, entity);
173 });
174 }
175
TEST(RuntimeView,MissingPool)176 TEST(RuntimeView, MissingPool) {
177 entt::registry registry;
178
179 const auto e0 = registry.create();
180 registry.emplace<int>(e0);
181
182 entt::id_type types[] = { entt::type_hash<int>::value(), entt::type_hash<char>::value() };
183 auto view = registry.runtime_view(std::begin(types), std::end(types));
184
185 ASSERT_EQ(view.size_hint(), 0u);
186
187 registry.emplace<char>(e0);
188
189 ASSERT_EQ(view.size_hint(), 0u);
190 ASSERT_FALSE(view.contains(e0));
191
192 view.each([](auto) { FAIL(); });
193
194 ASSERT_EQ((std::find(view.begin(), view.end(), e0)), view.end());
195 }
196
TEST(RuntimeView,EmptyRange)197 TEST(RuntimeView, EmptyRange) {
198 entt::registry registry;
199
200 const auto e0 = registry.create();
201 registry.emplace<int>(e0);
202
203 const entt::id_type *ptr = nullptr;
204 auto view = registry.runtime_view(ptr, ptr);
205
206 ASSERT_EQ(view.size_hint(), 0u);
207 ASSERT_FALSE(view.contains(e0));
208
209 view.each([](auto) { FAIL(); });
210
211 ASSERT_EQ((std::find(view.begin(), view.end(), e0)), view.end());
212 }
213
TEST(RuntimeView,ExcludedComponents)214 TEST(RuntimeView, ExcludedComponents) {
215 entt::registry registry;
216
217 const auto e0 = registry.create();
218 registry.emplace<int>(e0);
219
220 const auto e1 = registry.create();
221 registry.emplace<int>(e1);
222 registry.emplace<char>(e1);
223
224 entt::id_type components[] = { entt::type_hash<int>::value() };
225 entt::id_type filter[] = { entt::type_hash<char>::value(), entt::type_hash<double>::value() };
226 auto view = registry.runtime_view(std::begin(components), std::end(components), std::begin(filter), std::end(filter));
227
228 ASSERT_TRUE(view.contains(e0));
229 ASSERT_FALSE(view.contains(e1));
230
231 view.each([e0](auto entity) {
232 ASSERT_EQ(e0, entity);
233 });
234 }
235
TEST(RuntimeView,StableType)236 TEST(RuntimeView, StableType) {
237 entt::registry registry;
238
239 const auto e0 = registry.create();
240 const auto e1 = registry.create();
241 const auto e2 = registry.create();
242
243 registry.emplace<int>(e0);
244 registry.emplace<int>(e1);
245 registry.emplace<int>(e2);
246
247 registry.emplace<stable_type>(e0);
248 registry.emplace<stable_type>(e1);
249
250 registry.remove<stable_type>(e1);
251
252 entt::id_type components[] = { entt::type_hash<int>::value(), entt::type_hash<stable_type>::value() };
253 auto view = registry.runtime_view(std::begin(components), std::end(components));
254
255 ASSERT_EQ(view.size_hint(), 2u);
256 ASSERT_TRUE(view.contains(e0));
257 ASSERT_FALSE(view.contains(e1));
258
259 ASSERT_EQ(*view.begin(), e0);
260 ASSERT_EQ(++view.begin(), view.end());
261
262 view.each([e0](const auto entt) {
263 ASSERT_EQ(e0, entt);
264 });
265
266 for(auto entt: view) {
267 static_assert(std::is_same_v<decltype(entt), entt::entity>);
268 ASSERT_EQ(e0, entt);
269 }
270
271 registry.compact();
272
273 ASSERT_EQ(view.size_hint(), 1u);
274 }
275