view.hpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. #ifndef ENTT_ENTITY_VIEW_HPP
  2. #define ENTT_ENTITY_VIEW_HPP
  3. #include <array>
  4. #include <iterator>
  5. #include <tuple>
  6. #include <type_traits>
  7. #include <utility>
  8. #include "../config/config.h"
  9. #include "../core/iterator.hpp"
  10. #include "../core/type_traits.hpp"
  11. #include "entity.hpp"
  12. #include "fwd.hpp"
  13. namespace entt {
  14. /**
  15. * @cond TURN_OFF_DOXYGEN
  16. * Internal details not to be documented.
  17. */
  18. namespace internal {
  19. template<typename Type, typename Entity>
  20. [[nodiscard]] auto all_of(const Type *elem, const std::size_t len, const Entity entt) noexcept {
  21. std::size_t pos{};
  22. for(; pos < len && elem[pos]->contains(entt); ++pos) {}
  23. return pos == len;
  24. }
  25. template<typename Type, typename Entity>
  26. [[nodiscard]] auto none_of(const Type *elem, const std::size_t len, const Entity entt) noexcept {
  27. std::size_t pos{};
  28. for(; pos < len && !(elem[pos] && elem[pos]->contains(entt)); ++pos) {}
  29. return pos == len;
  30. }
  31. template<typename Type>
  32. [[nodiscard]] auto fully_initialized(const Type *elem, const std::size_t len) noexcept {
  33. std::size_t pos{};
  34. for(; pos < len && elem[pos] != nullptr; ++pos) {}
  35. return pos == len;
  36. }
  37. template<typename Type, typename View, typename Other, std::size_t... VGet, std::size_t... VExclude, std::size_t... OGet, std::size_t... OExclude>
  38. [[nodiscard]] auto view_pack(const View &view, const Other &other, std::index_sequence<VGet...>, std::index_sequence<VExclude...>, std::index_sequence<OGet...>, std::index_sequence<OExclude...>) {
  39. Type elem{};
  40. // friend-initialization, avoid multiple calls to refresh
  41. elem.pools = {view.template storage<VGet>()..., other.template storage<OGet>()...};
  42. elem.filter = {view.template storage<sizeof...(VGet) + VExclude>()..., other.template storage<sizeof...(OGet) + OExclude>()...};
  43. elem.refresh();
  44. return elem;
  45. }
  46. template<typename Type, std::size_t Get, std::size_t Exclude>
  47. class view_iterator final {
  48. using iterator_type = typename Type::const_iterator;
  49. [[nodiscard]] bool valid(const typename iterator_type::value_type entt) const noexcept {
  50. return ((Get != 0u) || (entt != tombstone)) && (all_of(pools.data(), Get, entt)) && none_of(filter.data(), Exclude, entt);
  51. }
  52. public:
  53. using value_type = typename iterator_type::value_type;
  54. using pointer = typename iterator_type::pointer;
  55. using reference = typename iterator_type::reference;
  56. using difference_type = typename iterator_type::difference_type;
  57. using iterator_category = std::forward_iterator_tag;
  58. constexpr view_iterator() noexcept
  59. : it{},
  60. last{},
  61. pools{},
  62. filter{} {}
  63. view_iterator(iterator_type curr, iterator_type to, std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl) noexcept
  64. : it{curr},
  65. last{to},
  66. pools{value},
  67. filter{excl} {
  68. while(it != last && !valid(*it)) {
  69. ++it;
  70. }
  71. }
  72. view_iterator &operator++() noexcept {
  73. while(++it != last && !valid(*it)) {}
  74. return *this;
  75. }
  76. view_iterator operator++(int) noexcept {
  77. view_iterator orig = *this;
  78. return ++(*this), orig;
  79. }
  80. [[nodiscard]] pointer operator->() const noexcept {
  81. return &*it;
  82. }
  83. [[nodiscard]] reference operator*() const noexcept {
  84. return *operator->();
  85. }
  86. template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
  87. friend constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &, const view_iterator<RhsType, RhsArgs...> &) noexcept;
  88. private:
  89. iterator_type it;
  90. iterator_type last;
  91. std::array<const Type *, Get> pools;
  92. std::array<const Type *, Exclude> filter;
  93. };
  94. template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
  95. [[nodiscard]] constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
  96. return lhs.it == rhs.it;
  97. }
  98. template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
  99. [[nodiscard]] constexpr bool operator!=(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
  100. return !(lhs == rhs);
  101. }
  102. template<typename It, typename... Type>
  103. struct extended_view_iterator final {
  104. using iterator_type = It;
  105. using difference_type = std::ptrdiff_t;
  106. using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Type>().get_as_tuple({})...));
  107. using pointer = input_iterator_pointer<value_type>;
  108. using reference = value_type;
  109. using iterator_category = std::input_iterator_tag;
  110. using iterator_concept = std::forward_iterator_tag;
  111. constexpr extended_view_iterator()
  112. : it{},
  113. pools{} {}
  114. extended_view_iterator(iterator_type from, std::tuple<Type *...> value)
  115. : it{from},
  116. pools{value} {}
  117. extended_view_iterator &operator++() noexcept {
  118. return ++it, *this;
  119. }
  120. extended_view_iterator operator++(int) noexcept {
  121. extended_view_iterator orig = *this;
  122. return ++(*this), orig;
  123. }
  124. [[nodiscard]] reference operator*() const noexcept {
  125. return std::apply([entt = *it](auto *...curr) { return std::tuple_cat(std::make_tuple(entt), curr->get_as_tuple(entt)...); }, pools);
  126. }
  127. [[nodiscard]] pointer operator->() const noexcept {
  128. return operator*();
  129. }
  130. [[nodiscard]] constexpr iterator_type base() const noexcept {
  131. return it;
  132. }
  133. template<typename... Lhs, typename... Rhs>
  134. friend bool constexpr operator==(const extended_view_iterator<Lhs...> &, const extended_view_iterator<Rhs...> &) noexcept;
  135. private:
  136. It it;
  137. std::tuple<Type *...> pools;
  138. };
  139. template<typename... Lhs, typename... Rhs>
  140. [[nodiscard]] constexpr bool operator==(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
  141. return lhs.it == rhs.it;
  142. }
  143. template<typename... Lhs, typename... Rhs>
  144. [[nodiscard]] constexpr bool operator!=(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
  145. return !(lhs == rhs);
  146. }
  147. } // namespace internal
  148. /**
  149. * Internal details not to be documented.
  150. * @endcond
  151. */
  152. /**
  153. * @brief View implementation.
  154. *
  155. * Primary template isn't defined on purpose. All the specializations give a
  156. * compile-time error, but for a few reasonable cases.
  157. *
  158. * @b Important
  159. *
  160. * View iterators aren't invalidated if:
  161. *
  162. * * New elements are added to the storage iterated by the view.
  163. * * The entity currently returned is modified (for example, components are
  164. * added or removed from it).
  165. * * The entity currently returned is destroyed.
  166. *
  167. * In all other cases, modifying the storage iterated by a view in any way can
  168. * invalidate all iterators.
  169. */
  170. template<typename, typename, typename>
  171. class basic_view;
  172. /**
  173. * @brief General purpose view.
  174. *
  175. * This view visits all entities that are at least in the given storage. During
  176. * initialization, it also looks at the number of elements available for each
  177. * storage and uses the smallest set in order to get a performance boost.
  178. *
  179. * @sa basic_view
  180. *
  181. * @tparam Get Types of storage iterated by the view.
  182. * @tparam Exclude Types of storage used to filter the view.
  183. */
  184. template<typename... Get, typename... Exclude>
  185. class basic_view<get_t<Get...>, exclude_t<Exclude...>> {
  186. template<typename Type, typename View, typename Other, std::size_t... VGet, std::size_t... VExclude, std::size_t... OGet, std::size_t... OExclude>
  187. friend auto internal::view_pack(const View &, const Other &, std::index_sequence<VGet...>, std::index_sequence<VExclude...>, std::index_sequence<OGet...>, std::index_sequence<OExclude...>);
  188. using base_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
  189. using underlying_type = typename base_type::entity_type;
  190. template<typename Type>
  191. static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::value_type..., typename Exclude::value_type...>>;
  192. [[nodiscard]] auto opaque_check_set() const noexcept {
  193. std::array<const common_type *, sizeof...(Get) - 1u> other{};
  194. std::apply([&other, pos = 0u, view = view](const auto *...curr) mutable { ((curr == view ? void() : void(other[pos++] = curr)), ...); }, pools);
  195. return other;
  196. }
  197. void unchecked_refresh() noexcept {
  198. view = std::get<0>(pools);
  199. std::apply([this](auto *, auto *...other) { ((this->view = other->size() < this->view->size() ? other : this->view), ...); }, pools);
  200. }
  201. template<std::size_t Curr, std::size_t Other, typename... Args>
  202. [[nodiscard]] auto dispatch_get(const std::tuple<underlying_type, Args...> &curr) const {
  203. if constexpr(Curr == Other) {
  204. return std::forward_as_tuple(std::get<Args>(curr)...);
  205. } else {
  206. return std::get<Other>(pools)->get_as_tuple(std::get<0>(curr));
  207. }
  208. }
  209. template<std::size_t Curr, typename Func, std::size_t... Index>
  210. void each(Func &func, std::index_sequence<Index...>) const {
  211. for(const auto curr: std::get<Curr>(pools)->each()) {
  212. if(const auto entt = std::get<0>(curr); ((sizeof...(Get) != 1u) || (entt != tombstone)) && ((Curr == Index || std::get<Index>(pools)->contains(entt)) && ...) && internal::none_of(filter.data(), filter.size(), entt)) {
  213. if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
  214. std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get<Curr, Index>(curr)...));
  215. } else {
  216. std::apply(func, std::tuple_cat(dispatch_get<Curr, Index>(curr)...));
  217. }
  218. }
  219. }
  220. }
  221. template<typename Func, std::size_t... Index>
  222. void pick_and_each(Func &func, std::index_sequence<Index...> seq) const {
  223. ((std::get<Index>(pools) == view ? each<Index>(func, seq) : void()), ...);
  224. }
  225. public:
  226. /*! @brief Common type among all storage types. */
  227. using common_type = base_type;
  228. /*! @brief Underlying entity identifier. */
  229. using entity_type = underlying_type;
  230. /*! @brief Unsigned integer type. */
  231. using size_type = std::size_t;
  232. /*! @brief Bidirectional iterator type. */
  233. using iterator = internal::view_iterator<common_type, sizeof...(Get) - 1u, sizeof...(Exclude)>;
  234. /*! @brief Iterable view type. */
  235. using iterable = iterable_adaptor<internal::extended_view_iterator<iterator, Get...>>;
  236. /*! @brief Default constructor to use to create empty, invalid views. */
  237. basic_view() noexcept
  238. : pools{},
  239. filter{},
  240. view{} {}
  241. /**
  242. * @brief Constructs a view from a set of storage classes.
  243. * @param value The storage for the types to iterate.
  244. * @param excl The storage for the types used to filter the view.
  245. */
  246. basic_view(Get &...value, Exclude &...excl) noexcept
  247. : pools{&value...},
  248. filter{&excl...},
  249. view{} {
  250. unchecked_refresh();
  251. }
  252. /**
  253. * @brief Constructs a view from a set of storage classes.
  254. * @param value The storage for the types to iterate.
  255. * @param excl The storage for the types used to filter the view.
  256. */
  257. basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...> excl = {}) noexcept
  258. : basic_view{std::make_from_tuple<basic_view>(std::tuple_cat(value, excl))} {}
  259. /**
  260. * @brief Forces a view to use a given component to drive iterations
  261. * @tparam Type Type of component to use to drive iterations.
  262. */
  263. template<typename Type>
  264. void use() noexcept {
  265. use<index_of<Type>>();
  266. }
  267. /**
  268. * @brief Forces a view to use a given component to drive iterations
  269. * @tparam Index Index of the component to use to drive iterations.
  270. */
  271. template<std::size_t Index>
  272. void use() noexcept {
  273. if(view) {
  274. view = std::get<Index>(pools);
  275. }
  276. }
  277. /*! @brief Updates the internal leading view if required. */
  278. void refresh() noexcept {
  279. if(view || std::apply([](const auto *...curr) { return ((curr != nullptr) && ...); }, pools)) {
  280. unchecked_refresh();
  281. }
  282. }
  283. /**
  284. * @brief Returns the leading storage of a view, if any.
  285. * @return The leading storage of the view.
  286. */
  287. [[nodiscard]] const common_type *handle() const noexcept {
  288. return view;
  289. }
  290. /**
  291. * @brief Returns the storage for a given component type, if any.
  292. * @tparam Type Type of component of which to return the storage.
  293. * @return The storage for the given component type.
  294. */
  295. template<typename Type>
  296. [[nodiscard]] auto *storage() const noexcept {
  297. return storage<index_of<Type>>();
  298. }
  299. /**
  300. * @brief Returns the storage for a given index, if any.
  301. * @tparam Index Index of the storage to return.
  302. * @return The storage for the given index.
  303. */
  304. template<std::size_t Index>
  305. [[nodiscard]] auto *storage() const noexcept {
  306. if constexpr(Index < sizeof...(Get)) {
  307. return std::get<Index>(pools);
  308. } else {
  309. using type = type_list_element_t<Index - sizeof...(Get), type_list<Exclude...>>;
  310. return static_cast<type *>(const_cast<constness_as_t<common_type, type> *>(filter[Index - sizeof...(Get)]));
  311. }
  312. }
  313. /**
  314. * @brief Assigns a storage to a view.
  315. * @tparam Type Type of storage to assign to the view.
  316. * @param elem A storage to assign to the view.
  317. */
  318. template<typename Type>
  319. void storage(Type &elem) noexcept {
  320. storage<index_of<typename Type::value_type>>(elem);
  321. }
  322. /**
  323. * @brief Assigns a storage to a view.
  324. * @tparam Index Index of the storage to assign to the view.
  325. * @tparam Type Type of storage to assign to the view.
  326. * @param elem A storage to assign to the view.
  327. */
  328. template<std::size_t Index, typename Type>
  329. void storage(Type &elem) noexcept {
  330. if constexpr(Index < sizeof...(Get)) {
  331. std::get<Index>(pools) = &elem;
  332. refresh();
  333. } else {
  334. std::get<Index - sizeof...(Get)>(filter) = &elem;
  335. }
  336. }
  337. /**
  338. * @brief Estimates the number of entities iterated by the view.
  339. * @return Estimated number of entities iterated by the view.
  340. */
  341. [[nodiscard]] size_type size_hint() const noexcept {
  342. return view ? view->size() : size_type{};
  343. }
  344. /**
  345. * @brief Returns an iterator to the first entity of the view.
  346. *
  347. * If the view is empty, the returned iterator will be equal to `end()`.
  348. *
  349. * @return An iterator to the first entity of the view.
  350. */
  351. [[nodiscard]] iterator begin() const noexcept {
  352. return view ? iterator{view->begin(0), view->end(0), opaque_check_set(), filter} : iterator{};
  353. }
  354. /**
  355. * @brief Returns an iterator that is past the last entity of the view.
  356. * @return An iterator to the entity following the last entity of the view.
  357. */
  358. [[nodiscard]] iterator end() const noexcept {
  359. return view ? iterator{view->end(0), view->end(0), opaque_check_set(), filter} : iterator{};
  360. }
  361. /**
  362. * @brief Returns the first entity of the view, if any.
  363. * @return The first entity of the view if one exists, the null entity
  364. * otherwise.
  365. */
  366. [[nodiscard]] entity_type front() const noexcept {
  367. const auto it = begin();
  368. return it != end() ? *it : null;
  369. }
  370. /**
  371. * @brief Returns the last entity of the view, if any.
  372. * @return The last entity of the view if one exists, the null entity
  373. * otherwise.
  374. */
  375. [[nodiscard]] entity_type back() const noexcept {
  376. if(view) {
  377. auto it = view->rbegin(0);
  378. const auto last = view->rend(0);
  379. for(; it != last && !contains(*it); ++it) {}
  380. return it == last ? null : *it;
  381. }
  382. return null;
  383. }
  384. /**
  385. * @brief Finds an entity.
  386. * @param entt A valid identifier.
  387. * @return An iterator to the given entity if it's found, past the end
  388. * iterator otherwise.
  389. */
  390. [[nodiscard]] iterator find(const entity_type entt) const noexcept {
  391. return contains(entt) ? iterator{view->find(entt), view->end(), opaque_check_set(), filter} : end();
  392. }
  393. /**
  394. * @brief Returns the components assigned to the given entity.
  395. * @param entt A valid identifier.
  396. * @return The components assigned to the given entity.
  397. */
  398. [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
  399. return get(entt);
  400. }
  401. /**
  402. * @brief Checks if a view is fully initialized.
  403. * @return True if the view is fully initialized, false otherwise.
  404. */
  405. [[nodiscard]] explicit operator bool() const noexcept {
  406. return std::apply([](const auto *...curr) { return ((curr != nullptr) && ...); }, pools) && internal::fully_initialized(filter.data(), filter.size());
  407. }
  408. /**
  409. * @brief Checks if a view contains an entity.
  410. * @param entt A valid identifier.
  411. * @return True if the view contains the given entity, false otherwise.
  412. */
  413. [[nodiscard]] bool contains(const entity_type entt) const noexcept {
  414. if(view) {
  415. auto check = opaque_check_set();
  416. const auto idx = view->find(entt).index();
  417. return (!(idx < 0 || idx > view->begin(0).index())) && internal::all_of(check.data(), check.size(), entt) && internal::none_of(filter.data(), filter.size(), entt);
  418. }
  419. return false;
  420. }
  421. /**
  422. * @brief Returns the components assigned to the given entity.
  423. * @tparam Type Type of the component to get.
  424. * @tparam Other Other types of components to get.
  425. * @param entt A valid identifier.
  426. * @return The components assigned to the entity.
  427. */
  428. template<typename Type, typename... Other>
  429. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  430. return get<index_of<Type>, index_of<Other>...>(entt);
  431. }
  432. /**
  433. * @brief Returns the components assigned to the given entity.
  434. * @tparam Index Indexes of the components to get.
  435. * @param entt A valid identifier.
  436. * @return The components assigned to the entity.
  437. */
  438. template<std::size_t... Index>
  439. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  440. if constexpr(sizeof...(Index) == 0) {
  441. return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, pools);
  442. } else if constexpr(sizeof...(Index) == 1) {
  443. return (std::get<Index>(pools)->get(entt), ...);
  444. } else {
  445. return std::tuple_cat(std::get<Index>(pools)->get_as_tuple(entt)...);
  446. }
  447. }
  448. /**
  449. * @brief Iterates entities and components and applies the given function
  450. * object to them.
  451. *
  452. * The signature of the function must be equivalent to one of the following
  453. * (non-empty types only, constness as requested):
  454. *
  455. * @code{.cpp}
  456. * void(const entity_type, Type &...);
  457. * void(Type &...);
  458. * @endcode
  459. *
  460. * @tparam Func Type of the function object to invoke.
  461. * @param func A valid function object.
  462. */
  463. template<typename Func>
  464. void each(Func func) const {
  465. view ? pick_and_each(func, std::index_sequence_for<Get...>{}) : void();
  466. }
  467. /**
  468. * @brief Returns an iterable object to use to _visit_ a view.
  469. *
  470. * The iterable object returns a tuple that contains the current entity and
  471. * a set of references to its non-empty components. The _constness_ of the
  472. * components is as requested.
  473. *
  474. * @return An iterable object to use to _visit_ the view.
  475. */
  476. [[nodiscard]] iterable each() const noexcept {
  477. return {internal::extended_view_iterator{begin(), pools}, internal::extended_view_iterator{end(), pools}};
  478. }
  479. /**
  480. * @brief Combines two views in a _more specific_ one.
  481. * @tparam OGet Component list of the view to combine with.
  482. * @tparam OExclude Filter list of the view to combine with.
  483. * @param other The view to combine with.
  484. * @return A more specific view.
  485. */
  486. template<typename... OGet, typename... OExclude>
  487. [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
  488. return internal::view_pack<basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>>(
  489. *this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
  490. }
  491. private:
  492. std::tuple<Get *...> pools;
  493. std::array<const common_type *, sizeof...(Exclude)> filter;
  494. const common_type *view;
  495. };
  496. /**
  497. * @brief Storage view specialization.
  498. *
  499. * This specialization offers a boost in terms of performance. It can access the
  500. * underlying data structure directly and avoid superfluous checks.
  501. *
  502. * @sa basic_view
  503. *
  504. * @tparam Get Type of storage iterated by the view.
  505. */
  506. template<typename Get>
  507. class basic_view<get_t<Get>, exclude_t<>, std::void_t<std::enable_if_t<!Get::traits_type::in_place_delete>>> {
  508. public:
  509. /*! @brief Common type among all storage types. */
  510. using common_type = typename Get::base_type;
  511. /*! @brief Underlying entity identifier. */
  512. using entity_type = typename Get::entity_type;
  513. /*! @brief Unsigned integer type. */
  514. using size_type = std::size_t;
  515. /*! @brief Random access iterator type. */
  516. using iterator = typename common_type::iterator;
  517. /*! @brief Reversed iterator type. */
  518. using reverse_iterator = typename common_type::reverse_iterator;
  519. /*! @brief Iterable view type. */
  520. using iterable = decltype(std::declval<Get>().each());
  521. /*! @brief Default constructor to use to create empty, invalid views. */
  522. basic_view() noexcept
  523. : view{} {}
  524. /**
  525. * @brief Constructs a view from a storage class.
  526. * @param value The storage for the type to iterate.
  527. */
  528. basic_view(Get &value) noexcept
  529. : view{&value} {}
  530. /**
  531. * @brief Constructs a view from a storage class.
  532. * @param value The storage for the type to iterate.
  533. */
  534. basic_view(std::tuple<Get &> value, std::tuple<> = {}) noexcept
  535. : basic_view{std::get<0>(value)} {}
  536. /**
  537. * @brief Returns the leading storage of a view, if any.
  538. * @return The leading storage of the view.
  539. */
  540. [[nodiscard]] const common_type *handle() const noexcept {
  541. return storage();
  542. }
  543. /**
  544. * @brief Returns the storage for a given component type, if any.
  545. * @tparam Type Type of component of which to return the storage.
  546. * @return The storage for the given component type.
  547. */
  548. template<typename Type = typename Get::value_type>
  549. [[nodiscard]] auto *storage() const noexcept {
  550. static_assert(std::is_same_v<std::remove_const_t<Type>, typename Get::value_type>, "Invalid component type");
  551. return view;
  552. }
  553. /**
  554. * @brief Returns the storage for a given index, if any.
  555. * @tparam Index Index of the storage to return.
  556. * @return The storage for the given index.
  557. */
  558. template<std::size_t Index>
  559. [[nodiscard]] auto *storage() const noexcept {
  560. static_assert(Index == 0u, "Index out of bounds");
  561. return view;
  562. }
  563. /**
  564. * @brief Assigns a storage to a view.
  565. * @param elem A storage to assign to the view.
  566. */
  567. void storage(Get &elem) noexcept {
  568. view = &elem;
  569. }
  570. /**
  571. * @brief Assigns a storage to a view.
  572. * @tparam Index Index of the storage to assign to the view.
  573. * @param elem A storage to assign to the view.
  574. */
  575. template<std::size_t Index>
  576. void storage(Get &elem) noexcept {
  577. static_assert(Index == 0u, "Index out of bounds");
  578. view = &elem;
  579. }
  580. /**
  581. * @brief Returns the number of entities that have the given component.
  582. * @return Number of entities that have the given component.
  583. */
  584. [[nodiscard]] size_type size() const noexcept {
  585. return view ? view->size() : size_type{};
  586. }
  587. /**
  588. * @brief Checks whether a view is empty.
  589. * @return True if the view is empty, false otherwise.
  590. */
  591. [[nodiscard]] bool empty() const noexcept {
  592. return !view || view->empty();
  593. }
  594. /**
  595. * @brief Returns an iterator to the first entity of the view.
  596. *
  597. * If the view is empty, the returned iterator will be equal to `end()`.
  598. *
  599. * @return An iterator to the first entity of the view.
  600. */
  601. [[nodiscard]] iterator begin() const noexcept {
  602. return view ? view->common_type::begin() : iterator{};
  603. }
  604. /**
  605. * @brief Returns an iterator that is past the last entity of the view.
  606. * @return An iterator to the entity following the last entity of the view.
  607. */
  608. [[nodiscard]] iterator end() const noexcept {
  609. return view ? view->common_type::end() : iterator{};
  610. }
  611. /**
  612. * @brief Returns an iterator to the first entity of the reversed view.
  613. *
  614. * If the view is empty, the returned iterator will be equal to `rend()`.
  615. *
  616. * @return An iterator to the first entity of the reversed view.
  617. */
  618. [[nodiscard]] reverse_iterator rbegin() const noexcept {
  619. return view ? view->common_type::rbegin() : reverse_iterator{};
  620. }
  621. /**
  622. * @brief Returns an iterator that is past the last entity of the reversed
  623. * view.
  624. * @return An iterator to the entity following the last entity of the
  625. * reversed view.
  626. */
  627. [[nodiscard]] reverse_iterator rend() const noexcept {
  628. return view ? view->common_type::rend() : reverse_iterator{};
  629. }
  630. /**
  631. * @brief Returns the first entity of the view, if any.
  632. * @return The first entity of the view if one exists, the null entity
  633. * otherwise.
  634. */
  635. [[nodiscard]] entity_type front() const noexcept {
  636. return empty() ? null : *view->common_type::begin();
  637. }
  638. /**
  639. * @brief Returns the last entity of the view, if any.
  640. * @return The last entity of the view if one exists, the null entity
  641. * otherwise.
  642. */
  643. [[nodiscard]] entity_type back() const noexcept {
  644. return empty() ? null : *view->common_type::rbegin();
  645. }
  646. /**
  647. * @brief Finds an entity.
  648. * @param entt A valid identifier.
  649. * @return An iterator to the given entity if it's found, past the end
  650. * iterator otherwise.
  651. */
  652. [[nodiscard]] iterator find(const entity_type entt) const noexcept {
  653. return view ? view->find(entt) : iterator{};
  654. }
  655. /**
  656. * @brief Returns the identifier that occupies the given position.
  657. * @param pos Position of the element to return.
  658. * @return The identifier that occupies the given position.
  659. */
  660. [[nodiscard]] entity_type operator[](const size_type pos) const {
  661. return begin()[pos];
  662. }
  663. /**
  664. * @brief Returns the component assigned to the given entity.
  665. * @param entt A valid identifier.
  666. * @return The component assigned to the given entity.
  667. */
  668. [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
  669. return storage()->get(entt);
  670. }
  671. /**
  672. * @brief Checks if a view is fully initialized.
  673. * @return True if the view is fully initialized, false otherwise.
  674. */
  675. [[nodiscard]] explicit operator bool() const noexcept {
  676. return (view != nullptr);
  677. }
  678. /**
  679. * @brief Checks if a view contains an entity.
  680. * @param entt A valid identifier.
  681. * @return True if the view contains the given entity, false otherwise.
  682. */
  683. [[nodiscard]] bool contains(const entity_type entt) const noexcept {
  684. return view && view->contains(entt);
  685. }
  686. /**
  687. * @brief Returns the component assigned to the given entity.
  688. * @tparam Elem Type of the component to get.
  689. * @param entt A valid identifier.
  690. * @return The component assigned to the entity.
  691. */
  692. template<typename Elem>
  693. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  694. static_assert(std::is_same_v<std::remove_const_t<Elem>, typename Get::value_type>, "Invalid component type");
  695. return get<0>(entt);
  696. }
  697. /**
  698. * @brief Returns the component assigned to the given entity.
  699. * @tparam Index Index of the component to get.
  700. * @param entt A valid identifier.
  701. * @return The component assigned to the entity.
  702. */
  703. template<std::size_t... Index>
  704. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  705. if constexpr(sizeof...(Index) == 0) {
  706. return storage()->get_as_tuple(entt);
  707. } else {
  708. return storage<Index...>()->get(entt);
  709. }
  710. }
  711. /**
  712. * @brief Iterates entities and components and applies the given function
  713. * object to them.
  714. *
  715. * The signature of the function must be equivalent to one of the following
  716. * (non-empty types only, constness as requested):
  717. *
  718. * @code{.cpp}
  719. * void(const entity_type, Type &);
  720. * void(typename Type &);
  721. * @endcode
  722. *
  723. * @tparam Func Type of the function object to invoke.
  724. * @param func A valid function object.
  725. */
  726. template<typename Func>
  727. void each(Func func) const {
  728. if(view) {
  729. if constexpr(is_applicable_v<Func, decltype(*view->each().begin())>) {
  730. for(const auto pack: view->each()) {
  731. std::apply(func, pack);
  732. }
  733. } else if constexpr(std::is_invocable_v<Func, decltype(*view->begin())>) {
  734. for(auto &&component: *view) {
  735. func(component);
  736. }
  737. } else {
  738. for(size_type pos = view->size(); pos; --pos) {
  739. func();
  740. }
  741. }
  742. }
  743. }
  744. /**
  745. * @brief Returns an iterable object to use to _visit_ a view.
  746. *
  747. * The iterable object returns a tuple that contains the current entity and
  748. * a reference to its component if it's a non-empty one. The _constness_ of
  749. * the component is as requested.
  750. *
  751. * @return An iterable object to use to _visit_ the view.
  752. */
  753. [[nodiscard]] iterable each() const noexcept {
  754. return storage() ? storage()->each() : iterable{};
  755. }
  756. /**
  757. * @brief Combines two views in a _more specific_ one.
  758. * @tparam OGet Component list of the view to combine with.
  759. * @tparam OExclude Filter list of the view to combine with.
  760. * @param other The view to combine with.
  761. * @return A more specific view.
  762. */
  763. template<typename... OGet, typename... OExclude>
  764. [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
  765. return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
  766. *this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
  767. }
  768. private:
  769. Get *view;
  770. };
  771. /**
  772. * @brief Deduction guide.
  773. * @tparam Type Type of storage classes used to create the view.
  774. * @param storage The storage for the types to iterate.
  775. */
  776. template<typename... Type>
  777. basic_view(Type &...storage) -> basic_view<get_t<Type...>, exclude_t<>>;
  778. /**
  779. * @brief Deduction guide.
  780. * @tparam Get Types of components iterated by the view.
  781. * @tparam Exclude Types of components used to filter the view.
  782. */
  783. template<typename... Get, typename... Exclude>
  784. basic_view(std::tuple<Get &...>, std::tuple<Exclude &...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
  785. } // namespace entt
  786. #endif