storage.cpp 69 KB

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