1#ifndef ENTT_ENTITY_MIXIN_HPP
2#define ENTT_ENTITY_MIXIN_HPP
6#include "../config/config.h"
7#include "../core/any.hpp"
8#include "../core/type_info.hpp"
9#include "../signal/sigh.hpp"
18template<
typename,
typename,
typename =
void>
19struct has_on_construct final: std::false_type {};
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()))>>
25template<
typename,
typename,
typename =
void>
26struct has_on_update final: std::false_type {};
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()))>>
32template<
typename,
typename,
typename =
void>
33struct has_on_destroy final: std::false_type {};
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()))>>
56template<
typename Type,
typename Registry>
58 using underlying_type = Type;
59 using owner_type = Registry;
62 using sigh_type =
sigh<void(owner_type &,
const typename underlying_type::entity_type),
typename underlying_type::allocator_type>;
63 using underlying_iterator =
typename underlying_type::base_type::basic_iterator;
65 static_assert(std::is_base_of_v<basic_registry_type, owner_type>,
"Invalid registry type");
67 [[nodiscard]]
auto &owner_or_assert()
const noexcept {
68 ENTT_ASSERT(owner !=
nullptr,
"Invalid pointer to registry");
69 return static_cast<owner_type &
>(*owner);
73 void pop(underlying_iterator first, underlying_iterator last)
final {
74 if(
auto ® = owner_or_assert(); destruction.empty()) {
75 underlying_type::pop(first, last);
77 for(; first != last; ++first) {
78 const auto entt = *first;
79 destruction.publish(reg,
entt);
80 const auto it = underlying_type::find(
entt);
81 underlying_type::pop(it, it + 1u);
86 void pop_all()
final {
87 if(
auto ® = owner_or_assert(); !destruction.empty()) {
88 if constexpr(std::is_same_v<typename underlying_type::element_type, entity_type>) {
89 for(
typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) {
90 destruction.publish(reg, underlying_type::base_type::operator[](pos));
93 for(
auto entt:
static_cast<typename underlying_type::base_type &
>(*
this)) {
96 destruction.publish(reg,
entt);
99 destruction.publish(reg,
entt);
105 underlying_type::pop_all();
108 underlying_iterator try_emplace(
const typename underlying_type::entity_type
entt,
const bool force_back,
const void *value)
final {
109 const auto it = underlying_type::try_emplace(
entt, force_back, value);
111 if(
auto ® = owner_or_assert(); it != underlying_type::base_type::end()) {
112 construction.publish(reg, *it);
118 void bind_any(
any value)
noexcept final {
121 if constexpr(!std::is_same_v<registry_type, basic_registry_type>) {
122 if(owner ==
nullptr) {
127 underlying_type::bind_any(std::move(value));
147 : underlying_type{allocator},
149 construction{allocator},
150 destruction{allocator},
152 if constexpr(internal::has_on_construct<typename underlying_type::element_type, Registry>::value) {
153 sink{construction}.template connect<&underlying_type::element_type::on_construct>();
156 if constexpr(internal::has_on_update<typename underlying_type::element_type, Registry>::value) {
157 sink{update}.template connect<&underlying_type::element_type::on_update>();
160 if constexpr(internal::has_on_destroy<typename underlying_type::element_type, Registry>::value) {
161 sink{destruction}.template connect<&underlying_type::element_type::on_destroy>();
173 : underlying_type{
static_cast<underlying_type &&
>(other)},
175 construction{std::move(other.construction)},
176 destruction{std::move(other.destruction)},
177 update{std::move(other.update)} {}
185 : underlying_type{static_cast<underlying_type &&>(other), allocator},
187 construction{std::move(other.construction), allocator},
188 destruction{std::move(other.destruction), allocator},
189 update{std::move(other.update), allocator} {}
216 swap(owner, other.owner);
217 swap(construction, other.construction);
218 swap(destruction, other.destruction);
219 swap(update, other.update);
220 underlying_type::swap(other);
235 return sink{construction};
265 return sink{destruction};
272 [[nodiscard]]
explicit operator bool() const noexcept {
273 return (owner !=
nullptr);
281 return owner_or_assert();
286 return owner_or_assert();
294 const auto entt = underlying_type::generate();
295 construction.publish(owner_or_assert(),
entt);
305 const auto entt = underlying_type::generate(hint);
306 construction.publish(owner_or_assert(),
entt);
316 template<
typename It>
318 underlying_type::generate(first, last);
320 if(
auto ® = owner_or_assert(); !construction.empty()) {
321 for(; first != last; ++first) {
322 construction.publish(reg, *first);
334 template<
typename... Args>
336 underlying_type::emplace(
entt, std::forward<Args>(args)...);
337 construction.publish(owner_or_assert(),
entt);
338 return this->
get(entt);
348 template<
typename... Func>
350 underlying_type::patch(
entt, std::forward<Func>(func)...);
351 update.publish(owner_or_assert(),
entt);
352 return this->
get(entt);
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)...);
369 if(
auto ® = owner_or_assert(); !construction.empty()) {
371 for(
const auto to = underlying_type::size(); from != to; ++from) {
372 construction.publish(reg, underlying_type::operator[](from));
378 basic_registry_type *owner;
379 sigh_type construction;
380 sigh_type destruction;
389template<
typename Type,
typename Registry>
391 using underlying_type = Type;
392 using owner_type = Registry;
394 using alloc_traits = std::allocator_traits<typename underlying_type::allocator_type>;
396 using container_type = std::vector<connection, typename alloc_traits::template rebind_alloc<connection>>;
398 static_assert(std::is_base_of_v<basic_registry_type, owner_type>,
"Invalid registry type");
400 [[nodiscard]]
auto &owner_or_assert()
const noexcept {
401 ENTT_ASSERT(owner !=
nullptr,
"Invalid pointer to registry");
402 return static_cast<owner_type &
>(*owner);
405 void emplace_element(
const Registry &,
typename underlying_type::entity_type
entity) {
406 if(!underlying_type::contains(
entity)) {
407 underlying_type::emplace(
entity);
412 void bind_any(
any value)
noexcept final {
415 if constexpr(!std::is_same_v<registry_type, basic_registry_type>) {
416 if(owner ==
nullptr) {
421 underlying_type::bind_any(std::move(value));
441 : underlying_type{allocator},
454 : underlying_type{
static_cast<underlying_type &&
>(other)},
456 conn{std::move(other.conn)} {
465 : underlying_type{static_cast<underlying_type &&>(other), allocator},
467 conn{std::move(other.conn), allocator} {
485 underlying_type::swap(other);
496 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
498 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_construct().template connect<Candidate>(*
this);
499 conn.push_back(std::move(curr));
510 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
512 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_update().template connect<Candidate>(*
this);
513 conn.push_back(std::move(curr));
524 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
526 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_destroy().template connect<Candidate>(*
this);
527 conn.push_back(std::move(curr));
535 [[nodiscard]]
explicit operator bool() const noexcept {
536 return (owner !=
nullptr);
544 return owner_or_assert();
549 return owner_or_assert();
558 template<
typename... Get,
typename... Exclude>
561 const owner_type &parent = owner_or_assert();
568 template<
typename... Get,
typename... Exclude>
571 std::conditional_t<((std::is_const_v<Get> && ...) && (std::is_const_v<Exclude> && ...)),
const owner_type, owner_type> &parent = owner_or_assert();
577 for(
auto &&curr: conn) {
585 basic_registry_type *owner;
basic_reactive_mixin & operator=(basic_reactive_mixin &&other) noexcept
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)
typename underlying_type::allocator_type allocator_type
typename underlying_type::entity_type entity_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
typename underlying_type::entity_type entity_type
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)
typename 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)
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
~basic_sigh_mixin() override=default
basic_sigh_mixin(const basic_sigh_mixin &)=delete
void insert(It first, It last, Args &&...args)
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.
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
entity
Default entity identifier.
std::remove_const_t< Type > any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
std::uint32_t id_type
Alias declaration for type identifiers.
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.
@ in_place
In-place deletion policy.
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.