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