1
0

sigh_mixin.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. #include <cstddef>
  2. #include <iterator>
  3. #include <memory>
  4. #include <type_traits>
  5. #include <utility>
  6. #include <gtest/gtest.h>
  7. #include <entt/core/any.hpp>
  8. #include <entt/core/type_info.hpp>
  9. #include <entt/entity/component.hpp>
  10. #include <entt/entity/entity.hpp>
  11. #include <entt/entity/mixin.hpp>
  12. #include <entt/entity/registry.hpp>
  13. #include <entt/entity/storage.hpp>
  14. #include "../common/custom_entity.h"
  15. #include "../common/non_default_constructible.h"
  16. #include "../common/pointer_stable.h"
  17. #include "../common/throwing_allocator.hpp"
  18. #include "../common/throwing_type.hpp"
  19. template<typename Registry>
  20. void listener(std::size_t &counter, Registry &, typename Registry::entity_type) {
  21. ++counter;
  22. }
  23. struct custom_registry: entt::basic_registry<test::custom_entity> {};
  24. template<typename Type>
  25. struct entt::storage_type<Type, test::custom_entity, std::allocator<Type>, std::enable_if_t<!std::is_same_v<Type, test::custom_entity>>> {
  26. using type = entt::basic_sigh_mixin<entt::basic_storage<Type, test::custom_entity>, custom_registry>;
  27. };
  28. template<typename Type>
  29. struct SighMixin: testing::Test {
  30. using type = Type;
  31. };
  32. using SighMixinTypes = ::testing::Types<int, test::pointer_stable>;
  33. TYPED_TEST_SUITE(SighMixin, SighMixinTypes, );
  34. TEST(SighMixin, GenericType) {
  35. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}}; // NOLINT
  36. entt::sigh_mixin<entt::storage<int>> pool;
  37. entt::registry registry;
  38. std::size_t on_construct{};
  39. std::size_t on_destroy{};
  40. pool.bind(entt::forward_as_any(registry));
  41. ASSERT_EQ(pool.size(), 0u);
  42. pool.insert(entity, entity + 1u); // NOLINT
  43. pool.erase(entity[0u]);
  44. ASSERT_EQ(pool.size(), 0u);
  45. ASSERT_EQ(on_construct, 0u);
  46. ASSERT_EQ(on_destroy, 0u);
  47. pool.on_construct().connect<&listener<entt::registry>>(on_construct);
  48. pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
  49. ASSERT_NE(pool.push(entity[0u]), pool.entt::sparse_set::end());
  50. pool.emplace(entity[1u]);
  51. ASSERT_EQ(on_construct, 2u);
  52. ASSERT_EQ(on_destroy, 0u);
  53. ASSERT_EQ(pool.size(), 2u);
  54. ASSERT_EQ(pool.get(entity[0u]), 0);
  55. ASSERT_EQ(pool.get(entity[1u]), 0);
  56. pool.erase(std::begin(entity), std::end(entity));
  57. ASSERT_EQ(on_construct, 2u);
  58. ASSERT_EQ(on_destroy, 2u);
  59. ASSERT_EQ(pool.size(), 0u);
  60. ASSERT_NE(pool.push(std::begin(entity), std::end(entity)), pool.entt::sparse_set::end());
  61. ASSERT_EQ(pool.get(entity[0u]), 0);
  62. ASSERT_EQ(pool.get(entity[1u]), 0);
  63. ASSERT_EQ(pool.size(), 2u);
  64. pool.erase(entity[1u]);
  65. ASSERT_EQ(on_construct, 4u);
  66. ASSERT_EQ(on_destroy, 3u);
  67. ASSERT_EQ(pool.size(), 1u);
  68. pool.erase(entity[0u]);
  69. ASSERT_EQ(on_construct, 4u);
  70. ASSERT_EQ(on_destroy, 4u);
  71. ASSERT_EQ(pool.size(), 0u);
  72. pool.insert(std::begin(entity), std::end(entity), 3);
  73. ASSERT_EQ(on_construct, 6u);
  74. ASSERT_EQ(on_destroy, 4u);
  75. ASSERT_EQ(pool.size(), 2u);
  76. ASSERT_EQ(pool.get(entity[0u]), 3);
  77. ASSERT_EQ(pool.get(entity[1u]), 3);
  78. pool.clear();
  79. ASSERT_EQ(on_construct, 6u);
  80. ASSERT_EQ(on_destroy, 6u);
  81. ASSERT_EQ(pool.size(), 0u);
  82. }
  83. TEST(SighMixin, StableType) {
  84. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}}; // NOLINT
  85. entt::sigh_mixin<entt::storage<test::pointer_stable>> pool;
  86. entt::registry registry;
  87. std::size_t on_construct{};
  88. std::size_t on_destroy{};
  89. pool.bind(entt::forward_as_any(registry));
  90. pool.on_construct().connect<&listener<entt::registry>>(on_construct);
  91. pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
  92. ASSERT_NE(pool.push(entity[0u]), pool.entt::sparse_set::end());
  93. pool.emplace(entity[1u]);
  94. ASSERT_EQ(on_construct, 2u);
  95. ASSERT_EQ(on_destroy, 0u);
  96. ASSERT_EQ(pool.size(), 2u);
  97. ASSERT_EQ(pool.get(entity[0u]).value, 0);
  98. ASSERT_EQ(pool.get(entity[1u]).value, 0);
  99. pool.erase(std::begin(entity), std::end(entity));
  100. ASSERT_EQ(on_construct, 2u);
  101. ASSERT_EQ(on_destroy, 2u);
  102. ASSERT_EQ(pool.size(), 2u);
  103. ASSERT_NE(pool.push(std::begin(entity), std::end(entity)), pool.entt::sparse_set::end());
  104. ASSERT_EQ(pool.get(entity[0u]).value, 0);
  105. ASSERT_EQ(pool.get(entity[1u]).value, 0);
  106. ASSERT_EQ(pool.size(), 4u);
  107. pool.erase(entity[1u]);
  108. ASSERT_EQ(on_construct, 4u);
  109. ASSERT_EQ(on_destroy, 3u);
  110. ASSERT_EQ(pool.size(), 4u);
  111. pool.erase(entity[0u]);
  112. ASSERT_EQ(on_construct, 4u);
  113. ASSERT_EQ(on_destroy, 4u);
  114. ASSERT_EQ(pool.size(), 4u);
  115. pool.insert(std::begin(entity), std::end(entity), test::pointer_stable{3});
  116. ASSERT_EQ(on_construct, 6u);
  117. ASSERT_EQ(on_destroy, 4u);
  118. ASSERT_EQ(pool.size(), 6u);
  119. ASSERT_EQ(pool.get(entity[0u]).value, 3);
  120. ASSERT_EQ(pool.get(entity[1u]).value, 3);
  121. pool.clear();
  122. ASSERT_EQ(on_construct, 6u);
  123. ASSERT_EQ(on_destroy, 6u);
  124. ASSERT_EQ(pool.size(), 0u);
  125. }
  126. TEST(SighMixin, NonDefaultConstructibleType) {
  127. entt::entity entity[2u]{entt::entity{3}, entt::entity{42}}; // NOLINT
  128. entt::sigh_mixin<entt::storage<test::non_default_constructible>> pool;
  129. entt::registry registry;
  130. std::size_t on_construct{};
  131. std::size_t on_destroy{};
  132. pool.bind(entt::forward_as_any(registry));
  133. pool.on_construct().connect<&listener<entt::registry>>(on_construct);
  134. pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
  135. ASSERT_EQ(pool.push(entity[0u]), pool.entt::sparse_set::end());
  136. pool.emplace(entity[1u], 3);
  137. ASSERT_EQ(on_construct, 1u);
  138. ASSERT_EQ(on_destroy, 0u);
  139. ASSERT_EQ(pool.size(), 1u);
  140. ASSERT_FALSE(pool.contains(entity[0u]));
  141. ASSERT_EQ(pool.get(entity[1u]).value, 3);
  142. pool.erase(entity[1u]);
  143. ASSERT_EQ(on_construct, 1u);
  144. ASSERT_EQ(on_destroy, 1u);
  145. ASSERT_EQ(pool.size(), 0u);
  146. ASSERT_EQ(pool.push(std::begin(entity), std::end(entity)), pool.entt::sparse_set::end());
  147. ASSERT_FALSE(pool.contains(entity[0u]));
  148. ASSERT_FALSE(pool.contains(entity[1u]));
  149. ASSERT_EQ(pool.size(), 0u);
  150. pool.insert(std::begin(entity), std::end(entity), 3);
  151. ASSERT_EQ(on_construct, 3u);
  152. ASSERT_EQ(on_destroy, 1u);
  153. ASSERT_EQ(pool.size(), 2u);
  154. ASSERT_EQ(pool.get(entity[0u]).value, 3);
  155. ASSERT_EQ(pool.get(entity[1u]).value, 3);
  156. pool.erase(std::begin(entity), std::end(entity));
  157. ASSERT_EQ(on_construct, 3u);
  158. ASSERT_EQ(on_destroy, 3u);
  159. ASSERT_EQ(pool.size(), 0u);
  160. }
  161. TEST(SighMixin, VoidType) {
  162. entt::sigh_mixin<entt::storage<void>> pool;
  163. entt::registry registry;
  164. std::size_t on_construct{};
  165. std::size_t on_destroy{};
  166. pool.bind(entt::forward_as_any(registry));
  167. pool.on_construct().connect<&listener<entt::registry>>(on_construct);
  168. pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
  169. pool.emplace(entt::entity{99}); // NOLINT
  170. ASSERT_EQ(pool.type(), entt::type_id<void>());
  171. ASSERT_TRUE(pool.contains(entt::entity{99}));
  172. entt::sigh_mixin<entt::storage<void>> other{std::move(pool)};
  173. ASSERT_FALSE(pool.contains(entt::entity{99})); // NOLINT
  174. ASSERT_TRUE(other.contains(entt::entity{99}));
  175. pool = std::move(other);
  176. ASSERT_TRUE(pool.contains(entt::entity{99}));
  177. ASSERT_FALSE(other.contains(entt::entity{99})); // NOLINT
  178. pool.clear();
  179. ASSERT_EQ(on_construct, 1u);
  180. ASSERT_EQ(on_destroy, 1u);
  181. }
  182. TEST(SighMixin, StorageEntity) {
  183. using traits_type = entt::entt_traits<entt::entity>;
  184. entt::sigh_mixin<entt::storage<entt::entity>> pool;
  185. entt::registry registry;
  186. std::size_t on_construct{};
  187. std::size_t on_destroy{};
  188. pool.bind(entt::forward_as_any(registry));
  189. pool.on_construct().connect<&listener<entt::registry>>(on_construct);
  190. pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
  191. pool.push(entt::entity{1});
  192. ASSERT_EQ(on_construct, 1u);
  193. ASSERT_EQ(on_destroy, 0u);
  194. ASSERT_EQ(pool.size(), 2u);
  195. ASSERT_EQ(pool.free_list(), 1u);
  196. pool.erase(entt::entity{1});
  197. ASSERT_EQ(on_construct, 1u);
  198. ASSERT_EQ(on_destroy, 1u);
  199. ASSERT_EQ(pool.size(), 2u);
  200. ASSERT_EQ(pool.free_list(), 0u);
  201. pool.push(traits_type::construct(0, 2));
  202. pool.push(traits_type::construct(2, 1));
  203. ASSERT_TRUE(pool.contains(traits_type::construct(0, 2)));
  204. ASSERT_TRUE(pool.contains(traits_type::construct(1, 1)));
  205. ASSERT_TRUE(pool.contains(traits_type::construct(2, 1)));
  206. ASSERT_EQ(on_construct, 3u);
  207. ASSERT_EQ(on_destroy, 1u);
  208. ASSERT_EQ(pool.size(), 3u);
  209. ASSERT_EQ(pool.free_list(), 2u);
  210. pool.clear();
  211. ASSERT_EQ(pool.size(), 0u);
  212. ASSERT_EQ(pool.free_list(), 0u);
  213. ASSERT_EQ(on_construct, 3u);
  214. ASSERT_EQ(on_destroy, 3u);
  215. pool.emplace();
  216. pool.emplace(entt::entity{0});
  217. entt::entity entity[1u]{}; // NOLINT
  218. pool.insert(entity, entity + 1u); // NOLINT
  219. ASSERT_EQ(on_construct, 6u);
  220. ASSERT_EQ(on_destroy, 3u);
  221. ASSERT_EQ(pool.size(), 3u);
  222. ASSERT_EQ(pool.free_list(), 3u);
  223. pool.clear();
  224. ASSERT_EQ(pool.size(), 0u);
  225. ASSERT_EQ(pool.free_list(), 0u);
  226. }
  227. TYPED_TEST(SighMixin, Move) {
  228. using value_type = typename TestFixture::type;
  229. entt::sigh_mixin<entt::storage<value_type>> pool;
  230. entt::registry registry;
  231. std::size_t on_construct{};
  232. std::size_t on_destroy{};
  233. pool.bind(entt::forward_as_any(registry));
  234. pool.on_construct().template connect<&listener<entt::registry>>(on_construct);
  235. pool.on_destroy().template connect<&listener<entt::registry>>(on_destroy);
  236. pool.emplace(entt::entity{3}, 3);
  237. static_assert(std::is_move_constructible_v<decltype(pool)>, "Move constructible type required");
  238. static_assert(std::is_move_assignable_v<decltype(pool)>, "Move assignable type required");
  239. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  240. entt::sigh_mixin<entt::storage<value_type>> other{std::move(pool)};
  241. ASSERT_TRUE(pool.empty()); // NOLINT
  242. ASSERT_FALSE(other.empty());
  243. ASSERT_EQ(other.type(), entt::type_id<value_type>());
  244. ASSERT_EQ(other.index(entt::entity{3}), 0u);
  245. ASSERT_EQ(other.get(entt::entity{3}), value_type{3});
  246. pool = std::move(other);
  247. ASSERT_FALSE(pool.empty());
  248. ASSERT_TRUE(other.empty()); // NOLINT
  249. ASSERT_EQ(pool.index(entt::entity{3}), 0u);
  250. ASSERT_EQ(pool.get(entt::entity{3}), value_type{3});
  251. other = entt::sigh_mixin<entt::storage<value_type>>{};
  252. other.bind(entt::forward_as_any(registry));
  253. other.emplace(entt::entity{42}, 42); // NOLINT
  254. other = std::move(pool);
  255. ASSERT_TRUE(pool.empty()); // NOLINT
  256. ASSERT_FALSE(other.empty());
  257. ASSERT_EQ(other.index(entt::entity{3}), 0u);
  258. ASSERT_EQ(other.get(entt::entity{3}), value_type{3});
  259. other.clear();
  260. ASSERT_EQ(on_construct, 1u);
  261. ASSERT_EQ(on_destroy, 1u);
  262. }
  263. TYPED_TEST(SighMixin, Swap) {
  264. using value_type = typename TestFixture::type;
  265. using traits_type = entt::component_traits<value_type>;
  266. entt::sigh_mixin<entt::storage<value_type>> pool;
  267. entt::sigh_mixin<entt::storage<value_type>> other;
  268. entt::registry registry;
  269. std::size_t on_construct{};
  270. std::size_t on_destroy{};
  271. pool.bind(entt::forward_as_any(registry));
  272. pool.on_construct().template connect<&listener<entt::registry>>(on_construct);
  273. pool.on_destroy().template connect<&listener<entt::registry>>(on_destroy);
  274. other.bind(entt::forward_as_any(registry));
  275. other.on_construct().template connect<&listener<entt::registry>>(on_construct);
  276. other.on_destroy().template connect<&listener<entt::registry>>(on_destroy);
  277. pool.emplace(entt::entity{42}, 41); // NOLINT
  278. other.emplace(entt::entity{9}, 8); // NOLINT
  279. other.emplace(entt::entity{3}, 2);
  280. other.erase(entt::entity{9}); // NOLINT
  281. ASSERT_EQ(pool.size(), 1u);
  282. ASSERT_EQ(other.size(), 1u + traits_type::in_place_delete);
  283. pool.swap(other);
  284. ASSERT_EQ(pool.type(), entt::type_id<value_type>());
  285. ASSERT_EQ(other.type(), entt::type_id<value_type>());
  286. ASSERT_EQ(pool.size(), 1u + traits_type::in_place_delete);
  287. ASSERT_EQ(other.size(), 1u);
  288. ASSERT_EQ(pool.index(entt::entity{3}), traits_type::in_place_delete);
  289. ASSERT_EQ(other.index(entt::entity{42}), 0u);
  290. ASSERT_EQ(pool.get(entt::entity{3}), value_type{2});
  291. ASSERT_EQ(other.get(entt::entity{42}), value_type{41});
  292. pool.clear();
  293. other.clear();
  294. ASSERT_EQ(on_construct, 3u);
  295. ASSERT_EQ(on_destroy, 3u);
  296. }
  297. TYPED_TEST(SighMixin, CustomRegistry) {
  298. using value_type = typename TestFixture::type;
  299. entt::basic_sigh_mixin<entt::basic_storage<value_type, test::custom_entity>, custom_registry> pool;
  300. custom_registry registry;
  301. std::size_t on_construct{};
  302. std::size_t on_destroy{};
  303. pool.bind(entt::forward_as_any(static_cast<entt::basic_registry<test::custom_entity> &>(registry)));
  304. pool.on_construct().template connect<&listener<custom_registry>>(on_construct);
  305. pool.on_destroy().template connect<&listener<custom_registry>>(on_destroy);
  306. pool.emplace(test::custom_entity{3});
  307. pool.emplace(test::custom_entity{42}); // NOLINT
  308. ASSERT_EQ(on_construct, 2u);
  309. ASSERT_EQ(on_destroy, 0u);
  310. pool.clear();
  311. ASSERT_EQ(on_construct, 2u);
  312. ASSERT_EQ(on_destroy, 2u);
  313. }
  314. TYPED_TEST(SighMixin, CustomAllocator) {
  315. using value_type = typename TestFixture::type;
  316. const test::throwing_allocator<entt::entity> allocator{};
  317. entt::sigh_mixin<entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>>> pool{allocator};
  318. using registry_type = typename decltype(pool)::registry_type;
  319. registry_type registry;
  320. std::size_t on_construct{};
  321. std::size_t on_destroy{};
  322. pool.bind(entt::forward_as_any(registry));
  323. pool.on_construct().template connect<&listener<registry_type>>(on_construct);
  324. pool.on_destroy().template connect<&listener<registry_type>>(on_destroy);
  325. pool.reserve(1u);
  326. ASSERT_NE(pool.capacity(), 0u);
  327. pool.emplace(entt::entity{0});
  328. pool.emplace(entt::entity{1});
  329. decltype(pool) other{std::move(pool), allocator};
  330. ASSERT_TRUE(pool.empty()); // NOLINT
  331. ASSERT_FALSE(other.empty());
  332. ASSERT_EQ(pool.capacity(), 0u); // NOLINT
  333. ASSERT_NE(other.capacity(), 0u);
  334. ASSERT_EQ(other.size(), 2u);
  335. pool = std::move(other);
  336. ASSERT_FALSE(pool.empty());
  337. ASSERT_TRUE(other.empty()); // NOLINT
  338. ASSERT_EQ(other.capacity(), 0u); // NOLINT
  339. ASSERT_NE(pool.capacity(), 0u);
  340. ASSERT_EQ(pool.size(), 2u);
  341. pool.swap(other);
  342. pool = std::move(other);
  343. ASSERT_FALSE(pool.empty());
  344. ASSERT_TRUE(other.empty()); // NOLINT
  345. ASSERT_EQ(other.capacity(), 0u); // NOLINT
  346. ASSERT_NE(pool.capacity(), 0u);
  347. ASSERT_EQ(pool.size(), 2u);
  348. pool.clear();
  349. ASSERT_NE(pool.capacity(), 0u);
  350. ASSERT_EQ(pool.size(), 0u);
  351. ASSERT_EQ(on_construct, 2u);
  352. ASSERT_EQ(on_destroy, 2u);
  353. }
  354. TYPED_TEST(SighMixin, ThrowingAllocator) {
  355. using value_type = typename TestFixture::type;
  356. entt::sigh_mixin<entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>>> pool{};
  357. typename std::decay_t<decltype(pool)>::base_type &base = pool;
  358. using registry_type = typename decltype(pool)::registry_type;
  359. registry_type registry;
  360. constexpr auto packed_page_size = entt::component_traits<typename decltype(pool)::value_type>::page_size;
  361. constexpr auto sparse_page_size = entt::entt_traits<typename decltype(pool)::entity_type>::page_size;
  362. std::size_t on_construct{};
  363. std::size_t on_destroy{};
  364. pool.bind(entt::forward_as_any(registry));
  365. pool.on_construct().template connect<&listener<registry_type>>(on_construct);
  366. pool.on_destroy().template connect<&listener<registry_type>>(on_destroy);
  367. pool.get_allocator().template throw_counter<value_type>(0u);
  368. ASSERT_THROW(pool.reserve(1u), test::throwing_allocator_exception);
  369. ASSERT_EQ(pool.capacity(), 0u);
  370. pool.get_allocator().template throw_counter<value_type>(1u);
  371. ASSERT_THROW(pool.reserve(2 * packed_page_size), test::throwing_allocator_exception);
  372. ASSERT_EQ(pool.capacity(), packed_page_size);
  373. pool.shrink_to_fit();
  374. ASSERT_EQ(pool.capacity(), 0u);
  375. pool.get_allocator().template throw_counter<entt::entity>(0u);
  376. ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator_exception);
  377. ASSERT_FALSE(pool.contains(entt::entity{0}));
  378. ASSERT_TRUE(pool.empty());
  379. pool.get_allocator().template throw_counter<entt::entity>(0u);
  380. ASSERT_THROW(base.push(entt::entity{0}), test::throwing_allocator_exception);
  381. ASSERT_FALSE(base.contains(entt::entity{0}));
  382. ASSERT_TRUE(base.empty());
  383. pool.get_allocator().template throw_counter<value_type>(0u);
  384. ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator_exception);
  385. ASSERT_FALSE(pool.contains(entt::entity{0}));
  386. ASSERT_NO_THROW(pool.compact());
  387. ASSERT_TRUE(pool.empty());
  388. pool.emplace(entt::entity{0}, 0);
  389. const entt::entity entity[2u]{entt::entity{1}, entt::entity{sparse_page_size}}; // NOLINT
  390. pool.get_allocator().template throw_counter<entt::entity>(1u);
  391. ASSERT_THROW(pool.insert(std::begin(entity), std::end(entity), value_type{0}), test::throwing_allocator_exception);
  392. ASSERT_TRUE(pool.contains(entt::entity{1}));
  393. ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
  394. pool.erase(entt::entity{1});
  395. const value_type components[2u]{value_type{1}, value_type{sparse_page_size}}; // NOLINT
  396. pool.get_allocator().template throw_counter<entt::entity>(0u);
  397. pool.compact();
  398. ASSERT_THROW(pool.insert(std::begin(entity), std::end(entity), std::begin(components)), test::throwing_allocator_exception);
  399. ASSERT_TRUE(pool.contains(entt::entity{1}));
  400. ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
  401. ASSERT_EQ(on_construct, 1u);
  402. ASSERT_EQ(on_destroy, 1u);
  403. }
  404. TEST(SighMixin, ThrowingComponent) {
  405. entt::sigh_mixin<entt::storage<test::throwing_type>> pool;
  406. using registry_type = typename decltype(pool)::registry_type;
  407. registry_type registry;
  408. std::size_t on_construct{};
  409. std::size_t on_destroy{};
  410. pool.bind(entt::forward_as_any(registry));
  411. pool.on_construct().connect<&listener<registry_type>>(on_construct);
  412. pool.on_destroy().connect<&listener<registry_type>>(on_destroy);
  413. const entt::entity entity[2u]{entt::entity{42}, entt::entity{1}}; // NOLINT
  414. const test::throwing_type value[2u]{true, false}; // NOLINT
  415. // strong exception safety
  416. ASSERT_THROW(pool.emplace(entity[0u], value[0u]), test::throwing_type_exception);
  417. ASSERT_TRUE(pool.empty());
  418. // basic exception safety
  419. ASSERT_THROW(pool.insert(std::begin(entity), std::end(entity), value[0u]), test::throwing_type_exception);
  420. ASSERT_EQ(pool.size(), 0u);
  421. ASSERT_FALSE(pool.contains(entity[1u]));
  422. // basic exception safety
  423. ASSERT_THROW(pool.insert(std::begin(entity), std::end(entity), std::begin(value)), test::throwing_type_exception);
  424. ASSERT_EQ(pool.size(), 0u);
  425. ASSERT_FALSE(pool.contains(entity[1u]));
  426. // basic exception safety
  427. ASSERT_THROW(pool.insert(std::rbegin(entity), std::rend(entity), std::rbegin(value)), test::throwing_type_exception);
  428. ASSERT_EQ(pool.size(), 1u);
  429. ASSERT_TRUE(pool.contains(entity[1u]));
  430. ASSERT_EQ(pool.get(entity[1u]), value[1u]);
  431. pool.clear();
  432. pool.emplace(entity[1u], value[0u].throw_on_copy());
  433. pool.emplace(entity[0u], value[1u].throw_on_copy());
  434. // basic exception safety
  435. ASSERT_THROW(pool.erase(entity[1u]), test::throwing_type_exception);
  436. ASSERT_EQ(pool.size(), 2u);
  437. ASSERT_TRUE(pool.contains(entity[0u]));
  438. ASSERT_TRUE(pool.contains(entity[1u]));
  439. ASSERT_EQ(pool.index(entity[0u]), 1u);
  440. ASSERT_EQ(pool.index(entity[1u]), 0u);
  441. ASSERT_EQ(pool.get(entity[0u]), value[1u]);
  442. // the element may have been moved but it's still there
  443. ASSERT_EQ(pool.get(entity[1u]), value[0u]);
  444. pool.get(entity[1u]).throw_on_copy(false);
  445. pool.erase(entity[1u]);
  446. ASSERT_EQ(pool.size(), 1u);
  447. ASSERT_TRUE(pool.contains(entity[0u]));
  448. ASSERT_FALSE(pool.contains(entity[1u]));
  449. ASSERT_EQ(pool.index(entity[0u]), 0u);
  450. ASSERT_EQ(pool.get(entity[0u]), value[1u]);
  451. ASSERT_EQ(on_construct, 2u);
  452. ASSERT_EQ(on_destroy, 3u);
  453. }