view.hpp 34 KB

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