EnTT 3.13.0
Loading...
Searching...
No Matches
observer.hpp
1#ifndef ENTT_ENTITY_OBSERVER_HPP
2#define ENTT_ENTITY_OBSERVER_HPP
3
4#include <cstddef>
5#include <cstdint>
6#include <limits>
7#include <type_traits>
8#include <utility>
9#include "../core/type_traits.hpp"
10#include "../signal/delegate.hpp"
11#include "fwd.hpp"
12#include "storage.hpp"
13
14namespace entt {
15
17template<typename...>
18struct matcher {};
19
26template<typename...>
28
37template<>
45 template<typename... AllOf, typename... NoneOf>
46 static constexpr auto group(exclude_t<NoneOf...> = exclude_t{}) noexcept {
47 return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>>{};
48 }
49
55 template<typename AnyOf>
56 static constexpr auto update() noexcept {
58 }
59};
60
69template<typename... Reject, typename... Require, typename... Rule, typename... Other>
70struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule...>, Other...> {
72 using current_type = matcher<type_list<Reject...>, type_list<Require...>, Rule...>;
73
80 template<typename... AllOf, typename... NoneOf>
81 static constexpr auto group(exclude_t<NoneOf...> = exclude_t{}) noexcept {
82 return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>, current_type, Other...>{};
83 }
84
90 template<typename AnyOf>
91 static constexpr auto update() noexcept {
93 }
94
101 template<typename... AllOf, typename... NoneOf>
102 static constexpr auto where(exclude_t<NoneOf...> = exclude_t{}) noexcept {
103 using extended_type = matcher<type_list<Reject..., NoneOf...>, type_list<Require..., AllOf...>, Rule...>;
104 return basic_collector<extended_type, Other...>{};
105 }
106};
107
109inline constexpr basic_collector<> collector{};
110
161template<typename Registry, typename Mask, typename Allocator>
162class basic_observer: private basic_storage<Mask, typename Registry::entity_type, Allocator> {
164
165 template<typename>
166 struct matcher_handler;
167
168 template<typename... Reject, typename... Require, typename AnyOf>
169 struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
170 template<std::size_t Index>
171 static void maybe_valid_if(basic_observer &obs, Registry &reg, const typename Registry::entity_type entt) {
172 if(reg.template all_of<Require...>(entt) && !reg.template any_of<Reject...>(entt)) {
173 if(!obs.contains(entt)) {
174 obs.emplace(entt);
175 }
176
177 obs.get(entt) |= (1 << Index);
178 }
179 }
180
181 template<std::size_t Index>
182 static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) {
183 if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) {
184 obs.erase(entt);
185 }
186 }
187
188 template<std::size_t Index>
189 static void connect(basic_observer &obs, Registry &reg) {
190 (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
191 (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
192 reg.template on_update<AnyOf>().template connect<&maybe_valid_if<Index>>(obs);
193 reg.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(obs);
194 }
195
196 static void disconnect(basic_observer &obs, Registry &reg) {
197 (reg.template on_destroy<Require>().disconnect(&obs), ...);
198 (reg.template on_construct<Reject>().disconnect(&obs), ...);
199 reg.template on_update<AnyOf>().disconnect(&obs);
200 reg.template on_destroy<AnyOf>().disconnect(&obs);
201 }
202 };
203
204 template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
205 struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
206 template<std::size_t Index, typename... Ignore>
207 static void maybe_valid_if(basic_observer &obs, Registry &reg, const typename Registry::entity_type entt) {
208 auto condition = [&reg, entt]() {
209 if constexpr(sizeof...(Ignore) == 0) {
210 return reg.template all_of<AllOf..., Require...>(entt) && !reg.template any_of<NoneOf..., Reject...>(entt);
211 } else {
212 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);
213 }
214 };
215
216 if(condition()) {
217 if(!obs.contains(entt)) {
218 obs.emplace(entt);
219 }
220
221 obs.get(entt) |= (1 << Index);
222 }
223 }
224
225 template<std::size_t Index>
226 static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) {
227 if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) {
228 obs.erase(entt);
229 }
230 }
231
232 template<std::size_t Index>
233 static void connect(basic_observer &obs, Registry &reg) {
234 (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
235 (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
236 (reg.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(obs), ...);
237 (reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index, NoneOf>>(obs), ...);
238 (reg.template on_destroy<AllOf>().template connect<&discard_if<Index>>(obs), ...);
239 (reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(obs), ...);
240 }
241
242 static void disconnect(basic_observer &obs, Registry &reg) {
243 (reg.template on_destroy<Require>().disconnect(&obs), ...);
244 (reg.template on_construct<Reject>().disconnect(&obs), ...);
245 (reg.template on_construct<AllOf>().disconnect(&obs), ...);
246 (reg.template on_destroy<NoneOf>().disconnect(&obs), ...);
247 (reg.template on_destroy<AllOf>().disconnect(&obs), ...);
248 (reg.template on_construct<NoneOf>().disconnect(&obs), ...);
249 }
250 };
251
252 template<typename... Matcher>
253 static void disconnect(Registry &reg, basic_observer &obs) {
254 (matcher_handler<Matcher>::disconnect(obs, reg), ...);
255 }
256
257 template<typename... Matcher, std::size_t... Index>
258 void connect(Registry &reg, std::index_sequence<Index...>) {
259 static_assert(sizeof...(Matcher) < std::numeric_limits<typename base_type::value_type>::digits, "Too many matchers");
260 (matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
261 release.template connect<&basic_observer::disconnect<Matcher...>>(reg);
262 }
263
264public:
266 using registry_type = Registry;
268 using entity_type = typename registry_type::entity_type;
270 using size_type = std::size_t;
272 using allocator_type = Allocator;
274 using iterator = typename registry_type::common_type::iterator;
275
279
284 explicit basic_observer(const allocator_type &allocator)
285 : base_type{allocator},
286 release{} {}
287
290
293
300 template<typename... Matcher>
302 : basic_observer{allocator} {
303 connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
304 }
305
311
317
323 template<typename... Matcher>
325 disconnect();
326 connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
328 }
329
331 void disconnect() {
332 if(release) {
333 release(*this);
334 release.reset();
335 }
336 }
337
342 [[nodiscard]] size_type size() const noexcept {
343 return base_type::size();
344 }
345
350 [[nodiscard]] bool empty() const noexcept {
351 return base_type::empty();
352 }
353
366 [[nodiscard]] const entity_type *data() const noexcept {
367 return base_type::data();
368 }
369
377 [[nodiscard]] iterator begin() const noexcept {
379 }
380
386 [[nodiscard]] iterator end() const noexcept {
388 }
389
391 void clear() noexcept {
393 }
394
408 template<typename Func>
409 void each(Func func) const {
410 for(const auto entity: *this) {
411 func(entity);
412 }
413 }
414
424 template<typename Func>
425 void each(Func func) {
426 std::as_const(*this).each(std::move(func));
427 clear();
428 }
429
430private:
431 delegate<void(basic_observer &)> release;
432};
433
434} // namespace entt
435
436#endif
void each(Func func)
Iterates entities and applies the given function object to them, then clears the observer.
Definition observer.hpp:425
basic_observer(const allocator_type &allocator)
Constructs an empty storage with a given allocator.
Definition observer.hpp:284
void disconnect()
Disconnects an observer from the registry it keeps track of.
Definition observer.hpp:331
const entity_type * data() const noexcept
Direct access to the list of entities of the observer.
Definition observer.hpp:366
iterator end() const noexcept
Returns an iterator that is past the last entity of the observer.
Definition observer.hpp:386
basic_observer & operator=(const basic_observer &)=delete
Default copy assignment operator, deleted on purpose.
iterator begin() const noexcept
Returns an iterator to the first entity of the observer.
Definition observer.hpp:377
basic_observer(basic_observer &&)=delete
Default move constructor, deleted on purpose.
typename registry_type::common_type::iterator iterator
Random access iterator type.
Definition observer.hpp:274
bool empty() const noexcept
Checks whether an observer is empty.
Definition observer.hpp:350
Allocator allocator_type
Allocator type.
Definition observer.hpp:272
basic_observer & operator=(basic_observer &&)=delete
Default move assignment operator, deleted on purpose.
basic_observer(registry_type &reg, basic_collector< Matcher... >, const allocator_type &allocator=allocator_type{})
Creates an observer and connects it to a given registry.
Definition observer.hpp:301
void each(Func func) const
Iterates entities and applies the given function object to them.
Definition observer.hpp:409
basic_observer()
Default constructor.
Definition observer.hpp:277
size_type size() const noexcept
Returns the number of elements in an observer.
Definition observer.hpp:342
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition observer.hpp:268
void clear() noexcept
Clears the underlying container.
Definition observer.hpp:391
void connect(registry_type &reg, basic_collector< Matcher... >)
Connects an observer to a given registry.
Definition observer.hpp:324
basic_observer(const basic_observer &)=delete
Default copy constructor, deleted on purpose.
std::size_t size_type
Unsigned integer type.
Definition observer.hpp:270
size_type size() const noexcept
Returns the number of elements in a sparse set.
Basic storage implementation.
Definition storage.hpp:229
const_iterator end() const noexcept
Returns an iterator to the end.
Definition storage.hpp:568
const_iterator begin() const noexcept
Returns an iterator to the beginning.
Definition storage.hpp:548
Basic delegate implementation.
Definition delegate.hpp:51
EnTT default namespace.
Definition dense_map.hpp:21
entity
Default entity identifier.
Definition fwd.hpp:13
constexpr basic_collector collector
Variable template used to ease the definition of collectors.
Definition observer.hpp:109
static constexpr auto update() noexcept
Adds an observing matcher to the collector.
Definition observer.hpp:91
static constexpr auto group(exclude_t< NoneOf... >=exclude_t{}) noexcept
Adds a grouping matcher to the collector.
Definition observer.hpp:81
static constexpr auto where(exclude_t< NoneOf... >=exclude_t{}) noexcept
Updates the filter of the last added matcher.
Definition observer.hpp:102
static constexpr auto update() noexcept
Adds an observing matcher to the collector.
Definition observer.hpp:56
static constexpr auto group(exclude_t< NoneOf... >=exclude_t{}) noexcept
Adds a grouping matcher to the collector.
Definition observer.hpp:46
Alias for exclusion lists.
Definition fwd.hpp:130
Grouping matcher.
Definition observer.hpp:18
A class to use to push around lists of types, nothing more.