group.cpp 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468
  1. #include <algorithm>
  2. #include <cstddef>
  3. #include <functional>
  4. #include <iterator>
  5. #include <tuple>
  6. #include <type_traits>
  7. #include <utility>
  8. #include <gtest/gtest.h>
  9. #include <entt/entity/group.hpp>
  10. #include <entt/entity/registry.hpp>
  11. struct empty_type {};
  12. struct boxed_int {
  13. int value;
  14. };
  15. bool operator==(const boxed_int &lhs, const boxed_int &rhs) {
  16. return lhs.value == rhs.value;
  17. }
  18. TEST(NonOwningGroup, Functionalities) {
  19. entt::registry registry;
  20. auto group = registry.group(entt::get<int, char>);
  21. auto cgroup = std::as_const(registry).group_if_exists(entt::get<const int, const char>);
  22. ASSERT_TRUE(group.empty());
  23. const auto e0 = registry.create();
  24. registry.emplace<char>(e0, '1');
  25. const auto e1 = registry.create();
  26. registry.emplace<int>(e1, 42);
  27. registry.emplace<char>(e1, '2');
  28. ASSERT_FALSE(group.empty());
  29. ASSERT_NO_FATAL_FAILURE(group.begin()++);
  30. ASSERT_NO_FATAL_FAILURE(++cgroup.begin());
  31. ASSERT_NO_FATAL_FAILURE([](auto it) { return it++; }(group.rbegin()));
  32. ASSERT_NO_FATAL_FAILURE([](auto it) { return ++it; }(cgroup.rbegin()));
  33. ASSERT_NE(group.begin(), group.end());
  34. ASSERT_NE(cgroup.begin(), cgroup.end());
  35. ASSERT_NE(group.rbegin(), group.rend());
  36. ASSERT_NE(cgroup.rbegin(), cgroup.rend());
  37. ASSERT_EQ(group.size(), 1u);
  38. registry.emplace<int>(e0);
  39. ASSERT_EQ(group.size(), 2u);
  40. registry.erase<int>(e0);
  41. ASSERT_EQ(group.size(), 1u);
  42. for(auto entity: group) {
  43. ASSERT_EQ(std::get<0>(cgroup.get<const int, const char>(entity)), 42);
  44. ASSERT_EQ(std::get<1>(group.get<int, char>(entity)), '2');
  45. ASSERT_EQ(cgroup.get<const char>(entity), '2');
  46. }
  47. ASSERT_EQ(group.handle().data()[0u], e1);
  48. registry.erase<char>(e0);
  49. registry.erase<char>(e1);
  50. ASSERT_EQ(group.begin(), group.end());
  51. ASSERT_EQ(cgroup.begin(), cgroup.end());
  52. ASSERT_EQ(group.rbegin(), group.rend());
  53. ASSERT_EQ(cgroup.rbegin(), cgroup.rend());
  54. ASSERT_TRUE(group.empty());
  55. ASSERT_NE(group.capacity(), 0u);
  56. group.shrink_to_fit();
  57. ASSERT_EQ(group.capacity(), 0u);
  58. decltype(group) invalid{};
  59. ASSERT_TRUE(group);
  60. ASSERT_TRUE(cgroup);
  61. ASSERT_FALSE(invalid);
  62. }
  63. TEST(NonOwningGroup, Handle) {
  64. entt::registry registry;
  65. const auto entity = registry.create();
  66. auto group = registry.group(entt::get<int, char>);
  67. auto &&handle = group.handle();
  68. ASSERT_TRUE(handle.empty());
  69. ASSERT_FALSE(handle.contains(entity));
  70. ASSERT_EQ(&handle, &group.handle());
  71. registry.emplace<int>(entity);
  72. registry.emplace<char>(entity);
  73. ASSERT_FALSE(handle.empty());
  74. ASSERT_TRUE(handle.contains(entity));
  75. ASSERT_EQ(&handle, &group.handle());
  76. }
  77. TEST(NonOwningGroup, Invalid) {
  78. entt::registry registry{};
  79. auto group = std::as_const(registry).group_if_exists(entt::get<const empty_type, const int>);
  80. const auto entity = registry.create();
  81. registry.emplace<empty_type>(entity);
  82. registry.emplace<int>(entity);
  83. ASSERT_FALSE(group);
  84. ASSERT_TRUE(group.empty());
  85. ASSERT_EQ(group.size(), 0u);
  86. ASSERT_EQ(group.capacity(), 0u);
  87. ASSERT_NO_FATAL_FAILURE(group.shrink_to_fit());
  88. ASSERT_EQ(group.begin(), group.end());
  89. ASSERT_EQ(group.rbegin(), group.rend());
  90. ASSERT_FALSE(group.contains(entity));
  91. ASSERT_EQ(group.find(entity), group.end());
  92. ASSERT_EQ(group.front(), entt::entity{entt::null});
  93. ASSERT_EQ(group.back(), entt::entity{entt::null});
  94. }
  95. TEST(NonOwningGroup, ElementAccess) {
  96. entt::registry registry;
  97. auto group = registry.group(entt::get<int, char>);
  98. auto cgroup = std::as_const(registry).group_if_exists(entt::get<const int, const char>);
  99. const auto e0 = registry.create();
  100. registry.emplace<int>(e0);
  101. registry.emplace<char>(e0);
  102. const auto e1 = registry.create();
  103. registry.emplace<int>(e1);
  104. registry.emplace<char>(e1);
  105. for(auto i = 0u; i < group.size(); ++i) {
  106. ASSERT_EQ(group[i], i ? e0 : e1);
  107. ASSERT_EQ(cgroup[i], i ? e0 : e1);
  108. }
  109. }
  110. TEST(NonOwningGroup, Contains) {
  111. entt::registry registry;
  112. auto group = registry.group(entt::get<int, char>);
  113. const auto e0 = registry.create();
  114. registry.emplace<int>(e0);
  115. registry.emplace<char>(e0);
  116. const auto e1 = registry.create();
  117. registry.emplace<int>(e1);
  118. registry.emplace<char>(e1);
  119. registry.destroy(e0);
  120. ASSERT_FALSE(group.contains(e0));
  121. ASSERT_TRUE(group.contains(e1));
  122. }
  123. TEST(NonOwningGroup, Empty) {
  124. entt::registry registry;
  125. const auto e0 = registry.create();
  126. registry.emplace<double>(e0);
  127. registry.emplace<int>(e0);
  128. registry.emplace<float>(e0);
  129. const auto e1 = registry.create();
  130. registry.emplace<char>(e1);
  131. registry.emplace<float>(e1);
  132. ASSERT_TRUE(registry.group(entt::get<char, int, float>).empty());
  133. ASSERT_TRUE(registry.group(entt::get<double, char, int, float>).empty());
  134. }
  135. TEST(NonOwningGroup, Each) {
  136. entt::registry registry;
  137. entt::entity entity[2]{registry.create(), registry.create()};
  138. auto group = registry.group(entt::get<int, char>);
  139. auto cgroup = std::as_const(registry).group_if_exists(entt::get<const int, const char>);
  140. registry.emplace<int>(entity[0u], 0);
  141. registry.emplace<char>(entity[0u], 0);
  142. registry.emplace<int>(entity[1u], 1);
  143. registry.emplace<char>(entity[1u], 1);
  144. auto iterable = group.each();
  145. auto citerable = cgroup.each();
  146. ASSERT_NE(citerable.begin(), citerable.end());
  147. ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin()));
  148. ASSERT_EQ(decltype(iterable.end()){}, iterable.end());
  149. auto it = iterable.begin();
  150. ASSERT_EQ((it++, ++it), iterable.end());
  151. group.each([expected = 1u](auto entt, int &ivalue, char &cvalue) mutable {
  152. ASSERT_EQ(entt::to_integral(entt), expected);
  153. ASSERT_EQ(ivalue, expected);
  154. ASSERT_EQ(cvalue, expected);
  155. --expected;
  156. });
  157. cgroup.each([expected = 1u](const int &ivalue, const char &cvalue) mutable {
  158. ASSERT_EQ(ivalue, expected);
  159. ASSERT_EQ(cvalue, expected);
  160. --expected;
  161. });
  162. ASSERT_EQ(std::get<0>(*iterable.begin()), entity[1u]);
  163. ASSERT_EQ(std::get<0>(*++citerable.begin()), entity[0u]);
  164. static_assert(std::is_same_v<decltype(std::get<1>(*iterable.begin())), int &>);
  165. static_assert(std::is_same_v<decltype(std::get<2>(*citerable.begin())), const char &>);
  166. // do not use iterable, make sure an iterable group works when created from a temporary
  167. for(auto [entt, ivalue, cvalue]: registry.group(entt::get<int, char>).each()) {
  168. ASSERT_EQ(entt::to_integral(entt), ivalue);
  169. ASSERT_EQ(entt::to_integral(entt), cvalue);
  170. }
  171. }
  172. TEST(NonOwningGroup, Sort) {
  173. entt::registry registry;
  174. auto group = registry.group(entt::get<const int, unsigned int>);
  175. const auto e0 = registry.create();
  176. const auto e1 = registry.create();
  177. const auto e2 = registry.create();
  178. const auto e3 = registry.create();
  179. registry.emplace<unsigned int>(e0, 0u);
  180. registry.emplace<unsigned int>(e1, 1u);
  181. registry.emplace<unsigned int>(e2, 2u);
  182. registry.emplace<unsigned int>(e3, 3u);
  183. registry.emplace<int>(e0, 0);
  184. registry.emplace<int>(e1, 1);
  185. registry.emplace<int>(e2, 2);
  186. ASSERT_EQ(group.handle().data()[0u], e0);
  187. ASSERT_EQ(group.handle().data()[1u], e1);
  188. ASSERT_EQ(group.handle().data()[2u], e2);
  189. group.sort([](const entt::entity lhs, const entt::entity rhs) {
  190. return entt::to_integral(lhs) < entt::to_integral(rhs);
  191. });
  192. ASSERT_EQ(group.handle().data()[0u], e2);
  193. ASSERT_EQ(group.handle().data()[1u], e1);
  194. ASSERT_EQ(group.handle().data()[2u], e0);
  195. ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
  196. ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
  197. ASSERT_EQ((group.get<const int, unsigned int>(e2)), (std::make_tuple(2, 2u)));
  198. ASSERT_FALSE(group.contains(e3));
  199. group.sort<const int>([](const int lhs, const int rhs) {
  200. return lhs > rhs;
  201. });
  202. ASSERT_EQ(group.handle().data()[0u], e0);
  203. ASSERT_EQ(group.handle().data()[1u], e1);
  204. ASSERT_EQ(group.handle().data()[2u], e2);
  205. ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
  206. ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
  207. ASSERT_EQ((group.get<const int, unsigned int>(e2)), (std::make_tuple(2, 2u)));
  208. ASSERT_FALSE(group.contains(e3));
  209. group.sort<const int, unsigned int>([](const auto lhs, const auto rhs) {
  210. static_assert(std::is_same_v<decltype(std::get<0>(lhs)), const int &>);
  211. static_assert(std::is_same_v<decltype(std::get<1>(rhs)), unsigned int &>);
  212. return std::get<0>(lhs) < std::get<0>(rhs);
  213. });
  214. ASSERT_EQ(group.handle().data()[0u], e2);
  215. ASSERT_EQ(group.handle().data()[1u], e1);
  216. ASSERT_EQ(group.handle().data()[2u], e0);
  217. ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
  218. ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
  219. ASSERT_EQ((group.get<const int, unsigned int>(e2)), (std::make_tuple(2, 2u)));
  220. ASSERT_FALSE(group.contains(e3));
  221. }
  222. TEST(NonOwningGroup, SortAsAPool) {
  223. entt::registry registry;
  224. auto group = registry.group(entt::get<const int, unsigned int>);
  225. const auto e0 = registry.create();
  226. const auto e1 = registry.create();
  227. const auto e2 = registry.create();
  228. const auto e3 = registry.create();
  229. auto uval = 0u;
  230. auto ival = 0;
  231. registry.emplace<unsigned int>(e0, uval++);
  232. registry.emplace<unsigned int>(e1, uval++);
  233. registry.emplace<unsigned int>(e2, uval++);
  234. registry.emplace<unsigned int>(e3, uval + 1);
  235. registry.emplace<int>(e0, ival++);
  236. registry.emplace<int>(e1, ival++);
  237. registry.emplace<int>(e2, ival++);
  238. for(auto entity: group) {
  239. ASSERT_EQ(group.get<unsigned int>(entity), --uval);
  240. ASSERT_EQ(group.get<const int>(entity), --ival);
  241. }
  242. registry.sort<unsigned int>(std::less<unsigned int>{});
  243. group.sort<unsigned int>();
  244. ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
  245. ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
  246. ASSERT_EQ((group.get<const int, unsigned int>(e2)), (std::make_tuple(2, 2u)));
  247. ASSERT_FALSE(group.contains(e3));
  248. for(auto entity: group) {
  249. ASSERT_EQ(group.get<unsigned int>(entity), uval++);
  250. ASSERT_EQ(group.get<const int>(entity), ival++);
  251. }
  252. }
  253. TEST(NonOwningGroup, IndexRebuiltOnDestroy) {
  254. entt::registry registry;
  255. auto group = registry.group(entt::get<int, unsigned int>);
  256. const auto e0 = registry.create();
  257. const auto e1 = registry.create();
  258. registry.emplace<unsigned int>(e0, 0u);
  259. registry.emplace<unsigned int>(e1, 1u);
  260. registry.emplace<int>(e0, 0);
  261. registry.emplace<int>(e1, 1);
  262. registry.destroy(e0);
  263. registry.emplace<int>(registry.create(), 42);
  264. ASSERT_EQ(group.size(), 1u);
  265. ASSERT_EQ(group[{}], e1);
  266. ASSERT_EQ(group.get<int>(e1), 1);
  267. ASSERT_EQ(group.get<unsigned int>(e1), 1u);
  268. group.each([e1](auto entity, auto ivalue, auto uivalue) {
  269. ASSERT_EQ(entity, e1);
  270. ASSERT_EQ(ivalue, 1);
  271. ASSERT_EQ(uivalue, 1u);
  272. });
  273. for(auto &&curr: group.each()) {
  274. ASSERT_EQ(std::get<0>(curr), e1);
  275. ASSERT_EQ(std::get<1>(curr), 1);
  276. ASSERT_EQ(std::get<2>(curr), 1u);
  277. }
  278. }
  279. TEST(NonOwningGroup, ConstNonConstAndAllInBetween) {
  280. entt::registry registry;
  281. auto group = registry.group(entt::get<int, empty_type, const char>);
  282. ASSERT_EQ(group.size(), 0u);
  283. const auto entity = registry.create();
  284. registry.emplace<int>(entity, 0);
  285. registry.emplace<empty_type>(entity);
  286. registry.emplace<char>(entity, 'c');
  287. ASSERT_EQ(group.size(), 1u);
  288. static_assert(std::is_same_v<decltype(group.get<int>({})), int &>);
  289. static_assert(std::is_same_v<decltype(group.get<const char>({})), const char &>);
  290. static_assert(std::is_same_v<decltype(group.get<int, const char>({})), std::tuple<int &, const char &>>);
  291. static_assert(std::is_same_v<decltype(group.get({})), std::tuple<int &, const char &>>);
  292. static_assert(std::is_same_v<decltype(std::as_const(registry).group_if_exists(entt::get<int, char>)), decltype(std::as_const(registry).group_if_exists(entt::get<const int, const char>))>);
  293. static_assert(std::is_same_v<decltype(std::as_const(registry).group_if_exists(entt::get<const int, char>)), decltype(std::as_const(registry).group_if_exists(entt::get<const int, const char>))>);
  294. static_assert(std::is_same_v<decltype(std::as_const(registry).group_if_exists(entt::get<int, const char>)), decltype(std::as_const(registry).group_if_exists(entt::get<const int, const char>))>);
  295. group.each([](auto &&i, auto &&c) {
  296. static_assert(std::is_same_v<decltype(i), int &>);
  297. static_assert(std::is_same_v<decltype(c), const char &>);
  298. });
  299. for(auto [entt, iv, cv]: group.each()) {
  300. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  301. static_assert(std::is_same_v<decltype(iv), int &>);
  302. static_assert(std::is_same_v<decltype(cv), const char &>);
  303. }
  304. }
  305. TEST(NonOwningGroup, Find) {
  306. entt::registry registry;
  307. auto group = registry.group(entt::get<int, const char>);
  308. const auto e0 = registry.create();
  309. registry.emplace<int>(e0);
  310. registry.emplace<char>(e0);
  311. const auto e1 = registry.create();
  312. registry.emplace<int>(e1);
  313. registry.emplace<char>(e1);
  314. const auto e2 = registry.create();
  315. registry.emplace<int>(e2);
  316. registry.emplace<char>(e2);
  317. const auto e3 = registry.create();
  318. registry.emplace<int>(e3);
  319. registry.emplace<char>(e3);
  320. registry.erase<int>(e1);
  321. ASSERT_NE(group.find(e0), group.end());
  322. ASSERT_EQ(group.find(e1), group.end());
  323. ASSERT_NE(group.find(e2), group.end());
  324. ASSERT_NE(group.find(e3), group.end());
  325. auto it = group.find(e2);
  326. ASSERT_EQ(*it, e2);
  327. ASSERT_EQ(*(++it), e3);
  328. ASSERT_EQ(*(++it), e0);
  329. ASSERT_EQ(++it, group.end());
  330. ASSERT_EQ(++group.find(e0), group.end());
  331. const auto e4 = registry.create();
  332. registry.destroy(e4);
  333. const auto e5 = registry.create();
  334. registry.emplace<int>(e5);
  335. registry.emplace<char>(e5);
  336. ASSERT_NE(group.find(e5), group.end());
  337. ASSERT_EQ(group.find(e4), group.end());
  338. }
  339. TEST(NonOwningGroup, ExcludedComponents) {
  340. entt::registry registry;
  341. const auto e0 = registry.create();
  342. registry.emplace<int>(e0, 0);
  343. const auto e1 = registry.create();
  344. registry.emplace<int>(e1, 1);
  345. registry.emplace<char>(e1);
  346. const auto group = registry.group(entt::get<int>, entt::exclude<char>);
  347. const auto e2 = registry.create();
  348. registry.emplace<int>(e2, 2);
  349. const auto e3 = registry.create();
  350. registry.emplace<int>(e3, 3);
  351. registry.emplace<char>(e3);
  352. for(const auto entity: group) {
  353. ASSERT_TRUE(entity == e0 || entity == e2);
  354. if(entity == e0) {
  355. ASSERT_EQ(group.get<int>(e0), 0);
  356. } else if(entity == e2) {
  357. ASSERT_EQ(group.get<int>(e2), 2);
  358. }
  359. }
  360. registry.emplace<char>(e0);
  361. registry.emplace<char>(e2);
  362. ASSERT_TRUE(group.empty());
  363. registry.erase<char>(e1);
  364. registry.erase<char>(e3);
  365. for(const auto entity: group) {
  366. ASSERT_TRUE(entity == e1 || entity == e3);
  367. if(entity == e1) {
  368. ASSERT_EQ(group.get<int>(e1), 1);
  369. } else if(entity == e3) {
  370. ASSERT_EQ(group.get<int>(e3), 3);
  371. }
  372. }
  373. }
  374. TEST(NonOwningGroup, EmptyAndNonEmptyTypes) {
  375. entt::registry registry;
  376. const auto group = registry.group(entt::get<int, empty_type>);
  377. const auto e0 = registry.create();
  378. registry.emplace<empty_type>(e0);
  379. registry.emplace<int>(e0);
  380. const auto e1 = registry.create();
  381. registry.emplace<empty_type>(e1);
  382. registry.emplace<int>(e1);
  383. registry.emplace<int>(registry.create());
  384. for(const auto entity: group) {
  385. ASSERT_TRUE(entity == e0 || entity == e1);
  386. }
  387. group.each([e0, e1](const auto entity, const int &) {
  388. ASSERT_TRUE(entity == e0 || entity == e1);
  389. });
  390. for(auto [entt, iv]: group.each()) {
  391. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  392. static_assert(std::is_same_v<decltype(iv), int &>);
  393. ASSERT_TRUE(entt == e0 || entt == e1);
  394. }
  395. ASSERT_EQ(group.size(), 2u);
  396. }
  397. TEST(NonOwningGroup, TrackEntitiesOnComponentDestruction) {
  398. entt::registry registry;
  399. const auto group = registry.group(entt::get<int>, entt::exclude<char>);
  400. const auto cgroup = std::as_const(registry).group_if_exists(entt::get<const int>, entt::exclude<char>);
  401. const auto entity = registry.create();
  402. registry.emplace<int>(entity);
  403. registry.emplace<char>(entity);
  404. ASSERT_TRUE(group.empty());
  405. ASSERT_TRUE(cgroup.empty());
  406. registry.erase<char>(entity);
  407. ASSERT_FALSE(group.empty());
  408. ASSERT_FALSE(cgroup.empty());
  409. }
  410. TEST(NonOwningGroup, EmptyTypes) {
  411. entt::registry registry;
  412. const auto entity = registry.create();
  413. registry.emplace<int>(entity);
  414. registry.emplace<char>(entity);
  415. registry.emplace<empty_type>(entity);
  416. registry.group(entt::get<int, char, empty_type>).each([entity](const auto entt, int, char) {
  417. ASSERT_EQ(entity, entt);
  418. });
  419. for(auto [entt, iv, cv]: registry.group(entt::get<int, char, empty_type>).each()) {
  420. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  421. static_assert(std::is_same_v<decltype(iv), int &>);
  422. static_assert(std::is_same_v<decltype(cv), char &>);
  423. ASSERT_EQ(entity, entt);
  424. }
  425. registry.group(entt::get<int, empty_type, char>).each([check = true](int, char) mutable {
  426. ASSERT_TRUE(check);
  427. check = false;
  428. });
  429. for(auto [entt, iv, cv]: registry.group(entt::get<int, empty_type, char>).each()) {
  430. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  431. static_assert(std::is_same_v<decltype(iv), int &>);
  432. static_assert(std::is_same_v<decltype(cv), char &>);
  433. ASSERT_EQ(entity, entt);
  434. }
  435. registry.group(entt::get<empty_type, int, char>).each([entity](const auto entt, int, char) {
  436. ASSERT_EQ(entity, entt);
  437. });
  438. for(auto [entt, iv, cv]: registry.group(entt::get<empty_type, int, char>).each()) {
  439. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  440. static_assert(std::is_same_v<decltype(iv), int &>);
  441. static_assert(std::is_same_v<decltype(cv), char &>);
  442. ASSERT_EQ(entity, entt);
  443. }
  444. auto iterable = registry.group(entt::get<int, char, double>).each();
  445. ASSERT_EQ(iterable.begin(), iterable.end());
  446. }
  447. TEST(NonOwningGroup, FrontBack) {
  448. entt::registry registry;
  449. auto group = registry.group<>(entt::get<const int, const char>);
  450. ASSERT_EQ(group.front(), static_cast<entt::entity>(entt::null));
  451. ASSERT_EQ(group.back(), static_cast<entt::entity>(entt::null));
  452. const auto e0 = registry.create();
  453. registry.emplace<int>(e0);
  454. registry.emplace<char>(e0);
  455. const auto e1 = registry.create();
  456. registry.emplace<int>(e1);
  457. registry.emplace<char>(e1);
  458. const auto entity = registry.create();
  459. registry.emplace<char>(entity);
  460. ASSERT_EQ(group.front(), e1);
  461. ASSERT_EQ(group.back(), e0);
  462. }
  463. TEST(NonOwningGroup, SignalRace) {
  464. entt::registry registry;
  465. registry.on_construct<double>().connect<&entt::registry::emplace_or_replace<int>>();
  466. const auto group = registry.group(entt::get<int, double>);
  467. auto entity = registry.create();
  468. registry.emplace<double>(entity);
  469. ASSERT_EQ(group.size(), 1u);
  470. }
  471. TEST(NonOwningGroup, ExtendedGet) {
  472. using type = decltype(std::declval<entt::registry>().group(entt::get<int, empty_type, char>).get({}));
  473. static_assert(std::tuple_size_v<type> == 2u);
  474. static_assert(std::is_same_v<std::tuple_element_t<0, type>, int &>);
  475. static_assert(std::is_same_v<std::tuple_element_t<1, type>, char &>);
  476. entt::registry registry;
  477. const auto entity = registry.create();
  478. registry.emplace<int>(entity, 42);
  479. registry.emplace<char>(entity, 'c');
  480. const auto tup = registry.group(entt::get<int, char>).get(entity);
  481. ASSERT_EQ(std::get<0>(tup), 42);
  482. ASSERT_EQ(std::get<1>(tup), 'c');
  483. }
  484. TEST(NonOwningGroup, IterableGroupAlgorithmCompatibility) {
  485. entt::registry registry;
  486. const auto entity = registry.create();
  487. registry.emplace<int>(entity);
  488. registry.emplace<char>(entity);
  489. const auto group = registry.group(entt::get<int, char>);
  490. const auto iterable = group.each();
  491. const auto it = std::find_if(iterable.begin(), iterable.end(), [entity](auto args) { return std::get<0>(args) == entity; });
  492. ASSERT_EQ(std::get<0>(*it), entity);
  493. }
  494. TEST(NonOwningGroup, Storage) {
  495. entt::registry registry;
  496. const auto entity = registry.create();
  497. const auto group = registry.group(entt::get<int, const char>);
  498. static_assert(std::is_same_v<decltype(group.storage<0u>()), typename entt::storage_traits<entt::entity, int>::storage_type &>);
  499. static_assert(std::is_same_v<decltype(group.storage<int>()), typename entt::storage_traits<entt::entity, int>::storage_type &>);
  500. static_assert(std::is_same_v<decltype(group.storage<1u>()), const typename entt::storage_traits<entt::entity, char>::storage_type &>);
  501. static_assert(std::is_same_v<decltype(group.storage<const char>()), const typename entt::storage_traits<entt::entity, char>::storage_type &>);
  502. ASSERT_EQ(group.size(), 0u);
  503. group.storage<int>().emplace(entity);
  504. registry.emplace<char>(entity);
  505. ASSERT_EQ(group.size(), 1u);
  506. ASSERT_TRUE(group.storage<int>().contains(entity));
  507. ASSERT_TRUE(group.storage<const char>().contains(entity));
  508. ASSERT_TRUE((registry.all_of<int, char>(entity)));
  509. group.storage<0u>().erase(entity);
  510. ASSERT_EQ(group.size(), 0u);
  511. ASSERT_TRUE(group.storage<1u>().contains(entity));
  512. ASSERT_FALSE((registry.all_of<int, char>(entity)));
  513. }
  514. TEST(OwningGroup, Functionalities) {
  515. entt::registry registry;
  516. auto group = registry.group<int>(entt::get<char>);
  517. auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::get<const char>);
  518. ASSERT_TRUE(group.empty());
  519. const auto e0 = registry.create();
  520. registry.emplace<char>(e0, '1');
  521. const auto e1 = registry.create();
  522. registry.emplace<int>(e1, 42);
  523. registry.emplace<char>(e1, '2');
  524. ASSERT_FALSE(group.empty());
  525. ASSERT_NO_FATAL_FAILURE(group.begin()++);
  526. ASSERT_NO_FATAL_FAILURE(++cgroup.begin());
  527. ASSERT_NO_FATAL_FAILURE([](auto it) { return it++; }(group.rbegin()));
  528. ASSERT_NO_FATAL_FAILURE([](auto it) { return ++it; }(cgroup.rbegin()));
  529. ASSERT_NE(group.begin(), group.end());
  530. ASSERT_NE(cgroup.begin(), cgroup.end());
  531. ASSERT_NE(group.rbegin(), group.rend());
  532. ASSERT_NE(cgroup.rbegin(), cgroup.rend());
  533. ASSERT_EQ(group.size(), 1u);
  534. registry.emplace<int>(e0);
  535. ASSERT_EQ(group.size(), 2u);
  536. registry.erase<int>(e0);
  537. ASSERT_EQ(group.size(), 1u);
  538. ASSERT_EQ(cgroup.storage<const int>().raw()[0u][0u], 42);
  539. ASSERT_EQ(group.storage<int>().raw()[0u][0u], 42);
  540. for(auto entity: group) {
  541. ASSERT_EQ(std::get<0>(cgroup.get<const int, const char>(entity)), 42);
  542. ASSERT_EQ(std::get<1>(group.get<int, char>(entity)), '2');
  543. ASSERT_EQ(cgroup.get<const char>(entity), '2');
  544. }
  545. ASSERT_EQ(group.storage<int>().raw()[0u][0u], 42);
  546. registry.erase<char>(e0);
  547. registry.erase<char>(e1);
  548. ASSERT_EQ(group.begin(), group.end());
  549. ASSERT_EQ(cgroup.begin(), cgroup.end());
  550. ASSERT_EQ(group.rbegin(), group.rend());
  551. ASSERT_EQ(cgroup.rbegin(), cgroup.rend());
  552. ASSERT_TRUE(group.empty());
  553. decltype(group) invalid{};
  554. ASSERT_TRUE(group);
  555. ASSERT_TRUE(cgroup);
  556. ASSERT_FALSE(invalid);
  557. }
  558. TEST(OwningGroup, Invalid) {
  559. entt::registry registry{};
  560. auto group = std::as_const(registry).group_if_exists<const int>(entt::get<const empty_type>);
  561. const auto entity = registry.create();
  562. registry.emplace<empty_type>(entity);
  563. registry.emplace<int>(entity);
  564. ASSERT_FALSE(group);
  565. ASSERT_TRUE(group.empty());
  566. ASSERT_EQ(group.size(), 0u);
  567. ASSERT_EQ(group.begin(), group.end());
  568. ASSERT_EQ(group.rbegin(), group.rend());
  569. ASSERT_FALSE(group.contains(entity));
  570. ASSERT_EQ(group.find(entity), group.end());
  571. ASSERT_EQ(group.front(), entt::entity{entt::null});
  572. ASSERT_EQ(group.back(), entt::entity{entt::null});
  573. }
  574. TEST(OwningGroup, ElementAccess) {
  575. entt::registry registry;
  576. auto group = registry.group<int>(entt::get<char>);
  577. auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::get<const char>);
  578. const auto e0 = registry.create();
  579. registry.emplace<int>(e0);
  580. registry.emplace<char>(e0);
  581. const auto e1 = registry.create();
  582. registry.emplace<int>(e1);
  583. registry.emplace<char>(e1);
  584. for(auto i = 0u; i < group.size(); ++i) {
  585. ASSERT_EQ(group[i], i ? e0 : e1);
  586. ASSERT_EQ(cgroup[i], i ? e0 : e1);
  587. }
  588. }
  589. TEST(OwningGroup, Contains) {
  590. entt::registry registry;
  591. auto group = registry.group<int>(entt::get<char>);
  592. const auto e0 = registry.create();
  593. registry.emplace<int>(e0);
  594. registry.emplace<char>(e0);
  595. const auto e1 = registry.create();
  596. registry.emplace<int>(e1);
  597. registry.emplace<char>(e1);
  598. registry.destroy(e0);
  599. ASSERT_FALSE(group.contains(e0));
  600. ASSERT_TRUE(group.contains(e1));
  601. }
  602. TEST(OwningGroup, Empty) {
  603. entt::registry registry;
  604. const auto e0 = registry.create();
  605. registry.emplace<double>(e0);
  606. registry.emplace<int>(e0);
  607. registry.emplace<float>(e0);
  608. const auto e1 = registry.create();
  609. registry.emplace<char>(e1);
  610. registry.emplace<float>(e1);
  611. ASSERT_TRUE((registry.group<char, int>(entt::get<float>).empty()));
  612. ASSERT_TRUE((registry.group<double, float>(entt::get<char, int>).empty()));
  613. }
  614. TEST(OwningGroup, Each) {
  615. entt::registry registry;
  616. entt::entity entity[2]{registry.create(), registry.create()};
  617. auto group = registry.group<int>(entt::get<char>);
  618. auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::get<const char>);
  619. registry.emplace<int>(entity[0u], 0);
  620. registry.emplace<char>(entity[0u], 0);
  621. registry.emplace<int>(entity[1u], 1);
  622. registry.emplace<char>(entity[1u], 1);
  623. auto iterable = group.each();
  624. auto citerable = cgroup.each();
  625. ASSERT_NE(citerable.begin(), citerable.end());
  626. ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin()));
  627. ASSERT_EQ(decltype(iterable.end()){}, iterable.end());
  628. auto it = iterable.begin();
  629. ASSERT_EQ((it++, ++it), iterable.end());
  630. group.each([expected = 1u](auto entt, int &ivalue, char &cvalue) mutable {
  631. ASSERT_EQ(entt::to_integral(entt), expected);
  632. ASSERT_EQ(ivalue, expected);
  633. ASSERT_EQ(cvalue, expected);
  634. --expected;
  635. });
  636. cgroup.each([expected = 1u](const int &ivalue, const char &cvalue) mutable {
  637. ASSERT_EQ(ivalue, expected);
  638. ASSERT_EQ(cvalue, expected);
  639. --expected;
  640. });
  641. ASSERT_EQ(std::get<0>(*iterable.begin()), entity[1u]);
  642. ASSERT_EQ(std::get<0>(*++citerable.begin()), entity[0u]);
  643. static_assert(std::is_same_v<decltype(std::get<1>(*iterable.begin())), int &>);
  644. static_assert(std::is_same_v<decltype(std::get<2>(*citerable.begin())), const char &>);
  645. // do not use iterable, make sure an iterable group works when created from a temporary
  646. for(auto [entt, ivalue, cvalue]: registry.group<int>(entt::get<char>).each()) {
  647. ASSERT_EQ(entt::to_integral(entt), ivalue);
  648. ASSERT_EQ(entt::to_integral(entt), cvalue);
  649. }
  650. }
  651. TEST(OwningGroup, SortOrdered) {
  652. entt::registry registry;
  653. auto group = registry.group<boxed_int, char>();
  654. entt::entity entities[5]{};
  655. registry.create(std::begin(entities), std::end(entities));
  656. registry.emplace<boxed_int>(entities[0], 12);
  657. registry.emplace<char>(entities[0], 'a');
  658. registry.emplace<boxed_int>(entities[1], 9);
  659. registry.emplace<char>(entities[1], 'b');
  660. registry.emplace<boxed_int>(entities[2], 6);
  661. registry.emplace<char>(entities[2], 'c');
  662. registry.emplace<boxed_int>(entities[3], 1);
  663. registry.emplace<boxed_int>(entities[4], 2);
  664. group.sort([&group](const entt::entity lhs, const entt::entity rhs) {
  665. return group.get<boxed_int>(lhs).value < group.get<boxed_int>(rhs).value;
  666. });
  667. ASSERT_EQ(group.storage<boxed_int>().data()[0u], entities[0]);
  668. ASSERT_EQ(group.storage<boxed_int>().data()[1u], entities[1]);
  669. ASSERT_EQ(group.storage<boxed_int>().data()[2u], entities[2]);
  670. ASSERT_EQ(group.storage<boxed_int>().data()[3u], entities[3]);
  671. ASSERT_EQ(group.storage<boxed_int>().data()[4u], entities[4]);
  672. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][0u].value, 12);
  673. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][1u].value, 9);
  674. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][2u].value, 6);
  675. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][3u].value, 1);
  676. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][4u].value, 2);
  677. ASSERT_EQ(group.storage<char>().raw()[0u][0u], 'a');
  678. ASSERT_EQ(group.storage<char>().raw()[0u][1u], 'b');
  679. ASSERT_EQ(group.storage<char>().raw()[0u][2u], 'c');
  680. ASSERT_EQ((group.get<boxed_int, char>(entities[0])), (std::make_tuple(boxed_int{12}, 'a')));
  681. ASSERT_EQ((group.get<boxed_int, char>(entities[1])), (std::make_tuple(boxed_int{9}, 'b')));
  682. ASSERT_EQ((group.get<boxed_int, char>(entities[2])), (std::make_tuple(boxed_int{6}, 'c')));
  683. ASSERT_FALSE(group.contains(entities[3]));
  684. ASSERT_FALSE(group.contains(entities[4]));
  685. }
  686. TEST(OwningGroup, SortReverse) {
  687. entt::registry registry;
  688. auto group = registry.group<boxed_int, char>();
  689. entt::entity entities[5]{};
  690. registry.create(std::begin(entities), std::end(entities));
  691. registry.emplace<boxed_int>(entities[0], 6);
  692. registry.emplace<char>(entities[0], 'a');
  693. registry.emplace<boxed_int>(entities[1], 9);
  694. registry.emplace<char>(entities[1], 'b');
  695. registry.emplace<boxed_int>(entities[2], 12);
  696. registry.emplace<char>(entities[2], 'c');
  697. registry.emplace<boxed_int>(entities[3], 1);
  698. registry.emplace<boxed_int>(entities[4], 2);
  699. group.sort<boxed_int>([](const auto &lhs, const auto &rhs) {
  700. return lhs.value < rhs.value;
  701. });
  702. ASSERT_EQ(group.storage<boxed_int>().data()[0u], entities[2]);
  703. ASSERT_EQ(group.storage<boxed_int>().data()[1u], entities[1]);
  704. ASSERT_EQ(group.storage<boxed_int>().data()[2u], entities[0]);
  705. ASSERT_EQ(group.storage<boxed_int>().data()[3u], entities[3]);
  706. ASSERT_EQ(group.storage<boxed_int>().data()[4u], entities[4]);
  707. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][0u].value, 12);
  708. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][1u].value, 9);
  709. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][2u].value, 6);
  710. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][3u].value, 1);
  711. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][4u].value, 2);
  712. ASSERT_EQ(group.storage<char>().raw()[0u][0u], 'c');
  713. ASSERT_EQ(group.storage<char>().raw()[0u][1u], 'b');
  714. ASSERT_EQ(group.storage<char>().raw()[0u][2u], 'a');
  715. ASSERT_EQ((group.get<boxed_int, char>(entities[0])), (std::make_tuple(boxed_int{6}, 'a')));
  716. ASSERT_EQ((group.get<boxed_int, char>(entities[1])), (std::make_tuple(boxed_int{9}, 'b')));
  717. ASSERT_EQ((group.get<boxed_int, char>(entities[2])), (std::make_tuple(boxed_int{12}, 'c')));
  718. ASSERT_FALSE(group.contains(entities[3]));
  719. ASSERT_FALSE(group.contains(entities[4]));
  720. }
  721. TEST(OwningGroup, SortUnordered) {
  722. entt::registry registry;
  723. auto group = registry.group<boxed_int>(entt::get<char>);
  724. entt::entity entities[7]{};
  725. registry.create(std::begin(entities), std::end(entities));
  726. registry.emplace<boxed_int>(entities[0], 6);
  727. registry.emplace<char>(entities[0], 'c');
  728. registry.emplace<boxed_int>(entities[1], 3);
  729. registry.emplace<char>(entities[1], 'b');
  730. registry.emplace<boxed_int>(entities[2], 1);
  731. registry.emplace<char>(entities[2], 'a');
  732. registry.emplace<boxed_int>(entities[3], 9);
  733. registry.emplace<char>(entities[3], 'd');
  734. registry.emplace<boxed_int>(entities[4], 12);
  735. registry.emplace<char>(entities[4], 'e');
  736. registry.emplace<boxed_int>(entities[5], 4);
  737. registry.emplace<boxed_int>(entities[6], 5);
  738. group.sort<boxed_int, char>([](const auto lhs, const auto rhs) {
  739. static_assert(std::is_same_v<decltype(std::get<0>(lhs)), boxed_int &>);
  740. static_assert(std::is_same_v<decltype(std::get<1>(rhs)), char &>);
  741. return std::get<1>(lhs) < std::get<1>(rhs);
  742. });
  743. ASSERT_EQ(group.storage<boxed_int>().data()[0u], entities[4]);
  744. ASSERT_EQ(group.storage<boxed_int>().data()[1u], entities[3]);
  745. ASSERT_EQ(group.storage<boxed_int>().data()[2u], entities[0]);
  746. ASSERT_EQ(group.storage<boxed_int>().data()[3u], entities[1]);
  747. ASSERT_EQ(group.storage<boxed_int>().data()[4u], entities[2]);
  748. ASSERT_EQ(group.storage<boxed_int>().data()[5u], entities[5]);
  749. ASSERT_EQ(group.storage<boxed_int>().data()[6u], entities[6]);
  750. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][0u].value, 12);
  751. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][1u].value, 9);
  752. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][2u].value, 6);
  753. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][3u].value, 3);
  754. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][4u].value, 1);
  755. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][5u].value, 4);
  756. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][6u].value, 5);
  757. ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[0u]), 'e');
  758. ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[1u]), 'd');
  759. ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[2u]), 'c');
  760. ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[3u]), 'b');
  761. ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[4u]), 'a');
  762. ASSERT_FALSE(group.contains(entities[5]));
  763. ASSERT_FALSE(group.contains(entities[6]));
  764. }
  765. TEST(OwningGroup, SortWithExclusionList) {
  766. entt::registry registry;
  767. auto group = registry.group<boxed_int>(entt::exclude<char>);
  768. entt::entity entities[5]{};
  769. registry.create(std::begin(entities), std::end(entities));
  770. registry.emplace<boxed_int>(entities[0], 0);
  771. registry.emplace<boxed_int>(entities[1], 1);
  772. registry.emplace<boxed_int>(entities[2], 2);
  773. registry.emplace<boxed_int>(entities[3], 3);
  774. registry.emplace<boxed_int>(entities[4], 4);
  775. registry.emplace<char>(entities[2]);
  776. group.sort([](const entt::entity lhs, const entt::entity rhs) {
  777. return lhs < rhs;
  778. });
  779. ASSERT_EQ(group.storage<boxed_int>().data()[0u], entities[4]);
  780. ASSERT_EQ(group.storage<boxed_int>().data()[1u], entities[3]);
  781. ASSERT_EQ(group.storage<boxed_int>().data()[2u], entities[1]);
  782. ASSERT_EQ(group.storage<boxed_int>().data()[3u], entities[0]);
  783. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][0u].value, 4);
  784. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][1u].value, 3);
  785. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][2u].value, 1);
  786. ASSERT_EQ(group.storage<boxed_int>().raw()[0u][3u].value, 0);
  787. ASSERT_EQ(group.get<boxed_int>(entities[0]).value, 0);
  788. ASSERT_EQ(group.get<boxed_int>(entities[1]).value, 1);
  789. ASSERT_EQ(group.get<boxed_int>(entities[3]).value, 3);
  790. ASSERT_EQ(group.get<boxed_int>(entities[4]).value, 4);
  791. ASSERT_FALSE(group.contains(entities[2]));
  792. }
  793. TEST(OwningGroup, IndexRebuiltOnDestroy) {
  794. entt::registry registry;
  795. auto group = registry.group<int>(entt::get<unsigned int>);
  796. const auto e0 = registry.create();
  797. const auto e1 = registry.create();
  798. registry.emplace<unsigned int>(e0, 0u);
  799. registry.emplace<unsigned int>(e1, 1u);
  800. registry.emplace<int>(e0, 0);
  801. registry.emplace<int>(e1, 1);
  802. registry.destroy(e0);
  803. registry.emplace<int>(registry.create(), 42);
  804. ASSERT_EQ(group.size(), 1u);
  805. ASSERT_EQ(group[{}], e1);
  806. ASSERT_EQ(group.get<int>(e1), 1);
  807. ASSERT_EQ(group.get<unsigned int>(e1), 1u);
  808. group.each([e1](auto entity, auto ivalue, auto uivalue) {
  809. ASSERT_EQ(entity, e1);
  810. ASSERT_EQ(ivalue, 1);
  811. ASSERT_EQ(uivalue, 1u);
  812. });
  813. for(auto &&curr: group.each()) {
  814. ASSERT_EQ(std::get<0>(curr), e1);
  815. ASSERT_EQ(std::get<1>(curr), 1);
  816. ASSERT_EQ(std::get<2>(curr), 1u);
  817. }
  818. }
  819. TEST(OwningGroup, ConstNonConstAndAllInBetween) {
  820. entt::registry registry;
  821. auto group = registry.group<int, const char>(entt::get<empty_type, double, const float>);
  822. ASSERT_EQ(group.size(), 0u);
  823. const auto entity = registry.create();
  824. registry.emplace<int>(entity, 0);
  825. registry.emplace<char>(entity, 'c');
  826. registry.emplace<empty_type>(entity);
  827. registry.emplace<double>(entity, 0.);
  828. registry.emplace<float>(entity, 0.f);
  829. ASSERT_EQ(group.size(), 1u);
  830. static_assert(std::is_same_v<decltype(group.get<int>({})), int &>);
  831. static_assert(std::is_same_v<decltype(group.get<const char>({})), const char &>);
  832. static_assert(std::is_same_v<decltype(group.get<double>({})), double &>);
  833. static_assert(std::is_same_v<decltype(group.get<const float>({})), const float &>);
  834. static_assert(std::is_same_v<decltype(group.get<int, const char, double, const float>({})), std::tuple<int &, const char &, double &, const float &>>);
  835. static_assert(std::is_same_v<decltype(group.get({})), std::tuple<int &, const char &, double &, const float &>>);
  836. static_assert(std::is_same_v<decltype(std::as_const(registry).group_if_exists<int>(entt::get<char>)), decltype(std::as_const(registry).group_if_exists<const int>(entt::get<const char>))>);
  837. static_assert(std::is_same_v<decltype(std::as_const(registry).group_if_exists<const int>(entt::get<char>)), decltype(std::as_const(registry).group_if_exists<const int>(entt::get<const char>))>);
  838. static_assert(std::is_same_v<decltype(std::as_const(registry).group_if_exists<int>(entt::get<const char>)), decltype(std::as_const(registry).group_if_exists<const int>(entt::get<const char>))>);
  839. group.each([](auto &&i, auto &&c, auto &&d, auto &&f) {
  840. static_assert(std::is_same_v<decltype(i), int &>);
  841. static_assert(std::is_same_v<decltype(c), const char &>);
  842. static_assert(std::is_same_v<decltype(d), double &>);
  843. static_assert(std::is_same_v<decltype(f), const float &>);
  844. });
  845. for(auto [entt, iv, cv, dv, fv]: group.each()) {
  846. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  847. static_assert(std::is_same_v<decltype(iv), int &>);
  848. static_assert(std::is_same_v<decltype(cv), const char &>);
  849. static_assert(std::is_same_v<decltype(dv), double &>);
  850. static_assert(std::is_same_v<decltype(fv), const float &>);
  851. }
  852. }
  853. TEST(OwningGroup, Find) {
  854. entt::registry registry;
  855. auto group = registry.group<int>(entt::get<const char>);
  856. const auto e0 = registry.create();
  857. registry.emplace<int>(e0);
  858. registry.emplace<char>(e0);
  859. const auto e1 = registry.create();
  860. registry.emplace<int>(e1);
  861. registry.emplace<char>(e1);
  862. const auto e2 = registry.create();
  863. registry.emplace<int>(e2);
  864. registry.emplace<char>(e2);
  865. const auto e3 = registry.create();
  866. registry.emplace<int>(e3);
  867. registry.emplace<char>(e3);
  868. registry.erase<int>(e1);
  869. ASSERT_NE(group.find(e0), group.end());
  870. ASSERT_EQ(group.find(e1), group.end());
  871. ASSERT_NE(group.find(e2), group.end());
  872. ASSERT_NE(group.find(e3), group.end());
  873. auto it = group.find(e2);
  874. ASSERT_EQ(*it, e2);
  875. ASSERT_EQ(*(++it), e3);
  876. ASSERT_EQ(*(++it), e0);
  877. ASSERT_EQ(++it, group.end());
  878. ASSERT_EQ(++group.find(e0), group.end());
  879. const auto e4 = registry.create();
  880. registry.destroy(e4);
  881. const auto e5 = registry.create();
  882. registry.emplace<int>(e5);
  883. registry.emplace<char>(e5);
  884. ASSERT_NE(group.find(e5), group.end());
  885. ASSERT_EQ(group.find(e4), group.end());
  886. }
  887. TEST(OwningGroup, ExcludedComponents) {
  888. entt::registry registry;
  889. const auto e0 = registry.create();
  890. registry.emplace<int>(e0, 0);
  891. const auto e1 = registry.create();
  892. registry.emplace<int>(e1, 1);
  893. registry.emplace<char>(e1);
  894. const auto group = registry.group<int>(entt::exclude<char, double>);
  895. const auto e2 = registry.create();
  896. registry.emplace<int>(e2, 2);
  897. const auto e3 = registry.create();
  898. registry.emplace<int>(e3, 3);
  899. registry.emplace<double>(e3);
  900. for(const auto entity: group) {
  901. ASSERT_TRUE(entity == e0 || entity == e2);
  902. if(entity == e0) {
  903. ASSERT_EQ(group.get<int>(e0), 0);
  904. } else if(entity == e2) {
  905. ASSERT_EQ(group.get<int>(e2), 2);
  906. }
  907. }
  908. registry.emplace<char>(e0);
  909. registry.emplace<double>(e2);
  910. ASSERT_TRUE(group.empty());
  911. registry.erase<char>(e1);
  912. registry.erase<double>(e3);
  913. for(const auto entity: group) {
  914. ASSERT_TRUE(entity == e1 || entity == e3);
  915. if(entity == e1) {
  916. ASSERT_EQ(group.get<int>(e1), 1);
  917. } else if(entity == e3) {
  918. ASSERT_EQ(group.get<int>(e3), 3);
  919. }
  920. }
  921. }
  922. TEST(OwningGroup, EmptyAndNonEmptyTypes) {
  923. entt::registry registry;
  924. const auto group = registry.group<int>(entt::get<empty_type>);
  925. const auto e0 = registry.create();
  926. registry.emplace<empty_type>(e0);
  927. registry.emplace<int>(e0);
  928. const auto e1 = registry.create();
  929. registry.emplace<empty_type>(e1);
  930. registry.emplace<int>(e1);
  931. registry.emplace<int>(registry.create());
  932. for(const auto entity: group) {
  933. ASSERT_TRUE(entity == e0 || entity == e1);
  934. }
  935. group.each([e0, e1](const auto entity, const int &) {
  936. ASSERT_TRUE(entity == e0 || entity == e1);
  937. });
  938. for(auto [entt, iv]: group.each()) {
  939. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  940. static_assert(std::is_same_v<decltype(iv), int &>);
  941. ASSERT_TRUE(entt == e0 || entt == e1);
  942. }
  943. ASSERT_EQ(group.size(), 2u);
  944. }
  945. TEST(OwningGroup, TrackEntitiesOnComponentDestruction) {
  946. entt::registry registry;
  947. const auto group = registry.group<int>(entt::exclude<char>);
  948. const auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::exclude<char>);
  949. const auto entity = registry.create();
  950. registry.emplace<int>(entity);
  951. registry.emplace<char>(entity);
  952. ASSERT_TRUE(group.empty());
  953. ASSERT_TRUE(cgroup.empty());
  954. registry.erase<char>(entity);
  955. ASSERT_FALSE(group.empty());
  956. ASSERT_FALSE(cgroup.empty());
  957. }
  958. TEST(OwningGroup, EmptyTypes) {
  959. entt::registry registry;
  960. const auto entity = registry.create();
  961. registry.emplace<int>(entity);
  962. registry.emplace<char>(entity);
  963. registry.emplace<empty_type>(entity);
  964. registry.group<int>(entt::get<char, empty_type>).each([entity](const auto entt, int, char) {
  965. ASSERT_EQ(entity, entt);
  966. });
  967. for(auto [entt, iv, cv]: registry.group<int>(entt::get<char, empty_type>).each()) {
  968. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  969. static_assert(std::is_same_v<decltype(iv), int &>);
  970. static_assert(std::is_same_v<decltype(cv), char &>);
  971. ASSERT_EQ(entity, entt);
  972. }
  973. registry.group<char>(entt::get<empty_type, int>).each([check = true](char, int) mutable {
  974. ASSERT_TRUE(check);
  975. check = false;
  976. });
  977. for(auto [entt, cv, iv]: registry.group<char>(entt::get<empty_type, int>).each()) {
  978. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  979. static_assert(std::is_same_v<decltype(cv), char &>);
  980. static_assert(std::is_same_v<decltype(iv), int &>);
  981. ASSERT_EQ(entity, entt);
  982. }
  983. registry.group<empty_type>(entt::get<int, char>).each([entity](const auto entt, int, char) {
  984. ASSERT_EQ(entity, entt);
  985. });
  986. for(auto [entt, iv, cv]: registry.group<empty_type>(entt::get<int, char>).each()) {
  987. static_assert(std::is_same_v<decltype(entt), entt::entity>);
  988. static_assert(std::is_same_v<decltype(iv), int &>);
  989. static_assert(std::is_same_v<decltype(cv), char &>);
  990. ASSERT_EQ(entity, entt);
  991. }
  992. auto iterable = registry.group<double>(entt::get<int, char>).each();
  993. ASSERT_EQ(iterable.begin(), iterable.end());
  994. }
  995. TEST(OwningGroup, FrontBack) {
  996. entt::registry registry;
  997. auto group = registry.group<const char>(entt::get<const int>);
  998. ASSERT_EQ(group.front(), static_cast<entt::entity>(entt::null));
  999. ASSERT_EQ(group.back(), static_cast<entt::entity>(entt::null));
  1000. const auto e0 = registry.create();
  1001. registry.emplace<int>(e0);
  1002. registry.emplace<char>(e0);
  1003. const auto e1 = registry.create();
  1004. registry.emplace<int>(e1);
  1005. registry.emplace<char>(e1);
  1006. const auto entity = registry.create();
  1007. registry.emplace<char>(entity);
  1008. ASSERT_EQ(group.front(), e1);
  1009. ASSERT_EQ(group.back(), e0);
  1010. }
  1011. TEST(OwningGroup, SignalRace) {
  1012. entt::registry registry;
  1013. registry.on_construct<double>().connect<&entt::registry::emplace_or_replace<int>>();
  1014. const auto group = registry.group<int>(entt::get<double>);
  1015. auto entity = registry.create();
  1016. registry.emplace<double>(entity);
  1017. ASSERT_EQ(group.size(), 1u);
  1018. }
  1019. TEST(OwningGroup, StableLateInitialization) {
  1020. entt::registry registry;
  1021. for(std::size_t i{}; i < 30u; ++i) {
  1022. auto entity = registry.create();
  1023. if(!(i % 2u)) registry.emplace<int>(entity);
  1024. if(!(i % 3u)) registry.emplace<char>(entity);
  1025. }
  1026. // thanks to @pgruenbacher for pointing out this corner case
  1027. ASSERT_EQ((registry.group<int, char>().size()), 5u);
  1028. }
  1029. TEST(OwningGroup, PreventEarlyOptOut) {
  1030. entt::registry registry;
  1031. registry.emplace<int>(registry.create(), 3);
  1032. const auto entity = registry.create();
  1033. registry.emplace<char>(entity, 'c');
  1034. registry.emplace<int>(entity, 2);
  1035. // thanks to @pgruenbacher for pointing out this corner case
  1036. registry.group<char, int>().each([entity](const auto entt, const auto &c, const auto &i) {
  1037. ASSERT_EQ(entity, entt);
  1038. ASSERT_EQ(c, 'c');
  1039. ASSERT_EQ(i, 2);
  1040. });
  1041. }
  1042. TEST(OwningGroup, SwappingValuesIsAllowed) {
  1043. entt::registry registry;
  1044. const auto group = registry.group<boxed_int>(entt::get<empty_type>);
  1045. for(std::size_t i{}; i < 2u; ++i) {
  1046. const auto entity = registry.create();
  1047. registry.emplace<boxed_int>(entity, static_cast<int>(i));
  1048. registry.emplace<empty_type>(entity);
  1049. }
  1050. registry.destroy(group.back());
  1051. // thanks to @andranik3949 for pointing out this missing test
  1052. registry.view<const boxed_int>().each([](const auto entity, const auto &value) {
  1053. ASSERT_EQ(entt::to_integral(entity), value.value);
  1054. });
  1055. }
  1056. TEST(OwningGroup, ExtendedGet) {
  1057. using type = decltype(std::declval<entt::registry>().group<int, empty_type>(entt::get<char>).get({}));
  1058. static_assert(std::tuple_size_v<type> == 2u);
  1059. static_assert(std::is_same_v<std::tuple_element_t<0, type>, int &>);
  1060. static_assert(std::is_same_v<std::tuple_element_t<1, type>, char &>);
  1061. entt::registry registry;
  1062. const auto entity = registry.create();
  1063. registry.emplace<int>(entity, 42);
  1064. registry.emplace<char>(entity, 'c');
  1065. const auto tup = registry.group<int>(entt::get<char>).get(entity);
  1066. ASSERT_EQ(std::get<0>(tup), 42);
  1067. ASSERT_EQ(std::get<1>(tup), 'c');
  1068. }
  1069. TEST(OwningGroup, IterableGroupAlgorithmCompatibility) {
  1070. entt::registry registry;
  1071. const auto entity = registry.create();
  1072. registry.emplace<int>(entity);
  1073. registry.emplace<char>(entity);
  1074. const auto group = registry.group<int>(entt::get<char>);
  1075. const auto iterable = group.each();
  1076. const auto it = std::find_if(iterable.begin(), iterable.end(), [entity](auto args) { return std::get<0>(args) == entity; });
  1077. ASSERT_EQ(std::get<0>(*it), entity);
  1078. }
  1079. TEST(OwningGroup, Storage) {
  1080. entt::registry registry;
  1081. const auto entity = registry.create();
  1082. const auto group = registry.group<int>(entt::get<const char>);
  1083. static_assert(std::is_same_v<decltype(group.storage<0u>()), typename entt::storage_traits<entt::entity, int>::storage_type &>);
  1084. static_assert(std::is_same_v<decltype(group.storage<int>()), typename entt::storage_traits<entt::entity, int>::storage_type &>);
  1085. static_assert(std::is_same_v<decltype(group.storage<1u>()), const typename entt::storage_traits<entt::entity, char>::storage_type &>);
  1086. static_assert(std::is_same_v<decltype(group.storage<const char>()), const typename entt::storage_traits<entt::entity, char>::storage_type &>);
  1087. ASSERT_EQ(group.size(), 0u);
  1088. group.storage<int>().emplace(entity);
  1089. registry.emplace<char>(entity);
  1090. ASSERT_EQ(group.size(), 1u);
  1091. ASSERT_TRUE(group.storage<int>().contains(entity));
  1092. ASSERT_TRUE(group.storage<const char>().contains(entity));
  1093. ASSERT_TRUE((registry.all_of<int, char>(entity)));
  1094. group.storage<0u>().erase(entity);
  1095. ASSERT_EQ(group.size(), 0u);
  1096. ASSERT_TRUE(group.storage<1u>().contains(entity));
  1097. ASSERT_FALSE((registry.all_of<int, char>(entity)));
  1098. }