observer.hpp 16 KB

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