runtime_view.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. #ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
  2. #define ENTT_ENTITY_RUNTIME_VIEW_HPP
  3. #include <algorithm>
  4. #include <cstddef>
  5. #include <iterator>
  6. #include <utility>
  7. #include <vector>
  8. #include "entity.hpp"
  9. #include "fwd.hpp"
  10. namespace entt {
  11. /**
  12. * @cond TURN_OFF_DOXYGEN
  13. * Internal details not to be documented.
  14. */
  15. namespace internal {
  16. template<typename Set>
  17. class runtime_view_iterator final {
  18. using iterator_type = typename Set::iterator;
  19. [[nodiscard]] bool valid() const {
  20. return (!tombstone_check || *it != tombstone)
  21. && std::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
  22. && std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
  23. }
  24. public:
  25. using difference_type = typename iterator_type::difference_type;
  26. using value_type = typename iterator_type::value_type;
  27. using pointer = typename iterator_type::pointer;
  28. using reference = typename iterator_type::reference;
  29. using iterator_category = std::bidirectional_iterator_tag;
  30. constexpr runtime_view_iterator() noexcept
  31. : pools{},
  32. filter{},
  33. it{},
  34. tombstone_check{} {}
  35. runtime_view_iterator(const std::vector<Set *> &cpools, const std::vector<Set *> &ignore, iterator_type curr) noexcept
  36. : pools{&cpools},
  37. filter{&ignore},
  38. it{curr},
  39. tombstone_check{pools->size() == 1u && (*pools)[0u]->policy() == deletion_policy::in_place} {
  40. if(it != (*pools)[0]->end() && !valid()) {
  41. ++(*this);
  42. }
  43. }
  44. runtime_view_iterator &operator++() {
  45. while(++it != (*pools)[0]->end() && !valid()) {}
  46. return *this;
  47. }
  48. runtime_view_iterator operator++(int) {
  49. runtime_view_iterator orig = *this;
  50. return ++(*this), orig;
  51. }
  52. runtime_view_iterator &operator--() {
  53. while(--it != (*pools)[0]->begin() && !valid()) {}
  54. return *this;
  55. }
  56. runtime_view_iterator operator--(int) {
  57. runtime_view_iterator orig = *this;
  58. return operator--(), orig;
  59. }
  60. [[nodiscard]] pointer operator->() const noexcept {
  61. return it.operator->();
  62. }
  63. [[nodiscard]] reference operator*() const noexcept {
  64. return *operator->();
  65. }
  66. [[nodiscard]] constexpr bool operator==(const runtime_view_iterator &other) const noexcept {
  67. return it == other.it;
  68. }
  69. [[nodiscard]] constexpr bool operator!=(const runtime_view_iterator &other) const noexcept {
  70. return !(*this == other);
  71. }
  72. private:
  73. const std::vector<Set *> *pools;
  74. const std::vector<Set *> *filter;
  75. iterator_type it;
  76. bool tombstone_check;
  77. };
  78. } // namespace internal
  79. /**
  80. * Internal details not to be documented.
  81. * @endcond
  82. */
  83. /**
  84. * @brief Generic runtime view.
  85. *
  86. * Runtime views iterate over those entities that are at least in the given
  87. * storage. During initialization, a runtime view looks at the number of
  88. * entities available for each component and uses the smallest set in order to
  89. * get a performance boost when iterating.
  90. *
  91. * @b Important
  92. *
  93. * Iterators aren't invalidated if:
  94. *
  95. * * New elements are added to the storage.
  96. * * The entity currently pointed is modified (for example, components are added
  97. * or removed from it).
  98. * * The entity currently pointed is destroyed.
  99. *
  100. * In all other cases, modifying the storage iterated by the view in any way
  101. * invalidates all the iterators.
  102. *
  103. * @tparam Type Common base type.
  104. * @tparam Allocator Type of allocator used to manage memory and elements.
  105. */
  106. template<typename Type, typename Allocator>
  107. class basic_runtime_view {
  108. using alloc_traits = std::allocator_traits<Allocator>;
  109. static_assert(std::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
  110. using container_type = std::vector<Type *, Allocator>;
  111. public:
  112. /*! @brief Allocator type. */
  113. using allocator_type = Allocator;
  114. /*! @brief Underlying entity identifier. */
  115. using entity_type = typename Type::entity_type;
  116. /*! @brief Unsigned integer type. */
  117. using size_type = std::size_t;
  118. /*! @brief Common type among all storage types. */
  119. using common_type = Type;
  120. /*! @brief Bidirectional iterator type. */
  121. using iterator = internal::runtime_view_iterator<common_type>;
  122. /*! @brief Default constructor to use to create empty, invalid views. */
  123. basic_runtime_view() noexcept
  124. : basic_runtime_view{allocator_type{}} {}
  125. /**
  126. * @brief Constructs an empty, invalid view with a given allocator.
  127. * @param allocator The allocator to use.
  128. */
  129. explicit basic_runtime_view(const allocator_type &allocator)
  130. : pools{allocator},
  131. filter{allocator} {}
  132. /*! @brief Default copy constructor. */
  133. basic_runtime_view(const basic_runtime_view &) = default;
  134. /**
  135. * @brief Allocator-extended copy constructor.
  136. * @param other The instance to copy from.
  137. * @param allocator The allocator to use.
  138. */
  139. basic_runtime_view(const basic_runtime_view &other, const allocator_type &allocator)
  140. : pools{other.pools, allocator},
  141. filter{other.filter, allocator} {}
  142. /*! @brief Default move constructor. */
  143. basic_runtime_view(basic_runtime_view &&) noexcept(std::is_nothrow_move_constructible_v<container_type>) = default;
  144. /**
  145. * @brief Allocator-extended move constructor.
  146. * @param other The instance to move from.
  147. * @param allocator The allocator to use.
  148. */
  149. basic_runtime_view(basic_runtime_view &&other, const allocator_type &allocator)
  150. : pools{std::move(other.pools), allocator},
  151. filter{std::move(other.filter), allocator} {}
  152. /**
  153. * @brief Default copy assignment operator.
  154. * @return This container.
  155. */
  156. basic_runtime_view &operator=(const basic_runtime_view &) = default;
  157. /**
  158. * @brief Default move assignment operator.
  159. * @return This container.
  160. */
  161. basic_runtime_view &operator=(basic_runtime_view &&) noexcept(std::is_nothrow_move_assignable_v<container_type>) = default;
  162. /**
  163. * @brief Exchanges the contents with those of a given view.
  164. * @param other View to exchange the content with.
  165. */
  166. void swap(basic_runtime_view &other) {
  167. using std::swap;
  168. swap(pools, other.pools);
  169. swap(filter, other.filter);
  170. }
  171. /**
  172. * @brief Returns the associated allocator.
  173. * @return The associated allocator.
  174. */
  175. [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
  176. return pools.get_allocator();
  177. }
  178. /*! @brief Clears the view. */
  179. void clear() {
  180. pools.clear();
  181. filter.clear();
  182. }
  183. /**
  184. * @brief Appends an opaque storage object to a runtime view.
  185. * @param base An opaque reference to a storage object.
  186. * @return This runtime view.
  187. */
  188. basic_runtime_view &iterate(common_type &base) {
  189. if(pools.empty() || !(base.size() < pools[0u]->size())) {
  190. pools.push_back(&base);
  191. } else {
  192. pools.push_back(std::exchange(pools[0u], &base));
  193. }
  194. return *this;
  195. }
  196. /**
  197. * @brief Adds an opaque storage object as a filter of a runtime view.
  198. * @param base An opaque reference to a storage object.
  199. * @return This runtime view.
  200. */
  201. basic_runtime_view &exclude(common_type &base) {
  202. filter.push_back(&base);
  203. return *this;
  204. }
  205. /**
  206. * @brief Estimates the number of entities iterated by the view.
  207. * @return Estimated number of entities iterated by the view.
  208. */
  209. [[nodiscard]] size_type size_hint() const {
  210. return pools.empty() ? size_type{} : pools.front()->size();
  211. }
  212. /**
  213. * @brief Returns an iterator to the first entity that has the given
  214. * components.
  215. *
  216. * If the view is empty, the returned iterator will be equal to `end()`.
  217. *
  218. * @return An iterator to the first entity that has the given components.
  219. */
  220. [[nodiscard]] iterator begin() const {
  221. return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->begin()};
  222. }
  223. /**
  224. * @brief Returns an iterator that is past the last entity that has the
  225. * given components.
  226. * @return An iterator to the entity following the last entity that has the
  227. * given components.
  228. */
  229. [[nodiscard]] iterator end() const {
  230. return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->end()};
  231. }
  232. /**
  233. * @brief Checks if a view contains an entity.
  234. * @param entt A valid identifier.
  235. * @return True if the view contains the given entity, false otherwise.
  236. */
  237. [[nodiscard]] bool contains(const entity_type entt) const {
  238. return !pools.empty()
  239. && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
  240. && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
  241. }
  242. /**
  243. * @brief Iterates entities and applies the given function object to them.
  244. *
  245. * The function object is invoked for each entity. It is provided only with
  246. * the entity itself.<br/>
  247. * The signature of the function should be equivalent to the following:
  248. *
  249. * @code{.cpp}
  250. * void(const entity_type);
  251. * @endcode
  252. *
  253. * @tparam Func Type of the function object to invoke.
  254. * @param func A valid function object.
  255. */
  256. template<typename Func>
  257. void each(Func func) const {
  258. for(const auto entity: *this) {
  259. func(entity);
  260. }
  261. }
  262. private:
  263. container_type pools;
  264. container_type filter;
  265. };
  266. } // namespace entt
  267. #endif