observer.hpp 16 KB

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