🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

914 lines
33 KiB

  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/compressed_pair.hpp"
  12. #include "../core/iterator.hpp"
  13. #include "../core/memory.hpp"
  14. #include "../core/type_info.hpp"
  15. #include "component.hpp"
  16. #include "entity.hpp"
  17. #include "fwd.hpp"
  18. #include "sigh_storage_mixin.hpp"
  19. #include "sparse_set.hpp"
  20. namespace entt {
  21. /**
  22. * @cond TURN_OFF_DOXYGEN
  23. * Internal details not to be documented.
  24. */
  25. namespace internal {
  26. template<typename Container>
  27. class storage_iterator final {
  28. friend storage_iterator<const Container>;
  29. using container_type = std::remove_const_t<Container>;
  30. using alloc_traits = std::allocator_traits<typename container_type::allocator_type>;
  31. using comp_traits = component_traits<typename container_type::value_type>;
  32. using iterator_traits = std::iterator_traits<std::conditional_t<
  33. std::is_const_v<Container>,
  34. typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
  35. typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
  36. public:
  37. using value_type = typename iterator_traits::value_type;
  38. using pointer = typename iterator_traits::pointer;
  39. using reference = typename iterator_traits::reference;
  40. using difference_type = typename iterator_traits::difference_type;
  41. using iterator_category = std::random_access_iterator_tag;
  42. storage_iterator() ENTT_NOEXCEPT = default;
  43. storage_iterator(Container *ref, difference_type idx) ENTT_NOEXCEPT
  44. : packed{ref},
  45. offset{idx} {}
  46. template<bool Const = std::is_const_v<Container>, typename = std::enable_if_t<Const>>
  47. storage_iterator(const storage_iterator<std::remove_const_t<Container>> &other) ENTT_NOEXCEPT
  48. : packed{other.packed},
  49. offset{other.offset} {}
  50. storage_iterator &operator++() ENTT_NOEXCEPT {
  51. return --offset, *this;
  52. }
  53. storage_iterator operator++(int) ENTT_NOEXCEPT {
  54. storage_iterator orig = *this;
  55. return ++(*this), orig;
  56. }
  57. storage_iterator &operator--() ENTT_NOEXCEPT {
  58. return ++offset, *this;
  59. }
  60. storage_iterator operator--(int) ENTT_NOEXCEPT {
  61. storage_iterator orig = *this;
  62. return operator--(), orig;
  63. }
  64. storage_iterator &operator+=(const difference_type value) ENTT_NOEXCEPT {
  65. offset -= value;
  66. return *this;
  67. }
  68. storage_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
  69. storage_iterator copy = *this;
  70. return (copy += value);
  71. }
  72. storage_iterator &operator-=(const difference_type value) ENTT_NOEXCEPT {
  73. return (*this += -value);
  74. }
  75. storage_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
  76. return (*this + -value);
  77. }
  78. [[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT {
  79. const auto pos = index() - value;
  80. return (*packed)[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)];
  81. }
  82. [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
  83. const auto pos = index();
  84. return (*packed)[pos / comp_traits::page_size] + fast_mod(pos, comp_traits::page_size);
  85. }
  86. [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
  87. return *operator->();
  88. }
  89. [[nodiscard]] difference_type index() const ENTT_NOEXCEPT {
  90. return offset - 1;
  91. }
  92. private:
  93. Container *packed;
  94. difference_type offset;
  95. };
  96. template<typename CLhs, typename CRhs>
  97. [[nodiscard]] std::ptrdiff_t operator-(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) ENTT_NOEXCEPT {
  98. return rhs.index() - lhs.index();
  99. }
  100. template<typename CLhs, typename CRhs>
  101. [[nodiscard]] bool operator==(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) ENTT_NOEXCEPT {
  102. return lhs.index() == rhs.index();
  103. }
  104. template<typename CLhs, typename CRhs>
  105. [[nodiscard]] bool operator!=(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) ENTT_NOEXCEPT {
  106. return !(lhs == rhs);
  107. }
  108. template<typename CLhs, typename CRhs>
  109. [[nodiscard]] bool operator<(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) ENTT_NOEXCEPT {
  110. return lhs.index() > rhs.index();
  111. }
  112. template<typename CLhs, typename CRhs>
  113. [[nodiscard]] bool operator>(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) ENTT_NOEXCEPT {
  114. return lhs.index() < rhs.index();
  115. }
  116. template<typename CLhs, typename CRhs>
  117. [[nodiscard]] bool operator<=(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) ENTT_NOEXCEPT {
  118. return !(lhs > rhs);
  119. }
  120. template<typename CLhs, typename CRhs>
  121. [[nodiscard]] bool operator>=(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) ENTT_NOEXCEPT {
  122. return !(lhs < rhs);
  123. }
  124. template<typename It, typename... Other>
  125. class extended_storage_iterator final {
  126. template<typename Iter, typename... Args>
  127. friend class extended_storage_iterator;
  128. public:
  129. using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::forward_as_tuple(*std::declval<Other>()...)));
  130. using pointer = input_iterator_pointer<value_type>;
  131. using reference = value_type;
  132. using difference_type = std::ptrdiff_t;
  133. using iterator_category = std::input_iterator_tag;
  134. extended_storage_iterator() = default;
  135. extended_storage_iterator(It base, Other... other)
  136. : it{base, other...} {}
  137. template<typename... Args, typename = std::enable_if_t<(!std::is_same_v<Other, Args> && ...) && (std::is_constructible_v<Other, Args> && ...)>>
  138. extended_storage_iterator(const extended_storage_iterator<It, Args...> &other)
  139. : it{other.it} {}
  140. extended_storage_iterator &operator++() ENTT_NOEXCEPT {
  141. return ++std::get<It>(it), (++std::get<Other>(it), ...), *this;
  142. }
  143. extended_storage_iterator operator++(int) ENTT_NOEXCEPT {
  144. extended_storage_iterator orig = *this;
  145. return ++(*this), orig;
  146. }
  147. [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
  148. return operator*();
  149. }
  150. [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
  151. return {*std::get<It>(it), *std::get<Other>(it)...};
  152. }
  153. template<typename... CLhs, typename... CRhs>
  154. friend bool operator==(const extended_storage_iterator<CLhs...> &, const extended_storage_iterator<CRhs...> &) ENTT_NOEXCEPT;
  155. private:
  156. std::tuple<It, Other...> it;
  157. };
  158. template<typename... CLhs, typename... CRhs>
  159. [[nodiscard]] bool operator==(const extended_storage_iterator<CLhs...> &lhs, const extended_storage_iterator<CRhs...> &rhs) ENTT_NOEXCEPT {
  160. return std::get<0>(lhs.it) == std::get<0>(rhs.it);
  161. }
  162. template<typename... CLhs, typename... CRhs>
  163. [[nodiscard]] bool operator!=(const extended_storage_iterator<CLhs...> &lhs, const extended_storage_iterator<CRhs...> &rhs) ENTT_NOEXCEPT {
  164. return !(lhs == rhs);
  165. }
  166. } // namespace internal
  167. /**
  168. * Internal details not to be documented.
  169. * @endcond
  170. */
  171. /**
  172. * @brief Basic storage implementation.
  173. *
  174. * Internal data structures arrange elements to maximize performance. There are
  175. * no guarantees that objects are returned in the insertion order when iterate
  176. * a storage. Do not make assumption on the order in any case.
  177. *
  178. * @warning
  179. * Empty types aren't explicitly instantiated. Therefore, many of the functions
  180. * normally available for non-empty types will not be available for empty ones.
  181. *
  182. * @tparam Entity A valid entity type (see entt_traits for more details).
  183. * @tparam Type Type of objects assigned to the entities.
  184. * @tparam Allocator Type of allocator used to manage memory and elements.
  185. */
  186. template<typename Entity, typename Type, typename Allocator, typename>
  187. class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
  188. static_assert(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>, "The type must be at least move constructible/assignable");
  189. using alloc_traits = std::allocator_traits<Allocator>;
  190. static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
  191. using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
  192. using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
  193. using comp_traits = component_traits<Type>;
  194. [[nodiscard]] auto &element_at(const std::size_t pos) const {
  195. return packed.first()[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)];
  196. }
  197. auto assure_at_least(const std::size_t pos) {
  198. auto &&container = packed.first();
  199. const auto idx = pos / comp_traits::page_size;
  200. if(!(idx < container.size())) {
  201. auto curr = container.size();
  202. container.resize(idx + 1u, nullptr);
  203. ENTT_TRY {
  204. for(const auto last = container.size(); curr < last; ++curr) {
  205. container[curr] = alloc_traits::allocate(packed.second(), comp_traits::page_size);
  206. }
  207. }
  208. ENTT_CATCH {
  209. container.resize(curr);
  210. ENTT_THROW;
  211. }
  212. }
  213. return container[idx] + fast_mod(pos, comp_traits::page_size);
  214. }
  215. template<typename... Args>
  216. auto emplace_element(const Entity entt, const bool force_back, Args &&...args) {
  217. const auto it = base_type::try_emplace(entt, force_back);
  218. ENTT_TRY {
  219. auto elem = assure_at_least(static_cast<size_type>(it.index()));
  220. entt::uninitialized_construct_using_allocator(to_address(elem), packed.second(), std::forward<Args>(args)...);
  221. }
  222. ENTT_CATCH {
  223. if constexpr(comp_traits::in_place_delete) {
  224. base_type::in_place_pop(it, it + 1u);
  225. } else {
  226. base_type::swap_and_pop(it, it + 1u);
  227. }
  228. ENTT_THROW;
  229. }
  230. return it;
  231. }
  232. void shrink_to_size(const std::size_t sz) {
  233. for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
  234. if constexpr(comp_traits::in_place_delete) {
  235. if(base_type::at(pos) != tombstone) {
  236. std::destroy_at(std::addressof(element_at(pos)));
  237. }
  238. } else {
  239. std::destroy_at(std::addressof(element_at(pos)));
  240. }
  241. }
  242. auto &&container = packed.first();
  243. auto page_allocator{packed.second()};
  244. const auto from = (sz + comp_traits::page_size - 1u) / comp_traits::page_size;
  245. for(auto pos = from, last = container.size(); pos < last; ++pos) {
  246. alloc_traits::deallocate(page_allocator, container[pos], comp_traits::page_size);
  247. }
  248. container.resize(from);
  249. }
  250. private:
  251. const void *get_at(const std::size_t pos) const final {
  252. return std::addressof(element_at(pos));
  253. }
  254. void swap_at(const std::size_t lhs, const std::size_t rhs) final {
  255. using std::swap;
  256. swap(element_at(lhs), element_at(rhs));
  257. }
  258. void move_element(const std::size_t from, const std::size_t to) final {
  259. auto &elem = element_at(from);
  260. entt::uninitialized_construct_using_allocator(to_address(assure_at_least(to)), packed.second(), std::move(elem));
  261. std::destroy_at(std::addressof(elem));
  262. }
  263. protected:
  264. /**
  265. * @brief Erases elements from a storage.
  266. * @param first An iterator to the first element to erase.
  267. * @param last An iterator past the last element to erase.
  268. */
  269. void swap_and_pop(typename underlying_type::basic_iterator first, typename underlying_type::basic_iterator last) override {
  270. for(; first != last; ++first) {
  271. // cannot use first::index() because it would break with cross iterators
  272. const auto pos = base_type::index(*first);
  273. auto &elem = element_at(base_type::size() - 1u);
  274. // destroying on exit allows reentrant destructors
  275. [[maybe_unused]] auto unused = std::exchange(element_at(pos), std::move(elem));
  276. std::destroy_at(std::addressof(elem));
  277. base_type::swap_and_pop(first, first + 1u);
  278. }
  279. }
  280. /**
  281. * @brief Erases elements from a storage.
  282. * @param first An iterator to the first element to erase.
  283. * @param last An iterator past the last element to erase.
  284. */
  285. void in_place_pop(typename underlying_type::basic_iterator first, typename underlying_type::basic_iterator last) override {
  286. for(; first != last; ++first) {
  287. // cannot use first::index() because it would break with cross iterators
  288. const auto pos = base_type::index(*first);
  289. base_type::in_place_pop(first, first + 1u);
  290. std::destroy_at(std::addressof(element_at(pos)));
  291. }
  292. }
  293. /**
  294. * @brief Assigns an entity to a storage.
  295. * @param entt A valid identifier.
  296. * @param value Optional opaque value.
  297. * @param force_back Force back insertion.
  298. * @return Iterator pointing to the emplaced element.
  299. */
  300. typename underlying_type::basic_iterator try_emplace([[maybe_unused]] const Entity entt, const bool force_back, const void *value) override {
  301. if(value) {
  302. if constexpr(std::is_copy_constructible_v<value_type>) {
  303. return emplace_element(entt, force_back, *static_cast<const value_type *>(value));
  304. } else {
  305. return base_type::end();
  306. }
  307. } else {
  308. if constexpr(std::is_default_constructible_v<value_type>) {
  309. return emplace_element(entt, force_back);
  310. } else {
  311. return base_type::end();
  312. }
  313. }
  314. }
  315. public:
  316. /*! @brief Base type. */
  317. using base_type = underlying_type;
  318. /*! @brief Allocator type. */
  319. using allocator_type = Allocator;
  320. /*! @brief Type of the objects assigned to entities. */
  321. using value_type = Type;
  322. /*! @brief Underlying entity identifier. */
  323. using entity_type = Entity;
  324. /*! @brief Unsigned integer type. */
  325. using size_type = std::size_t;
  326. /*! @brief Pointer type to contained elements. */
  327. using pointer = typename container_type::pointer;
  328. /*! @brief Constant pointer type to contained elements. */
  329. using const_pointer = typename alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
  330. /*! @brief Random access iterator type. */
  331. using iterator = internal::storage_iterator<container_type>;
  332. /*! @brief Constant random access iterator type. */
  333. using const_iterator = internal::storage_iterator<const container_type>;
  334. /*! @brief Reverse iterator type. */
  335. using reverse_iterator = std::reverse_iterator<iterator>;
  336. /*! @brief Constant reverse iterator type. */
  337. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  338. /*! @brief Extended iterable storage proxy. */
  339. using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator, iterator>>;
  340. /*! @brief Constant extended iterable storage proxy. */
  341. using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator, const_iterator>>;
  342. /*! @brief Default constructor. */
  343. basic_storage()
  344. : basic_storage{allocator_type{}} {}
  345. /**
  346. * @brief Constructs an empty storage with a given allocator.
  347. * @param allocator The allocator to use.
  348. */
  349. explicit basic_storage(const allocator_type &allocator)
  350. : base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete}, allocator},
  351. packed{container_type{allocator}, allocator} {}
  352. /**
  353. * @brief Move constructor.
  354. * @param other The instance to move from.
  355. */
  356. basic_storage(basic_storage &&other) ENTT_NOEXCEPT
  357. : base_type{std::move(other)},
  358. packed{std::move(other.packed)} {}
  359. /**
  360. * @brief Allocator-extended move constructor.
  361. * @param other The instance to move from.
  362. * @param allocator The allocator to use.
  363. */
  364. basic_storage(basic_storage &&other, const allocator_type &allocator) ENTT_NOEXCEPT
  365. : base_type{std::move(other), allocator},
  366. packed{container_type{std::move(other.packed.first()), allocator}, allocator} {
  367. ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.second() == other.packed.second(), "Copying a storage is not allowed");
  368. }
  369. /*! @brief Default destructor. */
  370. ~basic_storage() override {
  371. shrink_to_size(0u);
  372. }
  373. /**
  374. * @brief Move assignment operator.
  375. * @param other The instance to move from.
  376. * @return This storage.
  377. */
  378. basic_storage &operator=(basic_storage &&other) ENTT_NOEXCEPT {
  379. ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.second() == other.packed.second(), "Copying a storage is not allowed");
  380. shrink_to_size(0u);
  381. base_type::operator=(std::move(other));
  382. packed.first() = std::move(other.packed.first());
  383. propagate_on_container_move_assignment(packed.second(), other.packed.second());
  384. return *this;
  385. }
  386. /**
  387. * @brief Exchanges the contents with those of a given storage.
  388. * @param other Storage to exchange the content with.
  389. */
  390. void swap(basic_storage &other) {
  391. using std::swap;
  392. underlying_type::swap(other);
  393. propagate_on_container_swap(packed.second(), other.packed.second());
  394. swap(packed.first(), other.packed.first());
  395. }
  396. /**
  397. * @brief Returns the associated allocator.
  398. * @return The associated allocator.
  399. */
  400. [[nodiscard]] constexpr allocator_type get_allocator() const ENTT_NOEXCEPT {
  401. return allocator_type{packed.second()};
  402. }
  403. /**
  404. * @brief Increases the capacity of a storage.
  405. *
  406. * If the new capacity is greater than the current capacity, new storage is
  407. * allocated, otherwise the method does nothing.
  408. *
  409. * @param cap Desired capacity.
  410. */
  411. void reserve(const size_type cap) override {
  412. if(cap != 0u) {
  413. base_type::reserve(cap);
  414. assure_at_least(cap - 1u);
  415. }
  416. }
  417. /**
  418. * @brief Returns the number of elements that a storage has currently
  419. * allocated space for.
  420. * @return Capacity of the storage.
  421. */
  422. [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT override {
  423. return packed.first().size() * comp_traits::page_size;
  424. }
  425. /*! @brief Requests the removal of unused capacity. */
  426. void shrink_to_fit() override {
  427. base_type::shrink_to_fit();
  428. shrink_to_size(base_type::size());
  429. }
  430. /**
  431. * @brief Direct access to the array of objects.
  432. * @return A pointer to the array of objects.
  433. */
  434. [[nodiscard]] const_pointer raw() const ENTT_NOEXCEPT {
  435. return packed.first().data();
  436. }
  437. /*! @copydoc raw */
  438. [[nodiscard]] pointer raw() ENTT_NOEXCEPT {
  439. return packed.first().data();
  440. }
  441. /**
  442. * @brief Returns an iterator to the beginning.
  443. *
  444. * The returned iterator points to the first instance of the internal array.
  445. * If the storage is empty, the returned iterator will be equal to `end()`.
  446. *
  447. * @return An iterator to the first instance of the internal array.
  448. */
  449. [[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT {
  450. const auto pos = static_cast<typename iterator::difference_type>(base_type::size());
  451. return const_iterator{&packed.first(), pos};
  452. }
  453. /*! @copydoc cbegin */
  454. [[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT {
  455. return cbegin();
  456. }
  457. /*! @copydoc begin */
  458. [[nodiscard]] iterator begin() ENTT_NOEXCEPT {
  459. const auto pos = static_cast<typename iterator::difference_type>(base_type::size());
  460. return iterator{&packed.first(), pos};
  461. }
  462. /**
  463. * @brief Returns an iterator to the end.
  464. *
  465. * The returned iterator points to the element following the last instance
  466. * of the internal array. Attempting to dereference the returned iterator
  467. * results in undefined behavior.
  468. *
  469. * @return An iterator to the element following the last instance of the
  470. * internal array.
  471. */
  472. [[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT {
  473. return const_iterator{&packed.first(), {}};
  474. }
  475. /*! @copydoc cend */
  476. [[nodiscard]] const_iterator end() const ENTT_NOEXCEPT {
  477. return cend();
  478. }
  479. /*! @copydoc end */
  480. [[nodiscard]] iterator end() ENTT_NOEXCEPT {
  481. return iterator{&packed.first(), {}};
  482. }
  483. /**
  484. * @brief Returns a reverse iterator to the beginning.
  485. *
  486. * The returned iterator points to the first instance of the reversed
  487. * internal array. If the storage is empty, the returned iterator will be
  488. * equal to `rend()`.
  489. *
  490. * @return An iterator to the first instance of the reversed internal array.
  491. */
  492. [[nodiscard]] const_reverse_iterator crbegin() const ENTT_NOEXCEPT {
  493. return std::make_reverse_iterator(cend());
  494. }
  495. /*! @copydoc crbegin */
  496. [[nodiscard]] const_reverse_iterator rbegin() const ENTT_NOEXCEPT {
  497. return crbegin();
  498. }
  499. /*! @copydoc rbegin */
  500. [[nodiscard]] reverse_iterator rbegin() ENTT_NOEXCEPT {
  501. return std::make_reverse_iterator(end());
  502. }
  503. /**
  504. * @brief Returns a reverse iterator to the end.
  505. *
  506. * The returned iterator points to the element following the last instance
  507. * of the reversed internal array. Attempting to dereference the returned
  508. * iterator results in undefined behavior.
  509. *
  510. * @return An iterator to the element following the last instance of the
  511. * reversed internal array.
  512. */
  513. [[nodiscard]] const_reverse_iterator crend() const ENTT_NOEXCEPT {
  514. return std::make_reverse_iterator(cbegin());
  515. }
  516. /*! @copydoc crend */
  517. [[nodiscard]] const_reverse_iterator rend() const ENTT_NOEXCEPT {
  518. return crend();
  519. }
  520. /*! @copydoc rend */
  521. [[nodiscard]] reverse_iterator rend() ENTT_NOEXCEPT {
  522. return std::make_reverse_iterator(begin());
  523. }
  524. /**
  525. * @brief Returns the object assigned to an entity.
  526. *
  527. * @warning
  528. * Attempting to use an entity that doesn't belong to the storage results in
  529. * undefined behavior.
  530. *
  531. * @param entt A valid identifier.
  532. * @return The object assigned to the entity.
  533. */
  534. [[nodiscard]] const value_type &get(const entity_type entt) const ENTT_NOEXCEPT {
  535. return element_at(base_type::index(entt));
  536. }
  537. /*! @copydoc get */
  538. [[nodiscard]] value_type &get(const entity_type entt) ENTT_NOEXCEPT {
  539. return const_cast<value_type &>(std::as_const(*this).get(entt));
  540. }
  541. /**
  542. * @brief Returns the object assigned to an entity as a tuple.
  543. * @param entt A valid identifier.
  544. * @return The object assigned to the entity as a tuple.
  545. */
  546. [[nodiscard]] std::tuple<const value_type &> get_as_tuple(const entity_type entt) const ENTT_NOEXCEPT {
  547. return std::forward_as_tuple(get(entt));
  548. }
  549. /*! @copydoc get_as_tuple */
  550. [[nodiscard]] std::tuple<value_type &> get_as_tuple(const entity_type entt) ENTT_NOEXCEPT {
  551. return std::forward_as_tuple(get(entt));
  552. }
  553. /**
  554. * @brief Assigns an entity to a storage and constructs its object.
  555. *
  556. * @warning
  557. * Attempting to use an entity that already belongs to the storage results
  558. * in undefined behavior.
  559. *
  560. * @tparam Args Types of arguments to use to construct the object.
  561. * @param entt A valid identifier.
  562. * @param args Parameters to use to construct an object for the entity.
  563. * @return A reference to the newly created object.
  564. */
  565. template<typename... Args>
  566. value_type &emplace(const entity_type entt, Args &&...args) {
  567. if constexpr(std::is_aggregate_v<value_type>) {
  568. const auto it = emplace_element(entt, false, Type{std::forward<Args>(args)...});
  569. return element_at(static_cast<size_type>(it.index()));
  570. } else {
  571. const auto it = emplace_element(entt, false, std::forward<Args>(args)...);
  572. return element_at(static_cast<size_type>(it.index()));
  573. }
  574. }
  575. /**
  576. * @brief Updates the instance assigned to a given entity in-place.
  577. * @tparam Func Types of the function objects to invoke.
  578. * @param entt A valid identifier.
  579. * @param func Valid function objects.
  580. * @return A reference to the updated instance.
  581. */
  582. template<typename... Func>
  583. value_type &patch(const entity_type entt, Func &&...func) {
  584. const auto idx = base_type::index(entt);
  585. auto &elem = element_at(idx);
  586. (std::forward<Func>(func)(elem), ...);
  587. return elem;
  588. }
  589. /**
  590. * @brief Assigns one or more entities to a storage and constructs their
  591. * objects from a given instance.
  592. *
  593. * @warning
  594. * Attempting to assign an entity that already belongs to the storage
  595. * results in undefined behavior.
  596. *
  597. * @tparam It Type of input iterator.
  598. * @param first An iterator to the first element of the range of entities.
  599. * @param last An iterator past the last element of the range of entities.
  600. * @param value An instance of the object to construct.
  601. */
  602. template<typename It>
  603. void insert(It first, It last, const value_type &value = {}) {
  604. for(; first != last; ++first) {
  605. emplace_element(*first, true, value);
  606. }
  607. }
  608. /**
  609. * @brief Assigns one or more entities to a storage and constructs their
  610. * objects from a given range.
  611. *
  612. * @sa construct
  613. *
  614. * @tparam EIt Type of input iterator.
  615. * @tparam CIt Type of input iterator.
  616. * @param first An iterator to the first element of the range of entities.
  617. * @param last An iterator past the last element of the range of entities.
  618. * @param from An iterator to the first element of the range of objects.
  619. */
  620. template<typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, value_type>>>
  621. void insert(EIt first, EIt last, CIt from) {
  622. for(; first != last; ++first, ++from) {
  623. emplace_element(*first, true, *from);
  624. }
  625. }
  626. /**
  627. * @brief Returns an iterable object to use to _visit_ a storage.
  628. *
  629. * The iterable object returns a tuple that contains the current entity and
  630. * a reference to its component.
  631. *
  632. * @return An iterable object to use to _visit_ the storage.
  633. */
  634. [[nodiscard]] iterable each() ENTT_NOEXCEPT {
  635. return {internal::extended_storage_iterator{base_type::begin(), begin()}, internal::extended_storage_iterator{base_type::end(), end()}};
  636. }
  637. /*! @copydoc each */
  638. [[nodiscard]] const_iterable each() const ENTT_NOEXCEPT {
  639. return {internal::extended_storage_iterator{base_type::cbegin(), cbegin()}, internal::extended_storage_iterator{base_type::cend(), cend()}};
  640. }
  641. private:
  642. compressed_pair<container_type, allocator_type> packed;
  643. };
  644. /*! @copydoc basic_storage */
  645. template<typename Entity, typename Type, typename Allocator>
  646. class basic_storage<Entity, Type, Allocator, std::enable_if_t<ignore_as_empty_v<Type>>>
  647. : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
  648. using alloc_traits = std::allocator_traits<Allocator>;
  649. static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
  650. using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
  651. using comp_traits = component_traits<Type>;
  652. public:
  653. /*! @brief Base type. */
  654. using base_type = underlying_type;
  655. /*! @brief Allocator type. */
  656. using allocator_type = Allocator;
  657. /*! @brief Type of the objects assigned to entities. */
  658. using value_type = Type;
  659. /*! @brief Underlying entity identifier. */
  660. using entity_type = Entity;
  661. /*! @brief Unsigned integer type. */
  662. using size_type = std::size_t;
  663. /*! @brief Extended iterable storage proxy. */
  664. using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
  665. /*! @brief Constant extended iterable storage proxy. */
  666. using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator>>;
  667. /*! @brief Default constructor. */
  668. basic_storage()
  669. : basic_storage{allocator_type{}} {}
  670. /**
  671. * @brief Constructs an empty container with a given allocator.
  672. * @param allocator The allocator to use.
  673. */
  674. explicit basic_storage(const allocator_type &allocator)
  675. : base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete}, allocator} {}
  676. /**
  677. * @brief Move constructor.
  678. * @param other The instance to move from.
  679. */
  680. basic_storage(basic_storage &&other) ENTT_NOEXCEPT = default;
  681. /**
  682. * @brief Allocator-extended move constructor.
  683. * @param other The instance to move from.
  684. * @param allocator The allocator to use.
  685. */
  686. basic_storage(basic_storage &&other, const allocator_type &allocator) ENTT_NOEXCEPT
  687. : base_type{std::move(other), allocator} {}
  688. /**
  689. * @brief Move assignment operator.
  690. * @param other The instance to move from.
  691. * @return This storage.
  692. */
  693. basic_storage &operator=(basic_storage &&other) ENTT_NOEXCEPT = default;
  694. /**
  695. * @brief Returns the associated allocator.
  696. * @return The associated allocator.
  697. */
  698. [[nodiscard]] constexpr allocator_type get_allocator() const ENTT_NOEXCEPT {
  699. return allocator_type{base_type::get_allocator()};
  700. }
  701. /**
  702. * @brief Returns the object assigned to an entity, that is `void`.
  703. *
  704. * @warning
  705. * Attempting to use an entity that doesn't belong to the storage results in
  706. * undefined behavior.
  707. *
  708. * @param entt A valid identifier.
  709. */
  710. void get([[maybe_unused]] const entity_type entt) const ENTT_NOEXCEPT {
  711. ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity");
  712. }
  713. /**
  714. * @brief Returns an empty tuple.
  715. *
  716. * @warning
  717. * Attempting to use an entity that doesn't belong to the storage results in
  718. * undefined behavior.
  719. *
  720. * @param entt A valid identifier.
  721. * @return Returns an empty tuple.
  722. */
  723. [[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const ENTT_NOEXCEPT {
  724. ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity");
  725. return std::tuple{};
  726. }
  727. /**
  728. * @brief Assigns an entity to a storage and constructs its object.
  729. *
  730. * @warning
  731. * Attempting to use an entity that already belongs to the storage results
  732. * in undefined behavior.
  733. *
  734. * @tparam Args Types of arguments to use to construct the object.
  735. * @param entt A valid identifier.
  736. */
  737. template<typename... Args>
  738. void emplace(const entity_type entt, Args &&...) {
  739. base_type::try_emplace(entt, false);
  740. }
  741. /**
  742. * @brief Updates the instance assigned to a given entity in-place.
  743. * @tparam Func Types of the function objects to invoke.
  744. * @param entt A valid identifier.
  745. * @param func Valid function objects.
  746. */
  747. template<typename... Func>
  748. void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
  749. ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity");
  750. (std::forward<Func>(func)(), ...);
  751. }
  752. /**
  753. * @brief Assigns entities to a storage.
  754. * @tparam It Type of input iterator.
  755. * @tparam Args Types of optional arguments.
  756. * @param first An iterator to the first element of the range of entities.
  757. * @param last An iterator past the last element of the range of entities.
  758. */
  759. template<typename It, typename... Args>
  760. void insert(It first, It last, Args &&...) {
  761. for(; first != last; ++first) {
  762. base_type::try_emplace(*first, true);
  763. }
  764. }
  765. /**
  766. * @brief Returns an iterable object to use to _visit_ a storage.
  767. *
  768. * The iterable object returns a tuple that contains the current entity.
  769. *
  770. * @return An iterable object to use to _visit_ the storage.
  771. */
  772. [[nodiscard]] iterable each() ENTT_NOEXCEPT {
  773. return {internal::extended_storage_iterator{base_type::begin()}, internal::extended_storage_iterator{base_type::end()}};
  774. }
  775. /*! @copydoc each */
  776. [[nodiscard]] const_iterable each() const ENTT_NOEXCEPT {
  777. return {internal::extended_storage_iterator{base_type::cbegin()}, internal::extended_storage_iterator{base_type::cend()}};
  778. }
  779. };
  780. /**
  781. * @brief Provides a common way to access certain properties of storage types.
  782. * @tparam Entity A valid entity type (see entt_traits for more details).
  783. * @tparam Type Type of objects managed by the storage class.
  784. */
  785. template<typename Entity, typename Type, typename = void>
  786. struct storage_traits {
  787. /*! @brief Resulting type after component-to-storage conversion. */
  788. using storage_type = sigh_storage_mixin<basic_storage<Entity, Type>>;
  789. };
  790. } // namespace entt
  791. #endif