1 #include <gtest/gtest.h>
2 #include <entt/core/hashed_string.hpp>
3 #include <entt/meta/container.hpp>
4 #include <entt/meta/factory.hpp>
5 #include <entt/meta/meta.hpp>
6 #include <entt/meta/resolve.hpp>
7 
8 struct MetaContainer: ::testing::Test {
SetUpMetaContainer9     void SetUp() override {
10         using namespace entt::literals;
11 
12         entt::meta<double>()
13             .type("double"_hs)
14             .conv<int>();
15 
16         entt::meta<int>()
17             .type("int"_hs)
18             .conv<char>();
19     }
20 
TearDownMetaContainer21     void TearDown() override {
22         for(auto type: entt::resolve()) {
23             type.reset();
24         }
25     }
26 };
27 
TEST_F(MetaContainer,InvalidContainer)28 TEST_F(MetaContainer, InvalidContainer) {
29     ASSERT_FALSE(entt::meta_any{42}.as_sequence_container());
30     ASSERT_FALSE(entt::meta_any{42}.as_associative_container());
31 
32     ASSERT_FALSE((entt::meta_any{std::map<int, char>{}}.as_sequence_container()));
33     ASSERT_FALSE(entt::meta_any{std::vector<int>{}}.as_associative_container());
34 }
35 
TEST_F(MetaContainer,EmptySequenceContainer)36 TEST_F(MetaContainer, EmptySequenceContainer) {
37     entt::meta_sequence_container container{};
38 
39     ASSERT_FALSE(container);
40 
41     entt::meta_any any{std::vector<int>{}};
42     container = any.as_sequence_container();
43 
44     ASSERT_TRUE(container);
45 }
46 
TEST_F(MetaContainer,EmptyAssociativeContainer)47 TEST_F(MetaContainer, EmptyAssociativeContainer) {
48     entt::meta_associative_container container{};
49 
50     ASSERT_FALSE(container);
51 
52     entt::meta_any any{std::map<int, char>{}};
53     container = any.as_associative_container();
54 
55     ASSERT_TRUE(container);
56 }
57 
TEST_F(MetaContainer,SequenceContainerIterator)58 TEST_F(MetaContainer, SequenceContainerIterator) {
59     std::vector<int> vec{2, 3, 4};
60     auto any = entt::forward_as_meta(vec);
61     entt::meta_sequence_container::iterator first{};
62     auto view = any.as_sequence_container();
63 
64     ASSERT_FALSE(first);
65 
66     first = view.begin();
67     const auto last = view.end();
68 
69     ASSERT_TRUE(first);
70     ASSERT_TRUE(last);
71 
72     ASSERT_FALSE(first == last);
73     ASSERT_TRUE(first != last);
74 
75     ASSERT_NE(first, last);
76     ASSERT_EQ((*(first++)).cast<int>(), 2);
77     ASSERT_EQ((*(++first)).cast<int>(), 4);
78     ASSERT_NE(first++, last);
79     ASSERT_EQ(first, last);
80 
81     ASSERT_TRUE(first == last);
82     ASSERT_FALSE(first != last);
83 }
84 
TEST_F(MetaContainer,AssociativeContainerIterator)85 TEST_F(MetaContainer, AssociativeContainerIterator) {
86     std::map<int, char> map{{2, 'c'}, {3, 'd'}, {4, 'e'}};
87     auto any = entt::forward_as_meta(map);
88     entt::meta_associative_container::iterator first{};
89     auto view = any.as_associative_container();
90 
91     ASSERT_FALSE(first);
92 
93     first = view.begin();
94     const auto last = view.end();
95 
96     ASSERT_TRUE(first);
97     ASSERT_TRUE(last);
98 
99     ASSERT_FALSE(first == last);
100     ASSERT_TRUE(first != last);
101 
102     ASSERT_NE(first, last);
103     ASSERT_EQ((*(first++)).first.cast<int>(), 2);
104     ASSERT_EQ((*(++first)).second.cast<char>(), 'e');
105     ASSERT_NE(first++, last);
106     ASSERT_EQ(first, last);
107 
108     ASSERT_TRUE(first == last);
109     ASSERT_FALSE(first != last);
110 }
111 
TEST_F(MetaContainer,StdVector)112 TEST_F(MetaContainer, StdVector) {
113     std::vector<int> vec{};
114     auto any = entt::forward_as_meta(vec);
115 
116     auto view = any.as_sequence_container();
117 
118     ASSERT_TRUE(view);
119     ASSERT_EQ(view.value_type(), entt::resolve<int>());
120 
121     ASSERT_EQ(view.size(), 0u);
122     ASSERT_EQ(view.begin(), view.end());
123     ASSERT_TRUE(view.resize(3u));
124     ASSERT_EQ(view.size(), 3u);
125     ASSERT_NE(view.begin(), view.end());
126 
127     view[0].cast<int &>() = 2;
128     view[1].cast<int &>() = 3;
129     view[2].cast<int &>() = 4;
130 
131     ASSERT_EQ(view[1u].cast<int>(), 3);
132 
133     auto it = view.begin();
134     auto ret = view.insert(it, 0);
135 
136     ASSERT_TRUE(ret.second);
137     ASSERT_FALSE(view.insert(ret.first, 'c').second);
138     ASSERT_TRUE(view.insert(++ret.first, 1.).second);
139 
140     ASSERT_EQ(view.size(), 5u);
141     ASSERT_EQ((*view.begin()).cast<int>(), 0);
142     ASSERT_EQ((*++view.begin()).cast<int>(), 1);
143 
144     it = view.begin();
145     ret = view.erase(it);
146 
147     ASSERT_TRUE(ret.second);
148     ASSERT_EQ(view.size(), 4u);
149     ASSERT_EQ((*ret.first).cast<int>(), 1);
150 
151     ASSERT_TRUE(view.clear());
152     ASSERT_EQ(view.size(), 0u);
153 }
154 
TEST_F(MetaContainer,StdArray)155 TEST_F(MetaContainer, StdArray) {
156     std::array<int, 3> arr{};
157     auto any = entt::forward_as_meta(arr);
158 
159     auto view = any.as_sequence_container();
160 
161     ASSERT_TRUE(view);
162     ASSERT_EQ(view.value_type(), entt::resolve<int>());
163 
164     ASSERT_EQ(view.size(), 3u);
165     ASSERT_NE(view.begin(), view.end());
166     ASSERT_FALSE(view.resize(5u));
167     ASSERT_EQ(view.size(), 3u);
168 
169     view[0].cast<int &>() = 2;
170     view[1].cast<int &>() = 3;
171     view[2].cast<int &>() = 4;
172 
173     ASSERT_EQ(view[1u].cast<int>(), 3);
174 
175     auto it = view.begin();
176     auto ret = view.insert(it, 0);
177 
178     ASSERT_FALSE(ret.second);
179     ASSERT_FALSE(view.insert(it, 'c').second);
180     ASSERT_FALSE(view.insert(++it, 1).second);
181 
182     ASSERT_EQ(view.size(), 3u);
183     ASSERT_EQ((*view.begin()).cast<int>(), 2);
184     ASSERT_EQ((*++view.begin()).cast<int>(), 3);
185 
186     it = view.begin();
187     ret = view.erase(it);
188 
189     ASSERT_FALSE(ret.second);
190     ASSERT_EQ(view.size(), 3u);
191     ASSERT_EQ((*it).cast<int>(), 2);
192 
193     ASSERT_FALSE(view.clear());
194     ASSERT_EQ(view.size(), 3u);
195 }
196 
TEST_F(MetaContainer,StdMap)197 TEST_F(MetaContainer, StdMap) {
198     std::map<int, char> map{{2, 'c'}, {3, 'd'}, {4, 'e'}};
199     auto any = entt::forward_as_meta(map);
200 
201     auto view = any.as_associative_container();
202 
203     ASSERT_TRUE(view);
204     ASSERT_FALSE(view.key_only());
205     ASSERT_EQ(view.key_type(), entt::resolve<int>());
206     ASSERT_EQ(view.mapped_type(), entt::resolve<char>());
207     ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
208 
209     ASSERT_EQ(view.size(), 3u);
210     ASSERT_NE(view.begin(), view.end());
211 
212     ASSERT_EQ((*view.find(3)).second.cast<char>(), 'd');
213 
214     ASSERT_FALSE(view.insert('a', 'a'));
215     ASSERT_FALSE(view.insert(1, 1.));
216 
217     ASSERT_TRUE(view.insert(0, 'a'));
218     ASSERT_TRUE(view.insert(1., static_cast<int>('b')));
219 
220     ASSERT_EQ(view.size(), 5u);
221     ASSERT_EQ((*view.find(0)).second.cast<char>(), 'a');
222     ASSERT_EQ((*view.find(1.)).second.cast<char>(), 'b');
223 
224     ASSERT_FALSE(view.erase('c'));
225     ASSERT_EQ(view.size(), 5u);
226     ASSERT_FALSE(view.find('c'));
227 
228     ASSERT_TRUE(view.erase(0));
229     ASSERT_EQ(view.size(), 4u);
230     ASSERT_EQ(view.find(0), view.end());
231 
232     (*view.find(1)).second.cast<char &>() = 'f';
233 
234     ASSERT_EQ((*view.find(1)).second.cast<char>(), 'f');
235 
236     ASSERT_TRUE(view.erase(1.));
237     ASSERT_TRUE(view.clear());
238     ASSERT_EQ(view.size(), 0u);
239 }
240 
TEST_F(MetaContainer,StdSet)241 TEST_F(MetaContainer, StdSet) {
242     std::set<int> set{2, 3, 4};
243     auto any = entt::forward_as_meta(set);
244 
245     auto view = any.as_associative_container();
246 
247     ASSERT_TRUE(view);
248     ASSERT_TRUE(view.key_only());
249     ASSERT_EQ(view.key_type(), entt::resolve<int>());
250     ASSERT_EQ(view.mapped_type(), entt::meta_type{});
251     ASSERT_EQ(view.value_type(), entt::resolve<int>());
252 
253     ASSERT_EQ(view.size(), 3u);
254     ASSERT_NE(view.begin(), view.end());
255 
256     ASSERT_EQ((*view.find(3)).first.cast<int>(), 3);
257 
258     ASSERT_FALSE(view.insert('0'));
259 
260     ASSERT_TRUE(view.insert(0));
261     ASSERT_TRUE(view.insert(1));
262 
263     ASSERT_EQ(view.size(), 5u);
264     ASSERT_EQ((*view.find(0)).first.cast<int>(), 0);
265     ASSERT_EQ((*view.find(1.)).first.cast<int>(), 1);
266 
267     ASSERT_FALSE(view.erase('c'));
268     ASSERT_EQ(view.size(), 5u);
269     ASSERT_FALSE(view.find('c'));
270 
271     ASSERT_TRUE(view.erase(0));
272     ASSERT_EQ(view.size(), 4u);
273     ASSERT_EQ(view.find(0), view.end());
274 
275     ASSERT_EQ((*view.find(1)).first.try_cast<int>(), nullptr);
276     ASSERT_NE((*view.find(1)).first.try_cast<const int>(), nullptr);
277     ASSERT_EQ((*view.find(1)).first.cast<const int &>(), 1);
278 
279     ASSERT_TRUE(view.erase(1.));
280     ASSERT_TRUE(view.clear());
281     ASSERT_EQ(view.size(), 0u);
282 }
283 
TEST_F(MetaContainer,ConstSequenceContainer)284 TEST_F(MetaContainer, ConstSequenceContainer) {
285     std::vector<int> vec{};
286     auto any = entt::forward_as_meta(std::as_const(vec));
287 
288     auto view = any.as_sequence_container();
289 
290     ASSERT_TRUE(view);
291     ASSERT_EQ(view.value_type(), entt::resolve<int>());
292 
293     ASSERT_EQ(view.size(), 0u);
294     ASSERT_EQ(view.begin(), view.end());
295     ASSERT_FALSE(view.resize(3u));
296     ASSERT_EQ(view.size(), 0u);
297     ASSERT_EQ(view.begin(), view.end());
298 
299     vec.push_back(42);
300 
301     ASSERT_EQ(view.size(), 1u);
302     ASSERT_NE(view.begin(), view.end());
303 
304     ASSERT_DEATH(view[0].cast<int &>() = 2, "");
305     ASSERT_EQ(view[0].cast<const int &>(), 42);
306 
307     auto it = view.begin();
308     auto ret = view.insert(it, 0);
309 
310     ASSERT_FALSE(ret.second);
311     ASSERT_EQ(view.size(), 1u);
312     ASSERT_EQ((*it).cast<int>(), 42);
313     ASSERT_EQ(++it, view.end());
314 
315     it = view.begin();
316     ret = view.erase(it);
317 
318     ASSERT_FALSE(ret.second);
319     ASSERT_EQ(view.size(), 1u);
320 
321     ASSERT_FALSE(view.clear());
322     ASSERT_EQ(view.size(), 1u);
323 }
324 
TEST_F(MetaContainer,ConstKeyValueAssociativeContainer)325 TEST_F(MetaContainer, ConstKeyValueAssociativeContainer) {
326     std::map<int, char> map{};
327     auto any = entt::forward_as_meta(std::as_const(map));
328 
329     auto view = any.as_associative_container();
330 
331     ASSERT_TRUE(view);
332     ASSERT_FALSE(view.key_only());
333     ASSERT_EQ(view.key_type(), entt::resolve<int>());
334     ASSERT_EQ(view.mapped_type(), entt::resolve<char>());
335     ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
336 
337     ASSERT_EQ(view.size(), 0u);
338     ASSERT_EQ(view.begin(), view.end());
339 
340     map[2] = 'c';
341 
342     ASSERT_EQ(view.size(), 1u);
343     ASSERT_NE(view.begin(), view.end());
344 
345     ASSERT_DEATH((*view.find(2)).second.cast<char &>() = 'a', "");
346     ASSERT_EQ((*view.find(2)).second.cast<const char &>(), 'c');
347 
348     ASSERT_FALSE(view.insert(0, 'a'));
349     ASSERT_EQ(view.size(), 1u);
350     ASSERT_EQ(view.find(0), view.end());
351     ASSERT_EQ((*view.find(2)).second.cast<char>(), 'c');
352 
353     ASSERT_FALSE(view.erase(2));
354     ASSERT_EQ(view.size(), 1u);
355     ASSERT_NE(view.find(2), view.end());
356 
357     ASSERT_FALSE(view.clear());
358     ASSERT_EQ(view.size(), 1u);
359 }
360 
TEST_F(MetaContainer,ConstKeyOnlyAssociativeContainer)361 TEST_F(MetaContainer, ConstKeyOnlyAssociativeContainer) {
362     std::set<int> set{};
363     auto any = entt::forward_as_meta(std::as_const(set));
364 
365     auto view = any.as_associative_container();
366 
367     ASSERT_TRUE(view);
368     ASSERT_TRUE(view.key_only());
369     ASSERT_EQ(view.key_type(), entt::resolve<int>());
370     ASSERT_EQ(view.mapped_type(), entt::meta_type{});
371     ASSERT_EQ(view.value_type(), (entt::resolve<int>()));
372 
373     ASSERT_EQ(view.size(), 0u);
374     ASSERT_EQ(view.begin(), view.end());
375 
376     set.insert(2);
377 
378     ASSERT_EQ(view.size(), 1u);
379     ASSERT_NE(view.begin(), view.end());
380 
381     ASSERT_EQ((*view.find(2)).first.try_cast<int>(), nullptr);
382     ASSERT_NE((*view.find(2)).first.try_cast<const int>(), nullptr);
383     ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
384     ASSERT_EQ((*view.find(2)).first.cast<const int &>(), 2);
385 
386     ASSERT_FALSE(view.insert(0));
387     ASSERT_EQ(view.size(), 1u);
388     ASSERT_EQ(view.find(0), view.end());
389     ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
390 
391     ASSERT_FALSE(view.erase(2));
392     ASSERT_EQ(view.size(), 1u);
393     ASSERT_NE(view.find(2), view.end());
394 
395     ASSERT_FALSE(view.clear());
396     ASSERT_EQ(view.size(), 1u);
397 }
398 
TEST_F(MetaContainer,SequenceContainerConstMetaAny)399 TEST_F(MetaContainer, SequenceContainerConstMetaAny) {
400     auto test = [](const entt::meta_any any) {
401         auto view = any.as_sequence_container();
402 
403         ASSERT_TRUE(view);
404         ASSERT_EQ(view.value_type(), entt::resolve<int>());
405         ASSERT_DEATH(view[0].cast<int &>() = 2, "");
406         ASSERT_EQ(view[0].cast<const int &>(), 42);
407     };
408 
409     std::vector<int> vec{42};
410 
411     test(vec);
412     test(entt::forward_as_meta(vec));
413     test(entt::forward_as_meta(std::as_const(vec)));
414 }
415 
TEST_F(MetaContainer,KeyValueAssociativeContainerConstMetaAny)416 TEST_F(MetaContainer, KeyValueAssociativeContainerConstMetaAny) {
417     auto test = [](const entt::meta_any any) {
418         auto view = any.as_associative_container();
419 
420         ASSERT_TRUE(view);
421         ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
422         ASSERT_DEATH((*view.find(2)).second.cast<char &>() = 'a', "");
423         ASSERT_EQ((*view.find(2)).second.cast<const char &>(), 'c');
424     };
425 
426     std::map<int, char> map{{2, 'c'}};
427 
428     test(map);
429     test(entt::forward_as_meta(map));
430     test(entt::forward_as_meta(std::as_const(map)));
431 }
432 
TEST_F(MetaContainer,KeyOnlyAssociativeContainerConstMetaAny)433 TEST_F(MetaContainer, KeyOnlyAssociativeContainerConstMetaAny) {
434     auto test = [](const entt::meta_any any) {
435         auto view = any.as_associative_container();
436 
437         ASSERT_TRUE(view);
438         ASSERT_EQ(view.value_type(), (entt::resolve<int>()));
439 
440         ASSERT_EQ((*view.find(2)).first.try_cast<int>(), nullptr);
441         ASSERT_NE((*view.find(2)).first.try_cast<const int>(), nullptr);
442         ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
443         ASSERT_EQ((*view.find(2)).first.cast<const int &>(), 2);
444     };
445 
446     std::set<int> set{2};
447 
448     test(set);
449     test(entt::forward_as_meta(set));
450     test(entt::forward_as_meta(std::as_const(set)));
451 }
452 
TEST_F(MetaContainer,StdVectorBool)453 TEST_F(MetaContainer, StdVectorBool) {
454     using proxy_type = typename std::vector<bool>::reference;
455     using const_proxy_type = typename std::vector<bool>::const_reference;
456 
457     std::vector<bool> vec{};
458     auto any = entt::forward_as_meta(vec);
459     auto cany = std::as_const(any).as_ref();
460 
461     auto view = any.as_sequence_container();
462     auto cview = cany.as_sequence_container();
463 
464     ASSERT_TRUE(view);
465     ASSERT_EQ(view.value_type(), entt::resolve<bool>());
466 
467     ASSERT_EQ(view.size(), 0u);
468     ASSERT_EQ(view.begin(), view.end());
469     ASSERT_TRUE(view.resize(3u));
470     ASSERT_EQ(view.size(), 3u);
471     ASSERT_NE(view.begin(), view.end());
472 
473     view[0].cast<proxy_type>() = true;
474     view[1].cast<proxy_type>() = true;
475     view[2].cast<proxy_type>() = false;
476 
477     ASSERT_EQ(cview[1u].cast<const_proxy_type>(), true);
478 
479     auto it = view.begin();
480     auto ret = view.insert(it, true);
481 
482     ASSERT_TRUE(ret.second);
483     ASSERT_FALSE(view.insert(ret.first, 'c').second);
484     ASSERT_TRUE(view.insert(++ret.first, false).second);
485 
486     ASSERT_EQ(view.size(), 5u);
487     ASSERT_EQ((*view.begin()).cast<proxy_type>(), true);
488     ASSERT_EQ((*++cview.begin()).cast<const_proxy_type>(), false);
489 
490     it = view.begin();
491     ret = view.erase(it);
492 
493     ASSERT_TRUE(ret.second);
494     ASSERT_EQ(view.size(), 4u);
495     ASSERT_EQ((*ret.first).cast<proxy_type>(), false);
496 
497     ASSERT_TRUE(view.clear());
498     ASSERT_EQ(cview.size(), 0u);
499 }
500