EnTT 3.14.0
Loading...
Searching...
No Matches
mixin.hpp
1#ifndef ENTT_ENTITY_MIXIN_HPP
2#define ENTT_ENTITY_MIXIN_HPP
3
4#include <type_traits>
5#include <utility>
6#include "../config/config.h"
7#include "../core/any.hpp"
8#include "../core/type_info.hpp"
9#include "../signal/sigh.hpp"
10#include "entity.hpp"
11#include "fwd.hpp"
12
13namespace entt {
14
16namespace internal {
17
18template<typename, typename, typename = void>
19struct has_on_construct final: std::false_type {};
20
21template<typename Type, typename Registry>
22struct has_on_construct<Type, Registry, std::void_t<decltype(Type::on_construct(std::declval<Registry &>(), std::declval<Registry>().create()))>>
23 : std::true_type {};
24
25template<typename, typename, typename = void>
26struct has_on_update final: std::false_type {};
27
28template<typename Type, typename Registry>
29struct has_on_update<Type, Registry, std::void_t<decltype(Type::on_update(std::declval<Registry &>(), std::declval<Registry>().create()))>>
30 : std::true_type {};
31
32template<typename, typename, typename = void>
33struct has_on_destroy final: std::false_type {};
34
35template<typename Type, typename Registry>
36struct has_on_destroy<Type, Registry, std::void_t<decltype(Type::on_destroy(std::declval<Registry &>(), std::declval<Registry>().create()))>>
37 : std::true_type {};
38
39template<typename Type>
40auto *any_to_owner(any &value) noexcept {
41 using base_type = basic_registry<typename Type::entity_type, typename Type::allocator_type>;
42 auto *reg = any_cast<base_type>(&value);
43
44 if constexpr(!std::is_same_v<Type, base_type>) {
45 if(!reg) {
46 reg = any_cast<Type>(&value);
47 }
48 }
49
50 return reg;
51}
52
53} // namespace internal
70template<typename Type, typename Registry>
71class basic_sigh_mixin final: public Type {
72 using underlying_type = Type;
73 using owner_type = Registry;
74
76 using sigh_type = sigh<void(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
77 using underlying_iterator = typename underlying_type::base_type::basic_iterator;
78
79 static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
80
81 [[nodiscard]] auto &owner_or_assert() const noexcept {
82 ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
83 return static_cast<owner_type &>(*owner);
84 }
85
86private:
87 void pop(underlying_iterator first, underlying_iterator last) final {
88 if(auto &reg = owner_or_assert(); destruction.empty()) {
89 underlying_type::pop(first, last);
90 } else {
91 for(; first != last; ++first) {
92 const auto entt = *first;
93 destruction.publish(reg, entt);
94 const auto it = underlying_type::find(entt);
95 underlying_type::pop(it, it + 1u);
96 }
97 }
98 }
99
100 void pop_all() final {
101 if(auto &reg = owner_or_assert(); !destruction.empty()) {
102 if constexpr(std::is_same_v<typename underlying_type::element_type, entity_type>) {
103 for(typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) {
104 destruction.publish(reg, underlying_type::base_type::operator[](pos));
105 }
106 } else {
107 for(auto entt: static_cast<typename underlying_type::base_type &>(*this)) {
108 if constexpr(underlying_type::storage_policy == deletion_policy::in_place) {
109 if(entt != tombstone) {
110 destruction.publish(reg, entt);
111 }
112 } else {
113 destruction.publish(reg, entt);
114 }
115 }
116 }
117 }
118
119 underlying_type::pop_all();
120 }
121
122 underlying_iterator try_emplace(const typename underlying_type::entity_type entt, const bool force_back, const void *value) final {
123 const auto it = underlying_type::try_emplace(entt, force_back, value);
124
125 if(auto &reg = owner_or_assert(); it != underlying_type::base_type::end()) {
126 construction.publish(reg, *it);
127 }
128
129 return it;
130 }
131
132 void bind_any(any value) noexcept final {
133 owner = internal::any_to_owner<registry_type>(value);
134 underlying_type::bind_any(std::move(value));
135 }
136
137public:
139 using allocator_type = typename underlying_type::allocator_type;
141 using entity_type = typename underlying_type::entity_type;
143 using registry_type = owner_type;
144
148
154 : underlying_type{allocator},
155 owner{},
156 construction{allocator},
157 destruction{allocator},
158 update{allocator} {
159 if constexpr(internal::has_on_construct<typename underlying_type::element_type, Registry>::value) {
161 }
162
163 if constexpr(internal::has_on_update<typename underlying_type::element_type, Registry>::value) {
165 }
166
167 if constexpr(internal::has_on_destroy<typename underlying_type::element_type, Registry>::value) {
169 }
170 }
171
174
180 : underlying_type{std::move(other)},
181 owner{other.owner},
182 construction{std::move(other.construction)},
183 destruction{std::move(other.destruction)},
184 update{std::move(other.update)} {}
185
192 : underlying_type{std::move(other), allocator},
193 owner{other.owner},
194 construction{std::move(other.construction), allocator},
195 destruction{std::move(other.destruction), allocator},
196 update{std::move(other.update), allocator} {}
197
199 ~basic_sigh_mixin() override = default;
200
206
213 swap(other);
214 return *this;
215 }
216
221 void swap(basic_sigh_mixin &other) noexcept {
222 using std::swap;
223 swap(owner, other.owner);
224 swap(construction, other.construction);
225 swap(destruction, other.destruction);
226 swap(update, other.update);
227 underlying_type::swap(other);
228 }
229
242 return sink{construction};
243 }
244
257 return sink{update};
258 }
259
272 return sink{destruction};
273 }
274
279 [[nodiscard]] explicit operator bool() const noexcept {
280 return (owner != nullptr);
281 }
282
288 return owner_or_assert();
289 }
290
293 return owner_or_assert();
294 }
295
305 auto emplace() {
306 const auto entt = underlying_type::emplace();
307 construction.publish(owner_or_assert(), entt);
308 return entt;
309 }
310
323 template<typename... Args>
324 std::conditional_t<std::is_same_v<typename underlying_type::element_type, entity_type>, entity_type, decltype(std::declval<underlying_type>().get({}))>
326 if constexpr(std::is_same_v<typename underlying_type::element_type, entity_type>) {
327 const auto entt = underlying_type::emplace(hint, std::forward<Args>(args)...);
328 construction.publish(owner_or_assert(), entt);
329 return entt;
330 } else {
331 underlying_type::emplace(hint, std::forward<Args>(args)...);
332 construction.publish(owner_or_assert(), hint);
333 return this->get(hint);
334 }
335 }
336
344 template<typename... Func>
345 decltype(auto) patch(const entity_type entt, Func &&...func) {
346 underlying_type::patch(entt, std::forward<Func>(func)...);
347 update.publish(owner_or_assert(), entt);
348 return this->get(entt);
349 }
350
364 template<typename It, typename... Args>
365 void insert(It first, It last, Args &&...args) {
366 auto from = underlying_type::size();
367 underlying_type::insert(first, last, std::forward<Args>(args)...);
368
369 if(auto &reg = owner_or_assert(); !construction.empty()) {
370 for(const auto to = underlying_type::size(); from != to; ++from) {
371 construction.publish(reg, underlying_type::operator[](from));
372 }
373 }
374 }
375
376private:
377 basic_registry_type *owner;
378 sigh_type construction;
379 sigh_type destruction;
380 sigh_type update;
381};
382
388template<typename Type, typename Registry>
389class basic_reactive_mixin final: public Type {
390 using underlying_type = Type;
391 using owner_type = Registry;
392
394
395 static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
396
397 [[nodiscard]] auto &owner_or_assert() const noexcept {
398 ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
399 return static_cast<owner_type &>(*owner);
400 }
401
402 void emplace_element(const Registry &, typename underlying_type::entity_type entity) {
403 if(!underlying_type::contains(entity)) {
404 underlying_type::emplace(entity);
405 }
406 }
407
408private:
409 void bind_any(any value) noexcept final {
410 owner = internal::any_to_owner<registry_type>(value);
411 underlying_type::bind_any(std::move(value));
412 }
413
414public:
416 using allocator_type = typename underlying_type::allocator_type;
418 using entity_type = typename underlying_type::entity_type;
420 using registry_type = owner_type;
421
425
431 : underlying_type{allocator},
432 owner{} {
433 }
434
437
443 : underlying_type{std::move(other)},
444 owner{other.owner} {}
445
452 : underlying_type{std::move(other), allocator},
453 owner{other.owner} {}
454
456 ~basic_reactive_mixin() override = default;
457
463
470 swap(other);
471 return *this;
472 }
473
479 using std::swap;
480 swap(owner, other.owner);
481 underlying_type::swap(other);
482 }
483
491 template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
493 owner_or_assert().template storage<Clazz>(id).on_construct().template connect<Candidate>(*this);
494 return *this;
495 }
496
504 template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
506 owner_or_assert().template storage<Clazz>(id).on_update().template connect<Candidate>(*this);
507 return *this;
508 }
509
517 template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
519 owner_or_assert().template storage<Clazz>(id).on_destroy().template connect<Candidate>(*this);
520 return *this;
521 }
522
527 [[nodiscard]] explicit operator bool() const noexcept {
528 return (owner != nullptr);
529 }
530
536 return owner_or_assert();
537 }
538
541 return owner_or_assert();
542 }
543
550 template<typename... Get, typename... Exclude>
553 const owner_type &parent = owner_or_assert();
555 [&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(parent.template storage<std::remove_const_t<Exclude>>()..., parent.template storage<std::remove_const_t<Get>>()..., this);
556 return elem;
557 }
558
560 template<typename... Get, typename... Exclude>
563 owner_type &parent = owner_or_assert();
564 return {*this, parent.template storage<std::remove_const_t<Get>>()..., parent.template storage<std::remove_const_t<Exclude>>()...};
565 }
566
567private:
568 basic_registry_type *owner;
569};
570
571} // namespace entt
572
573#endif
Mixin type used to add reactive support to storage types.
Definition mixin.hpp:389
basic_reactive_mixin & operator=(basic_reactive_mixin &&other) noexcept
Move assignment operator.
Definition mixin.hpp:469
basic_reactive_mixin(const allocator_type &allocator)
Constructs an empty storage with a given allocator.
Definition mixin.hpp:430
const registry_type & registry() const noexcept
Returns a pointer to the underlying registry, if any.
Definition mixin.hpp:535
basic_view< get_t< const basic_reactive_mixin, typename basic_registry_type::template storage_for_type< Get >... >, exclude_t< typename basic_registry_type::template storage_for_type< Exclude >... > > view(exclude_t< Exclude... >=exclude_t{})
Returns a view that is filtered by the underlying storage.
Definition mixin.hpp:562
basic_reactive_mixin(basic_reactive_mixin &&other) noexcept
Move constructor.
Definition mixin.hpp:442
void swap(basic_reactive_mixin &other) noexcept
Exchanges the contents with those of a given storage.
Definition mixin.hpp:478
basic_reactive_mixin()
Default constructor.
Definition mixin.hpp:423
~basic_reactive_mixin() override=default
Default destructor.
basic_view< get_t< const basic_reactive_mixin, typename basic_registry_type::template storage_for_type< const Get >... >, exclude_t< typename basic_registry_type::template storage_for_type< const Exclude >... > > view(exclude_t< Exclude... >=exclude_t{}) const
Returns a view that is filtered by the underlying storage.
Definition mixin.hpp:552
basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator)
Allocator-extended move constructor.
Definition mixin.hpp:451
typename underlying_type::allocator_type allocator_type
Allocator type.
Definition mixin.hpp:416
typename underlying_type::entity_type entity_type
Underlying entity identifier.
Definition mixin.hpp:418
basic_reactive_mixin(const basic_reactive_mixin &)=delete
Default copy constructor, deleted on purpose.
basic_reactive_mixin & on_update(const id_type id=type_hash< Clazz >::value())
Makes storage react to update of objects of the given type.
Definition mixin.hpp:505
owner_type registry_type
Expected registry type.
Definition mixin.hpp:420
basic_reactive_mixin & on_destroy(const id_type id=type_hash< Clazz >::value())
Makes storage react to destruction of objects of the given type.
Definition mixin.hpp:518
registry_type & registry() noexcept
Returns a pointer to the underlying registry, if any.
Definition mixin.hpp:540
basic_reactive_mixin & operator=(const basic_reactive_mixin &)=delete
Default copy assignment operator, deleted on purpose.
basic_reactive_mixin & on_construct(const id_type id=type_hash< Clazz >::value())
Makes storage react to creation of objects of the given type.
Definition mixin.hpp:492
Fast and reliable entity-component system.
Definition registry.hpp:234
Mixin type used to add signal support to storage types.
Definition mixin.hpp:71
auto on_update() noexcept
Returns a sink object.
Definition mixin.hpp:256
typename underlying_type::entity_type entity_type
Underlying entity identifier.
Definition mixin.hpp:141
auto on_construct() noexcept
Returns a sink object.
Definition mixin.hpp:241
const registry_type & registry() const noexcept
Returns a pointer to the underlying registry, if any.
Definition mixin.hpp:287
decltype(auto) patch(const entity_type entt, Func &&...func)
Patches the given instance for an entity.
Definition mixin.hpp:345
auto emplace()
Emplace elements into a storage.
Definition mixin.hpp:305
typename underlying_type::allocator_type allocator_type
Allocator type.
Definition mixin.hpp:139
void swap(basic_sigh_mixin &other) noexcept
Exchanges the contents with those of a given storage.
Definition mixin.hpp:221
basic_sigh_mixin & operator=(basic_sigh_mixin &&other) noexcept
Move assignment operator.
Definition mixin.hpp:212
basic_sigh_mixin(const allocator_type &allocator)
Constructs an empty storage with a given allocator.
Definition mixin.hpp:153
owner_type registry_type
Expected registry type.
Definition mixin.hpp:143
basic_sigh_mixin()
Default constructor.
Definition mixin.hpp:146
registry_type & registry() noexcept
Returns a pointer to the underlying registry, if any.
Definition mixin.hpp:292
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
Move constructor.
Definition mixin.hpp:179
~basic_sigh_mixin() override=default
Default destructor.
basic_sigh_mixin(const basic_sigh_mixin &)=delete
Default copy constructor, deleted on purpose.
void insert(It first, It last, Args &&...args)
Emplace elements into a storage.
Definition mixin.hpp:365
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator)
Allocator-extended move constructor.
Definition mixin.hpp:191
auto on_destroy() noexcept
Returns a sink object.
Definition mixin.hpp:271
basic_sigh_mixin & operator=(const basic_sigh_mixin &)=delete
Default copy assignment operator, deleted on purpose.
std::conditional_t< std::is_same_v< typename underlying_type::element_type, entity_type >, entity_type, decltype(std::declval< underlying_type >().get({}))> emplace(const entity_type hint, Args &&...args)
Emplace elements into a storage.
Definition mixin.hpp:325
Storage implementation.
Definition storage.hpp:230
View implementation.
Definition fwd.hpp:42
Sink class.
Definition fwd.hpp:22
EnTT default namespace.
Definition dense_map.hpp:22
entity
Default entity identifier.
Definition fwd.hpp:14
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:219
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
Definition entity.hpp:384
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:14
constexpr get_t< Type... > get
Variable template for lists of observed elements.
Definition fwd.hpp:168
@ in_place
In-place deletion policy.
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition fwd.hpp:76
Alias for exclusion lists.
Definition fwd.hpp:141
Type hash.
Definition type_info.hpp:92