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 entt::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 entt::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 entt::sink{destruction}.template connect<&underlying_type::element_type::on_destroy>();
174 : underlying_type{std::move(other)},
176 construction{std::move(other.construction)},
177 destruction{std::move(other.destruction)},
178 update{std::move(other.update)} {}
188 : underlying_type{std::move(other), allocator},
190 construction{std::move(other.construction), allocator},
191 destruction{std::move(other.destruction), allocator},
192 update{std::move(other.update), allocator} {}
220 swap(owner, other.owner);
221 swap(construction, other.construction);
222 swap(destruction, other.destruction);
223 swap(update, other.update);
224 underlying_type::swap(other);
239 return sink{construction};
269 return sink{destruction};
276 [[nodiscard]]
explicit operator bool() const noexcept {
277 return (owner !=
nullptr);
285 return owner_or_assert();
290 return owner_or_assert();
298 const auto entt = underlying_type::generate();
299 construction.publish(owner_or_assert(),
entt);
309 const auto entt = underlying_type::generate(hint);
310 construction.publish(owner_or_assert(),
entt);
320 template<
typename It>
322 underlying_type::generate(first, last);
324 if(
auto ® = owner_or_assert(); !construction.empty()) {
325 for(; first != last; ++first) {
326 construction.publish(reg, *first);
338 template<
typename... Args>
340 underlying_type::emplace(
entt, std::forward<Args>(args)...);
341 construction.publish(owner_or_assert(),
entt);
342 return this->
get(entt);
352 template<
typename... Func>
354 underlying_type::patch(
entt, std::forward<Func>(func)...);
355 update.publish(owner_or_assert(),
entt);
356 return this->
get(entt);
368 template<
typename It,
typename... Args>
369 void insert(It first, It last, Args &&...args) {
370 auto from = underlying_type::size();
371 underlying_type::insert(first, last, std::forward<Args>(args)...);
373 if(
auto ® = owner_or_assert(); !construction.empty()) {
375 for(
const auto to = underlying_type::size(); from != to; ++from) {
376 construction.publish(reg, underlying_type::operator[](from));
382 basic_registry_type *owner;
383 sigh_type construction;
384 sigh_type destruction;
393template<
typename Type,
typename Registry>
395 using underlying_type = Type;
396 using owner_type = Registry;
398 using alloc_traits = std::allocator_traits<typename underlying_type::allocator_type>;
400 using container_type = std::vector<connection, typename alloc_traits::template rebind_alloc<connection>>;
402 static_assert(std::is_base_of_v<basic_registry_type, owner_type>,
"Invalid registry type");
404 [[nodiscard]]
auto &owner_or_assert()
const noexcept {
405 ENTT_ASSERT(owner !=
nullptr,
"Invalid pointer to registry");
406 return static_cast<owner_type &
>(*owner);
409 void emplace_element(
const Registry &,
typename underlying_type::entity_type
entity) {
410 if(!underlying_type::contains(
entity)) {
411 underlying_type::emplace(
entity);
416 void bind_any(
any value)
noexcept final {
419 if constexpr(!std::is_same_v<registry_type, basic_registry_type>) {
420 if(owner ==
nullptr) {
425 underlying_type::bind_any(std::move(value));
445 : underlying_type{allocator},
459 : underlying_type{std::move(other)},
472 : underlying_type{std::move(other), allocator},
493 underlying_type::swap(other);
504 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
506 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_construct().template connect<Candidate>(*
this);
507 conn.push_back(std::move(curr));
518 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
520 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_update().template connect<Candidate>(*
this);
521 conn.push_back(std::move(curr));
532 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
534 auto curr = owner_or_assert().template
storage<Clazz>(
id).on_destroy().template connect<Candidate>(*
this);
535 conn.push_back(std::move(curr));
543 [[nodiscard]]
explicit operator bool() const noexcept {
544 return (owner !=
nullptr);
552 return owner_or_assert();
557 return owner_or_assert();
566 template<
typename... Get,
typename... Exclude>
569 const owner_type &parent = owner_or_assert();
576 template<
typename... Get,
typename... Exclude>
579 std::conditional_t<((std::is_const_v<Get> && ...) && (std::is_const_v<Exclude> && ...)),
const owner_type, owner_type> &parent = owner_or_assert();
585 for(
auto &&curr: conn) {
593 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.