group.cpp 56 KB

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