storage.hpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198
  1. #ifndef ENTT_ENTITY_STORAGE_HPP
  2. #define ENTT_ENTITY_STORAGE_HPP
  3. #include <cstddef>
  4. #include <iterator>
  5. #include <memory>
  6. #include <tuple>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <vector>
  10. #include "../config/config.h"
  11. #include "../core/iterator.hpp"
  12. #include "../core/memory.hpp"
  13. #include "../core/type_info.hpp"
  14. #include "component.hpp"
  15. #include "entity.hpp"
  16. #include "fwd.hpp"
  17. #include "sparse_set.hpp"
  18. namespace entt {
  19. /**
  20. * @cond TURN_OFF_DOXYGEN
  21. * Internal details not to be documented.
  22. */
  23. namespace internal {
  24. template<typename Container, std::size_t Size>
  25. class storage_iterator final {
  26. friend storage_iterator<const Container, Size>;
  27. using container_type = std::remove_const_t<Container>;
  28. using alloc_traits = std::allocator_traits<typename container_type::allocator_type>;
  29. using iterator_traits = std::iterator_traits<std::conditional_t<
  30. std::is_const_v<Container>,
  31. typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
  32. typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
  33. public:
  34. using value_type = typename iterator_traits::value_type;
  35. using pointer = typename iterator_traits::pointer;
  36. using reference = typename iterator_traits::reference;
  37. using difference_type = typename iterator_traits::difference_type;
  38. using iterator_category = std::random_access_iterator_tag;
  39. constexpr storage_iterator() noexcept = default;
  40. constexpr storage_iterator(Container *ref, const difference_type idx) noexcept
  41. : payload{ref},
  42. offset{idx} {}
  43. template<bool Const = std::is_const_v<Container>, typename = std::enable_if_t<Const>>
  44. constexpr storage_iterator(const storage_iterator<std::remove_const_t<Container>, Size> &other) noexcept
  45. : storage_iterator{other.payload, other.offset} {}
  46. constexpr storage_iterator &operator++() noexcept {
  47. return --offset, *this;
  48. }
  49. constexpr storage_iterator operator++(int) noexcept {
  50. storage_iterator orig = *this;
  51. return ++(*this), orig;
  52. }
  53. constexpr storage_iterator &operator--() noexcept {
  54. return ++offset, *this;
  55. }
  56. constexpr storage_iterator operator--(int) noexcept {
  57. storage_iterator orig = *this;
  58. return operator--(), orig;
  59. }
  60. constexpr storage_iterator &operator+=(const difference_type value) noexcept {
  61. offset -= value;
  62. return *this;
  63. }
  64. constexpr storage_iterator operator+(const difference_type value) const noexcept {
  65. storage_iterator copy = *this;
  66. return (copy += value);
  67. }
  68. constexpr storage_iterator &operator-=(const difference_type value) noexcept {
  69. return (*this += -value);
  70. }
  71. constexpr storage_iterator operator-(const difference_type value) const noexcept {
  72. return (*this + -value);
  73. }
  74. [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
  75. const auto pos = index() - value;
  76. return (*payload)[pos / Size][fast_mod(pos, Size)];
  77. }
  78. [[nodiscard]] constexpr pointer operator->() const noexcept {
  79. const auto pos = index();
  80. return (*payload)[pos / Size] + fast_mod(pos, Size);
  81. }
  82. [[nodiscard]] constexpr reference operator*() const noexcept {
  83. return *operator->();
  84. }
  85. [[nodiscard]] constexpr difference_type index() const noexcept {
  86. return offset - 1;
  87. }
  88. private:
  89. Container *payload;
  90. difference_type offset;
  91. };
  92. template<typename Lhs, typename Rhs, std::size_t Size>
  93. [[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator<Lhs, Size> &lhs, const storage_iterator<Rhs, Size> &rhs) noexcept {
  94. return rhs.index() - lhs.index();
  95. }
  96. template<typename Lhs, typename Rhs, std::size_t Size>
  97. [[nodiscard]] constexpr bool operator==(const storage_iterator<Lhs, Size> &lhs, const storage_iterator<Rhs, Size> &rhs) noexcept {
  98. return lhs.index() == rhs.index();
  99. }
  100. template<typename Lhs, typename Rhs, std::size_t Size>
  101. [[nodiscard]] constexpr bool operator!=(const storage_iterator<Lhs, Size> &lhs, const storage_iterator<Rhs, Size> &rhs) noexcept {
  102. return !(lhs == rhs);
  103. }
  104. template<typename Lhs, typename Rhs, std::size_t Size>
  105. [[nodiscard]] constexpr bool operator<(const storage_iterator<Lhs, Size> &lhs, const storage_iterator<Rhs, Size> &rhs) noexcept {
  106. return lhs.index() > rhs.index();
  107. }
  108. template<typename Lhs, typename Rhs, std::size_t Size>
  109. [[nodiscard]] constexpr bool operator>(const storage_iterator<Lhs, Size> &lhs, const storage_iterator<Rhs, Size> &rhs) noexcept {
  110. return rhs < lhs;
  111. }
  112. template<typename Lhs, typename Rhs, std::size_t Size>
  113. [[nodiscard]] constexpr bool operator<=(const storage_iterator<Lhs, Size> &lhs, const storage_iterator<Rhs, Size> &rhs) noexcept {
  114. return !(lhs > rhs);
  115. }
  116. template<typename Lhs, typename Rhs, std::size_t Size>
  117. [[nodiscard]] constexpr bool operator>=(const storage_iterator<Lhs, Size> &lhs, const storage_iterator<Rhs, Size> &rhs) noexcept {
  118. return !(lhs < rhs);
  119. }
  120. template<typename It, typename... Other>
  121. class extended_storage_iterator final {
  122. template<typename Iter, typename... Args>
  123. friend class extended_storage_iterator;
  124. public:
  125. using iterator_type = It;
  126. using difference_type = std::ptrdiff_t;
  127. using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::forward_as_tuple(*std::declval<Other>()...)));
  128. using pointer = input_iterator_pointer<value_type>;
  129. using reference = value_type;
  130. using iterator_category = std::input_iterator_tag;
  131. using iterator_concept = std::forward_iterator_tag;
  132. constexpr extended_storage_iterator()
  133. : it{} {}
  134. constexpr extended_storage_iterator(iterator_type base, Other... other)
  135. : it{base, other...} {}
  136. template<typename... Args, typename = std::enable_if_t<(!std::is_same_v<Other, Args> && ...) && (std::is_constructible_v<Other, Args> && ...)>>
  137. constexpr extended_storage_iterator(const extended_storage_iterator<It, Args...> &other)
  138. : it{other.it} {}
  139. constexpr extended_storage_iterator &operator++() noexcept {
  140. return ++std::get<It>(it), (++std::get<Other>(it), ...), *this;
  141. }
  142. constexpr extended_storage_iterator operator++(int) noexcept {
  143. extended_storage_iterator orig = *this;
  144. return ++(*this), orig;
  145. }
  146. [[nodiscard]] constexpr pointer operator->() const noexcept {
  147. return operator*();
  148. }
  149. [[nodiscard]] constexpr reference operator*() const noexcept {
  150. return {*std::get<It>(it), *std::get<Other>(it)...};
  151. }
  152. [[nodiscard]] constexpr iterator_type base() const noexcept {
  153. return std::get<It>(it);
  154. }
  155. template<typename... Lhs, typename... Rhs>
  156. friend constexpr bool operator==(const extended_storage_iterator<Lhs...> &, const extended_storage_iterator<Rhs...> &) noexcept;
  157. private:
  158. std::tuple<It, Other...> it;
  159. };
  160. template<typename... Lhs, typename... Rhs>
  161. [[nodiscard]] constexpr bool operator==(const extended_storage_iterator<Lhs...> &lhs, const extended_storage_iterator<Rhs...> &rhs) noexcept {
  162. return std::get<0>(lhs.it) == std::get<0>(rhs.it);
  163. }
  164. template<typename... Lhs, typename... Rhs>
  165. [[nodiscard]] constexpr bool operator!=(const extended_storage_iterator<Lhs...> &lhs, const extended_storage_iterator<Rhs...> &rhs) noexcept {
  166. return !(lhs == rhs);
  167. }
  168. } // namespace internal
  169. /**
  170. * Internal details not to be documented.
  171. * @endcond
  172. */
  173. /**
  174. * @brief Basic storage implementation.
  175. *
  176. * Internal data structures arrange elements to maximize performance. There are
  177. * no guarantees that objects are returned in the insertion order when iterate
  178. * a storage. Do not make assumption on the order in any case.
  179. *
  180. * @warning
  181. * Empty types aren't explicitly instantiated. Therefore, many of the functions
  182. * normally available for non-empty types will not be available for empty ones.
  183. *
  184. * @tparam Type Type of objects assigned to the entities.
  185. * @tparam Entity A valid entity type.
  186. * @tparam Allocator Type of allocator used to manage memory and elements.
  187. */
  188. template<typename Type, typename Entity, typename Allocator, typename>
  189. class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
  190. using alloc_traits = std::allocator_traits<Allocator>;
  191. static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
  192. using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
  193. using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
  194. using underlying_iterator = typename underlying_type::basic_iterator;
  195. [[nodiscard]] auto &element_at(const std::size_t pos) const {
  196. return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
  197. }
  198. auto assure_at_least(const std::size_t pos) {
  199. const auto idx = pos / traits_type::page_size;
  200. if(!(idx < payload.size())) {
  201. auto curr = payload.size();
  202. allocator_type allocator{get_allocator()};
  203. payload.resize(idx + 1u, nullptr);
  204. ENTT_TRY {
  205. for(const auto last = payload.size(); curr < last; ++curr) {
  206. payload[curr] = alloc_traits::allocate(allocator, traits_type::page_size);
  207. }
  208. }
  209. ENTT_CATCH {
  210. payload.resize(curr);
  211. ENTT_THROW;
  212. }
  213. }
  214. return payload[idx] + fast_mod(pos, traits_type::page_size);
  215. }
  216. template<typename... Args>
  217. auto emplace_element(const Entity entt, const bool force_back, Args &&...args) {
  218. const auto it = base_type::try_emplace(entt, force_back);
  219. ENTT_TRY {
  220. auto elem = assure_at_least(static_cast<size_type>(it.index()));
  221. entt::uninitialized_construct_using_allocator(to_address(elem), get_allocator(), std::forward<Args>(args)...);
  222. }
  223. ENTT_CATCH {
  224. base_type::pop(it, it + 1u);
  225. ENTT_THROW;
  226. }
  227. return it;
  228. }
  229. void shrink_to_size(const std::size_t sz) {
  230. const auto from = (sz + traits_type::page_size - 1u) / traits_type::page_size;
  231. allocator_type allocator{get_allocator()};
  232. for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
  233. if constexpr(traits_type::in_place_delete) {
  234. if(base_type::at(pos) != tombstone) {
  235. alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
  236. }
  237. } else {
  238. alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
  239. }
  240. }
  241. for(auto pos = from, last = payload.size(); pos < last; ++pos) {
  242. alloc_traits::deallocate(allocator, payload[pos], traits_type::page_size);
  243. }
  244. payload.resize(from);
  245. }
  246. private:
  247. const void *get_at(const std::size_t pos) const final {
  248. return std::addressof(element_at(pos));
  249. }
  250. void swap_or_move([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) override {
  251. static constexpr bool is_pinned_type_v = !(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>);
  252. // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy
  253. ENTT_ASSERT((from + 1u) && !is_pinned_type_v, "Pinned type");
  254. if constexpr(!is_pinned_type_v) {
  255. auto &elem = element_at(from);
  256. if constexpr(traits_type::in_place_delete) {
  257. if(base_type::operator[](to) == tombstone) {
  258. allocator_type allocator{get_allocator()};
  259. entt::uninitialized_construct_using_allocator(to_address(assure_at_least(to)), allocator, std::move(elem));
  260. alloc_traits::destroy(allocator, std::addressof(elem));
  261. return;
  262. }
  263. }
  264. using std::swap;
  265. swap(elem, element_at(to));
  266. }
  267. }
  268. protected:
  269. /**
  270. * @brief Erases entities from a storage.
  271. * @param first An iterator to the first element of the range of entities.
  272. * @param last An iterator past the last element of the range of entities.
  273. */
  274. void pop(underlying_iterator first, underlying_iterator last) override {
  275. for(allocator_type allocator{get_allocator()}; first != last; ++first) {
  276. // cannot use first.index() because it would break with cross iterators
  277. auto &elem = element_at(base_type::index(*first));
  278. if constexpr(traits_type::in_place_delete) {
  279. base_type::in_place_pop(first);
  280. alloc_traits::destroy(allocator, std::addressof(elem));
  281. } else {
  282. auto &other = element_at(base_type::size() - 1u);
  283. // destroying on exit allows reentrant destructors
  284. [[maybe_unused]] auto unused = std::exchange(elem, std::move(other));
  285. alloc_traits::destroy(allocator, std::addressof(other));
  286. base_type::swap_and_pop(first);
  287. }
  288. }
  289. }
  290. /*! @brief Erases all entities of a storage. */
  291. void pop_all() override {
  292. allocator_type allocator{get_allocator()};
  293. for(auto first = base_type::begin(); !(first.index() < 0); ++first) {
  294. if constexpr(traits_type::in_place_delete) {
  295. if(*first != tombstone) {
  296. base_type::in_place_pop(first);
  297. alloc_traits::destroy(allocator, std::addressof(element_at(static_cast<size_type>(first.index()))));
  298. }
  299. } else {
  300. base_type::swap_and_pop(first);
  301. alloc_traits::destroy(allocator, std::addressof(element_at(static_cast<size_type>(first.index()))));
  302. }
  303. }
  304. }
  305. /**
  306. * @brief Assigns an entity to a storage.
  307. * @param entt A valid identifier.
  308. * @param value Optional opaque value.
  309. * @param force_back Force back insertion.
  310. * @return Iterator pointing to the emplaced element.
  311. */
  312. underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override {
  313. if(value) {
  314. if constexpr(std::is_copy_constructible_v<value_type>) {
  315. return emplace_element(entt, force_back, *static_cast<const value_type *>(value));
  316. } else {
  317. return base_type::end();
  318. }
  319. } else {
  320. if constexpr(std::is_default_constructible_v<value_type>) {
  321. return emplace_element(entt, force_back);
  322. } else {
  323. return base_type::end();
  324. }
  325. }
  326. }
  327. public:
  328. /*! @brief Base type. */
  329. using base_type = underlying_type;
  330. /*! @brief Type of the objects assigned to entities. */
  331. using value_type = Type;
  332. /*! @brief Component traits. */
  333. using traits_type = component_traits<value_type>;
  334. /*! @brief Underlying entity identifier. */
  335. using entity_type = Entity;
  336. /*! @brief Unsigned integer type. */
  337. using size_type = std::size_t;
  338. /*! @brief Allocator type. */
  339. using allocator_type = Allocator;
  340. /*! @brief Pointer type to contained elements. */
  341. using pointer = typename container_type::pointer;
  342. /*! @brief Constant pointer type to contained elements. */
  343. using const_pointer = typename alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
  344. /*! @brief Random access iterator type. */
  345. using iterator = internal::storage_iterator<container_type, traits_type::page_size>;
  346. /*! @brief Constant random access iterator type. */
  347. using const_iterator = internal::storage_iterator<const container_type, traits_type::page_size>;
  348. /*! @brief Reverse iterator type. */
  349. using reverse_iterator = std::reverse_iterator<iterator>;
  350. /*! @brief Constant reverse iterator type. */
  351. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  352. /*! @brief Extended iterable storage proxy. */
  353. using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator, iterator>>;
  354. /*! @brief Constant extended iterable storage proxy. */
  355. using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator, const_iterator>>;
  356. /*! @brief Extended reverse iterable storage proxy. */
  357. using reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::reverse_iterator, reverse_iterator>>;
  358. /*! @brief Constant extended reverse iterable storage proxy. */
  359. using const_reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_reverse_iterator, const_reverse_iterator>>;
  360. /*! @brief Default constructor. */
  361. basic_storage()
  362. : basic_storage{allocator_type{}} {}
  363. /**
  364. * @brief Constructs an empty storage with a given allocator.
  365. * @param allocator The allocator to use.
  366. */
  367. explicit basic_storage(const allocator_type &allocator)
  368. : base_type{type_id<value_type>(), deletion_policy{traits_type::in_place_delete}, allocator},
  369. payload{allocator} {}
  370. /**
  371. * @brief Move constructor.
  372. * @param other The instance to move from.
  373. */
  374. basic_storage(basic_storage &&other) noexcept
  375. : base_type{std::move(other)},
  376. payload{std::move(other.payload)} {}
  377. /**
  378. * @brief Allocator-extended move constructor.
  379. * @param other The instance to move from.
  380. * @param allocator The allocator to use.
  381. */
  382. basic_storage(basic_storage &&other, const allocator_type &allocator) noexcept
  383. : base_type{std::move(other), allocator},
  384. payload{std::move(other.payload), allocator} {
  385. ENTT_ASSERT(alloc_traits::is_always_equal::value || payload.get_allocator() == other.payload.get_allocator(), "Copying a storage is not allowed");
  386. }
  387. /*! @brief Default destructor. */
  388. ~basic_storage() override {
  389. shrink_to_size(0u);
  390. }
  391. /**
  392. * @brief Move assignment operator.
  393. * @param other The instance to move from.
  394. * @return This storage.
  395. */
  396. basic_storage &operator=(basic_storage &&other) noexcept {
  397. ENTT_ASSERT(alloc_traits::is_always_equal::value || payload.get_allocator() == other.payload.get_allocator(), "Copying a storage is not allowed");
  398. shrink_to_size(0u);
  399. base_type::operator=(std::move(other));
  400. payload = std::move(other.payload);
  401. return *this;
  402. }
  403. /**
  404. * @brief Exchanges the contents with those of a given storage.
  405. * @param other Storage to exchange the content with.
  406. */
  407. void swap(basic_storage &other) {
  408. using std::swap;
  409. base_type::swap(other);
  410. swap(payload, other.payload);
  411. }
  412. /**
  413. * @brief Returns the associated allocator.
  414. * @return The associated allocator.
  415. */
  416. [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
  417. return payload.get_allocator();
  418. }
  419. /**
  420. * @brief Increases the capacity of a storage.
  421. *
  422. * If the new capacity is greater than the current capacity, new storage is
  423. * allocated, otherwise the method does nothing.
  424. *
  425. * @param cap Desired capacity.
  426. */
  427. void reserve(const size_type cap) override {
  428. if(cap != 0u) {
  429. base_type::reserve(cap);
  430. assure_at_least(cap - 1u);
  431. }
  432. }
  433. /**
  434. * @brief Returns the number of elements that a storage has currently
  435. * allocated space for.
  436. * @return Capacity of the storage.
  437. */
  438. [[nodiscard]] size_type capacity() const noexcept override {
  439. return payload.size() * traits_type::page_size;
  440. }
  441. /*! @brief Requests the removal of unused capacity. */
  442. void shrink_to_fit() override {
  443. base_type::shrink_to_fit();
  444. shrink_to_size(base_type::size());
  445. }
  446. /**
  447. * @brief Direct access to the array of objects.
  448. * @return A pointer to the array of objects.
  449. */
  450. [[nodiscard]] const_pointer raw() const noexcept {
  451. return payload.data();
  452. }
  453. /*! @copydoc raw */
  454. [[nodiscard]] pointer raw() noexcept {
  455. return payload.data();
  456. }
  457. /**
  458. * @brief Returns an iterator to the beginning.
  459. *
  460. * If the storage is empty, the returned iterator will be equal to `end()`.
  461. *
  462. * @return An iterator to the first instance of the internal array.
  463. */
  464. [[nodiscard]] const_iterator cbegin() const noexcept {
  465. const auto pos = static_cast<typename iterator::difference_type>(base_type::size());
  466. return const_iterator{&payload, pos};
  467. }
  468. /*! @copydoc cbegin */
  469. [[nodiscard]] const_iterator begin() const noexcept {
  470. return cbegin();
  471. }
  472. /*! @copydoc begin */
  473. [[nodiscard]] iterator begin() noexcept {
  474. const auto pos = static_cast<typename iterator::difference_type>(base_type::size());
  475. return iterator{&payload, pos};
  476. }
  477. /**
  478. * @brief Returns an iterator to the end.
  479. * @return An iterator to the element following the last instance of the
  480. * internal array.
  481. */
  482. [[nodiscard]] const_iterator cend() const noexcept {
  483. return const_iterator{&payload, {}};
  484. }
  485. /*! @copydoc cend */
  486. [[nodiscard]] const_iterator end() const noexcept {
  487. return cend();
  488. }
  489. /*! @copydoc end */
  490. [[nodiscard]] iterator end() noexcept {
  491. return iterator{&payload, {}};
  492. }
  493. /**
  494. * @brief Returns a reverse iterator to the beginning.
  495. *
  496. * If the storage is empty, the returned iterator will be equal to `rend()`.
  497. *
  498. * @return An iterator to the first instance of the reversed internal array.
  499. */
  500. [[nodiscard]] const_reverse_iterator crbegin() const noexcept {
  501. return std::make_reverse_iterator(cend());
  502. }
  503. /*! @copydoc crbegin */
  504. [[nodiscard]] const_reverse_iterator rbegin() const noexcept {
  505. return crbegin();
  506. }
  507. /*! @copydoc rbegin */
  508. [[nodiscard]] reverse_iterator rbegin() noexcept {
  509. return std::make_reverse_iterator(end());
  510. }
  511. /**
  512. * @brief Returns a reverse iterator to the end.
  513. * @return An iterator to the element following the last instance of the
  514. * reversed internal array.
  515. */
  516. [[nodiscard]] const_reverse_iterator crend() const noexcept {
  517. return std::make_reverse_iterator(cbegin());
  518. }
  519. /*! @copydoc crend */
  520. [[nodiscard]] const_reverse_iterator rend() const noexcept {
  521. return crend();
  522. }
  523. /*! @copydoc rend */
  524. [[nodiscard]] reverse_iterator rend() noexcept {
  525. return std::make_reverse_iterator(begin());
  526. }
  527. /**
  528. * @brief Returns the object assigned to an entity.
  529. *
  530. * @warning
  531. * Attempting to use an entity that doesn't belong to the storage results in
  532. * undefined behavior.
  533. *
  534. * @param entt A valid identifier.
  535. * @return The object assigned to the entity.
  536. */
  537. [[nodiscard]] const value_type &get(const entity_type entt) const noexcept {
  538. return element_at(base_type::index(entt));
  539. }
  540. /*! @copydoc get */
  541. [[nodiscard]] value_type &get(const entity_type entt) noexcept {
  542. return const_cast<value_type &>(std::as_const(*this).get(entt));
  543. }
  544. /**
  545. * @brief Returns the object assigned to an entity as a tuple.
  546. * @param entt A valid identifier.
  547. * @return The object assigned to the entity as a tuple.
  548. */
  549. [[nodiscard]] std::tuple<const value_type &> get_as_tuple(const entity_type entt) const noexcept {
  550. return std::forward_as_tuple(get(entt));
  551. }
  552. /*! @copydoc get_as_tuple */
  553. [[nodiscard]] std::tuple<value_type &> get_as_tuple(const entity_type entt) noexcept {
  554. return std::forward_as_tuple(get(entt));
  555. }
  556. /**
  557. * @brief Assigns an entity to a storage and constructs its object.
  558. *
  559. * @warning
  560. * Attempting to use an entity that already belongs to the storage results
  561. * in undefined behavior.
  562. *
  563. * @tparam Args Types of arguments to use to construct the object.
  564. * @param entt A valid identifier.
  565. * @param args Parameters to use to construct an object for the entity.
  566. * @return A reference to the newly created object.
  567. */
  568. template<typename... Args>
  569. value_type &emplace(const entity_type entt, Args &&...args) {
  570. if constexpr(std::is_aggregate_v<value_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<value_type>)) {
  571. const auto it = emplace_element(entt, false, Type{std::forward<Args>(args)...});
  572. return element_at(static_cast<size_type>(it.index()));
  573. } else {
  574. const auto it = emplace_element(entt, false, std::forward<Args>(args)...);
  575. return element_at(static_cast<size_type>(it.index()));
  576. }
  577. }
  578. /**
  579. * @brief Updates the instance assigned to a given entity in-place.
  580. * @tparam Func Types of the function objects to invoke.
  581. * @param entt A valid identifier.
  582. * @param func Valid function objects.
  583. * @return A reference to the updated instance.
  584. */
  585. template<typename... Func>
  586. value_type &patch(const entity_type entt, Func &&...func) {
  587. const auto idx = base_type::index(entt);
  588. auto &elem = element_at(idx);
  589. (std::forward<Func>(func)(elem), ...);
  590. return elem;
  591. }
  592. /**
  593. * @brief Assigns one or more entities to a storage and constructs their
  594. * objects from a given instance.
  595. *
  596. * @warning
  597. * Attempting to assign an entity that already belongs to the storage
  598. * results in undefined behavior.
  599. *
  600. * @tparam It Type of input iterator.
  601. * @param first An iterator to the first element of the range of entities.
  602. * @param last An iterator past the last element of the range of entities.
  603. * @param value An instance of the object to construct.
  604. * @return Iterator pointing to the last element inserted, if any.
  605. */
  606. template<typename It>
  607. iterator insert(It first, It last, const value_type &value = {}) {
  608. for(; first != last; ++first) {
  609. emplace_element(*first, true, value);
  610. }
  611. return begin();
  612. }
  613. /**
  614. * @brief Assigns one or more entities to a storage and constructs their
  615. * objects from a given range.
  616. *
  617. * @sa construct
  618. *
  619. * @tparam EIt Type of input iterator.
  620. * @tparam CIt Type of input iterator.
  621. * @param first An iterator to the first element of the range of entities.
  622. * @param last An iterator past the last element of the range of entities.
  623. * @param from An iterator to the first element of the range of objects.
  624. * @return Iterator pointing to the first element inserted, if any.
  625. */
  626. template<typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, value_type>>>
  627. iterator insert(EIt first, EIt last, CIt from) {
  628. for(; first != last; ++first, ++from) {
  629. emplace_element(*first, true, *from);
  630. }
  631. return begin();
  632. }
  633. /**
  634. * @brief Returns an iterable object to use to _visit_ a storage.
  635. *
  636. * The iterable object returns a tuple that contains the current entity and
  637. * a reference to its component.
  638. *
  639. * @return An iterable object to use to _visit_ the storage.
  640. */
  641. [[nodiscard]] iterable each() noexcept {
  642. return {internal::extended_storage_iterator{base_type::begin(), begin()}, internal::extended_storage_iterator{base_type::end(), end()}};
  643. }
  644. /*! @copydoc each */
  645. [[nodiscard]] const_iterable each() const noexcept {
  646. return {internal::extended_storage_iterator{base_type::cbegin(), cbegin()}, internal::extended_storage_iterator{base_type::cend(), cend()}};
  647. }
  648. /**
  649. * @brief Returns a reverse iterable object to use to _visit_ a storage.
  650. *
  651. * @sa each
  652. *
  653. * @return A reverse iterable object to use to _visit_ the storage.
  654. */
  655. [[nodiscard]] reverse_iterable reach() noexcept {
  656. return {internal::extended_storage_iterator{base_type::rbegin(), rbegin()}, internal::extended_storage_iterator{base_type::rend(), rend()}};
  657. }
  658. /*! @copydoc reach */
  659. [[nodiscard]] const_reverse_iterable reach() const noexcept {
  660. return {internal::extended_storage_iterator{base_type::crbegin(), crbegin()}, internal::extended_storage_iterator{base_type::crend(), crend()}};
  661. }
  662. private:
  663. container_type payload;
  664. };
  665. /*! @copydoc basic_storage */
  666. template<typename Type, typename Entity, typename Allocator>
  667. class basic_storage<Type, Entity, Allocator, std::enable_if_t<component_traits<Type>::page_size == 0u>>
  668. : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
  669. using alloc_traits = std::allocator_traits<Allocator>;
  670. static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
  671. public:
  672. /*! @brief Base type. */
  673. using base_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
  674. /*! @brief Type of the objects assigned to entities. */
  675. using value_type = Type;
  676. /*! @brief Component traits. */
  677. using traits_type = component_traits<value_type>;
  678. /*! @brief Underlying entity identifier. */
  679. using entity_type = Entity;
  680. /*! @brief Unsigned integer type. */
  681. using size_type = std::size_t;
  682. /*! @brief Allocator type. */
  683. using allocator_type = Allocator;
  684. /*! @brief Extended iterable storage proxy. */
  685. using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
  686. /*! @brief Constant extended iterable storage proxy. */
  687. using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator>>;
  688. /*! @brief Extended reverse iterable storage proxy. */
  689. using reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::reverse_iterator>>;
  690. /*! @brief Constant extended reverse iterable storage proxy. */
  691. using const_reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_reverse_iterator>>;
  692. /*! @brief Default constructor. */
  693. basic_storage()
  694. : basic_storage{allocator_type{}} {}
  695. /**
  696. * @brief Constructs an empty container with a given allocator.
  697. * @param allocator The allocator to use.
  698. */
  699. explicit basic_storage(const allocator_type &allocator)
  700. : base_type{type_id<value_type>(), deletion_policy{traits_type::in_place_delete}, allocator} {}
  701. /**
  702. * @brief Move constructor.
  703. * @param other The instance to move from.
  704. */
  705. basic_storage(basic_storage &&other) noexcept = default;
  706. /**
  707. * @brief Allocator-extended move constructor.
  708. * @param other The instance to move from.
  709. * @param allocator The allocator to use.
  710. */
  711. basic_storage(basic_storage &&other, const allocator_type &allocator) noexcept
  712. : base_type{std::move(other), allocator} {}
  713. /**
  714. * @brief Move assignment operator.
  715. * @param other The instance to move from.
  716. * @return This storage.
  717. */
  718. basic_storage &operator=(basic_storage &&other) noexcept = default;
  719. /**
  720. * @brief Returns the associated allocator.
  721. * @return The associated allocator.
  722. */
  723. [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
  724. // std::allocator<void> has no cross constructors (waiting for C++20)
  725. if constexpr(std::is_void_v<value_type> && !std::is_constructible_v<allocator_type, typename base_type::allocator_type>) {
  726. return allocator_type{};
  727. } else {
  728. return allocator_type{base_type::get_allocator()};
  729. }
  730. }
  731. /**
  732. * @brief Returns the object assigned to an entity, that is `void`.
  733. *
  734. * @warning
  735. * Attempting to use an entity that doesn't belong to the storage results in
  736. * undefined behavior.
  737. *
  738. * @param entt A valid identifier.
  739. */
  740. void get([[maybe_unused]] const entity_type entt) const noexcept {
  741. ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity");
  742. }
  743. /**
  744. * @brief Returns an empty tuple.
  745. *
  746. * @warning
  747. * Attempting to use an entity that doesn't belong to the storage results in
  748. * undefined behavior.
  749. *
  750. * @param entt A valid identifier.
  751. * @return Returns an empty tuple.
  752. */
  753. [[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
  754. ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity");
  755. return std::tuple{};
  756. }
  757. /**
  758. * @brief Assigns an entity to a storage and constructs its object.
  759. *
  760. * @warning
  761. * Attempting to use an entity that already belongs to the storage results
  762. * in undefined behavior.
  763. *
  764. * @tparam Args Types of arguments to use to construct the object.
  765. * @param entt A valid identifier.
  766. */
  767. template<typename... Args>
  768. void emplace(const entity_type entt, Args &&...) {
  769. base_type::try_emplace(entt, false);
  770. }
  771. /**
  772. * @brief Updates the instance assigned to a given entity in-place.
  773. * @tparam Func Types of the function objects to invoke.
  774. * @param entt A valid identifier.
  775. * @param func Valid function objects.
  776. */
  777. template<typename... Func>
  778. void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
  779. ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity");
  780. (std::forward<Func>(func)(), ...);
  781. }
  782. /**
  783. * @brief Assigns entities to a storage.
  784. * @tparam It Type of input iterator.
  785. * @tparam Args Types of optional arguments.
  786. * @param first An iterator to the first element of the range of entities.
  787. * @param last An iterator past the last element of the range of entities.
  788. */
  789. template<typename It, typename... Args>
  790. void insert(It first, It last, Args &&...) {
  791. for(; first != last; ++first) {
  792. base_type::try_emplace(*first, true);
  793. }
  794. }
  795. /**
  796. * @brief Returns an iterable object to use to _visit_ a storage.
  797. *
  798. * The iterable object returns a tuple that contains the current entity.
  799. *
  800. * @return An iterable object to use to _visit_ the storage.
  801. */
  802. [[nodiscard]] iterable each() noexcept {
  803. return {internal::extended_storage_iterator{base_type::begin()}, internal::extended_storage_iterator{base_type::end()}};
  804. }
  805. /*! @copydoc each */
  806. [[nodiscard]] const_iterable each() const noexcept {
  807. return {internal::extended_storage_iterator{base_type::cbegin()}, internal::extended_storage_iterator{base_type::cend()}};
  808. }
  809. /**
  810. * @brief Returns a reverse iterable object to use to _visit_ a storage.
  811. *
  812. * @sa each
  813. *
  814. * @return A reverse iterable object to use to _visit_ the storage.
  815. */
  816. [[nodiscard]] reverse_iterable reach() noexcept {
  817. return {internal::extended_storage_iterator{base_type::rbegin()}, internal::extended_storage_iterator{base_type::rend()}};
  818. }
  819. /*! @copydoc reach */
  820. [[nodiscard]] const_reverse_iterable reach() const noexcept {
  821. return {internal::extended_storage_iterator{base_type::crbegin()}, internal::extended_storage_iterator{base_type::crend()}};
  822. }
  823. };
  824. /**
  825. * @brief Swap-only entity storage specialization.
  826. * @tparam Entity A valid entity type.
  827. * @tparam Allocator Type of allocator used to manage memory and elements.
  828. */
  829. template<typename Entity, typename Allocator>
  830. class basic_storage<Entity, Entity, Allocator>
  831. : public basic_sparse_set<Entity, Allocator> {
  832. using alloc_traits = std::allocator_traits<Allocator>;
  833. static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
  834. using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
  835. using underlying_iterator = typename underlying_type::basic_iterator;
  836. auto entity_at(const std::size_t pos) const noexcept {
  837. ENTT_ASSERT(pos < underlying_type::traits_type::to_entity(null), "Invalid element");
  838. return underlying_type::traits_type::combine(static_cast<typename underlying_type::traits_type::entity_type>(pos), {});
  839. }
  840. protected:
  841. /**
  842. * @brief Assigns an entity to a storage.
  843. * @param hint A valid identifier.
  844. * @return Iterator pointing to the emplaced element.
  845. */
  846. underlying_iterator try_emplace(const Entity hint, const bool, const void *) override {
  847. return base_type::find(emplace(hint));
  848. }
  849. public:
  850. /*! @brief Base type. */
  851. using base_type = basic_sparse_set<Entity, Allocator>;
  852. /*! @brief Type of the objects assigned to entities. */
  853. using value_type = Entity;
  854. /*! @brief Underlying entity identifier. */
  855. using entity_type = Entity;
  856. /*! @brief Unsigned integer type. */
  857. using size_type = std::size_t;
  858. /*! @brief Allocator type. */
  859. using allocator_type = Allocator;
  860. /*! @brief Extended iterable storage proxy. */
  861. using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
  862. /*! @brief Constant extended iterable storage proxy. */
  863. using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator>>;
  864. /*! @brief Extended reverse iterable storage proxy. */
  865. using reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::reverse_iterator>>;
  866. /*! @brief Constant extended reverse iterable storage proxy. */
  867. using const_reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_reverse_iterator>>;
  868. /*! @brief Default constructor. */
  869. basic_storage()
  870. : basic_storage{allocator_type{}} {
  871. }
  872. /**
  873. * @brief Constructs an empty container with a given allocator.
  874. * @param allocator The allocator to use.
  875. */
  876. explicit basic_storage(const allocator_type &allocator)
  877. : base_type{type_id<void>(), deletion_policy::swap_only, allocator} {}
  878. /**
  879. * @brief Move constructor.
  880. * @param other The instance to move from.
  881. */
  882. basic_storage(basic_storage &&other) noexcept
  883. : base_type{std::move(other)} {}
  884. /**
  885. * @brief Allocator-extended move constructor.
  886. * @param other The instance to move from.
  887. * @param allocator The allocator to use.
  888. */
  889. basic_storage(basic_storage &&other, const allocator_type &allocator) noexcept
  890. : base_type{std::move(other), allocator} {}
  891. /**
  892. * @brief Move assignment operator.
  893. * @param other The instance to move from.
  894. * @return This storage.
  895. */
  896. basic_storage &operator=(basic_storage &&other) noexcept {
  897. base_type::operator=(std::move(other));
  898. return *this;
  899. }
  900. /**
  901. * @brief Returns the object assigned to an entity, that is `void`.
  902. *
  903. * @warning
  904. * Attempting to use an entity that doesn't belong to the storage results in
  905. * undefined behavior.
  906. *
  907. * @param entt A valid identifier.
  908. */
  909. void get([[maybe_unused]] const entity_type entt) const noexcept {
  910. ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
  911. }
  912. /**
  913. * @brief Returns an empty tuple.
  914. *
  915. * @warning
  916. * Attempting to use an entity that doesn't belong to the storage results in
  917. * undefined behavior.
  918. *
  919. * @param entt A valid identifier.
  920. * @return Returns an empty tuple.
  921. */
  922. [[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
  923. ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
  924. return std::tuple{};
  925. }
  926. /**
  927. * @brief Creates a new identifier or recycles a destroyed one.
  928. * @return A valid identifier.
  929. */
  930. entity_type emplace() {
  931. const auto len = base_type::free_list();
  932. const auto entt = (len == base_type::size()) ? entity_at(len) : base_type::at(len);
  933. return *base_type::try_emplace(entt, true);
  934. }
  935. /**
  936. * @brief Creates a new identifier or recycles a destroyed one.
  937. *
  938. * If the requested identifier isn't in use, the suggested one is used.
  939. * Otherwise, a new identifier is returned.
  940. *
  941. * @param hint Required identifier.
  942. * @return A valid identifier.
  943. */
  944. entity_type emplace(const entity_type hint) {
  945. if(hint == null || hint == tombstone) {
  946. return emplace();
  947. } else if(const auto curr = underlying_type::traits_type::construct(underlying_type::traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone) {
  948. const auto pos = static_cast<size_type>(underlying_type::traits_type::to_entity(hint));
  949. const auto entt = *base_type::try_emplace(hint, true);
  950. while(!(pos < base_type::size())) {
  951. base_type::try_emplace(entity_at(base_type::size() - 1u), false);
  952. }
  953. return entt;
  954. } else if(const auto idx = base_type::index(curr); idx < base_type::free_list()) {
  955. return emplace();
  956. } else {
  957. return *base_type::try_emplace(hint, true);
  958. }
  959. }
  960. /**
  961. * @brief Updates a given identifier.
  962. * @tparam Func Types of the function objects to invoke.
  963. * @param entt A valid identifier.
  964. * @param func Valid function objects.
  965. */
  966. template<typename... Func>
  967. void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
  968. ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
  969. (std::forward<Func>(func)(), ...);
  970. }
  971. /**
  972. * @brief Assigns each element in a range an identifier.
  973. * @tparam It Type of mutable forward iterator.
  974. * @param first An iterator to the first element of the range to generate.
  975. * @param last An iterator past the last element of the range to generate.
  976. */
  977. template<typename It>
  978. void insert(It first, It last) {
  979. for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) {
  980. *first = *base_type::try_emplace(base_type::at(base_type::free_list()), true);
  981. }
  982. for(; first != last; ++first) {
  983. *first = *base_type::try_emplace(entity_at(base_type::free_list()), true);
  984. }
  985. }
  986. /**
  987. * @brief Makes all elements in a range contiguous.
  988. * @tparam It Type of forward iterator.
  989. * @param first An iterator to the first element of the range to pack.
  990. * @param last An iterator past the last element of the range to pack.
  991. * @return The number of elements within the newly created range.
  992. */
  993. template<typename It>
  994. [[deprecated("use sort_as instead")]] size_type pack(It first, It last) {
  995. base_type::sort_as(first, last);
  996. return static_cast<size_type>(std::distance(first, last));
  997. }
  998. /**
  999. * @brief Returns the number of elements considered still in use.
  1000. * @return The number of elements considered still in use.
  1001. */
  1002. [[deprecated("use free_list() instead")]] [[nodiscard]] size_type in_use() const noexcept {
  1003. return base_type::free_list();
  1004. }
  1005. /**
  1006. * @brief Sets the number of elements considered still in use.
  1007. * @param len The number of elements considered still in use.
  1008. */
  1009. [[deprecated("use free_list(len) instead")]] void in_use(const size_type len) noexcept {
  1010. base_type::free_list(len);
  1011. }
  1012. /**
  1013. * @brief Returns an iterable object to use to _visit_ a storage.
  1014. *
  1015. * The iterable object returns a tuple that contains the current entity.
  1016. *
  1017. * @return An iterable object to use to _visit_ the storage.
  1018. */
  1019. [[nodiscard]] iterable each() noexcept {
  1020. return {internal::extended_storage_iterator{base_type::begin(0)}, internal::extended_storage_iterator{base_type::end(0)}};
  1021. }
  1022. /*! @copydoc each */
  1023. [[nodiscard]] const_iterable each() const noexcept {
  1024. return {internal::extended_storage_iterator{base_type::cbegin(0)}, internal::extended_storage_iterator{base_type::cend(0)}};
  1025. }
  1026. /**
  1027. * @brief Returns a reverse iterable object to use to _visit_ a storage.
  1028. *
  1029. * @sa each
  1030. *
  1031. * @return A reverse iterable object to use to _visit_ the storage.
  1032. */
  1033. [[nodiscard]] reverse_iterable reach() noexcept {
  1034. return {internal::extended_storage_iterator{base_type::rbegin()}, internal::extended_storage_iterator{base_type::rend(0)}};
  1035. }
  1036. /*! @copydoc reach */
  1037. [[nodiscard]] const_reverse_iterable reach() const noexcept {
  1038. return {internal::extended_storage_iterator{base_type::crbegin()}, internal::extended_storage_iterator{base_type::crend(0)}};
  1039. }
  1040. };
  1041. } // namespace entt
  1042. #endif