group.cpp 54 KB

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