1#ifndef ENTT_ENTITY_MIXIN_HPP
2#define ENTT_ENTITY_MIXIN_HPP
4#include "../config/config.h"
5#include "../core/any.hpp"
6#include "../core/type_info.hpp"
7#include "../signal/sigh.hpp"
8#include "../stl/concepts.hpp"
9#include "../stl/iterator.hpp"
10#include "../stl/type_traits.hpp"
11#include "../stl/utility.hpp"
12#include "../stl/vector.hpp"
21template<
typename,
typename>
22struct has_on_construct final: stl::false_type {};
24template<
typename Type,
typename Registry>
25requires stl::invocable<
decltype(&Type::on_construct), Registry &,
typename Registry::entity_type>
26struct has_on_construct<Type, Registry>: stl::true_type {};
28template<
typename,
typename>
29struct has_on_update final: stl::false_type {};
31template<
typename Type,
typename Registry>
32requires stl::invocable<
decltype(&Type::on_update), Registry &,
typename Registry::entity_type>
33struct has_on_update<Type, Registry>: stl::true_type {};
35template<
typename,
typename>
36struct has_on_destroy final: stl::false_type {};
38template<
typename Type,
typename Registry>
39requires stl::invocable<
decltype(&Type::on_destroy), Registry &,
typename Registry::entity_type>
40struct has_on_destroy<Type, Registry>: stl::true_type {};
59template<
typename Type,
typename Registry>
61 using underlying_type = Type;
62 using owner_type = Registry;
65 using sigh_type =
sigh<void(owner_type &,
const typename underlying_type::entity_type),
typename underlying_type::allocator_type>;
66 using underlying_iterator = underlying_type::base_type::basic_iterator;
68 static_assert(stl::is_base_of_v<basic_registry_type, owner_type>,
"Invalid registry type");
70 [[nodiscard]]
auto &owner_or_assert()
const noexcept {
71 ENTT_ASSERT(owner !=
nullptr,
"Invalid pointer to registry");
72 return static_cast<owner_type &
>(*owner);
76 void pop(underlying_iterator first, underlying_iterator last)
final {
77 if(
auto ® = owner_or_assert(); destruction.empty()) {
78 underlying_type::pop(first, last);
80 for(; first != last; ++first) {
81 const auto entt = *first;
82 destruction.publish(reg,
entt);
83 const auto it = underlying_type::find(
entt);
84 underlying_type::pop(it, it + 1u);
89 void pop_all()
final {
90 if(
auto ® = owner_or_assert(); !destruction.empty()) {
91 if constexpr(stl::is_same_v<typename underlying_type::element_type, entity_type>) {
92 for(
typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) {
93 destruction.publish(reg, underlying_type::base_type::operator[](pos));
96 for(
auto entt:
static_cast<underlying_type::base_type &
>(*
this)) {
99 destruction.publish(reg,
entt);
102 destruction.publish(reg,
entt);
108 underlying_type::pop_all();
111 underlying_iterator try_emplace(
const underlying_type::entity_type
entt,
const bool force_back,
const void *value)
final {
112 const auto it = underlying_type::try_emplace(
entt, force_back, value);
114 if(
auto ® = owner_or_assert(); it != underlying_type::base_type::end()) {
115 construction.publish(reg, *it);
121 void bind_any(
any value)
noexcept final {
124 if constexpr(!stl::is_same_v<registry_type, basic_registry_type>) {
125 if(owner ==
nullptr) {
130 underlying_type::bind_any(stl::move(value));
150 : underlying_type{allocator},
152 construction{allocator},
153 destruction{allocator},
155 if constexpr(internal::has_on_construct<typename underlying_type::element_type, Registry>::value) {
156 sink{construction}.template connect<&underlying_type::element_type::on_construct>();
159 if constexpr(internal::has_on_update<typename underlying_type::element_type, Registry>::value) {
160 sink{update}.template connect<&underlying_type::element_type::on_update>();
163 if constexpr(internal::has_on_destroy<typename underlying_type::element_type, Registry>::value) {
164 sink{destruction}.template connect<&underlying_type::element_type::on_destroy>();
176 : underlying_type{
static_cast<underlying_type &&
>(other)},
178 construction{stl::move(other.construction)},
179 destruction{stl::move(other.destruction)},
180 update{stl::move(other.update)} {}
188 : underlying_type{static_cast<underlying_type &&>(other), allocator},
190 construction{
stl::move(other.construction), allocator},
191 destruction{
stl::move(other.destruction), allocator},
192 update{
stl::move(other.update), allocator} {}
219 swap(owner, other.owner);
220 swap(construction, other.construction);
221 swap(destruction, other.destruction);
222 swap(update, other.update);
223 underlying_type::swap(other);
238 return sink{construction};
268 return sink{destruction};
275 [[nodiscard]]
explicit operator bool() const noexcept {
276 return (owner !=
nullptr);
284 return owner_or_assert();
289 return owner_or_assert();
297 const auto entt = underlying_type::generate();
298 construction.publish(owner_or_assert(),
entt);
308 const auto entt = underlying_type::generate(hint);
309 construction.publish(owner_or_assert(),
entt);
319 template<stl::output_iterator<entity_type> It>
321 underlying_type::generate(first, last);
323 if(
auto ® = owner_or_assert(); !construction.empty()) {
324 for(; first != last; ++first) {
325 construction.publish(reg, *first);
337 template<
typename... Args>
339 underlying_type::emplace(
entt, stl::forward<Args>(args)...);
340 construction.publish(owner_or_assert(),
entt);
341 return this->
get(entt);
351 template<
typename... Func>
353 underlying_type::patch(
entt, stl::forward<Func>(func)...);
354 update.publish(owner_or_assert(),
entt);
355 return this->
get(entt);
366 template<
typename... Args>
367 void insert(stl::input_iterator
auto first, stl::input_iterator
auto last, Args &&...args) {
368 auto from = underlying_type::size();
369 underlying_type::insert(first, last, stl::forward<Args>(args)...);
371 if(
auto ® = owner_or_assert(); !construction.empty()) {
373 for(
const auto to = underlying_type::size(); from != to; ++from) {
374 construction.publish(reg, underlying_type::operator[](from));
380 basic_registry_type *owner;
381 sigh_type construction;
382 sigh_type destruction;
391template<
typename Type,
typename Registry>
393 using underlying_type = Type;
394 using owner_type = Registry;
396 using alloc_traits = stl::allocator_traits<typename underlying_type::allocator_type>;
398 using container_type = stl::vector<connection, typename alloc_traits::template rebind_alloc<connection>>;
400 static_assert(stl::is_base_of_v<basic_registry_type, owner_type>,
"Invalid registry type");
402 [[nodiscard]]
auto &owner_or_assert()
const noexcept {
403 ENTT_ASSERT(owner !=
nullptr,
"Invalid pointer to registry");
404 return static_cast<owner_type &
>(*owner);
407 void emplace_element(
const Registry &, underlying_type::entity_type
entity) {
408 if(!underlying_type::contains(
entity)) {
409 underlying_type::emplace(
entity);
414 void bind_any(
any value)
noexcept final {
417 if constexpr(!stl::is_same_v<registry_type, basic_registry_type>) {
418 if(owner ==
nullptr) {
423 underlying_type::bind_any(stl::move(value));
443 : underlying_type{allocator},
456 : underlying_type{
static_cast<underlying_type &&
>(other)},
458 conn{stl::move(other.conn)} {
467 : underlying_type{static_cast<underlying_type &&>(other), allocator},
469 conn{
stl::move(other.conn), allocator} {
487 underlying_type::swap(other);
498 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
500 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_construct().template connect<Candidate>(*
this);
501 conn.push_back(stl::move(curr));
512 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
514 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_update().template connect<Candidate>(*
this);
515 conn.push_back(stl::move(curr));
526 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
528 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_destroy().template connect<Candidate>(*
this);
529 conn.push_back(stl::move(curr));
537 [[nodiscard]]
explicit operator bool() const noexcept {
538 return (owner !=
nullptr);
546 return owner_or_assert();
551 return owner_or_assert();
560 template<
typename... Get,
typename... Exclude>
563 const owner_type &parent = owner_or_assert();
570 template<
typename... Get,
typename... Exclude>
573 stl::conditional_t<((stl::is_const_v<Get> && ...) && (stl::is_const_v<Exclude> && ...)),
const owner_type, owner_type> &parent = owner_or_assert();
579 for(
auto &&curr: conn) {
587 basic_registry_type *owner;
basic_reactive_mixin & operator=(basic_reactive_mixin &&other) noexcept
underlying_type::entity_type entity_type
basic_reactive_mixin(const allocator_type &allocator)
const registry_type & registry() const noexcept
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{})
basic_reactive_mixin(basic_reactive_mixin &&other) noexcept
basic_reactive_mixin()
Default constructor.
~basic_reactive_mixin() override=default
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
basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator)
underlying_type::allocator_type allocator_type
basic_reactive_mixin(const basic_reactive_mixin &)=delete
basic_reactive_mixin & on_update(const id_type id=type_hash< Clazz >::value())
basic_reactive_mixin & on_destroy(const id_type id=type_hash< Clazz >::value())
registry_type & registry() noexcept
basic_reactive_mixin & operator=(const basic_reactive_mixin &)=delete
basic_reactive_mixin & on_construct(const id_type id=type_hash< Clazz >::value())
Fast and reliable entity-component system.
auto on_update() noexcept
auto on_construct() noexcept
const registry_type & registry() const noexcept
decltype(auto) patch(const entity_type entt, Func &&...func)
void generate(It first, It last)
underlying_type::entity_type entity_type
underlying_type::allocator_type allocator_type
entity_type generate(const entity_type hint)
void swap(basic_sigh_mixin &other) noexcept
Exchanges the contents with those of a given storage.
basic_sigh_mixin & operator=(basic_sigh_mixin &&other) noexcept
basic_sigh_mixin(const allocator_type &allocator)
basic_sigh_mixin()
Default constructor.
registry_type & registry() noexcept
decltype(auto) emplace(const entity_type entt, Args &&...args)
void insert(stl::input_iterator auto first, stl::input_iterator auto last, Args &&...args)
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
~basic_sigh_mixin() override=default
basic_sigh_mixin(const basic_sigh_mixin &)=delete
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator)
auto on_destroy() noexcept
basic_sigh_mixin & operator=(const basic_sigh_mixin &)=delete
Unmanaged signal handler.
Custom EnTT namespace for the standard template library.
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
entity
Default entity identifier.
@ in_place
In-place deletion policy.
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
basic_any<> any
Alias declaration for the most common use case.
constexpr get_t< Type... > get
Variable template for lists of observed elements.
stl::remove_const_t< Type > any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
stl::uint32_t id_type
Alias declaration for type identifiers.
basic_storage< Type > storage
Alias declaration for the most common use case.
Alias for exclusion lists.
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.