🛠️🐜 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.

436 lines
16 KiB

  1. #ifndef ENTT_ENTITY_OBSERVER_HPP
  2. #define ENTT_ENTITY_OBSERVER_HPP
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <limits>
  6. #include <type_traits>
  7. #include <utility>
  8. #include "../config/config.h"
  9. #include "../core/type_traits.hpp"
  10. #include "../signal/delegate.hpp"
  11. #include "entity.hpp"
  12. #include "fwd.hpp"
  13. #include "registry.hpp"
  14. #include "storage.hpp"
  15. #include "utility.hpp"
  16. namespace entt {
  17. /*! @brief Grouping matcher. */
  18. template<typename...>
  19. struct matcher {};
  20. /**
  21. * @brief Collector.
  22. *
  23. * Primary template isn't defined on purpose. All the specializations give a
  24. * compile-time error, but for a few reasonable cases.
  25. */
  26. template<typename...>
  27. struct basic_collector;
  28. /**
  29. * @brief Collector.
  30. *
  31. * A collector contains a set of rules (literally, matchers) to use to track
  32. * entities.<br/>
  33. * Its main purpose is to generate a descriptor that allows an observer to know
  34. * how to connect to a registry.
  35. */
  36. template<>
  37. struct basic_collector<> {
  38. /**
  39. * @brief Adds a grouping matcher to the collector.
  40. * @tparam AllOf Types of components tracked by the matcher.
  41. * @tparam NoneOf Types of components used to filter out entities.
  42. * @return The updated collector.
  43. */
  44. template<typename... AllOf, typename... NoneOf>
  45. static constexpr auto group(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
  46. return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>>{};
  47. }
  48. /**
  49. * @brief Adds an observing matcher to the collector.
  50. * @tparam AnyOf Type of component for which changes should be detected.
  51. * @return The updated collector.
  52. */
  53. template<typename AnyOf>
  54. static constexpr auto update() ENTT_NOEXCEPT {
  55. return basic_collector<matcher<type_list<>, type_list<>, AnyOf>>{};
  56. }
  57. };
  58. /**
  59. * @brief Collector.
  60. * @copydetails basic_collector<>
  61. * @tparam Reject Untracked types used to filter out entities.
  62. * @tparam Require Untracked types required by the matcher.
  63. * @tparam Rule Specific details of the current matcher.
  64. * @tparam Other Other matchers.
  65. */
  66. template<typename... Reject, typename... Require, typename... Rule, typename... Other>
  67. struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule...>, Other...> {
  68. /*! @brief Current matcher. */
  69. using current_type = matcher<type_list<Reject...>, type_list<Require...>, Rule...>;
  70. /**
  71. * @brief Adds a grouping matcher to the collector.
  72. * @tparam AllOf Types of components tracked by the matcher.
  73. * @tparam NoneOf Types of components used to filter out entities.
  74. * @return The updated collector.
  75. */
  76. template<typename... AllOf, typename... NoneOf>
  77. static constexpr auto group(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
  78. return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>, current_type, Other...>{};
  79. }
  80. /**
  81. * @brief Adds an observing matcher to the collector.
  82. * @tparam AnyOf Type of component for which changes should be detected.
  83. * @return The updated collector.
  84. */
  85. template<typename AnyOf>
  86. static constexpr auto update() ENTT_NOEXCEPT {
  87. return basic_collector<matcher<type_list<>, type_list<>, AnyOf>, current_type, Other...>{};
  88. }
  89. /**
  90. * @brief Updates the filter of the last added matcher.
  91. * @tparam AllOf Types of components required by the matcher.
  92. * @tparam NoneOf Types of components used to filter out entities.
  93. * @return The updated collector.
  94. */
  95. template<typename... AllOf, typename... NoneOf>
  96. static constexpr auto where(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
  97. using extended_type = matcher<type_list<Reject..., NoneOf...>, type_list<Require..., AllOf...>, Rule...>;
  98. return basic_collector<extended_type, Other...>{};
  99. }
  100. };
  101. /*! @brief Variable template used to ease the definition of collectors. */
  102. inline constexpr basic_collector<> collector{};
  103. /**
  104. * @brief Observer.
  105. *
  106. * An observer returns all the entities and only the entities that fit the
  107. * requirements of at least one matcher. Moreover, it's guaranteed that the
  108. * entity list is tightly packed in memory for fast iterations.<br/>
  109. * In general, observers don't stay true to the order of any set of components.
  110. *
  111. * Observers work mainly with two types of matchers, provided through a
  112. * collector:
  113. *
  114. * * Observing matcher: an observer will return at least all the living entities
  115. * for which one or more of the given components have been updated and not yet
  116. * destroyed.
  117. * * Grouping matcher: an observer will return at least all the living entities
  118. * that would have entered the given group if it existed and that would have
  119. * not yet left it.
  120. *
  121. * If an entity respects the requirements of multiple matchers, it will be
  122. * returned once and only once by the observer in any case.
  123. *
  124. * Matchers support also filtering by means of a _where_ clause that accepts
  125. * both a list of types and an exclusion list.<br/>
  126. * Whenever a matcher finds that an entity matches its requirements, the
  127. * condition of the filter is verified before to register the entity itself.
  128. * Moreover, a registered entity isn't returned by the observer if the condition
  129. * set by the filter is broken in the meantime.
  130. *
  131. * @b Important
  132. *
  133. * Iterators aren't invalidated if:
  134. *
  135. * * New instances of the given components are created and assigned to entities.
  136. * * The entity currently pointed is modified (as an example, if one of the
  137. * given components is removed from the entity to which the iterator points).
  138. * * The entity currently pointed is destroyed.
  139. *
  140. * In all the other cases, modifying the pools of the given components in any
  141. * way invalidates all the iterators and using them results in undefined
  142. * behavior.
  143. *
  144. * @warning
  145. * Lifetime of an observer doesn't necessarily have to overcome that of the
  146. * registry to which it is connected. However, the observer must be disconnected
  147. * from the registry before being destroyed to avoid crashes due to dangling
  148. * pointers.
  149. *
  150. * @tparam Entity A valid entity type (see entt_traits for more details).
  151. */
  152. template<typename Entity>
  153. class basic_observer {
  154. using payload_type = std::uint32_t;
  155. template<typename>
  156. struct matcher_handler;
  157. template<typename... Reject, typename... Require, typename AnyOf>
  158. struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
  159. template<std::size_t Index>
  160. static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> &reg, const Entity entt) {
  161. if(reg.template all_of<Require...>(entt) && !reg.template any_of<Reject...>(entt)) {
  162. if(!obs.storage.contains(entt)) {
  163. obs.storage.emplace(entt);
  164. }
  165. obs.storage.get(entt) |= (1 << Index);
  166. }
  167. }
  168. template<std::size_t Index>
  169. static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
  170. if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) {
  171. obs.storage.erase(entt);
  172. }
  173. }
  174. template<std::size_t Index>
  175. static void connect(basic_observer &obs, basic_registry<Entity> &reg) {
  176. (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
  177. (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
  178. reg.template on_update<AnyOf>().template connect<&maybe_valid_if<Index>>(obs);
  179. reg.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(obs);
  180. }
  181. static void disconnect(basic_observer &obs, basic_registry<Entity> &reg) {
  182. (reg.template on_destroy<Require>().disconnect(obs), ...);
  183. (reg.template on_construct<Reject>().disconnect(obs), ...);
  184. reg.template on_update<AnyOf>().disconnect(obs);
  185. reg.template on_destroy<AnyOf>().disconnect(obs);
  186. }
  187. };
  188. template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
  189. struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
  190. template<std::size_t Index, typename... Ignore>
  191. static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> &reg, const Entity entt) {
  192. auto condition = [&reg, entt]() {
  193. if constexpr(sizeof...(Ignore) == 0) {
  194. return reg.template all_of<AllOf..., Require...>(entt) && !reg.template any_of<NoneOf..., Reject...>(entt);
  195. } else {
  196. return reg.template all_of<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !reg.template any_of<NoneOf>(entt)) && ...) && !reg.template any_of<Reject...>(entt);
  197. }
  198. };
  199. if(condition()) {
  200. if(!obs.storage.contains(entt)) {
  201. obs.storage.emplace(entt);
  202. }
  203. obs.storage.get(entt) |= (1 << Index);
  204. }
  205. }
  206. template<std::size_t Index>
  207. static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
  208. if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) {
  209. obs.storage.erase(entt);
  210. }
  211. }
  212. template<std::size_t Index>
  213. static void connect(basic_observer &obs, basic_registry<Entity> &reg) {
  214. (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
  215. (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
  216. (reg.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(obs), ...);
  217. (reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index, NoneOf>>(obs), ...);
  218. (reg.template on_destroy<AllOf>().template connect<&discard_if<Index>>(obs), ...);
  219. (reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(obs), ...);
  220. }
  221. static void disconnect(basic_observer &obs, basic_registry<Entity> &reg) {
  222. (reg.template on_destroy<Require>().disconnect(obs), ...);
  223. (reg.template on_construct<Reject>().disconnect(obs), ...);
  224. (reg.template on_construct<AllOf>().disconnect(obs), ...);
  225. (reg.template on_destroy<NoneOf>().disconnect(obs), ...);
  226. (reg.template on_destroy<AllOf>().disconnect(obs), ...);
  227. (reg.template on_construct<NoneOf>().disconnect(obs), ...);
  228. }
  229. };
  230. template<typename... Matcher>
  231. static void disconnect(basic_registry<Entity> &reg, basic_observer &obs) {
  232. (matcher_handler<Matcher>::disconnect(obs, reg), ...);
  233. }
  234. template<typename... Matcher, std::size_t... Index>
  235. void connect(basic_registry<Entity> &reg, std::index_sequence<Index...>) {
  236. static_assert(sizeof...(Matcher) < std::numeric_limits<payload_type>::digits, "Too many matchers");
  237. (matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
  238. release.template connect<&basic_observer::disconnect<Matcher...>>(reg);
  239. }
  240. public:
  241. /*! @brief Underlying entity identifier. */
  242. using entity_type = Entity;
  243. /*! @brief Unsigned integer type. */
  244. using size_type = std::size_t;
  245. /*! @brief Random access iterator type. */
  246. using iterator = typename basic_sparse_set<Entity>::iterator;
  247. /*! @brief Default constructor. */
  248. basic_observer()
  249. : release{},
  250. storage{} {}
  251. /*! @brief Default copy constructor, deleted on purpose. */
  252. basic_observer(const basic_observer &) = delete;
  253. /*! @brief Default move constructor, deleted on purpose. */
  254. basic_observer(basic_observer &&) = delete;
  255. /**
  256. * @brief Creates an observer and connects it to a given registry.
  257. * @tparam Matcher Types of matchers to use to initialize the observer.
  258. * @param reg A valid reference to a registry.
  259. */
  260. template<typename... Matcher>
  261. basic_observer(basic_registry<entity_type> &reg, basic_collector<Matcher...>)
  262. : basic_observer{} {
  263. connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
  264. }
  265. /*! @brief Default destructor. */
  266. ~basic_observer() = default;
  267. /**
  268. * @brief Default copy assignment operator, deleted on purpose.
  269. * @return This observer.
  270. */
  271. basic_observer &operator=(const basic_observer &) = delete;
  272. /**
  273. * @brief Default move assignment operator, deleted on purpose.
  274. * @return This observer.
  275. */
  276. basic_observer &operator=(basic_observer &&) = delete;
  277. /**
  278. * @brief Connects an observer to a given registry.
  279. * @tparam Matcher Types of matchers to use to initialize the observer.
  280. * @param reg A valid reference to a registry.
  281. */
  282. template<typename... Matcher>
  283. void connect(basic_registry<entity_type> &reg, basic_collector<Matcher...>) {
  284. disconnect();
  285. connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
  286. storage.clear();
  287. }
  288. /*! @brief Disconnects an observer from the registry it keeps track of. */
  289. void disconnect() {
  290. if(release) {
  291. release(*this);
  292. release.reset();
  293. }
  294. }
  295. /**
  296. * @brief Returns the number of elements in an observer.
  297. * @return Number of elements.
  298. */
  299. [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
  300. return storage.size();
  301. }
  302. /**
  303. * @brief Checks whether an observer is empty.
  304. * @return True if the observer is empty, false otherwise.
  305. */
  306. [[nodiscard]] bool empty() const ENTT_NOEXCEPT {
  307. return storage.empty();
  308. }
  309. /**
  310. * @brief Direct access to the list of entities of the observer.
  311. *
  312. * The returned pointer is such that range `[data(), data() + size())` is
  313. * always a valid range, even if the container is empty.
  314. *
  315. * @note
  316. * Entities are in the reverse order as returned by the `begin`/`end`
  317. * iterators.
  318. *
  319. * @return A pointer to the array of entities.
  320. */
  321. [[nodiscard]] const entity_type *data() const ENTT_NOEXCEPT {
  322. return storage.data();
  323. }
  324. /**
  325. * @brief Returns an iterator to the first entity of the observer.
  326. *
  327. * The returned iterator points to the first entity of the observer. If the
  328. * container is empty, the returned iterator will be equal to `end()`.
  329. *
  330. * @return An iterator to the first entity of the observer.
  331. */
  332. [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
  333. return storage.basic_sparse_set<entity_type>::begin();
  334. }
  335. /**
  336. * @brief Returns an iterator that is past the last entity of the observer.
  337. *
  338. * The returned iterator points to the entity following the last entity of
  339. * the observer. Attempting to dereference the returned iterator results in
  340. * undefined behavior.
  341. *
  342. * @return An iterator to the entity following the last entity of the
  343. * observer.
  344. */
  345. [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
  346. return storage.basic_sparse_set<entity_type>::end();
  347. }
  348. /*! @brief Clears the underlying container. */
  349. void clear() ENTT_NOEXCEPT {
  350. storage.clear();
  351. }
  352. /**
  353. * @brief Iterates entities and applies the given function object to them.
  354. *
  355. * The function object is invoked for each entity.<br/>
  356. * The signature of the function must be equivalent to the following form:
  357. *
  358. * @code{.cpp}
  359. * void(const entity_type);
  360. * @endcode
  361. *
  362. * @tparam Func Type of the function object to invoke.
  363. * @param func A valid function object.
  364. */
  365. template<typename Func>
  366. void each(Func func) const {
  367. for(const auto entity: *this) {
  368. func(entity);
  369. }
  370. }
  371. /**
  372. * @brief Iterates entities and applies the given function object to them,
  373. * then clears the observer.
  374. *
  375. * @sa each
  376. *
  377. * @tparam Func Type of the function object to invoke.
  378. * @param func A valid function object.
  379. */
  380. template<typename Func>
  381. void each(Func func) {
  382. std::as_const(*this).each(std::move(func));
  383. clear();
  384. }
  385. private:
  386. delegate<void(basic_observer &)> release;
  387. basic_storage<entity_type, payload_type> storage;
  388. };
  389. } // namespace entt
  390. #endif