storage.cpp 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897
  1. #include <algorithm>
  2. #include <cstddef>
  3. #include <iterator>
  4. #include <memory>
  5. #include <tuple>
  6. #include <type_traits>
  7. #include <unordered_set>
  8. #include <utility>
  9. #include <gtest/gtest.h>
  10. #include <entt/entity/component.hpp>
  11. #include <entt/entity/storage.hpp>
  12. #include "../common/config.h"
  13. #include "../common/throwing_allocator.hpp"
  14. #include "../common/throwing_type.hpp"
  15. #include "../common/tracked_memory_resource.hpp"
  16. struct pointer_stable {
  17. static constexpr auto in_place_delete = true;
  18. int value{};
  19. };
  20. inline bool operator==(const pointer_stable &lhs, const pointer_stable &rhs) {
  21. return lhs.value == rhs.value;
  22. }
  23. inline bool operator<(const pointer_stable &lhs, const pointer_stable &rhs) {
  24. return lhs.value < rhs.value;
  25. }
  26. struct update_from_destructor {
  27. update_from_destructor(entt::storage<update_from_destructor> &ref, entt::entity other)
  28. : storage{&ref},
  29. target{other} {}
  30. update_from_destructor(update_from_destructor &&other) noexcept
  31. : storage{std::exchange(other.storage, nullptr)},
  32. target{std::exchange(other.target, entt::null)} {}
  33. update_from_destructor &operator=(update_from_destructor &&other) noexcept {
  34. storage = std::exchange(other.storage, nullptr);
  35. target = std::exchange(other.target, entt::null);
  36. return *this;
  37. }
  38. ~update_from_destructor() {
  39. if(target != entt::null && storage->contains(target)) {
  40. storage->erase(target);
  41. }
  42. }
  43. private:
  44. entt::storage<update_from_destructor> *storage{};
  45. entt::entity target{entt::null};
  46. };
  47. struct create_from_constructor {
  48. create_from_constructor(entt::storage<create_from_constructor> &ref, entt::entity other)
  49. : child{other} {
  50. if(child != entt::null) {
  51. ref.emplace(child, ref, entt::null);
  52. }
  53. }
  54. entt::entity child;
  55. };
  56. template<>
  57. struct entt::component_traits<std::unordered_set<char>> {
  58. static constexpr auto in_place_delete = true;
  59. static constexpr auto page_size = 4u;
  60. };
  61. template<typename Type>
  62. struct Storage: testing::Test {
  63. using type = Type;
  64. };
  65. template<typename Type>
  66. using StorageDeathTest = Storage<Type>;
  67. using StorageTypes = ::testing::Types<int, pointer_stable>;
  68. TYPED_TEST_SUITE(Storage, StorageTypes, );
  69. TYPED_TEST_SUITE(StorageDeathTest, StorageTypes, );
  70. TYPED_TEST(Storage, Constructors) {
  71. using value_type = typename TestFixture::type;
  72. using traits_type = entt::component_traits<value_type>;
  73. entt::storage<value_type> pool;
  74. ASSERT_EQ(pool.policy(), entt::deletion_policy{traits_type::in_place_delete});
  75. ASSERT_NO_FATAL_FAILURE([[maybe_unused]] auto alloc = pool.get_allocator());
  76. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  77. pool = entt::storage<value_type>{std::allocator<value_type>{}};
  78. ASSERT_EQ(pool.policy(), entt::deletion_policy{traits_type::in_place_delete});
  79. ASSERT_NO_FATAL_FAILURE([[maybe_unused]] auto alloc = pool.get_allocator());
  80. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  81. }
  82. TYPED_TEST(Storage, Move) {
  83. using value_type = typename TestFixture::type;
  84. entt::storage<value_type> pool;
  85. pool.emplace(entt::entity{3}, 3);
  86. ASSERT_TRUE(std::is_move_constructible_v<decltype(pool)>);
  87. ASSERT_TRUE(std::is_move_assignable_v<decltype(pool)>);
  88. entt::storage<value_type> other{std::move(pool)};
  89. ASSERT_TRUE(pool.empty());
  90. ASSERT_FALSE(other.empty());
  91. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  92. ASSERT_EQ(other.type(), entt::type_id<value_type>());
  93. ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
  94. ASSERT_EQ(other.at(0u), entt::entity{3});
  95. ASSERT_EQ(other.get(entt::entity{3}), value_type{3});
  96. entt::storage<value_type> extended{std::move(other), std::allocator<value_type>{}};
  97. ASSERT_TRUE(other.empty());
  98. ASSERT_FALSE(extended.empty());
  99. ASSERT_EQ(other.type(), entt::type_id<value_type>());
  100. ASSERT_EQ(extended.type(), entt::type_id<value_type>());
  101. ASSERT_EQ(other.at(0u), static_cast<entt::entity>(entt::null));
  102. ASSERT_EQ(extended.at(0u), entt::entity{3});
  103. ASSERT_EQ(extended.get(entt::entity{3}), value_type{3});
  104. pool = std::move(extended);
  105. ASSERT_FALSE(pool.empty());
  106. ASSERT_TRUE(other.empty());
  107. ASSERT_TRUE(extended.empty());
  108. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  109. ASSERT_EQ(other.type(), entt::type_id<value_type>());
  110. ASSERT_EQ(extended.type(), entt::type_id<value_type>());
  111. ASSERT_EQ(pool.at(0u), entt::entity{3});
  112. ASSERT_EQ(other.at(0u), static_cast<entt::entity>(entt::null));
  113. ASSERT_EQ(extended.at(0u), static_cast<entt::entity>(entt::null));
  114. ASSERT_EQ(pool.get(entt::entity{3}), value_type{3});
  115. other = entt::storage<value_type>{};
  116. other.emplace(entt::entity{42}, 42);
  117. other = std::move(pool);
  118. ASSERT_TRUE(pool.empty());
  119. ASSERT_FALSE(other.empty());
  120. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  121. ASSERT_EQ(other.type(), entt::type_id<value_type>());
  122. ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
  123. ASSERT_EQ(other.at(0u), entt::entity{3});
  124. ASSERT_EQ(other.get(entt::entity{3}), value_type{3});
  125. }
  126. TYPED_TEST(Storage, Swap) {
  127. using value_type = typename TestFixture::type;
  128. using traits_type = entt::component_traits<value_type>;
  129. entt::storage<value_type> pool;
  130. entt::storage<value_type> other;
  131. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  132. ASSERT_EQ(other.type(), entt::type_id<value_type>());
  133. pool.emplace(entt::entity{42}, 41);
  134. other.emplace(entt::entity{9}, 8);
  135. other.emplace(entt::entity{3}, 2);
  136. other.erase(entt::entity{9});
  137. ASSERT_EQ(pool.size(), 1u);
  138. ASSERT_EQ(other.size(), 1u + traits_type::in_place_delete);
  139. pool.swap(other);
  140. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  141. ASSERT_EQ(other.type(), entt::type_id<value_type>());
  142. ASSERT_EQ(pool.size(), 1u + traits_type::in_place_delete);
  143. ASSERT_EQ(other.size(), 1u);
  144. ASSERT_EQ(pool.at(traits_type::in_place_delete), entt::entity{3});
  145. ASSERT_EQ(other.at(0u), entt::entity{42});
  146. ASSERT_EQ(pool.get(entt::entity{3}), value_type{2});
  147. ASSERT_EQ(other.get(entt::entity{42}), value_type{41});
  148. }
  149. TYPED_TEST(Storage, Capacity) {
  150. using value_type = typename TestFixture::type;
  151. using traits_type = entt::component_traits<value_type>;
  152. entt::storage<value_type> pool;
  153. pool.reserve(42);
  154. ASSERT_EQ(pool.capacity(), traits_type::page_size);
  155. ASSERT_TRUE(pool.empty());
  156. pool.reserve(0);
  157. ASSERT_EQ(pool.capacity(), traits_type::page_size);
  158. ASSERT_TRUE(pool.empty());
  159. }
  160. TYPED_TEST(Storage, ShrinkToFit) {
  161. using value_type = typename TestFixture::type;
  162. using traits_type = entt::component_traits<value_type>;
  163. entt::storage<value_type> pool;
  164. for(std::size_t next{}; next < traits_type::page_size; ++next) {
  165. pool.emplace(entt::entity(next));
  166. }
  167. pool.emplace(entt::entity{traits_type::page_size});
  168. pool.erase(entt::entity{traits_type::page_size});
  169. pool.compact();
  170. ASSERT_EQ(pool.capacity(), 2 * traits_type::page_size);
  171. ASSERT_EQ(pool.size(), traits_type::page_size);
  172. pool.shrink_to_fit();
  173. ASSERT_EQ(pool.capacity(), traits_type::page_size);
  174. ASSERT_EQ(pool.size(), traits_type::page_size);
  175. pool.clear();
  176. ASSERT_EQ(pool.capacity(), traits_type::page_size);
  177. ASSERT_EQ(pool.size(), 0u);
  178. pool.shrink_to_fit();
  179. ASSERT_EQ(pool.capacity(), 0u);
  180. ASSERT_EQ(pool.size(), 0u);
  181. }
  182. TYPED_TEST(Storage, Raw) {
  183. using value_type = typename TestFixture::type;
  184. entt::storage<value_type> pool;
  185. pool.emplace(entt::entity{3}, 3);
  186. pool.emplace(entt::entity{12}, 6);
  187. pool.emplace(entt::entity{42}, 9);
  188. ASSERT_EQ(pool.get(entt::entity{3}), value_type{3});
  189. ASSERT_EQ(std::as_const(pool).get(entt::entity{12}), value_type{6});
  190. ASSERT_EQ(pool.get(entt::entity{42}), value_type{9});
  191. ASSERT_EQ(pool.raw()[0u][0u], value_type{3});
  192. ASSERT_EQ(std::as_const(pool).raw()[0u][1u], value_type{6});
  193. ASSERT_EQ(pool.raw()[0u][2u], value_type{9});
  194. }
  195. TYPED_TEST(Storage, Iterator) {
  196. using value_type = typename TestFixture::type;
  197. using iterator = typename entt::storage<value_type>::iterator;
  198. testing::StaticAssertTypeEq<typename iterator::value_type, value_type>();
  199. testing::StaticAssertTypeEq<typename iterator::pointer, value_type *>();
  200. testing::StaticAssertTypeEq<typename iterator::reference, value_type &>();
  201. entt::storage<value_type> pool;
  202. pool.emplace(entt::entity{3}, 42);
  203. iterator end{pool.begin()};
  204. iterator begin{};
  205. begin = pool.end();
  206. std::swap(begin, end);
  207. ASSERT_EQ(begin, pool.begin());
  208. ASSERT_EQ(end, pool.end());
  209. ASSERT_NE(begin, end);
  210. ASSERT_EQ(begin.index(), 0);
  211. ASSERT_EQ(end.index(), -1);
  212. ASSERT_EQ(begin++, pool.begin());
  213. ASSERT_EQ(begin--, pool.end());
  214. ASSERT_EQ(begin + 1, pool.end());
  215. ASSERT_EQ(end - 1, pool.begin());
  216. ASSERT_EQ(++begin, pool.end());
  217. ASSERT_EQ(--begin, pool.begin());
  218. ASSERT_EQ(begin += 1, pool.end());
  219. ASSERT_EQ(begin -= 1, pool.begin());
  220. ASSERT_EQ(begin + (end - begin), pool.end());
  221. ASSERT_EQ(begin - (begin - end), pool.end());
  222. ASSERT_EQ(end - (end - begin), pool.begin());
  223. ASSERT_EQ(end + (begin - end), pool.begin());
  224. ASSERT_EQ(begin[0u], *pool.begin().operator->());
  225. ASSERT_LT(begin, end);
  226. ASSERT_LE(begin, pool.begin());
  227. ASSERT_GT(end, begin);
  228. ASSERT_GE(end, pool.end());
  229. ASSERT_EQ(begin.index(), 0);
  230. ASSERT_EQ(end.index(), -1);
  231. pool.emplace(entt::entity{42}, 3);
  232. begin = pool.begin();
  233. ASSERT_EQ(begin.index(), 1);
  234. ASSERT_EQ(end.index(), -1);
  235. ASSERT_EQ(begin[0u], value_type{3});
  236. ASSERT_EQ(begin[1u], value_type{42});
  237. }
  238. TYPED_TEST(Storage, ConstIterator) {
  239. using value_type = typename TestFixture::type;
  240. using iterator = typename entt::storage<value_type>::const_iterator;
  241. testing::StaticAssertTypeEq<typename iterator::value_type, value_type>();
  242. testing::StaticAssertTypeEq<typename iterator::pointer, const value_type *>();
  243. testing::StaticAssertTypeEq<typename iterator::reference, const value_type &>();
  244. entt::storage<value_type> pool;
  245. pool.emplace(entt::entity{3}, 42);
  246. iterator cend{pool.cbegin()};
  247. iterator cbegin{};
  248. cbegin = pool.cend();
  249. std::swap(cbegin, cend);
  250. ASSERT_EQ(cbegin, std::as_const(pool).begin());
  251. ASSERT_EQ(cend, std::as_const(pool).end());
  252. ASSERT_EQ(cbegin, pool.cbegin());
  253. ASSERT_EQ(cend, pool.cend());
  254. ASSERT_NE(cbegin, cend);
  255. ASSERT_EQ(cbegin.index(), 0);
  256. ASSERT_EQ(cend.index(), -1);
  257. ASSERT_EQ(cbegin++, pool.cbegin());
  258. ASSERT_EQ(cbegin--, pool.cend());
  259. ASSERT_EQ(cbegin + 1, pool.cend());
  260. ASSERT_EQ(cend - 1, pool.cbegin());
  261. ASSERT_EQ(++cbegin, pool.cend());
  262. ASSERT_EQ(--cbegin, pool.cbegin());
  263. ASSERT_EQ(cbegin += 1, pool.cend());
  264. ASSERT_EQ(cbegin -= 1, pool.cbegin());
  265. ASSERT_EQ(cbegin + (cend - cbegin), pool.cend());
  266. ASSERT_EQ(cbegin - (cbegin - cend), pool.cend());
  267. ASSERT_EQ(cend - (cend - cbegin), pool.cbegin());
  268. ASSERT_EQ(cend + (cbegin - cend), pool.cbegin());
  269. ASSERT_EQ(cbegin[0u], *pool.cbegin().operator->());
  270. ASSERT_LT(cbegin, cend);
  271. ASSERT_LE(cbegin, pool.cbegin());
  272. ASSERT_GT(cend, cbegin);
  273. ASSERT_GE(cend, pool.cend());
  274. ASSERT_EQ(cbegin.index(), 0);
  275. ASSERT_EQ(cend.index(), -1);
  276. pool.emplace(entt::entity{42}, 3);
  277. cbegin = pool.cbegin();
  278. ASSERT_EQ(cbegin.index(), 1);
  279. ASSERT_EQ(cend.index(), -1);
  280. ASSERT_EQ(cbegin[0u], value_type{3});
  281. ASSERT_EQ(cbegin[1u], value_type{42});
  282. }
  283. TYPED_TEST(Storage, ReverseIterator) {
  284. using value_type = typename TestFixture::type;
  285. using reverse_iterator = typename entt::storage<value_type>::reverse_iterator;
  286. testing::StaticAssertTypeEq<typename reverse_iterator::value_type, value_type>();
  287. testing::StaticAssertTypeEq<typename reverse_iterator::pointer, value_type *>();
  288. testing::StaticAssertTypeEq<typename reverse_iterator::reference, value_type &>();
  289. entt::storage<value_type> pool;
  290. pool.emplace(entt::entity{3}, 42);
  291. reverse_iterator end{pool.rbegin()};
  292. reverse_iterator begin{};
  293. begin = pool.rend();
  294. std::swap(begin, end);
  295. ASSERT_EQ(begin, pool.rbegin());
  296. ASSERT_EQ(end, pool.rend());
  297. ASSERT_NE(begin, end);
  298. ASSERT_EQ(begin.base().index(), -1);
  299. ASSERT_EQ(end.base().index(), 0);
  300. ASSERT_EQ(begin++, pool.rbegin());
  301. ASSERT_EQ(begin--, pool.rend());
  302. ASSERT_EQ(begin + 1, pool.rend());
  303. ASSERT_EQ(end - 1, pool.rbegin());
  304. ASSERT_EQ(++begin, pool.rend());
  305. ASSERT_EQ(--begin, pool.rbegin());
  306. ASSERT_EQ(begin += 1, pool.rend());
  307. ASSERT_EQ(begin -= 1, pool.rbegin());
  308. ASSERT_EQ(begin + (end - begin), pool.rend());
  309. ASSERT_EQ(begin - (begin - end), pool.rend());
  310. ASSERT_EQ(end - (end - begin), pool.rbegin());
  311. ASSERT_EQ(end + (begin - end), pool.rbegin());
  312. ASSERT_EQ(begin[0u], *pool.rbegin().operator->());
  313. ASSERT_LT(begin, end);
  314. ASSERT_LE(begin, pool.rbegin());
  315. ASSERT_GT(end, begin);
  316. ASSERT_GE(end, pool.rend());
  317. ASSERT_EQ(begin.base().index(), -1);
  318. ASSERT_EQ(end.base().index(), 0);
  319. pool.emplace(entt::entity{42}, 3);
  320. end = pool.rend();
  321. ASSERT_EQ(begin.base().index(), -1);
  322. ASSERT_EQ(end.base().index(), 1);
  323. ASSERT_EQ(begin[0u], value_type{42});
  324. ASSERT_EQ(begin[1u], value_type{3});
  325. }
  326. TYPED_TEST(Storage, ConstReverseIterator) {
  327. using value_type = typename TestFixture::type;
  328. using const_reverse_iterator = typename entt::storage<value_type>::const_reverse_iterator;
  329. testing::StaticAssertTypeEq<typename const_reverse_iterator::value_type, value_type>();
  330. testing::StaticAssertTypeEq<typename const_reverse_iterator::pointer, const value_type *>();
  331. testing::StaticAssertTypeEq<typename const_reverse_iterator::reference, const value_type &>();
  332. entt::storage<value_type> pool;
  333. pool.emplace(entt::entity{3}, 42);
  334. const_reverse_iterator cend{pool.crbegin()};
  335. const_reverse_iterator cbegin{};
  336. cbegin = pool.crend();
  337. std::swap(cbegin, cend);
  338. ASSERT_EQ(cbegin, std::as_const(pool).rbegin());
  339. ASSERT_EQ(cend, std::as_const(pool).rend());
  340. ASSERT_EQ(cbegin, pool.crbegin());
  341. ASSERT_EQ(cend, pool.crend());
  342. ASSERT_NE(cbegin, cend);
  343. ASSERT_EQ(cbegin.base().index(), -1);
  344. ASSERT_EQ(cend.base().index(), 0);
  345. ASSERT_EQ(cbegin++, pool.crbegin());
  346. ASSERT_EQ(cbegin--, pool.crend());
  347. ASSERT_EQ(cbegin + 1, pool.crend());
  348. ASSERT_EQ(cend - 1, pool.crbegin());
  349. ASSERT_EQ(++cbegin, pool.crend());
  350. ASSERT_EQ(--cbegin, pool.crbegin());
  351. ASSERT_EQ(cbegin += 1, pool.crend());
  352. ASSERT_EQ(cbegin -= 1, pool.crbegin());
  353. ASSERT_EQ(cbegin + (cend - cbegin), pool.crend());
  354. ASSERT_EQ(cbegin - (cbegin - cend), pool.crend());
  355. ASSERT_EQ(cend - (cend - cbegin), pool.crbegin());
  356. ASSERT_EQ(cend + (cbegin - cend), pool.crbegin());
  357. ASSERT_EQ(cbegin[0u], *pool.crbegin().operator->());
  358. ASSERT_LT(cbegin, cend);
  359. ASSERT_LE(cbegin, pool.crbegin());
  360. ASSERT_GT(cend, cbegin);
  361. ASSERT_GE(cend, pool.crend());
  362. ASSERT_EQ(cbegin.base().index(), -1);
  363. ASSERT_EQ(cend.base().index(), 0);
  364. pool.emplace(entt::entity{42}, 3);
  365. cend = pool.crend();
  366. ASSERT_EQ(cbegin.base().index(), -1);
  367. ASSERT_EQ(cend.base().index(), 1);
  368. ASSERT_EQ(cbegin[0u], value_type{42});
  369. ASSERT_EQ(cbegin[1u], value_type{3});
  370. }
  371. TYPED_TEST(Storage, IteratorConversion) {
  372. using value_type = typename TestFixture::type;
  373. entt::storage<value_type> pool;
  374. pool.emplace(entt::entity{3}, 42);
  375. typename entt::storage<value_type>::iterator it = pool.begin();
  376. typename entt::storage<value_type>::const_iterator cit = it;
  377. testing::StaticAssertTypeEq<decltype(*it), value_type &>();
  378. testing::StaticAssertTypeEq<decltype(*cit), const value_type &>();
  379. ASSERT_EQ(*it.operator->(), value_type{42});
  380. ASSERT_EQ(*it.operator->(), *cit);
  381. ASSERT_EQ(it - cit, 0);
  382. ASSERT_EQ(cit - it, 0);
  383. ASSERT_LE(it, cit);
  384. ASSERT_LE(cit, it);
  385. ASSERT_GE(it, cit);
  386. ASSERT_GE(cit, it);
  387. ASSERT_EQ(it, cit);
  388. ASSERT_NE(++cit, it);
  389. }
  390. TYPED_TEST(Storage, IteratorPageSizeAwareness) {
  391. using value_type = typename TestFixture::type;
  392. using traits_type = entt::component_traits<value_type>;
  393. entt::storage<value_type> pool;
  394. const value_type check{42};
  395. for(unsigned int next{}; next < traits_type::page_size; ++next) {
  396. pool.emplace(entt::entity{next});
  397. }
  398. pool.emplace(entt::entity{traits_type::page_size}, check);
  399. // test the proper use of component traits by the storage iterator
  400. ASSERT_EQ(*pool.begin(), check);
  401. }
  402. TYPED_TEST(Storage, Getters) {
  403. using value_type = typename TestFixture::type;
  404. entt::storage<value_type> pool;
  405. pool.emplace(entt::entity{41}, 3);
  406. testing::StaticAssertTypeEq<decltype(pool.get({})), value_type &>();
  407. testing::StaticAssertTypeEq<decltype(std::as_const(pool).get({})), const value_type &>();
  408. testing::StaticAssertTypeEq<decltype(pool.get_as_tuple({})), std::tuple<value_type &>>();
  409. testing::StaticAssertTypeEq<decltype(std::as_const(pool).get_as_tuple({})), std::tuple<const value_type &>>();
  410. ASSERT_EQ(pool.get(entt::entity{41}), value_type{3});
  411. ASSERT_EQ(std::as_const(pool).get(entt::entity{41}), value_type{3});
  412. ASSERT_EQ(pool.get_as_tuple(entt::entity{41}), std::make_tuple(value_type{3}));
  413. ASSERT_EQ(std::as_const(pool).get_as_tuple(entt::entity{41}), std::make_tuple(value_type{3}));
  414. }
  415. ENTT_DEBUG_TYPED_TEST(StorageDeathTest, Getters) {
  416. using value_type = typename TestFixture::type;
  417. entt::storage<value_type> pool;
  418. ASSERT_DEATH([[maybe_unused]] const auto &value = pool.get(entt::entity{41}), "");
  419. ASSERT_DEATH([[maybe_unused]] const auto &value = std::as_const(pool).get(entt::entity{41}), "");
  420. ASSERT_DEATH([[maybe_unused]] const auto value = pool.get_as_tuple(entt::entity{41}), "");
  421. ASSERT_DEATH([[maybe_unused]] const auto value = std::as_const(pool).get_as_tuple(entt::entity{41}), "");
  422. }
  423. TYPED_TEST(Storage, Value) {
  424. using value_type = typename TestFixture::type;
  425. entt::storage<value_type> pool;
  426. pool.emplace(entt::entity{42});
  427. ASSERT_EQ(pool.value(entt::entity{42}), &pool.get(entt::entity{42}));
  428. }
  429. ENTT_DEBUG_TYPED_TEST(StorageDeathTest, Value) {
  430. using value_type = typename TestFixture::type;
  431. entt::storage<value_type> pool;
  432. ASSERT_DEATH([[maybe_unused]] const void *value = pool.value(entt::entity{42}), "");
  433. }
  434. TYPED_TEST(Storage, Emplace) {
  435. // ensure that we've at least an aggregate type to test here
  436. static_assert(std::is_aggregate_v<pointer_stable>, "Not an aggregate type");
  437. using value_type = typename TestFixture::type;
  438. entt::storage<value_type> pool;
  439. testing::StaticAssertTypeEq<decltype(pool.emplace({})), value_type &>();
  440. // aggregate types with no args enter the non-aggregate path
  441. ASSERT_EQ(pool.emplace(entt::entity{3}), value_type{});
  442. // aggregate types with args work despite the lack of support in the standard library
  443. ASSERT_EQ(pool.emplace(entt::entity{42}, 42), value_type{42});
  444. }
  445. TEST(Storage, EmplaceSelfMoveSupport) {
  446. // see #37 - this test shouldn't crash, that's all
  447. entt::storage<std::unordered_set<int>> pool;
  448. entt::entity entity{};
  449. ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_and_pop);
  450. pool.emplace(entity).insert(42);
  451. pool.erase(entity);
  452. ASSERT_FALSE(pool.contains(entity));
  453. }
  454. TEST(Storage, EmplaceSelfMoveSupportInPlaceDelete) {
  455. // see #37 - this test shouldn't crash, that's all
  456. entt::storage<std::unordered_set<char>> pool;
  457. entt::entity entity{};
  458. ASSERT_EQ(pool.policy(), entt::deletion_policy::in_place);
  459. pool.emplace(entity).insert(42);
  460. pool.erase(entity);
  461. ASSERT_FALSE(pool.contains(entity));
  462. }
  463. TYPED_TEST(Storage, TryEmplace) {
  464. using value_type = typename TestFixture::type;
  465. using traits_type = entt::component_traits<value_type>;
  466. entt::storage<value_type> pool;
  467. entt::sparse_set &base = pool;
  468. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}};
  469. value_type instance{42};
  470. ASSERT_NE(base.push(entity[0u], &instance), base.end());
  471. ASSERT_EQ(pool.size(), 1u);
  472. ASSERT_EQ(base.index(entity[0u]), 0u);
  473. ASSERT_EQ(base.value(entity[0u]), &pool.get(entity[0u]));
  474. ASSERT_EQ(pool.get(entity[0u]), value_type{42});
  475. base.erase(entity[0u]);
  476. ASSERT_NE(base.push(std::begin(entity), std::end(entity)), base.end());
  477. if constexpr(traits_type::in_place_delete) {
  478. ASSERT_EQ(pool.size(), 3u);
  479. ASSERT_EQ(base.index(entity[0u]), 1u);
  480. ASSERT_EQ(base.index(entity[1u]), 2u);
  481. } else {
  482. ASSERT_EQ(pool.size(), 2u);
  483. ASSERT_EQ(base.index(entity[0u]), 0u);
  484. ASSERT_EQ(base.index(entity[1u]), 1u);
  485. }
  486. ASSERT_EQ(pool.get(entity[0u]), value_type{});
  487. ASSERT_EQ(pool.get(entity[1u]), value_type{});
  488. base.erase(std::begin(entity), std::end(entity));
  489. ASSERT_NE(base.push(std::rbegin(entity), std::rend(entity)), base.end());
  490. if constexpr(traits_type::in_place_delete) {
  491. ASSERT_EQ(pool.size(), 5u);
  492. ASSERT_EQ(base.index(entity[0u]), 4u);
  493. ASSERT_EQ(base.index(entity[1u]), 3u);
  494. } else {
  495. ASSERT_EQ(pool.size(), 2u);
  496. ASSERT_EQ(base.index(entity[0u]), 1u);
  497. ASSERT_EQ(base.index(entity[1u]), 0u);
  498. }
  499. ASSERT_EQ(pool.get(entity[0u]), value_type{});
  500. ASSERT_EQ(pool.get(entity[1u]), value_type{});
  501. }
  502. TEST(Storage, TryEmplaceNonDefaultConstructible) {
  503. using value_type = std::pair<int &, int &>;
  504. static_assert(!std::is_default_constructible_v<value_type>, "Default constructible types not allowed");
  505. entt::storage<value_type> pool;
  506. entt::sparse_set &base = pool;
  507. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}};
  508. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  509. ASSERT_EQ(pool.type(), base.type());
  510. ASSERT_FALSE(pool.contains(entity[0u]));
  511. ASSERT_FALSE(pool.contains(entity[1u]));
  512. ASSERT_EQ(base.push(entity[0u]), base.end());
  513. ASSERT_FALSE(pool.contains(entity[0u]));
  514. ASSERT_FALSE(pool.contains(entity[1u]));
  515. ASSERT_EQ(base.find(entity[0u]), base.end());
  516. ASSERT_TRUE(pool.empty());
  517. int value = 42;
  518. value_type instance{value, value};
  519. ASSERT_NE(base.push(entity[0u], &instance), base.end());
  520. ASSERT_TRUE(pool.contains(entity[0u]));
  521. ASSERT_FALSE(pool.contains(entity[1u]));
  522. base.erase(entity[0u]);
  523. ASSERT_TRUE(pool.empty());
  524. ASSERT_FALSE(pool.contains(entity[0u]));
  525. ASSERT_EQ(base.push(std::begin(entity), std::end(entity)), base.end());
  526. ASSERT_FALSE(pool.contains(entity[0u]));
  527. ASSERT_FALSE(pool.contains(entity[1u]));
  528. ASSERT_EQ(base.find(entity[0u]), base.end());
  529. ASSERT_EQ(base.find(entity[1u]), base.end());
  530. ASSERT_TRUE(pool.empty());
  531. }
  532. TEST(Storage, TryEmplaceNonCopyConstructible) {
  533. using value_type = std::unique_ptr<int>;
  534. static_assert(!std::is_copy_constructible_v<value_type>, "Copy constructible types not allowed");
  535. entt::storage<value_type> pool;
  536. entt::sparse_set &base = pool;
  537. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}};
  538. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  539. ASSERT_EQ(pool.type(), base.type());
  540. ASSERT_FALSE(pool.contains(entity[0u]));
  541. ASSERT_FALSE(pool.contains(entity[1u]));
  542. ASSERT_NE(base.push(entity[0u]), base.end());
  543. ASSERT_TRUE(pool.contains(entity[0u]));
  544. ASSERT_FALSE(pool.contains(entity[1u]));
  545. ASSERT_NE(base.find(entity[0u]), base.end());
  546. ASSERT_FALSE(pool.empty());
  547. value_type instance = std::make_unique<int>(3);
  548. ASSERT_EQ(base.push(entity[1u], &instance), base.end());
  549. ASSERT_TRUE(pool.contains(entity[0u]));
  550. ASSERT_FALSE(pool.contains(entity[1u]));
  551. base.erase(entity[0u]);
  552. ASSERT_TRUE(pool.empty());
  553. ASSERT_FALSE(pool.contains(entity[0u]));
  554. ASSERT_NE(base.push(std::begin(entity), std::end(entity)), base.end());
  555. ASSERT_TRUE(pool.contains(entity[0u]));
  556. ASSERT_TRUE(pool.contains(entity[1u]));
  557. ASSERT_NE(base.find(entity[0u]), base.end());
  558. ASSERT_NE(base.find(entity[1u]), base.end());
  559. ASSERT_FALSE(pool.empty());
  560. }
  561. TYPED_TEST(Storage, Patch) {
  562. using value_type = typename TestFixture::type;
  563. entt::storage<value_type> pool;
  564. entt::entity entity{42};
  565. auto callback = [](auto &&elem) {
  566. if constexpr(std::is_class_v<std::remove_reference_t<decltype(elem)>>) {
  567. ++elem.value;
  568. } else {
  569. ++elem;
  570. }
  571. };
  572. pool.emplace(entity, 0);
  573. ASSERT_EQ(pool.get(entity), value_type{0});
  574. pool.patch(entity);
  575. pool.patch(entity, callback);
  576. pool.patch(entity, callback, callback);
  577. ASSERT_EQ(pool.get(entity), value_type{3});
  578. }
  579. ENTT_DEBUG_TYPED_TEST(StorageDeathTest, Patch) {
  580. using value_type = typename TestFixture::type;
  581. entt::storage<value_type> pool;
  582. ASSERT_DEATH(pool.patch(entt::null), "");
  583. }
  584. TYPED_TEST(Storage, Insert) {
  585. using value_type = typename TestFixture::type;
  586. using traits_type = entt::component_traits<value_type>;
  587. entt::storage<value_type> pool;
  588. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}};
  589. typename entt::storage<value_type>::iterator it{};
  590. it = pool.insert(std::begin(entity), std::end(entity), value_type{99});
  591. ASSERT_EQ(it, pool.cbegin());
  592. ASSERT_TRUE(pool.contains(entity[0u]));
  593. ASSERT_TRUE(pool.contains(entity[1u]));
  594. ASSERT_FALSE(pool.empty());
  595. ASSERT_EQ(pool.size(), 2u);
  596. ASSERT_EQ(pool.get(entity[0u]), value_type{99});
  597. ASSERT_EQ(pool.get(entity[1u]), value_type{99});
  598. ASSERT_EQ(*it++.operator->(), value_type{99});
  599. ASSERT_EQ(*it.operator->(), value_type{99});
  600. const value_type values[2u] = {value_type{42}, value_type{3}};
  601. pool.erase(std::begin(entity), std::end(entity));
  602. it = pool.insert(std::rbegin(entity), std::rend(entity), std::begin(values));
  603. ASSERT_EQ(it, pool.cbegin());
  604. if constexpr(traits_type::in_place_delete) {
  605. ASSERT_EQ(pool.size(), 4u);
  606. ASSERT_EQ(pool.at(2u), entity[1u]);
  607. ASSERT_EQ(pool.at(3u), entity[0u]);
  608. ASSERT_EQ(pool.index(entity[0u]), 3u);
  609. ASSERT_EQ(pool.index(entity[1u]), 2u);
  610. } else {
  611. ASSERT_EQ(pool.size(), 2u);
  612. ASSERT_EQ(pool.at(0u), entity[1u]);
  613. ASSERT_EQ(pool.at(1u), entity[0u]);
  614. ASSERT_EQ(pool.index(entity[0u]), 1u);
  615. ASSERT_EQ(pool.index(entity[1u]), 0u);
  616. }
  617. ASSERT_EQ(pool.get(entity[0u]), value_type{3});
  618. ASSERT_EQ(pool.get(entity[1u]), value_type{42});
  619. ASSERT_EQ(*it++.operator->(), value_type{3});
  620. ASSERT_EQ(*it.operator->(), value_type{42});
  621. }
  622. TYPED_TEST(Storage, Erase) {
  623. using value_type = typename TestFixture::type;
  624. using traits_type = entt::component_traits<value_type>;
  625. entt::storage<value_type> pool;
  626. entt::entity entity[3u]{entt::entity{3}, entt::entity{42}, entt::entity{9}};
  627. const value_type values[3u]{value_type{0}, value_type{1}, value_type{2}};
  628. pool.insert(std::begin(entity), std::end(entity), std::begin(values));
  629. pool.erase(std::begin(entity), std::end(entity));
  630. if constexpr(traits_type::in_place_delete) {
  631. ASSERT_EQ(pool.size(), 3u);
  632. ASSERT_TRUE(pool.at(2u) == entt::tombstone);
  633. } else {
  634. ASSERT_EQ(pool.size(), 0u);
  635. }
  636. pool.insert(std::begin(entity), std::end(entity), std::begin(values));
  637. pool.erase(entity, entity + 2u);
  638. ASSERT_EQ(*pool.begin(), values[2u]);
  639. if constexpr(traits_type::in_place_delete) {
  640. ASSERT_EQ(pool.size(), 6u);
  641. ASSERT_EQ(pool.index(entity[2u]), 5u);
  642. } else {
  643. ASSERT_EQ(pool.size(), 1u);
  644. }
  645. pool.erase(entity[2u]);
  646. if constexpr(traits_type::in_place_delete) {
  647. ASSERT_EQ(pool.size(), 6u);
  648. ASSERT_TRUE(pool.at(5u) == entt::tombstone);
  649. } else {
  650. ASSERT_EQ(pool.size(), 0u);
  651. }
  652. }
  653. TYPED_TEST(Storage, CrossErase) {
  654. using value_type = typename TestFixture::type;
  655. entt::storage<value_type> pool;
  656. entt::sparse_set set;
  657. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}};
  658. pool.emplace(entity[0u], 3);
  659. pool.emplace(entity[1u], 42);
  660. set.push(entity[1u]);
  661. pool.erase(set.begin(), set.end());
  662. ASSERT_TRUE(pool.contains(entity[0u]));
  663. ASSERT_FALSE(pool.contains(entity[1u]));
  664. ASSERT_EQ(pool.raw()[0u][0u], value_type{3});
  665. }
  666. TYPED_TEST(Storage, Remove) {
  667. using value_type = typename TestFixture::type;
  668. using traits_type = entt::component_traits<value_type>;
  669. entt::storage<value_type> pool;
  670. entt::entity entity[3u]{entt::entity{3}, entt::entity{42}, entt::entity{9}};
  671. const value_type values[3u]{value_type{0}, value_type{1}, value_type{2}};
  672. pool.insert(std::begin(entity), std::end(entity), std::begin(values));
  673. ASSERT_EQ(pool.remove(std::begin(entity), std::end(entity)), 3u);
  674. ASSERT_EQ(pool.remove(std::begin(entity), std::end(entity)), 0u);
  675. if constexpr(traits_type::in_place_delete) {
  676. ASSERT_EQ(pool.size(), 3u);
  677. ASSERT_TRUE(pool.at(2u) == entt::tombstone);
  678. } else {
  679. ASSERT_EQ(pool.size(), 0u);
  680. }
  681. pool.insert(std::begin(entity), std::end(entity), std::begin(values));
  682. ASSERT_EQ(pool.remove(entity, entity + 2u), 2u);
  683. ASSERT_EQ(*pool.begin(), values[2u]);
  684. if constexpr(traits_type::in_place_delete) {
  685. ASSERT_EQ(pool.size(), 6u);
  686. ASSERT_EQ(pool.index(entity[2u]), 5u);
  687. } else {
  688. ASSERT_EQ(pool.size(), 1u);
  689. }
  690. ASSERT_TRUE(pool.remove(entity[2u]));
  691. ASSERT_FALSE(pool.remove(entity[2u]));
  692. if constexpr(traits_type::in_place_delete) {
  693. ASSERT_EQ(pool.size(), 6u);
  694. ASSERT_TRUE(pool.at(5u) == entt::tombstone);
  695. } else {
  696. ASSERT_EQ(pool.size(), 0u);
  697. }
  698. }
  699. TYPED_TEST(Storage, CrossRemove) {
  700. using value_type = typename TestFixture::type;
  701. entt::storage<value_type> pool;
  702. entt::sparse_set set;
  703. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}};
  704. pool.emplace(entity[0u], 3);
  705. pool.emplace(entity[1u], 42);
  706. set.push(entity[1u]);
  707. pool.remove(set.begin(), set.end());
  708. ASSERT_TRUE(pool.contains(entity[0u]));
  709. ASSERT_FALSE(pool.contains(entity[1u]));
  710. ASSERT_EQ(pool.raw()[0u][0u], value_type{3});
  711. }
  712. TYPED_TEST(Storage, Clear) {
  713. using value_type = typename TestFixture::type;
  714. using traits_type = entt::component_traits<value_type>;
  715. entt::storage<value_type> pool;
  716. entt::entity entity[3u]{entt::entity{3}, entt::entity{42}, entt::entity{9}};
  717. pool.insert(std::begin(entity), std::end(entity));
  718. ASSERT_EQ(pool.size(), 3u);
  719. pool.clear();
  720. ASSERT_EQ(pool.size(), 0u);
  721. pool.insert(std::begin(entity), std::end(entity));
  722. pool.erase(entity[2u]);
  723. ASSERT_EQ(pool.size(), 2u + traits_type::in_place_delete);
  724. pool.clear();
  725. ASSERT_EQ(pool.size(), 0u);
  726. }
  727. TYPED_TEST(Storage, Compact) {
  728. using value_type = typename TestFixture::type;
  729. using traits_type = entt::component_traits<value_type>;
  730. entt::storage<value_type> pool;
  731. ASSERT_TRUE(pool.empty());
  732. pool.compact();
  733. ASSERT_TRUE(pool.empty());
  734. pool.emplace(entt::entity{0}, value_type{0});
  735. pool.compact();
  736. ASSERT_EQ(pool.size(), 1u);
  737. pool.emplace(entt::entity{42}, value_type{42});
  738. pool.erase(entt::entity{0});
  739. ASSERT_EQ(pool.size(), 1u + traits_type::in_place_delete);
  740. ASSERT_EQ(pool.index(entt::entity{42}), traits_type::in_place_delete);
  741. ASSERT_EQ(pool.get(entt::entity{42}), value_type{42});
  742. pool.compact();
  743. ASSERT_EQ(pool.size(), 1u);
  744. ASSERT_EQ(pool.index(entt::entity{42}), 0u);
  745. ASSERT_EQ(pool.get(entt::entity{42}), value_type{42});
  746. pool.emplace(entt::entity{0}, value_type{0});
  747. pool.compact();
  748. ASSERT_EQ(pool.size(), 2u);
  749. ASSERT_EQ(pool.index(entt::entity{42}), 0u);
  750. ASSERT_EQ(pool.index(entt::entity{0}), 1u);
  751. ASSERT_EQ(pool.get(entt::entity{42}), value_type{42});
  752. ASSERT_EQ(pool.get(entt::entity{0}), value_type{0});
  753. pool.erase(entt::entity{0});
  754. pool.erase(entt::entity{42});
  755. pool.compact();
  756. ASSERT_TRUE(pool.empty());
  757. }
  758. TYPED_TEST(Storage, SwapElements) {
  759. using value_type = typename TestFixture::type;
  760. using traits_type = entt::component_traits<value_type>;
  761. entt::storage<value_type> pool;
  762. pool.emplace(entt::entity{3}, 3);
  763. pool.emplace(entt::entity{12}, 6);
  764. pool.emplace(entt::entity{42}, 9);
  765. pool.erase(entt::entity{12});
  766. ASSERT_EQ(pool.get(entt::entity{3}), value_type{3});
  767. ASSERT_EQ(pool.get(entt::entity{42}), value_type{9});
  768. ASSERT_EQ(pool.index(entt::entity{3}), 0u);
  769. ASSERT_EQ(pool.index(entt::entity{42}), 1u + traits_type::in_place_delete);
  770. pool.swap_elements(entt::entity{3}, entt::entity{42});
  771. ASSERT_EQ(pool.get(entt::entity{3}), value_type{3});
  772. ASSERT_EQ(pool.get(entt::entity{42}), value_type{9});
  773. ASSERT_EQ(pool.index(entt::entity{3}), 1u + traits_type::in_place_delete);
  774. ASSERT_EQ(pool.index(entt::entity{42}), 0u);
  775. }
  776. TYPED_TEST(Storage, Iterable) {
  777. using value_type = typename TestFixture::type;
  778. using iterator = typename entt::storage<value_type>::iterable::iterator;
  779. testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity, value_type &>>();
  780. testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity, value_type &>>>();
  781. testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
  782. entt::storage<value_type> pool;
  783. entt::sparse_set &base = pool;
  784. pool.emplace(entt::entity{1}, 99);
  785. pool.emplace(entt::entity{3}, 42);
  786. auto iterable = pool.each();
  787. iterator end{iterable.begin()};
  788. iterator begin{};
  789. begin = iterable.end();
  790. std::swap(begin, end);
  791. ASSERT_EQ(begin, iterable.begin());
  792. ASSERT_EQ(end, iterable.end());
  793. ASSERT_NE(begin, end);
  794. ASSERT_EQ(begin.base(), base.begin());
  795. ASSERT_EQ(end.base(), base.end());
  796. ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{3});
  797. ASSERT_EQ(std::get<1>(*begin.operator->().operator->()), value_type{42});
  798. ASSERT_EQ(std::get<0>(*begin), entt::entity{3});
  799. ASSERT_EQ(std::get<1>(*begin), value_type{42});
  800. ASSERT_EQ(begin++, iterable.begin());
  801. ASSERT_EQ(begin.base(), ++base.begin());
  802. ASSERT_EQ(++begin, iterable.end());
  803. ASSERT_EQ(begin.base(), base.end());
  804. for(auto [entity, element]: iterable) {
  805. testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
  806. testing::StaticAssertTypeEq<decltype(element), value_type &>();
  807. ASSERT_TRUE(entity != entt::entity{1} || element == value_type{99});
  808. ASSERT_TRUE(entity != entt::entity{3} || element == value_type{42});
  809. }
  810. }
  811. TYPED_TEST(Storage, ConstIterable) {
  812. using value_type = typename TestFixture::type;
  813. using iterator = typename entt::storage<value_type>::const_iterable::iterator;
  814. testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity, const value_type &>>();
  815. testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity, const value_type &>>>();
  816. testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
  817. entt::storage<value_type> pool;
  818. entt::sparse_set &base = pool;
  819. pool.emplace(entt::entity{1}, 99);
  820. pool.emplace(entt::entity{3}, 42);
  821. auto iterable = std::as_const(pool).each();
  822. iterator end{iterable.cbegin()};
  823. iterator begin{};
  824. begin = iterable.cend();
  825. std::swap(begin, end);
  826. ASSERT_EQ(begin, iterable.cbegin());
  827. ASSERT_EQ(end, iterable.cend());
  828. ASSERT_NE(begin, end);
  829. ASSERT_EQ(begin.base(), base.begin());
  830. ASSERT_EQ(end.base(), base.end());
  831. ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{3});
  832. ASSERT_EQ(std::get<1>(*begin.operator->().operator->()), value_type{42});
  833. ASSERT_EQ(std::get<0>(*begin), entt::entity{3});
  834. ASSERT_EQ(std::get<1>(*begin), value_type{42});
  835. ASSERT_EQ(begin++, iterable.begin());
  836. ASSERT_EQ(begin.base(), ++base.begin());
  837. ASSERT_EQ(++begin, iterable.end());
  838. ASSERT_EQ(begin.base(), base.end());
  839. for(auto [entity, element]: iterable) {
  840. testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
  841. testing::StaticAssertTypeEq<decltype(element), const value_type &>();
  842. ASSERT_TRUE(entity != entt::entity{1} || element == value_type{99});
  843. ASSERT_TRUE(entity != entt::entity{3} || element == value_type{42});
  844. }
  845. }
  846. TYPED_TEST(Storage, IterableIteratorConversion) {
  847. using value_type = typename TestFixture::type;
  848. entt::storage<value_type> pool;
  849. pool.emplace(entt::entity{3}, 42);
  850. typename entt::storage<value_type>::iterable::iterator it = pool.each().begin();
  851. typename entt::storage<value_type>::const_iterable::iterator cit = it;
  852. testing::StaticAssertTypeEq<decltype(*it), std::tuple<entt::entity, value_type &>>();
  853. testing::StaticAssertTypeEq<decltype(*cit), std::tuple<entt::entity, const value_type &>>();
  854. ASSERT_EQ(it, cit);
  855. ASSERT_NE(++cit, it);
  856. }
  857. TYPED_TEST(Storage, IterableAlgorithmCompatibility) {
  858. using value_type = typename TestFixture::type;
  859. entt::storage<value_type> pool;
  860. pool.emplace(entt::entity{3}, 42);
  861. const auto iterable = pool.each();
  862. const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; });
  863. ASSERT_EQ(std::get<0>(*it), entt::entity{3});
  864. }
  865. TYPED_TEST(Storage, ReverseIterable) {
  866. using value_type = typename TestFixture::type;
  867. using iterator = typename entt::storage<value_type>::reverse_iterable::iterator;
  868. testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity, value_type &>>();
  869. testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity, value_type &>>>();
  870. testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
  871. entt::storage<value_type> pool;
  872. entt::sparse_set &base = pool;
  873. pool.emplace(entt::entity{1}, 99);
  874. pool.emplace(entt::entity{3}, 42);
  875. auto iterable = pool.reach();
  876. iterator end{iterable.begin()};
  877. iterator begin{};
  878. begin = iterable.end();
  879. std::swap(begin, end);
  880. ASSERT_EQ(begin, iterable.begin());
  881. ASSERT_EQ(end, iterable.end());
  882. ASSERT_NE(begin, end);
  883. ASSERT_EQ(begin.base(), base.rbegin());
  884. ASSERT_EQ(end.base(), base.rend());
  885. ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1});
  886. ASSERT_EQ(std::get<1>(*begin.operator->().operator->()), value_type{99});
  887. ASSERT_EQ(std::get<0>(*begin), entt::entity{1});
  888. ASSERT_EQ(std::get<1>(*begin), value_type{99});
  889. ASSERT_EQ(begin++, iterable.begin());
  890. ASSERT_EQ(begin.base(), ++base.rbegin());
  891. ASSERT_EQ(++begin, iterable.end());
  892. ASSERT_EQ(begin.base(), base.rend());
  893. for(auto [entity, element]: iterable) {
  894. testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
  895. testing::StaticAssertTypeEq<decltype(element), value_type &>();
  896. ASSERT_TRUE(entity != entt::entity{1} || element == value_type{99});
  897. ASSERT_TRUE(entity != entt::entity{3} || element == value_type{42});
  898. }
  899. }
  900. TYPED_TEST(Storage, ConstReverseIterable) {
  901. using value_type = typename TestFixture::type;
  902. using iterator = typename entt::storage<value_type>::const_reverse_iterable::iterator;
  903. testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity, const value_type &>>();
  904. testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity, const value_type &>>>();
  905. testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
  906. entt::storage<value_type> pool;
  907. entt::sparse_set &base = pool;
  908. pool.emplace(entt::entity{1}, 99);
  909. pool.emplace(entt::entity{3}, 42);
  910. auto iterable = std::as_const(pool).reach();
  911. iterator end{iterable.cbegin()};
  912. iterator begin{};
  913. begin = iterable.cend();
  914. std::swap(begin, end);
  915. ASSERT_EQ(begin, iterable.cbegin());
  916. ASSERT_EQ(end, iterable.cend());
  917. ASSERT_NE(begin, end);
  918. ASSERT_EQ(begin.base(), base.rbegin());
  919. ASSERT_EQ(end.base(), base.rend());
  920. ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1});
  921. ASSERT_EQ(std::get<1>(*begin.operator->().operator->()), value_type{99});
  922. ASSERT_EQ(std::get<0>(*begin), entt::entity{1});
  923. ASSERT_EQ(std::get<1>(*begin), value_type{99});
  924. ASSERT_EQ(begin++, iterable.begin());
  925. ASSERT_EQ(begin.base(), ++base.rbegin());
  926. ASSERT_EQ(++begin, iterable.end());
  927. ASSERT_EQ(begin.base(), base.rend());
  928. for(auto [entity, element]: iterable) {
  929. testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
  930. testing::StaticAssertTypeEq<decltype(element), const value_type &>();
  931. ASSERT_TRUE(entity != entt::entity{1} || element == value_type{99});
  932. ASSERT_TRUE(entity != entt::entity{3} || element == value_type{42});
  933. }
  934. }
  935. TYPED_TEST(Storage, ReverseIterableIteratorConversion) {
  936. using value_type = typename TestFixture::type;
  937. entt::storage<value_type> pool;
  938. pool.emplace(entt::entity{3}, 42);
  939. typename entt::storage<value_type>::reverse_iterable::iterator it = pool.reach().begin();
  940. typename entt::storage<value_type>::const_reverse_iterable::iterator cit = it;
  941. testing::StaticAssertTypeEq<decltype(*it), std::tuple<entt::entity, value_type &>>();
  942. testing::StaticAssertTypeEq<decltype(*cit), std::tuple<entt::entity, const value_type &>>();
  943. ASSERT_EQ(it, cit);
  944. ASSERT_NE(++cit, it);
  945. }
  946. TYPED_TEST(Storage, ReverseIterableAlgorithmCompatibility) {
  947. using value_type = typename TestFixture::type;
  948. entt::storage<value_type> pool;
  949. pool.emplace(entt::entity{3}, 42);
  950. const auto iterable = pool.reach();
  951. const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; });
  952. ASSERT_EQ(std::get<0>(*it), entt::entity{3});
  953. }
  954. TYPED_TEST(Storage, SortOrdered) {
  955. using value_type = typename TestFixture::type;
  956. entt::storage<value_type> pool;
  957. entt::entity entity[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
  958. value_type values[5u]{value_type{12}, value_type{9}, value_type{6}, value_type{3}, value_type{1}};
  959. pool.insert(std::begin(entity), std::end(entity), values);
  960. pool.sort([&pool](auto lhs, auto rhs) { return pool.get(lhs) < pool.get(rhs); });
  961. ASSERT_TRUE(std::equal(std::rbegin(entity), std::rend(entity), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
  962. ASSERT_TRUE(std::equal(std::rbegin(values), std::rend(values), pool.begin(), pool.end()));
  963. }
  964. TYPED_TEST(Storage, SortReverse) {
  965. using value_type = typename TestFixture::type;
  966. entt::storage<value_type> pool;
  967. entt::entity entity[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
  968. value_type values[5u]{value_type{1}, value_type{3}, value_type{6}, value_type{9}, value_type{12}};
  969. pool.insert(std::begin(entity), std::end(entity), values);
  970. pool.sort([&pool](auto lhs, auto rhs) { return pool.get(lhs) < pool.get(rhs); });
  971. ASSERT_TRUE(std::equal(std::begin(entity), std::end(entity), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
  972. ASSERT_TRUE(std::equal(std::begin(values), std::end(values), pool.begin(), pool.end()));
  973. }
  974. TYPED_TEST(Storage, SortUnordered) {
  975. using value_type = typename TestFixture::type;
  976. entt::storage<value_type> pool;
  977. entt::entity entity[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
  978. value_type values[5u]{value_type{6}, value_type{3}, value_type{1}, value_type{9}, value_type{12}};
  979. pool.insert(std::begin(entity), std::end(entity), values);
  980. pool.sort([&pool](auto lhs, auto rhs) { return pool.get(lhs) < pool.get(rhs); });
  981. auto begin = pool.begin();
  982. auto end = pool.end();
  983. ASSERT_EQ(*(begin++), values[2u]);
  984. ASSERT_EQ(*(begin++), values[1u]);
  985. ASSERT_EQ(*(begin++), values[0u]);
  986. ASSERT_EQ(*(begin++), values[3u]);
  987. ASSERT_EQ(*(begin++), values[4u]);
  988. ASSERT_EQ(begin, end);
  989. ASSERT_EQ(pool.data()[0u], entity[4u]);
  990. ASSERT_EQ(pool.data()[1u], entity[3u]);
  991. ASSERT_EQ(pool.data()[2u], entity[0u]);
  992. ASSERT_EQ(pool.data()[3u], entity[1u]);
  993. ASSERT_EQ(pool.data()[4u], entity[2u]);
  994. }
  995. TYPED_TEST(Storage, SortRange) {
  996. using value_type = typename TestFixture::type;
  997. entt::storage<value_type> pool;
  998. entt::entity entity[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
  999. value_type values[5u]{value_type{3}, value_type{6}, value_type{1}, value_type{9}, value_type{12}};
  1000. pool.insert(std::begin(entity), std::end(entity), values);
  1001. pool.sort_n(0u, [&pool](auto lhs, auto rhs) { return pool.get(lhs) < pool.get(rhs); });
  1002. ASSERT_TRUE(std::equal(std::rbegin(entity), std::rend(entity), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
  1003. ASSERT_TRUE(std::equal(std::rbegin(values), std::rend(values), pool.begin(), pool.end()));
  1004. pool.sort_n(2u, [&pool](auto lhs, auto rhs) { return pool.get(lhs) < pool.get(rhs); });
  1005. ASSERT_EQ(pool.raw()[0u][0u], values[1u]);
  1006. ASSERT_EQ(pool.raw()[0u][1u], values[0u]);
  1007. ASSERT_EQ(pool.raw()[0u][2u], values[2u]);
  1008. ASSERT_EQ(pool.data()[0u], entity[1u]);
  1009. ASSERT_EQ(pool.data()[1u], entity[0u]);
  1010. ASSERT_EQ(pool.data()[2u], entity[2u]);
  1011. pool.sort_n(5u, [&pool](auto lhs, auto rhs) { return pool.get(lhs) < pool.get(rhs); });
  1012. auto begin = pool.begin();
  1013. auto end = pool.end();
  1014. ASSERT_EQ(*(begin++), values[2u]);
  1015. ASSERT_EQ(*(begin++), values[0u]);
  1016. ASSERT_EQ(*(begin++), values[1u]);
  1017. ASSERT_EQ(*(begin++), values[3u]);
  1018. ASSERT_EQ(*(begin++), values[4u]);
  1019. ASSERT_EQ(begin, end);
  1020. ASSERT_EQ(pool.data()[0u], entity[4u]);
  1021. ASSERT_EQ(pool.data()[1u], entity[3u]);
  1022. ASSERT_EQ(pool.data()[2u], entity[1u]);
  1023. ASSERT_EQ(pool.data()[3u], entity[0u]);
  1024. ASSERT_EQ(pool.data()[4u], entity[2u]);
  1025. }
  1026. TYPED_TEST(Storage, RespectDisjoint) {
  1027. using value_type = typename TestFixture::type;
  1028. entt::storage<value_type> lhs;
  1029. entt::storage<value_type> rhs;
  1030. entt::entity lhs_entity[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
  1031. value_type lhs_values[3u]{value_type{3}, value_type{6}, value_type{9}};
  1032. lhs.insert(std::begin(lhs_entity), std::end(lhs_entity), lhs_values);
  1033. ASSERT_TRUE(std::equal(std::rbegin(lhs_entity), std::rend(lhs_entity), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  1034. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  1035. lhs.sort_as(rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end());
  1036. ASSERT_TRUE(std::equal(std::rbegin(lhs_entity), std::rend(lhs_entity), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  1037. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  1038. }
  1039. TYPED_TEST(Storage, RespectOverlap) {
  1040. using value_type = typename TestFixture::type;
  1041. entt::storage<value_type> lhs;
  1042. entt::storage<value_type> rhs;
  1043. entt::entity lhs_entity[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
  1044. value_type lhs_values[3u]{value_type{3}, value_type{6}, value_type{9}};
  1045. lhs.insert(std::begin(lhs_entity), std::end(lhs_entity), lhs_values);
  1046. entt::entity rhs_entity[1u]{entt::entity{12}};
  1047. value_type rhs_values[1u]{value_type{6}};
  1048. rhs.insert(std::begin(rhs_entity), std::end(rhs_entity), rhs_values);
  1049. ASSERT_TRUE(std::equal(std::rbegin(lhs_entity), std::rend(lhs_entity), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  1050. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  1051. ASSERT_TRUE(std::equal(std::rbegin(rhs_entity), std::rend(rhs_entity), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  1052. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  1053. lhs.sort_as(rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end());
  1054. auto begin = lhs.begin();
  1055. auto end = lhs.end();
  1056. ASSERT_EQ(*(begin++), lhs_values[1u]);
  1057. ASSERT_EQ(*(begin++), lhs_values[2u]);
  1058. ASSERT_EQ(*(begin++), lhs_values[0u]);
  1059. ASSERT_EQ(begin, end);
  1060. ASSERT_EQ(lhs.data()[0u], lhs_entity[0u]);
  1061. ASSERT_EQ(lhs.data()[1u], lhs_entity[2u]);
  1062. ASSERT_EQ(lhs.data()[2u], lhs_entity[1u]);
  1063. }
  1064. TYPED_TEST(Storage, RespectOrdered) {
  1065. using value_type = typename TestFixture::type;
  1066. entt::storage<value_type> lhs;
  1067. entt::storage<value_type> rhs;
  1068. entt::entity lhs_entity[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
  1069. value_type lhs_values[5u]{value_type{1}, value_type{2}, value_type{3}, value_type{4}, value_type{5}};
  1070. lhs.insert(std::begin(lhs_entity), std::end(lhs_entity), lhs_values);
  1071. entt::entity rhs_entity[6u]{entt::entity{6}, entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
  1072. value_type rhs_values[6u]{value_type{6}, value_type{1}, value_type{2}, value_type{3}, value_type{4}, value_type{5}};
  1073. rhs.insert(std::begin(rhs_entity), std::end(rhs_entity), rhs_values);
  1074. ASSERT_TRUE(std::equal(std::rbegin(lhs_entity), std::rend(lhs_entity), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  1075. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  1076. ASSERT_TRUE(std::equal(std::rbegin(rhs_entity), std::rend(rhs_entity), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  1077. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  1078. rhs.sort_as(lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end());
  1079. ASSERT_TRUE(std::equal(std::rbegin(rhs_entity), std::rend(rhs_entity), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  1080. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  1081. }
  1082. TYPED_TEST(Storage, RespectReverse) {
  1083. using value_type = typename TestFixture::type;
  1084. entt::storage<value_type> lhs;
  1085. entt::storage<value_type> rhs;
  1086. entt::entity lhs_entity[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
  1087. value_type lhs_values[5u]{value_type{1}, value_type{2}, value_type{3}, value_type{4}, value_type{5}};
  1088. lhs.insert(std::begin(lhs_entity), std::end(lhs_entity), lhs_values);
  1089. entt::entity rhs_entity[6u]{entt::entity{5}, entt::entity{4}, entt::entity{3}, entt::entity{2}, entt::entity{1}, entt::entity{6}};
  1090. value_type rhs_values[6u]{value_type{5}, value_type{4}, value_type{3}, value_type{2}, value_type{1}, value_type{6}};
  1091. rhs.insert(std::begin(rhs_entity), std::end(rhs_entity), rhs_values);
  1092. ASSERT_TRUE(std::equal(std::rbegin(lhs_entity), std::rend(lhs_entity), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  1093. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  1094. ASSERT_TRUE(std::equal(std::rbegin(rhs_entity), std::rend(rhs_entity), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  1095. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  1096. rhs.sort_as(lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end());
  1097. auto begin = rhs.begin();
  1098. auto end = rhs.end();
  1099. ASSERT_EQ(*(begin++), rhs_values[0u]);
  1100. ASSERT_EQ(*(begin++), rhs_values[1u]);
  1101. ASSERT_EQ(*(begin++), rhs_values[2u]);
  1102. ASSERT_EQ(*(begin++), rhs_values[3u]);
  1103. ASSERT_EQ(*(begin++), rhs_values[4u]);
  1104. ASSERT_EQ(*(begin++), rhs_values[5u]);
  1105. ASSERT_EQ(begin, end);
  1106. ASSERT_EQ(rhs.data()[0u], rhs_entity[5u]);
  1107. ASSERT_EQ(rhs.data()[1u], rhs_entity[4u]);
  1108. ASSERT_EQ(rhs.data()[2u], rhs_entity[3u]);
  1109. ASSERT_EQ(rhs.data()[3u], rhs_entity[2u]);
  1110. ASSERT_EQ(rhs.data()[4u], rhs_entity[1u]);
  1111. ASSERT_EQ(rhs.data()[5u], rhs_entity[0u]);
  1112. }
  1113. TYPED_TEST(Storage, RespectUnordered) {
  1114. using value_type = typename TestFixture::type;
  1115. entt::storage<value_type> lhs;
  1116. entt::storage<value_type> rhs;
  1117. entt::entity lhs_entity[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
  1118. value_type lhs_values[5u]{value_type{1}, value_type{2}, value_type{3}, value_type{4}, value_type{5}};
  1119. lhs.insert(std::begin(lhs_entity), std::end(lhs_entity), lhs_values);
  1120. entt::entity rhs_entity[6u]{entt::entity{3}, entt::entity{2}, entt::entity{6}, entt::entity{1}, entt::entity{4}, entt::entity{5}};
  1121. value_type rhs_values[6u]{value_type{3}, value_type{2}, value_type{6}, value_type{1}, value_type{4}, value_type{5}};
  1122. rhs.insert(std::begin(rhs_entity), std::end(rhs_entity), rhs_values);
  1123. ASSERT_TRUE(std::equal(std::rbegin(lhs_entity), std::rend(lhs_entity), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  1124. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  1125. ASSERT_TRUE(std::equal(std::rbegin(rhs_entity), std::rend(rhs_entity), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  1126. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  1127. rhs.sort_as(lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end());
  1128. auto begin = rhs.begin();
  1129. auto end = rhs.end();
  1130. ASSERT_EQ(*(begin++), rhs_values[5u]);
  1131. ASSERT_EQ(*(begin++), rhs_values[4u]);
  1132. ASSERT_EQ(*(begin++), rhs_values[0u]);
  1133. ASSERT_EQ(*(begin++), rhs_values[1u]);
  1134. ASSERT_EQ(*(begin++), rhs_values[3u]);
  1135. ASSERT_EQ(*(begin++), rhs_values[2u]);
  1136. ASSERT_EQ(begin, end);
  1137. ASSERT_EQ(rhs.data()[0u], rhs_entity[2u]);
  1138. ASSERT_EQ(rhs.data()[1u], rhs_entity[3u]);
  1139. ASSERT_EQ(rhs.data()[2u], rhs_entity[1u]);
  1140. ASSERT_EQ(rhs.data()[3u], rhs_entity[0u]);
  1141. ASSERT_EQ(rhs.data()[4u], rhs_entity[4u]);
  1142. ASSERT_EQ(rhs.data()[5u], rhs_entity[5u]);
  1143. }
  1144. TEST(Storage, MoveOnlyComponent) {
  1145. using value_type = std::unique_ptr<int>;
  1146. static_assert(!std::is_copy_assignable_v<value_type>, "Copy assignable types not allowed");
  1147. static_assert(std::is_move_assignable_v<value_type>, "Move assignable type required");
  1148. // the purpose is to ensure that move only components are always accepted
  1149. [[maybe_unused]] entt::storage<value_type> pool;
  1150. }
  1151. TEST(Storage, NonMovableComponent) {
  1152. using value_type = std::pair<const int, const int>;
  1153. static_assert(!std::is_move_assignable_v<value_type>, "Move assignable types not allowed");
  1154. // the purpose is to ensure that non-movable components are always accepted
  1155. [[maybe_unused]] entt::storage<value_type> pool;
  1156. }
  1157. ENTT_DEBUG_TEST(StorageDeathTest, NonMovableComponent) {
  1158. entt::storage<std::pair<const int, const int>> pool;
  1159. const entt::entity entity{0};
  1160. const entt::entity destroy{1};
  1161. const entt::entity other{2};
  1162. pool.emplace(entity);
  1163. pool.emplace(destroy);
  1164. pool.emplace(other);
  1165. pool.erase(destroy);
  1166. ASSERT_DEATH(pool.swap_elements(entity, other), "");
  1167. ASSERT_DEATH(pool.compact(), "");
  1168. ASSERT_DEATH(pool.sort([](auto &&lhs, auto &&rhs) { return lhs < rhs; }), "");
  1169. }
  1170. TYPED_TEST(Storage, CanModifyDuringIteration) {
  1171. using value_type = typename TestFixture::type;
  1172. using traits_type = entt::component_traits<value_type>;
  1173. entt::storage<value_type> pool;
  1174. auto *ptr = &pool.emplace(entt::entity{0}, 42);
  1175. ASSERT_EQ(pool.capacity(), traits_type::page_size);
  1176. const auto it = pool.cbegin();
  1177. pool.reserve(traits_type::page_size + 1u);
  1178. ASSERT_EQ(pool.capacity(), 2 * traits_type::page_size);
  1179. ASSERT_EQ(&pool.get(entt::entity{0}), ptr);
  1180. // this should crash with asan enabled if we break the constraint
  1181. [[maybe_unused]] const auto &value = *it;
  1182. }
  1183. TYPED_TEST(Storage, ReferencesGuaranteed) {
  1184. using value_type = typename TestFixture::type;
  1185. entt::storage<value_type> pool;
  1186. pool.emplace(entt::entity{0}, 0);
  1187. pool.emplace(entt::entity{1}, 1);
  1188. ASSERT_EQ(pool.get(entt::entity{0}), value_type{0});
  1189. ASSERT_EQ(pool.get(entt::entity{1}), value_type{1});
  1190. for(auto &&type: pool) {
  1191. if(!(type == value_type{})) {
  1192. type = value_type{42};
  1193. }
  1194. }
  1195. ASSERT_EQ(pool.get(entt::entity{0}), value_type{0});
  1196. ASSERT_EQ(pool.get(entt::entity{1}), value_type{42});
  1197. auto begin = pool.begin();
  1198. while(begin != pool.end()) {
  1199. *(begin++) = value_type{3};
  1200. }
  1201. ASSERT_EQ(pool.get(entt::entity{0}), value_type{3});
  1202. ASSERT_EQ(pool.get(entt::entity{1}), value_type{3});
  1203. }
  1204. TEST(Storage, UpdateFromDestructor) {
  1205. auto test = [](const auto target) {
  1206. constexpr auto size = 10u;
  1207. entt::storage<update_from_destructor> pool;
  1208. for(std::size_t next{}; next < size; ++next) {
  1209. const auto entity = entt::entity(next);
  1210. pool.emplace(entity, pool, entity == entt::entity(size / 2) ? target : entity);
  1211. }
  1212. pool.erase(entt::entity(size / 2));
  1213. ASSERT_EQ(pool.size(), size - 1u - (target != entt::null));
  1214. ASSERT_FALSE(pool.contains(entt::entity(size / 2)));
  1215. ASSERT_FALSE(pool.contains(target));
  1216. pool.clear();
  1217. ASSERT_TRUE(pool.empty());
  1218. for(std::size_t next{}; next < size; ++next) {
  1219. ASSERT_FALSE(pool.contains(entt::entity(next)));
  1220. }
  1221. };
  1222. test(entt::entity{9u});
  1223. test(entt::entity{8u});
  1224. test(entt::entity{0u});
  1225. }
  1226. TEST(Storage, CreateFromConstructor) {
  1227. entt::storage<create_from_constructor> pool;
  1228. const entt::entity entity{0u};
  1229. const entt::entity other{1u};
  1230. pool.emplace(entity, pool, other);
  1231. ASSERT_EQ(pool.get(entity).child, other);
  1232. ASSERT_EQ(pool.get(other).child, static_cast<entt::entity>(entt::null));
  1233. }
  1234. TYPED_TEST(Storage, CustomAllocator) {
  1235. using value_type = typename TestFixture::type;
  1236. test::throwing_allocator<entt::entity> allocator{};
  1237. entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>> pool{allocator};
  1238. pool.reserve(1u);
  1239. ASSERT_NE(pool.capacity(), 0u);
  1240. pool.emplace(entt::entity{0});
  1241. pool.emplace(entt::entity{1});
  1242. decltype(pool) other{std::move(pool), allocator};
  1243. ASSERT_TRUE(pool.empty());
  1244. ASSERT_FALSE(other.empty());
  1245. ASSERT_EQ(pool.capacity(), 0u);
  1246. ASSERT_NE(other.capacity(), 0u);
  1247. ASSERT_EQ(other.size(), 2u);
  1248. pool = std::move(other);
  1249. ASSERT_FALSE(pool.empty());
  1250. ASSERT_TRUE(other.empty());
  1251. ASSERT_EQ(other.capacity(), 0u);
  1252. ASSERT_NE(pool.capacity(), 0u);
  1253. ASSERT_EQ(pool.size(), 2u);
  1254. pool.swap(other);
  1255. pool = std::move(other);
  1256. ASSERT_FALSE(pool.empty());
  1257. ASSERT_TRUE(other.empty());
  1258. ASSERT_EQ(other.capacity(), 0u);
  1259. ASSERT_NE(pool.capacity(), 0u);
  1260. ASSERT_EQ(pool.size(), 2u);
  1261. pool.clear();
  1262. ASSERT_NE(pool.capacity(), 0u);
  1263. ASSERT_EQ(pool.size(), 0u);
  1264. }
  1265. TYPED_TEST(Storage, ThrowingAllocator) {
  1266. using value_type = typename TestFixture::type;
  1267. using allocator_type = test::throwing_allocator<value_type>;
  1268. entt::basic_storage<value_type, entt::entity, allocator_type> pool{};
  1269. typename std::decay_t<decltype(pool)>::base_type &base = pool;
  1270. constexpr auto packed_page_size = decltype(pool)::traits_type::page_size;
  1271. constexpr auto sparse_page_size = std::remove_reference_t<decltype(base)>::traits_type::page_size;
  1272. allocator_type::trigger_on_allocate = true;
  1273. ASSERT_THROW(pool.reserve(1u), typename allocator_type::exception_type);
  1274. ASSERT_EQ(pool.capacity(), 0u);
  1275. allocator_type::trigger_after_allocate = true;
  1276. ASSERT_THROW(pool.reserve(2 * packed_page_size), typename allocator_type::exception_type);
  1277. ASSERT_EQ(pool.capacity(), packed_page_size);
  1278. pool.shrink_to_fit();
  1279. ASSERT_EQ(pool.capacity(), 0u);
  1280. test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
  1281. ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator<entt::entity>::exception_type);
  1282. ASSERT_FALSE(pool.contains(entt::entity{0}));
  1283. ASSERT_TRUE(pool.empty());
  1284. test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
  1285. ASSERT_THROW(base.push(entt::entity{0}), test::throwing_allocator<entt::entity>::exception_type);
  1286. ASSERT_FALSE(base.contains(entt::entity{0}));
  1287. ASSERT_TRUE(base.empty());
  1288. allocator_type::trigger_on_allocate = true;
  1289. ASSERT_THROW(pool.emplace(entt::entity{0}, 0), typename allocator_type::exception_type);
  1290. ASSERT_FALSE(pool.contains(entt::entity{0}));
  1291. ASSERT_NO_FATAL_FAILURE(pool.compact());
  1292. ASSERT_TRUE(pool.empty());
  1293. pool.emplace(entt::entity{0}, 0);
  1294. const entt::entity entity[2u]{entt::entity{1}, entt::entity{sparse_page_size}};
  1295. test::throwing_allocator<entt::entity>::trigger_after_allocate = true;
  1296. ASSERT_THROW(pool.insert(std::begin(entity), std::end(entity), value_type{0}), test::throwing_allocator<entt::entity>::exception_type);
  1297. ASSERT_TRUE(pool.contains(entt::entity{1}));
  1298. ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
  1299. pool.erase(entt::entity{1});
  1300. const value_type components[2u]{value_type{1}, value_type{sparse_page_size}};
  1301. test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
  1302. pool.compact();
  1303. ASSERT_THROW(pool.insert(std::begin(entity), std::end(entity), std::begin(components)), test::throwing_allocator<entt::entity>::exception_type);
  1304. ASSERT_TRUE(pool.contains(entt::entity{1}));
  1305. ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
  1306. }
  1307. TEST(Storage, ThrowingComponent) {
  1308. entt::storage<test::throwing_type> pool;
  1309. test::throwing_type::trigger_on_value = 42;
  1310. // strong exception safety
  1311. ASSERT_THROW(pool.emplace(entt::entity{0}, test::throwing_type{42}), typename test::throwing_type::exception_type);
  1312. ASSERT_TRUE(pool.empty());
  1313. const entt::entity entity[2u]{entt::entity{42}, entt::entity{1}};
  1314. const test::throwing_type components[2u]{42, 1};
  1315. // basic exception safety
  1316. ASSERT_THROW(pool.insert(std::begin(entity), std::end(entity), test::throwing_type{42}), typename test::throwing_type::exception_type);
  1317. ASSERT_EQ(pool.size(), 0u);
  1318. ASSERT_FALSE(pool.contains(entt::entity{1}));
  1319. // basic exception safety
  1320. ASSERT_THROW(pool.insert(std::begin(entity), std::end(entity), std::begin(components)), typename test::throwing_type::exception_type);
  1321. ASSERT_EQ(pool.size(), 0u);
  1322. ASSERT_FALSE(pool.contains(entt::entity{1}));
  1323. // basic exception safety
  1324. ASSERT_THROW(pool.insert(std::rbegin(entity), std::rend(entity), std::rbegin(components)), typename test::throwing_type::exception_type);
  1325. ASSERT_EQ(pool.size(), 1u);
  1326. ASSERT_TRUE(pool.contains(entt::entity{1}));
  1327. ASSERT_EQ(pool.get(entt::entity{1}), 1);
  1328. pool.clear();
  1329. pool.emplace(entt::entity{1}, 1);
  1330. pool.emplace(entt::entity{42}, 42);
  1331. // basic exception safety
  1332. ASSERT_THROW(pool.erase(entt::entity{1}), typename test::throwing_type::exception_type);
  1333. ASSERT_EQ(pool.size(), 2u);
  1334. ASSERT_TRUE(pool.contains(entt::entity{42}));
  1335. ASSERT_TRUE(pool.contains(entt::entity{1}));
  1336. ASSERT_EQ(pool.at(0u), entt::entity{1});
  1337. ASSERT_EQ(pool.at(1u), entt::entity{42});
  1338. ASSERT_EQ(pool.get(entt::entity{42}), 42);
  1339. // the element may have been moved but it's still there
  1340. ASSERT_EQ(pool.get(entt::entity{1}), test::throwing_type::moved_from_value);
  1341. test::throwing_type::trigger_on_value = 99;
  1342. pool.erase(entt::entity{1});
  1343. ASSERT_EQ(pool.size(), 1u);
  1344. ASSERT_TRUE(pool.contains(entt::entity{42}));
  1345. ASSERT_FALSE(pool.contains(entt::entity{1}));
  1346. ASSERT_EQ(pool.at(0u), entt::entity{42});
  1347. ASSERT_EQ(pool.get(entt::entity{42}), 42);
  1348. }
  1349. #if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)
  1350. TYPED_TEST(Storage, NoUsesAllocatorConstruction) {
  1351. using value_type = typename TestFixture::type;
  1352. test::tracked_memory_resource memory_resource{};
  1353. entt::basic_storage<value_type, entt::entity, std::pmr::polymorphic_allocator<value_type>> pool{&memory_resource};
  1354. const entt::entity entity{};
  1355. pool.emplace(entity);
  1356. pool.erase(entity);
  1357. memory_resource.reset();
  1358. pool.emplace(entity, 0);
  1359. ASSERT_TRUE(pool.get_allocator().resource()->is_equal(memory_resource));
  1360. ASSERT_EQ(memory_resource.do_allocate_counter(), 0u);
  1361. ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
  1362. }
  1363. TEST(Storage, UsesAllocatorConstruction) {
  1364. using string_type = typename test::tracked_memory_resource::string_type;
  1365. test::tracked_memory_resource memory_resource{};
  1366. entt::basic_storage<string_type, entt::entity, std::pmr::polymorphic_allocator<string_type>> pool{&memory_resource};
  1367. const entt::entity entity{};
  1368. pool.emplace(entity);
  1369. pool.erase(entity);
  1370. memory_resource.reset();
  1371. pool.emplace(entity, test::tracked_memory_resource::default_value);
  1372. ASSERT_TRUE(pool.get_allocator().resource()->is_equal(memory_resource));
  1373. ASSERT_GT(memory_resource.do_allocate_counter(), 0u);
  1374. ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
  1375. }
  1376. #endif