storage.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  1. #include <memory>
  2. #include <utility>
  3. #include <iterator>
  4. #include <exception>
  5. #include <type_traits>
  6. #include <unordered_set>
  7. #include <gtest/gtest.h>
  8. #include <entt/entity/component.hpp>
  9. #include <entt/entity/fwd.hpp>
  10. #include <entt/entity/storage.hpp>
  11. #include "throwing_allocator.hpp"
  12. #include "throwing_component.hpp"
  13. struct empty_type {};
  14. struct boxed_int { int value; };
  15. struct stable_type { int value; };
  16. struct update_from_destructor {
  17. update_from_destructor(entt::storage<update_from_destructor> &ref, entt::entity other)
  18. : storage{&ref},
  19. target{other}
  20. {}
  21. update_from_destructor(update_from_destructor &&other) ENTT_NOEXCEPT
  22. : storage{std::exchange(other.storage, nullptr)},
  23. target{std::exchange(other.target, entt::null)}
  24. {}
  25. update_from_destructor & operator=(update_from_destructor &&other) ENTT_NOEXCEPT {
  26. storage = std::exchange(other.storage, nullptr);
  27. target = std::exchange(other.target, entt::null);
  28. return *this;
  29. }
  30. ~update_from_destructor() {
  31. if(target != entt::null && storage->contains(target)) {
  32. storage->erase(target);
  33. }
  34. }
  35. private:
  36. entt::storage<update_from_destructor> *storage{};
  37. entt::entity target{entt::null};
  38. };
  39. template<>
  40. struct entt::component_traits<stable_type>: basic_component_traits {
  41. using in_place_delete = std::true_type;
  42. };
  43. bool operator==(const boxed_int &lhs, const boxed_int &rhs) {
  44. return lhs.value == rhs.value;
  45. }
  46. TEST(Storage, Functionalities) {
  47. entt::storage<int> pool;
  48. ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
  49. pool.reserve(42);
  50. ASSERT_EQ(pool.capacity(), ENTT_PACKED_PAGE);
  51. ASSERT_TRUE(pool.empty());
  52. ASSERT_EQ(pool.size(), 0u);
  53. ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
  54. ASSERT_EQ(pool.begin(), pool.end());
  55. ASSERT_FALSE(pool.contains(entt::entity{0}));
  56. ASSERT_FALSE(pool.contains(entt::entity{41}));
  57. pool.reserve(0);
  58. ASSERT_EQ(pool.capacity(), ENTT_PACKED_PAGE);
  59. ASSERT_TRUE(pool.empty());
  60. pool.emplace(entt::entity{41}, 3);
  61. ASSERT_FALSE(pool.empty());
  62. ASSERT_EQ(pool.size(), 1u);
  63. ASSERT_NE(std::as_const(pool).begin(), std::as_const(pool).end());
  64. ASSERT_NE(pool.begin(), pool.end());
  65. ASSERT_FALSE(pool.contains(entt::entity{0}));
  66. ASSERT_TRUE(pool.contains(entt::entity{41}));
  67. ASSERT_EQ(pool.get(entt::entity{41}), 3);
  68. ASSERT_EQ(std::as_const(pool).get(entt::entity{41}), 3);
  69. ASSERT_EQ(pool.get_as_tuple(entt::entity{41}), std::make_tuple(3));
  70. ASSERT_EQ(std::as_const(pool).get_as_tuple(entt::entity{41}), std::make_tuple(3));
  71. pool.erase(entt::entity{41});
  72. ASSERT_TRUE(pool.empty());
  73. ASSERT_EQ(pool.size(), 0u);
  74. ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
  75. ASSERT_EQ(pool.begin(), pool.end());
  76. ASSERT_FALSE(pool.contains(entt::entity{0}));
  77. ASSERT_FALSE(pool.contains(entt::entity{41}));
  78. pool.emplace(entt::entity{41}, 12);
  79. ASSERT_EQ(pool.get(entt::entity{41}), 12);
  80. ASSERT_EQ(std::as_const(pool).get(entt::entity{41}), 12);
  81. ASSERT_EQ(pool.get_as_tuple(entt::entity{41}), std::make_tuple(12));
  82. ASSERT_EQ(std::as_const(pool).get_as_tuple(entt::entity{41}), std::make_tuple(12));
  83. pool.clear();
  84. ASSERT_TRUE(pool.empty());
  85. ASSERT_EQ(pool.size(), 0u);
  86. ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
  87. ASSERT_EQ(pool.begin(), pool.end());
  88. ASSERT_FALSE(pool.contains(entt::entity{0}));
  89. ASSERT_FALSE(pool.contains(entt::entity{41}));
  90. ASSERT_EQ(pool.capacity(), ENTT_PACKED_PAGE);
  91. pool.shrink_to_fit();
  92. ASSERT_EQ(pool.capacity(), 0u);
  93. }
  94. TEST(Storage, Move) {
  95. entt::storage<int> pool;
  96. pool.emplace(entt::entity{3}, 3);
  97. ASSERT_TRUE(std::is_move_constructible_v<decltype(pool)>);
  98. ASSERT_TRUE(std::is_move_assignable_v<decltype(pool)>);
  99. entt::storage<int> other{std::move(pool)};
  100. ASSERT_TRUE(pool.empty());
  101. ASSERT_FALSE(other.empty());
  102. ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
  103. ASSERT_EQ(other.at(0u), entt::entity{3});
  104. ASSERT_EQ(other.get(entt::entity{3}), 3);
  105. pool = std::move(other);
  106. ASSERT_FALSE(pool.empty());
  107. ASSERT_TRUE(other.empty());
  108. ASSERT_EQ(pool.at(0u), entt::entity{3});
  109. ASSERT_EQ(pool.get(entt::entity{3}), 3);
  110. ASSERT_EQ(other.at(0u), static_cast<entt::entity>(entt::null));
  111. other = entt::storage<int>{};
  112. other.emplace(entt::entity{42}, 42);
  113. other = std::move(pool);
  114. ASSERT_TRUE(pool.empty());
  115. ASSERT_FALSE(other.empty());
  116. ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
  117. ASSERT_EQ(other.at(0u), entt::entity{3});
  118. ASSERT_EQ(other.get(entt::entity{3}), 3);
  119. }
  120. TEST(Storage, EmptyType) {
  121. entt::storage<empty_type> pool;
  122. pool.emplace(entt::entity{99});
  123. ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
  124. ASSERT_TRUE(pool.contains(entt::entity{99}));
  125. }
  126. TEST(Storage, Insert) {
  127. entt::storage<stable_type> pool;
  128. entt::entity entities[2u];
  129. entities[0u] = entt::entity{3};
  130. entities[1u] = entt::entity{42};
  131. pool.insert(std::begin(entities), std::end(entities), stable_type{99});
  132. ASSERT_TRUE(pool.contains(entities[0u]));
  133. ASSERT_TRUE(pool.contains(entities[1u]));
  134. ASSERT_FALSE(pool.empty());
  135. ASSERT_EQ(pool.size(), 2u);
  136. ASSERT_EQ(pool.get(entities[0u]).value, 99);
  137. ASSERT_EQ(pool.get(entities[1u]).value, 99);
  138. pool.erase(std::begin(entities), std::end(entities));
  139. const stable_type values[2u] = { stable_type{42}, stable_type{3} };
  140. pool.insert(std::rbegin(entities), std::rend(entities), std::begin(values));
  141. ASSERT_EQ(pool.size(), 4u);
  142. ASSERT_TRUE(pool.at(0u) == entt::tombstone);
  143. ASSERT_TRUE(pool.at(1u) == entt::tombstone);
  144. ASSERT_EQ(pool.at(2u), entities[1u]);
  145. ASSERT_EQ(pool.at(3u), entities[0u]);
  146. ASSERT_EQ(pool.index(entities[0u]), 3u);
  147. ASSERT_EQ(pool.index(entities[1u]), 2u);
  148. ASSERT_EQ(pool.get(entities[0u]).value, 3);
  149. ASSERT_EQ(pool.get(entities[1u]).value, 42);
  150. }
  151. TEST(Storage, InsertEmptyType) {
  152. entt::storage<empty_type> pool;
  153. entt::entity entities[2u];
  154. entities[0u] = entt::entity{3};
  155. entities[1u] = entt::entity{42};
  156. pool.insert(std::begin(entities), std::end(entities));
  157. ASSERT_TRUE(pool.contains(entities[0u]));
  158. ASSERT_TRUE(pool.contains(entities[1u]));
  159. ASSERT_FALSE(pool.empty());
  160. ASSERT_EQ(pool.size(), 2u);
  161. }
  162. TEST(Storage, Erase) {
  163. entt::storage<int> pool;
  164. entt::entity entities[3u];
  165. entities[0u] = entt::entity{3};
  166. entities[1u] = entt::entity{42};
  167. entities[2u] = entt::entity{9};
  168. pool.emplace(entities[0u]);
  169. pool.emplace(entities[1u]);
  170. pool.emplace(entities[2u]);
  171. pool.erase(std::begin(entities), std::end(entities));
  172. ASSERT_DEATH(pool.erase(std::begin(entities), std::end(entities)), "");
  173. ASSERT_TRUE(pool.empty());
  174. pool.emplace(entities[0u], 0);
  175. pool.emplace(entities[1u], 1);
  176. pool.emplace(entities[2u], 2);
  177. pool.erase(entities, entities + 2u);
  178. ASSERT_FALSE(pool.empty());
  179. ASSERT_EQ(*pool.begin(), 2);
  180. pool.erase(entities[2u]);
  181. ASSERT_DEATH(pool.erase(entities[2u]), "");
  182. ASSERT_TRUE(pool.empty());
  183. pool.emplace(entities[0u], 0);
  184. pool.emplace(entities[1u], 1);
  185. pool.emplace(entities[2u], 2);
  186. std::swap(entities[1u], entities[2u]);
  187. pool.erase(entities, entities + 2u);
  188. ASSERT_FALSE(pool.empty());
  189. ASSERT_EQ(*pool.begin(), 1);
  190. }
  191. TEST(Storage, StableErase) {
  192. entt::storage<stable_type> pool;
  193. entt::entity entities[3u];
  194. ASSERT_DEATH([[maybe_unused]] auto &&value = pool.get(entt::tombstone), "");
  195. ASSERT_DEATH([[maybe_unused]] auto &&value = pool.get(entt::null), "");
  196. entities[0u] = entt::entity{3};
  197. entities[1u] = entt::entity{42};
  198. entities[2u] = entt::entity{9};
  199. pool.emplace(entities[0u], stable_type{0});
  200. pool.emplace(entities[1u], stable_type{1});
  201. pool.emplace(entities[2u], stable_type{2});
  202. pool.erase(std::begin(entities), std::end(entities));
  203. ASSERT_DEATH(pool.erase(std::begin(entities), std::end(entities)), "");
  204. ASSERT_FALSE(pool.empty());
  205. ASSERT_EQ(pool.size(), 3u);
  206. ASSERT_TRUE(pool.at(2u) == entt::tombstone);
  207. ASSERT_DEATH([[maybe_unused]] auto &&value = pool.get(entt::tombstone), "");
  208. ASSERT_DEATH([[maybe_unused]] auto &&value = pool.get(entt::null), "");
  209. ASSERT_DEATH([[maybe_unused]] auto &&value = pool.get(entities[1u]), "");
  210. pool.emplace(entities[2u], stable_type{2});
  211. pool.emplace(entities[0u], stable_type{0});
  212. pool.emplace(entities[1u], stable_type{1});
  213. ASSERT_EQ(pool.get(entities[0u]).value, 0);
  214. ASSERT_EQ(pool.get(entities[1u]).value, 1);
  215. ASSERT_EQ(pool.get(entities[2u]).value, 2);
  216. ASSERT_EQ(pool.begin()->value, 2);
  217. ASSERT_EQ(pool.index(entities[0u]), 1u);
  218. ASSERT_EQ(pool.index(entities[1u]), 0u);
  219. ASSERT_EQ(pool.index(entities[2u]), 2u);
  220. pool.erase(entities, entities + 2u);
  221. ASSERT_FALSE(pool.empty());
  222. ASSERT_EQ(pool.size(), 3u);
  223. ASSERT_EQ(pool.begin()->value, 2);
  224. ASSERT_EQ(pool.index(entities[2u]), 2u);
  225. pool.erase(entities[2u]);
  226. ASSERT_DEATH(pool.erase(entities[2u]), "");
  227. ASSERT_FALSE(pool.empty());
  228. ASSERT_EQ(pool.size(), 3u);
  229. ASSERT_FALSE(pool.contains(entities[0u]));
  230. ASSERT_FALSE(pool.contains(entities[1u]));
  231. ASSERT_FALSE(pool.contains(entities[2u]));
  232. pool.emplace(entities[0u], stable_type{0});
  233. pool.emplace(entities[1u], stable_type{1});
  234. pool.emplace(entities[2u], stable_type{2});
  235. std::swap(entities[1u], entities[2u]);
  236. pool.erase(entities, entities + 2u);
  237. ASSERT_FALSE(pool.empty());
  238. ASSERT_EQ(pool.size(), 3u);
  239. ASSERT_TRUE(pool.contains(entities[2u]));
  240. ASSERT_EQ(pool.index(entities[2u]), 0u);
  241. ASSERT_EQ(pool.get(entities[2u]).value, 1);
  242. pool.compact();
  243. ASSERT_FALSE(pool.empty());
  244. ASSERT_EQ(pool.size(), 1u);
  245. ASSERT_EQ(pool.begin()->value, 1);
  246. pool.clear();
  247. ASSERT_EQ(pool.size(), 0u);
  248. pool.emplace(entities[0u], stable_type{0});
  249. pool.emplace(entities[1u], stable_type{2});
  250. pool.emplace(entities[2u], stable_type{1});
  251. pool.erase(entities[2u]);
  252. ASSERT_DEATH(pool.erase(entities[2u]), "");
  253. pool.erase(entities[0u]);
  254. pool.erase(entities[1u]);
  255. ASSERT_DEATH(pool.erase(entities, entities + 2u), "");
  256. ASSERT_EQ(pool.size(), 3u);
  257. ASSERT_TRUE(pool.at(2u) == entt::tombstone);
  258. pool.emplace(entities[0u], stable_type{99});
  259. ASSERT_EQ((++pool.begin())->value, 99);
  260. pool.emplace(entities[1u], stable_type{2});
  261. pool.emplace(entities[2u], stable_type{1});
  262. pool.emplace(entt::entity{0}, stable_type{7});
  263. ASSERT_EQ(pool.size(), 4u);
  264. ASSERT_EQ(pool.begin()->value, 7);
  265. ASSERT_EQ(pool.at(0u), entities[1u]);
  266. ASSERT_EQ(pool.at(1u), entities[0u]);
  267. ASSERT_EQ(pool.at(2u), entities[2u]);
  268. ASSERT_EQ(pool.get(entities[0u]).value, 99);
  269. ASSERT_EQ(pool.get(entities[1u]).value, 2);
  270. ASSERT_EQ(pool.get(entities[2u]).value, 1);
  271. }
  272. TEST(Storage, Remove) {
  273. entt::storage<int> pool;
  274. entt::entity entities[3u];
  275. entities[0u] = entt::entity{3};
  276. entities[1u] = entt::entity{42};
  277. entities[2u] = entt::entity{9};
  278. pool.emplace(entities[0u]);
  279. pool.emplace(entities[1u]);
  280. pool.emplace(entities[2u]);
  281. ASSERT_EQ(pool.remove(std::begin(entities), std::end(entities)), 3u);
  282. ASSERT_EQ(pool.remove(std::begin(entities), std::end(entities)), 0u);
  283. ASSERT_TRUE(pool.empty());
  284. pool.emplace(entities[0u], 0);
  285. pool.emplace(entities[1u], 1);
  286. pool.emplace(entities[2u], 2);
  287. ASSERT_EQ(pool.remove(entities, entities + 2u), 2u);
  288. ASSERT_FALSE(pool.empty());
  289. ASSERT_EQ(*pool.begin(), 2);
  290. ASSERT_EQ(pool.remove(entities[2u]), 1u);
  291. ASSERT_EQ(pool.remove(entities[2u]), 0u);
  292. ASSERT_TRUE(pool.empty());
  293. pool.emplace(entities[0u], 0);
  294. pool.emplace(entities[1u], 1);
  295. pool.emplace(entities[2u], 2);
  296. std::swap(entities[1u], entities[2u]);
  297. ASSERT_EQ(pool.remove(entities, entities + 2u), 2u);
  298. ASSERT_FALSE(pool.empty());
  299. ASSERT_EQ(*pool.begin(), 1);
  300. }
  301. TEST(Storage, StableRemove) {
  302. entt::storage<stable_type> pool;
  303. entt::entity entities[3u];
  304. entities[0u] = entt::entity{3};
  305. entities[1u] = entt::entity{42};
  306. entities[2u] = entt::entity{9};
  307. pool.emplace(entities[0u], stable_type{0});
  308. pool.emplace(entities[1u], stable_type{1});
  309. pool.emplace(entities[2u], stable_type{2});
  310. ASSERT_EQ(pool.remove(std::begin(entities), std::end(entities)), 3u);
  311. ASSERT_EQ(pool.remove(std::begin(entities), std::end(entities)), 0u);
  312. ASSERT_FALSE(pool.empty());
  313. ASSERT_EQ(pool.size(), 3u);
  314. ASSERT_TRUE(pool.at(2u) == entt::tombstone);
  315. ASSERT_DEATH([[maybe_unused]] auto &&value = pool.get(entt::tombstone), "");
  316. ASSERT_DEATH([[maybe_unused]] auto &&value = pool.get(entt::null), "");
  317. ASSERT_DEATH([[maybe_unused]] auto &&value = pool.get(entities[1u]), "");
  318. pool.emplace(entities[2u], stable_type{2});
  319. pool.emplace(entities[0u], stable_type{0});
  320. pool.emplace(entities[1u], stable_type{1});
  321. ASSERT_EQ(pool.get(entities[0u]).value, 0);
  322. ASSERT_EQ(pool.get(entities[1u]).value, 1);
  323. ASSERT_EQ(pool.get(entities[2u]).value, 2);
  324. ASSERT_EQ(pool.begin()->value, 2);
  325. ASSERT_EQ(pool.index(entities[0u]), 1u);
  326. ASSERT_EQ(pool.index(entities[1u]), 0u);
  327. ASSERT_EQ(pool.index(entities[2u]), 2u);
  328. ASSERT_EQ(pool.remove(entities, entities + 2u), 2u);
  329. ASSERT_FALSE(pool.empty());
  330. ASSERT_EQ(pool.size(), 3u);
  331. ASSERT_EQ(pool.begin()->value, 2);
  332. ASSERT_EQ(pool.index(entities[2u]), 2u);
  333. ASSERT_EQ(pool.remove(entities[2u]), 1u);
  334. ASSERT_EQ(pool.remove(entities[2u]), 0u);
  335. ASSERT_EQ(pool.remove(entities[2u]), 0u);
  336. ASSERT_FALSE(pool.empty());
  337. ASSERT_EQ(pool.size(), 3u);
  338. ASSERT_FALSE(pool.contains(entities[0u]));
  339. ASSERT_FALSE(pool.contains(entities[1u]));
  340. ASSERT_FALSE(pool.contains(entities[2u]));
  341. pool.emplace(entities[0u], stable_type{0});
  342. pool.emplace(entities[1u], stable_type{1});
  343. pool.emplace(entities[2u], stable_type{2});
  344. std::swap(entities[1u], entities[2u]);
  345. ASSERT_EQ(pool.remove(entities, entities + 2u), 2u);
  346. ASSERT_FALSE(pool.empty());
  347. ASSERT_EQ(pool.size(), 3u);
  348. ASSERT_TRUE(pool.contains(entities[2u]));
  349. ASSERT_EQ(pool.index(entities[2u]), 0u);
  350. ASSERT_EQ(pool.get(entities[2u]).value, 1);
  351. pool.compact();
  352. ASSERT_FALSE(pool.empty());
  353. ASSERT_EQ(pool.size(), 1u);
  354. ASSERT_EQ(pool.begin()->value, 1);
  355. pool.clear();
  356. ASSERT_EQ(pool.size(), 0u);
  357. pool.emplace(entities[0u], stable_type{0});
  358. pool.emplace(entities[1u], stable_type{2});
  359. pool.emplace(entities[2u], stable_type{1});
  360. ASSERT_EQ(pool.remove(entities[2u]), 1u);
  361. ASSERT_EQ(pool.remove(entities[2u]), 0u);
  362. ASSERT_EQ(pool.remove(entities[0u]), 1u);
  363. ASSERT_EQ(pool.remove(entities[1u]), 1u);
  364. ASSERT_EQ(pool.remove(entities, entities + 2u), 0u);
  365. ASSERT_EQ(pool.size(), 3u);
  366. ASSERT_TRUE(pool.at(2u) == entt::tombstone);
  367. pool.emplace(entities[0u], stable_type{99});
  368. ASSERT_EQ((++pool.begin())->value, 99);
  369. pool.emplace(entities[1u], stable_type{2});
  370. pool.emplace(entities[2u], stable_type{1});
  371. pool.emplace(entt::entity{0}, stable_type{7});
  372. ASSERT_EQ(pool.size(), 4u);
  373. ASSERT_EQ(pool.begin()->value, 7);
  374. ASSERT_EQ(pool.at(0u), entities[1u]);
  375. ASSERT_EQ(pool.at(1u), entities[0u]);
  376. ASSERT_EQ(pool.at(2u), entities[2u]);
  377. ASSERT_EQ(pool.get(entities[0u]).value, 99);
  378. ASSERT_EQ(pool.get(entities[1u]).value, 2);
  379. ASSERT_EQ(pool.get(entities[2u]).value, 1);
  380. }
  381. TEST(Storage, Compact) {
  382. entt::storage<stable_type> pool;
  383. ASSERT_TRUE(pool.empty());
  384. ASSERT_EQ(pool.size(), 0u);
  385. pool.compact();
  386. ASSERT_TRUE(pool.empty());
  387. ASSERT_EQ(pool.size(), 0u);
  388. pool.emplace(entt::entity{0}, stable_type{0});
  389. pool.compact();
  390. ASSERT_FALSE(pool.empty());
  391. ASSERT_EQ(pool.size(), 1u);
  392. pool.emplace(entt::entity{42}, stable_type{42});
  393. pool.erase(entt::entity{0});
  394. ASSERT_EQ(pool.size(), 2u);
  395. ASSERT_EQ(pool.index(entt::entity{42}), 1u);
  396. ASSERT_EQ(pool.get(entt::entity{42}).value, 42);
  397. pool.compact();
  398. ASSERT_EQ(pool.size(), 1u);
  399. ASSERT_EQ(pool.index(entt::entity{42}), 0u);
  400. ASSERT_EQ(pool.get(entt::entity{42}).value, 42);
  401. pool.emplace(entt::entity{0}, stable_type{0});
  402. pool.compact();
  403. ASSERT_EQ(pool.size(), 2u);
  404. ASSERT_EQ(pool.index(entt::entity{42}), 0u);
  405. ASSERT_EQ(pool.index(entt::entity{0}), 1u);
  406. ASSERT_EQ(pool.get(entt::entity{42}).value, 42);
  407. ASSERT_EQ(pool.get(entt::entity{0}).value, 0);
  408. pool.erase(entt::entity{0});
  409. pool.erase(entt::entity{42});
  410. pool.compact();
  411. ASSERT_TRUE(pool.empty());
  412. }
  413. TEST(Storage, ShrinkToFit) {
  414. entt::storage<int> pool;
  415. for(std::size_t next{}; next < ENTT_PACKED_PAGE; ++next) {
  416. pool.emplace(entt::entity(next));
  417. }
  418. pool.emplace(entt::entity{ENTT_PACKED_PAGE});
  419. pool.erase(entt::entity{ENTT_PACKED_PAGE});
  420. ASSERT_EQ(pool.capacity(), 2 * ENTT_PACKED_PAGE);
  421. ASSERT_EQ(pool.size(), ENTT_PACKED_PAGE);
  422. pool.shrink_to_fit();
  423. ASSERT_EQ(pool.capacity(), ENTT_PACKED_PAGE);
  424. ASSERT_EQ(pool.size(), ENTT_PACKED_PAGE);
  425. pool.clear();
  426. ASSERT_EQ(pool.capacity(), ENTT_PACKED_PAGE);
  427. ASSERT_EQ(pool.size(), 0u);
  428. pool.shrink_to_fit();
  429. ASSERT_EQ(pool.capacity(), 0u);
  430. ASSERT_EQ(pool.size(), 0u);
  431. }
  432. TEST(Storage, AggregatesMustWork) {
  433. struct aggregate_type { int value; };
  434. // the goal of this test is to enforce the requirements for aggregate types
  435. entt::storage<aggregate_type>{}.emplace(entt::entity{0}, 42);
  436. }
  437. TEST(Storage, TypesFromStandardTemplateLibraryMustWork) {
  438. // see #37 - this test shouldn't crash, that's all
  439. entt::storage<std::unordered_set<int>> pool;
  440. pool.emplace(entt::entity{0}).insert(42);
  441. pool.erase(entt::entity{0});
  442. }
  443. TEST(Storage, Iterator) {
  444. using iterator = typename entt::storage<boxed_int>::iterator;
  445. entt::storage<boxed_int> pool;
  446. pool.emplace(entt::entity{3}, 42);
  447. iterator end{pool.begin()};
  448. iterator begin{};
  449. begin = pool.end();
  450. std::swap(begin, end);
  451. ASSERT_EQ(begin, pool.begin());
  452. ASSERT_EQ(end, pool.end());
  453. ASSERT_NE(begin, end);
  454. ASSERT_EQ(begin++, pool.begin());
  455. ASSERT_EQ(begin--, pool.end());
  456. ASSERT_EQ(begin+1, pool.end());
  457. ASSERT_EQ(end-1, pool.begin());
  458. ASSERT_EQ(++begin, pool.end());
  459. ASSERT_EQ(--begin, pool.begin());
  460. ASSERT_EQ(begin += 1, pool.end());
  461. ASSERT_EQ(begin -= 1, pool.begin());
  462. ASSERT_EQ(begin + (end - begin), pool.end());
  463. ASSERT_EQ(begin - (begin - end), pool.end());
  464. ASSERT_EQ(end - (end - begin), pool.begin());
  465. ASSERT_EQ(end + (begin - end), pool.begin());
  466. ASSERT_EQ(begin[0u].value, pool.begin()->value);
  467. ASSERT_LT(begin, end);
  468. ASSERT_LE(begin, pool.begin());
  469. ASSERT_GT(end, begin);
  470. ASSERT_GE(end, pool.end());
  471. }
  472. TEST(Storage, ConstIterator) {
  473. using iterator = typename entt::storage<boxed_int>::const_iterator;
  474. entt::storage<boxed_int> pool;
  475. pool.emplace(entt::entity{3}, 42);
  476. iterator cend{pool.cbegin()};
  477. iterator cbegin{};
  478. cbegin = pool.cend();
  479. std::swap(cbegin, cend);
  480. ASSERT_EQ(cbegin, pool.cbegin());
  481. ASSERT_EQ(cend, pool.cend());
  482. ASSERT_NE(cbegin, cend);
  483. ASSERT_EQ(cbegin++, pool.cbegin());
  484. ASSERT_EQ(cbegin--, pool.cend());
  485. ASSERT_EQ(cbegin+1, pool.cend());
  486. ASSERT_EQ(cend-1, pool.cbegin());
  487. ASSERT_EQ(++cbegin, pool.cend());
  488. ASSERT_EQ(--cbegin, pool.cbegin());
  489. ASSERT_EQ(cbegin += 1, pool.cend());
  490. ASSERT_EQ(cbegin -= 1, pool.cbegin());
  491. ASSERT_EQ(cbegin + (cend - cbegin), pool.cend());
  492. ASSERT_EQ(cbegin - (cbegin - cend), pool.cend());
  493. ASSERT_EQ(cend - (cend - cbegin), pool.cbegin());
  494. ASSERT_EQ(cend + (cbegin - cend), pool.cbegin());
  495. ASSERT_EQ(cbegin[0u].value, pool.cbegin()->value);
  496. ASSERT_LT(cbegin, cend);
  497. ASSERT_LE(cbegin, pool.cbegin());
  498. ASSERT_GT(cend, cbegin);
  499. ASSERT_GE(cend, pool.cend());
  500. }
  501. TEST(Storage, ReverseIterator) {
  502. using reverse_iterator = typename entt::storage<boxed_int>::reverse_iterator;
  503. entt::storage<boxed_int> pool;
  504. pool.emplace(entt::entity{3}, 42);
  505. reverse_iterator end{pool.rbegin()};
  506. reverse_iterator begin{};
  507. begin = pool.rend();
  508. std::swap(begin, end);
  509. ASSERT_EQ(begin, pool.rbegin());
  510. ASSERT_EQ(end, pool.rend());
  511. ASSERT_NE(begin, end);
  512. ASSERT_EQ(begin++, pool.rbegin());
  513. ASSERT_EQ(begin--, pool.rend());
  514. ASSERT_EQ(begin+1, pool.rend());
  515. ASSERT_EQ(end-1, pool.rbegin());
  516. ASSERT_EQ(++begin, pool.rend());
  517. ASSERT_EQ(--begin, pool.rbegin());
  518. ASSERT_EQ(begin += 1, pool.rend());
  519. ASSERT_EQ(begin -= 1, pool.rbegin());
  520. ASSERT_EQ(begin + (end - begin), pool.rend());
  521. ASSERT_EQ(begin - (begin - end), pool.rend());
  522. ASSERT_EQ(end - (end - begin), pool.rbegin());
  523. ASSERT_EQ(end + (begin - end), pool.rbegin());
  524. ASSERT_EQ(begin[0u].value, pool.rbegin()->value);
  525. ASSERT_LT(begin, end);
  526. ASSERT_LE(begin, pool.rbegin());
  527. ASSERT_GT(end, begin);
  528. ASSERT_GE(end, pool.rend());
  529. }
  530. TEST(Storage, ConstReverseIterator) {
  531. using const_reverse_iterator = typename entt::storage<boxed_int>::const_reverse_iterator;
  532. entt::storage<boxed_int> pool;
  533. pool.emplace(entt::entity{3}, 42);
  534. const_reverse_iterator cend{pool.crbegin()};
  535. const_reverse_iterator cbegin{};
  536. cbegin = pool.crend();
  537. std::swap(cbegin, cend);
  538. ASSERT_EQ(cbegin, pool.crbegin());
  539. ASSERT_EQ(cend, pool.crend());
  540. ASSERT_NE(cbegin, cend);
  541. ASSERT_EQ(cbegin++, pool.crbegin());
  542. ASSERT_EQ(cbegin--, pool.crend());
  543. ASSERT_EQ(cbegin+1, pool.crend());
  544. ASSERT_EQ(cend-1, pool.crbegin());
  545. ASSERT_EQ(++cbegin, pool.crend());
  546. ASSERT_EQ(--cbegin, pool.crbegin());
  547. ASSERT_EQ(cbegin += 1, pool.crend());
  548. ASSERT_EQ(cbegin -= 1, pool.crbegin());
  549. ASSERT_EQ(cbegin + (cend - cbegin), pool.crend());
  550. ASSERT_EQ(cbegin - (cbegin - cend), pool.crend());
  551. ASSERT_EQ(cend - (cend - cbegin), pool.crbegin());
  552. ASSERT_EQ(cend + (cbegin - cend), pool.crbegin());
  553. ASSERT_EQ(cbegin[0u].value, pool.crbegin()->value);
  554. ASSERT_LT(cbegin, cend);
  555. ASSERT_LE(cbegin, pool.crbegin());
  556. ASSERT_GT(cend, cbegin);
  557. ASSERT_GE(cend, pool.crend());
  558. }
  559. TEST(Storage, Raw) {
  560. entt::storage<int> pool;
  561. pool.emplace(entt::entity{3}, 3);
  562. pool.emplace(entt::entity{12}, 6);
  563. pool.emplace(entt::entity{42}, 9);
  564. ASSERT_EQ(pool.get(entt::entity{3}), 3);
  565. ASSERT_EQ(std::as_const(pool).get(entt::entity{12}), 6);
  566. ASSERT_EQ(pool.get(entt::entity{42}), 9);
  567. ASSERT_EQ(pool.raw()[0u][0u], 3);
  568. ASSERT_EQ(std::as_const(pool).raw()[0u][1u], 6);
  569. ASSERT_EQ(pool.raw()[0u][2u], 9);
  570. }
  571. TEST(Storage, SortOrdered) {
  572. entt::storage<boxed_int> pool;
  573. entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
  574. boxed_int values[5u]{{12}, {9}, {6}, {3}, {1}};
  575. pool.insert(std::begin(entities), std::end(entities), values);
  576. pool.sort([&pool](auto lhs, auto rhs) { return pool.get(lhs).value < pool.get(rhs).value; });
  577. ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
  578. ASSERT_TRUE(std::equal(std::rbegin(values), std::rend(values), pool.begin(), pool.end()));
  579. }
  580. TEST(Storage, SortReverse) {
  581. entt::storage<boxed_int> pool;
  582. entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
  583. boxed_int values[5u]{{1}, {3}, {6}, {9}, {12}};
  584. pool.insert(std::begin(entities), std::end(entities), values);
  585. pool.sort([&pool](auto lhs, auto rhs) { return pool.get(lhs).value < pool.get(rhs).value; });
  586. ASSERT_TRUE(std::equal(std::begin(entities), std::end(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
  587. ASSERT_TRUE(std::equal(std::begin(values), std::end(values), pool.begin(), pool.end()));
  588. }
  589. TEST(Storage, SortUnordered) {
  590. entt::storage<boxed_int> pool;
  591. entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
  592. boxed_int values[5u]{{6}, {3}, {1}, {9}, {12}};
  593. pool.insert(std::begin(entities), std::end(entities), values);
  594. pool.sort([&pool](auto lhs, auto rhs) { return pool.get(lhs).value < pool.get(rhs).value; });
  595. auto begin = pool.begin();
  596. auto end = pool.end();
  597. ASSERT_EQ(*(begin++), boxed_int{1});
  598. ASSERT_EQ(*(begin++), boxed_int{3});
  599. ASSERT_EQ(*(begin++), boxed_int{6});
  600. ASSERT_EQ(*(begin++), boxed_int{9});
  601. ASSERT_EQ(*(begin++), boxed_int{12});
  602. ASSERT_EQ(begin, end);
  603. ASSERT_EQ(pool.data()[0u], entt::entity{9});
  604. ASSERT_EQ(pool.data()[1u], entt::entity{3});
  605. ASSERT_EQ(pool.data()[2u], entt::entity{12});
  606. ASSERT_EQ(pool.data()[3u], entt::entity{42});
  607. ASSERT_EQ(pool.data()[4u], entt::entity{7});
  608. }
  609. TEST(Storage, SortRange) {
  610. entt::storage<boxed_int> pool;
  611. entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
  612. boxed_int values[5u]{{3}, {6}, {1}, {9}, {12}};
  613. pool.insert(std::begin(entities), std::end(entities), values);
  614. pool.sort_n(0u, [&pool](auto lhs, auto rhs) { return pool.get(lhs).value < pool.get(rhs).value; });
  615. ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
  616. ASSERT_TRUE(std::equal(std::rbegin(values), std::rend(values), pool.begin(), pool.end()));
  617. pool.sort_n(2u, [&pool](auto lhs, auto rhs) { return pool.get(lhs).value < pool.get(rhs).value; });
  618. ASSERT_EQ(pool.raw()[0u][0u], boxed_int{6});
  619. ASSERT_EQ(pool.raw()[0u][1u], boxed_int{3});
  620. ASSERT_EQ(pool.raw()[0u][2u], boxed_int{1});
  621. ASSERT_EQ(pool.data()[0u], entt::entity{42});
  622. ASSERT_EQ(pool.data()[1u], entt::entity{12});
  623. ASSERT_EQ(pool.data()[2u], entt::entity{7});
  624. pool.sort_n(5u, [&pool](auto lhs, auto rhs) { return pool.get(lhs).value < pool.get(rhs).value; });
  625. auto begin = pool.begin();
  626. auto end = pool.end();
  627. ASSERT_EQ(*(begin++), boxed_int{1});
  628. ASSERT_EQ(*(begin++), boxed_int{3});
  629. ASSERT_EQ(*(begin++), boxed_int{6});
  630. ASSERT_EQ(*(begin++), boxed_int{9});
  631. ASSERT_EQ(*(begin++), boxed_int{12});
  632. ASSERT_EQ(begin, end);
  633. ASSERT_EQ(pool.data()[0u], entt::entity{9});
  634. ASSERT_EQ(pool.data()[1u], entt::entity{3});
  635. ASSERT_EQ(pool.data()[2u], entt::entity{42});
  636. ASSERT_EQ(pool.data()[3u], entt::entity{12});
  637. ASSERT_EQ(pool.data()[4u], entt::entity{7});
  638. }
  639. TEST(Storage, RespectDisjoint) {
  640. entt::storage<int> lhs;
  641. entt::storage<int> rhs;
  642. entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
  643. int lhs_values[3u]{3, 6, 9};
  644. lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), lhs_values);
  645. ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  646. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  647. lhs.respect(rhs);
  648. ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  649. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  650. }
  651. TEST(Storage, RespectOverlap) {
  652. entt::storage<int> lhs;
  653. entt::storage<int> rhs;
  654. entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
  655. int lhs_values[3u]{3, 6, 9};
  656. lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), lhs_values);
  657. entt::entity rhs_entities[1u]{entt::entity{12}};
  658. int rhs_values[1u]{6};
  659. rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), rhs_values);
  660. ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  661. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  662. ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  663. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  664. lhs.respect(rhs);
  665. auto begin = lhs.begin();
  666. auto end = lhs.end();
  667. ASSERT_EQ(*(begin++), 6);
  668. ASSERT_EQ(*(begin++), 9);
  669. ASSERT_EQ(*(begin++), 3);
  670. ASSERT_EQ(begin, end);
  671. ASSERT_EQ(lhs.data()[0u], entt::entity{3});
  672. ASSERT_EQ(lhs.data()[1u], entt::entity{42});
  673. ASSERT_EQ(lhs.data()[2u], entt::entity{12});
  674. }
  675. TEST(Storage, RespectOrdered) {
  676. entt::storage<int> lhs;
  677. entt::storage<int> rhs;
  678. entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
  679. int lhs_values[5u]{1, 2, 3, 4, 5};
  680. lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), lhs_values);
  681. entt::entity rhs_entities[6u]{entt::entity{6}, entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
  682. int rhs_values[6u]{6, 1, 2, 3, 4, 5};
  683. rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), rhs_values);
  684. ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  685. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  686. ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  687. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  688. rhs.respect(lhs);
  689. ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  690. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  691. }
  692. TEST(Storage, RespectReverse) {
  693. entt::storage<int> lhs;
  694. entt::storage<int> rhs;
  695. entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
  696. int lhs_values[5u]{1, 2, 3, 4, 5};
  697. lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), lhs_values);
  698. entt::entity rhs_entities[6u]{entt::entity{5}, entt::entity{4}, entt::entity{3}, entt::entity{2}, entt::entity{1}, entt::entity{6}};
  699. int rhs_values[6u]{5, 4, 3, 2, 1, 6};
  700. rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), rhs_values);
  701. ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  702. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  703. ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  704. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  705. rhs.respect(lhs);
  706. auto begin = rhs.begin();
  707. auto end = rhs.end();
  708. ASSERT_EQ(*(begin++), 5);
  709. ASSERT_EQ(*(begin++), 4);
  710. ASSERT_EQ(*(begin++), 3);
  711. ASSERT_EQ(*(begin++), 2);
  712. ASSERT_EQ(*(begin++), 1);
  713. ASSERT_EQ(*(begin++), 6);
  714. ASSERT_EQ(begin, end);
  715. ASSERT_EQ(rhs.data()[0u], entt::entity{6});
  716. ASSERT_EQ(rhs.data()[1u], entt::entity{1});
  717. ASSERT_EQ(rhs.data()[2u], entt::entity{2});
  718. ASSERT_EQ(rhs.data()[3u], entt::entity{3});
  719. ASSERT_EQ(rhs.data()[4u], entt::entity{4});
  720. ASSERT_EQ(rhs.data()[5u], entt::entity{5});
  721. }
  722. TEST(Storage, RespectUnordered) {
  723. entt::storage<int> lhs;
  724. entt::storage<int> rhs;
  725. entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
  726. int lhs_values[5u]{1, 2, 3, 4, 5};
  727. lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), lhs_values);
  728. entt::entity rhs_entities[6u]{entt::entity{3}, entt::entity{2}, entt::entity{6}, entt::entity{1}, entt::entity{4}, entt::entity{5}};
  729. int rhs_values[6u]{3, 2, 6, 1, 4, 5};
  730. rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), rhs_values);
  731. ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
  732. ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
  733. ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
  734. ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
  735. rhs.respect(lhs);
  736. auto begin = rhs.begin();
  737. auto end = rhs.end();
  738. ASSERT_EQ(*(begin++), 5);
  739. ASSERT_EQ(*(begin++), 4);
  740. ASSERT_EQ(*(begin++), 3);
  741. ASSERT_EQ(*(begin++), 2);
  742. ASSERT_EQ(*(begin++), 1);
  743. ASSERT_EQ(*(begin++), 6);
  744. ASSERT_EQ(begin, end);
  745. ASSERT_EQ(rhs.data()[0u], entt::entity{6});
  746. ASSERT_EQ(rhs.data()[1u], entt::entity{1});
  747. ASSERT_EQ(rhs.data()[2u], entt::entity{2});
  748. ASSERT_EQ(rhs.data()[3u], entt::entity{3});
  749. ASSERT_EQ(rhs.data()[4u], entt::entity{4});
  750. ASSERT_EQ(rhs.data()[5u], entt::entity{5});
  751. }
  752. TEST(Storage, CanModifyDuringIteration) {
  753. entt::storage<int> pool;
  754. auto *ptr = &pool.emplace(entt::entity{0}, 42);
  755. ASSERT_EQ(pool.capacity(), ENTT_PACKED_PAGE);
  756. const auto it = pool.cbegin();
  757. pool.reserve(ENTT_PACKED_PAGE + 1u);
  758. ASSERT_EQ(pool.capacity(), 2 * ENTT_PACKED_PAGE);
  759. ASSERT_EQ(&pool.get(entt::entity{0}), ptr);
  760. // this should crash with asan enabled if we break the constraint
  761. [[maybe_unused]] const int &value = *it;
  762. }
  763. TEST(Storage, ReferencesGuaranteed) {
  764. entt::storage<boxed_int> pool;
  765. pool.emplace(entt::entity{0}, 0);
  766. pool.emplace(entt::entity{1}, 1);
  767. ASSERT_EQ(pool.get(entt::entity{0}).value, 0);
  768. ASSERT_EQ(pool.get(entt::entity{1}).value, 1);
  769. for(auto &&type: pool) {
  770. if(type.value) {
  771. type.value = 42;
  772. }
  773. }
  774. ASSERT_EQ(pool.get(entt::entity{0}).value, 0);
  775. ASSERT_EQ(pool.get(entt::entity{1}).value, 42);
  776. auto begin = pool.begin();
  777. while(begin != pool.end()) {
  778. (begin++)->value = 3;
  779. }
  780. ASSERT_EQ(pool.get(entt::entity{0}).value, 3);
  781. ASSERT_EQ(pool.get(entt::entity{1}).value, 3);
  782. }
  783. TEST(Storage, MoveOnlyComponent) {
  784. // the purpose is to ensure that move only components are always accepted
  785. [[maybe_unused]] entt::storage<std::unique_ptr<int>> pool;
  786. }
  787. TEST(Storage, UpdateFromDestructor) {
  788. static constexpr auto size = 10u;
  789. auto test = [](const auto target) {
  790. entt::storage<update_from_destructor> pool;
  791. for(std::size_t next{}; next < size; ++next) {
  792. const auto entity = entt::entity(next);
  793. pool.emplace(entity, pool, entity == entt::entity(size/2) ? target : entity);
  794. }
  795. pool.erase(entt::entity(size/2));
  796. ASSERT_EQ(pool.size(), size - 1u - (target != entt::null));
  797. ASSERT_FALSE(pool.contains(entt::entity(size/2)));
  798. ASSERT_FALSE(pool.contains(target));
  799. pool.clear();
  800. ASSERT_TRUE(pool.empty());
  801. for(std::size_t next{}; next < size; ++next) {
  802. ASSERT_FALSE(pool.contains(entt::entity(next)));
  803. }
  804. };
  805. test(entt::entity(size - 1u));
  806. test(entt::entity(size - 2u));
  807. test(entt::entity{0u});
  808. }
  809. TEST(Storage, ThrowingComponent) {
  810. entt::storage<test::throwing_component> pool;
  811. test::throwing_component::trigger_on_value = 42;
  812. // strong exception safety
  813. ASSERT_THROW(pool.emplace(entt::entity{0}, test::throwing_component{42}), typename test::throwing_component::exception_type);
  814. ASSERT_TRUE(pool.empty());
  815. const entt::entity entities[2u]{entt::entity{42}, entt::entity{1}};
  816. const test::throwing_component components[2u]{42, 1};
  817. // basic exception safety
  818. ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), test::throwing_component{42}), typename test::throwing_component::exception_type);
  819. ASSERT_EQ(pool.size(), 0u);
  820. ASSERT_FALSE(pool.contains(entt::entity{1}));
  821. // basic exception safety
  822. ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), std::begin(components)), typename test::throwing_component::exception_type);
  823. ASSERT_EQ(pool.size(), 0u);
  824. ASSERT_FALSE(pool.contains(entt::entity{1}));
  825. // basic exception safety
  826. ASSERT_THROW(pool.insert(std::rbegin(entities), std::rend(entities), std::rbegin(components)), typename test::throwing_component::exception_type);
  827. ASSERT_EQ(pool.size(), 1u);
  828. ASSERT_TRUE(pool.contains(entt::entity{1}));
  829. ASSERT_EQ(pool.get(entt::entity{1}), 1);
  830. pool.clear();
  831. pool.emplace(entt::entity{1}, 1);
  832. pool.emplace(entt::entity{42}, 42);
  833. // basic exception safety
  834. ASSERT_THROW(pool.erase(entt::entity{1}), typename test::throwing_component::exception_type);
  835. ASSERT_EQ(pool.size(), 2u);
  836. ASSERT_TRUE(pool.contains(entt::entity{42}));
  837. ASSERT_TRUE(pool.contains(entt::entity{1}));
  838. ASSERT_EQ(pool.at(0u), entt::entity{1});
  839. ASSERT_EQ(pool.at(1u), entt::entity{42});
  840. ASSERT_EQ(pool.get(entt::entity{42}), 42);
  841. // the element may have been moved but it's still there
  842. ASSERT_EQ(pool.get(entt::entity{1}), test::throwing_component::moved_from_value);
  843. test::throwing_component::trigger_on_value = 99;
  844. pool.erase(entt::entity{1});
  845. ASSERT_EQ(pool.size(), 1u);
  846. ASSERT_TRUE(pool.contains(entt::entity{42}));
  847. ASSERT_FALSE(pool.contains(entt::entity{1}));
  848. ASSERT_EQ(pool.at(0u), entt::entity{42});
  849. ASSERT_EQ(pool.get(entt::entity{42}), 42);
  850. }
  851. TEST(Storage, ThrowingAllocator) {
  852. entt::basic_storage<entt::entity, int, test::throwing_allocator<int>> pool;
  853. test::throwing_allocator<int>::trigger_on_allocate = true;
  854. // strong exception safety
  855. ASSERT_THROW(pool.reserve(1u), test::throwing_allocator<int>::exception_type);
  856. ASSERT_EQ(pool.capacity(), 0u);
  857. test::throwing_allocator<int>::trigger_after_allocate = true;
  858. // strong exception safety
  859. ASSERT_THROW(pool.reserve(2 * ENTT_PACKED_PAGE), test::throwing_allocator<int>::exception_type);
  860. ASSERT_EQ(pool.capacity(), 0u);
  861. pool.shrink_to_fit();
  862. test::throwing_allocator<int>::trigger_on_allocate = true;
  863. // strong exception safety
  864. ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator<int>::exception_type);
  865. ASSERT_FALSE(pool.contains(entt::entity{0}));
  866. ASSERT_TRUE(pool.empty());
  867. test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
  868. // strong exception safety
  869. ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator<entt::entity>::exception_type);
  870. ASSERT_FALSE(pool.contains(entt::entity{0}));
  871. ASSERT_TRUE(pool.empty());
  872. pool.emplace(entt::entity{0}, 0);
  873. const entt::entity entities[2u]{entt::entity{1}, entt::entity{ENTT_SPARSE_PAGE}};
  874. test::throwing_allocator<entt::entity>::trigger_after_allocate = true;
  875. // basic exception safety
  876. ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), 0), test::throwing_allocator<entt::entity>::exception_type);
  877. ASSERT_TRUE(pool.contains(entt::entity{1}));
  878. ASSERT_FALSE(pool.contains(entt::entity{ENTT_SPARSE_PAGE}));
  879. pool.erase(entt::entity{1});
  880. const int components[2u]{1, ENTT_SPARSE_PAGE};
  881. test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
  882. // basic exception safety
  883. ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), std::begin(components)), test::throwing_allocator<entt::entity>::exception_type);
  884. ASSERT_TRUE(pool.contains(entt::entity{1}));
  885. ASSERT_FALSE(pool.contains(entt::entity{ENTT_SPARSE_PAGE}));
  886. }