storage.cpp 57 KB

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