storage.cpp 70 KB

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