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()))>>
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);
44 if constexpr(!std::is_same_v<Type, base_type>) {
46 reg = any_cast<Type>(&value);
70template<
typename Type,
typename Registry>
72 using underlying_type = Type;
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;
79 static_assert(std::is_base_of_v<basic_registry_type, owner_type>,
"Invalid registry type");
81 [[
nodiscard]]
auto &owner_or_assert()
const noexcept {
82 ENTT_ASSERT(owner !=
nullptr,
"Invalid pointer to registry");
83 return static_cast<owner_type &
>(*owner);
87 void pop(underlying_iterator first, underlying_iterator last)
final {
88 if(
auto ® = owner_or_assert(); destruction.empty()) {
89 underlying_type::pop(first, last);
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);
100 void pop_all()
final {
101 if(
auto ® = 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));
107 for(
auto entt:
static_cast<typename underlying_type::base_type &
>(*this)) {
110 destruction.publish(reg,
entt);
113 destruction.publish(reg,
entt);
119 underlying_type::pop_all();
122 underlying_iterator try_emplace(
const typename underlying_type::entity_type
entt,
const bool force_back,
const void *value)
final {
125 if(
auto ® = owner_or_assert();
it != underlying_type::base_type::end()) {
126 construction.publish(reg, *
it);
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));
159 if constexpr(internal::has_on_construct<typename underlying_type::element_type, Registry>::value) {
163 if constexpr(internal::has_on_update<typename underlying_type::element_type, Registry>::value) {
167 if constexpr(internal::has_on_destroy<typename underlying_type::element_type, Registry>::value) {
180 : underlying_type{std::move(
other)},
182 construction{std::move(
other.construction)},
183 destruction{std::move(
other.destruction)},
184 update{std::move(
other.update)} {}
227 underlying_type::swap(
other);
242 return sink{construction};
272 return sink{destruction};
280 return (owner !=
nullptr);
288 return owner_or_assert();
293 return owner_or_assert();
306 const auto entt = underlying_type::emplace();
307 construction.publish(owner_or_assert(),
entt);
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);
331 underlying_type::emplace(
hint, std::forward<Args>(
args)...);
332 construction.publish(owner_or_assert(),
hint);
333 return this->
get(hint);
344 template<
typename... Func>
346 underlying_type::patch(
entt, std::forward<Func>(func)...);
347 update.publish(owner_or_assert(),
entt);
348 return this->
get(entt);
364 template<
typename It,
typename...
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()) {
370 for(
const auto to = underlying_type::size();
from !=
to; ++
from) {
371 construction.publish(reg, underlying_type::operator[](
from));
377 basic_registry_type *owner;
378 sigh_type construction;
379 sigh_type destruction;
388template<
typename Type,
typename Registry>
390 using underlying_type = Type;
395 static_assert(std::is_base_of_v<basic_registry_type, owner_type>,
"Invalid registry type");
397 [[
nodiscard]]
auto &owner_or_assert()
const noexcept {
398 ENTT_ASSERT(owner !=
nullptr,
"Invalid pointer to registry");
399 return static_cast<owner_type &
>(*owner);
402 void emplace_element(
const Registry &,
typename underlying_type::entity_type
entity) {
403 if(!underlying_type::contains(
entity)) {
404 underlying_type::emplace(
entity);
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));
443 : underlying_type{std::move(
other)},
444 owner{
other.owner} {}
453 owner{
other.owner} {}
481 underlying_type::swap(
other);
491 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
504 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
517 template<
typename Clazz, auto Cand
idate = &basic_reactive_mixin::emplace_element>
528 return (owner !=
nullptr);
536 return owner_or_assert();
541 return owner_or_assert();
550 template<
typename...
Get,
typename...
Exclude>
553 const owner_type &parent = owner_or_assert();
560 template<
typename...
Get,
typename...
Exclude>
563 owner_type &parent = owner_or_assert();
568 basic_registry_type *owner;
Mixin type used to add reactive support to storage types.
basic_reactive_mixin & operator=(basic_reactive_mixin &&other) noexcept
Move assignment operator.
basic_reactive_mixin(const allocator_type &allocator)
Constructs an empty storage with a given allocator.
const registry_type & registry() const noexcept
Returns a pointer to the underlying registry, if any.
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.
basic_reactive_mixin(basic_reactive_mixin &&other) noexcept
Move constructor.
void swap(basic_reactive_mixin &other) noexcept
Exchanges the contents with those of a given storage.
basic_reactive_mixin()
Default constructor.
~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.
basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator)
Allocator-extended move constructor.
typename underlying_type::allocator_type allocator_type
Allocator type.
typename underlying_type::entity_type entity_type
Underlying entity identifier.
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.
owner_type registry_type
Expected registry type.
basic_reactive_mixin & on_destroy(const id_type id=type_hash< Clazz >::value())
Makes storage react to destruction of objects of the given type.
registry_type & registry() noexcept
Returns a pointer to the underlying registry, if any.
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.
Fast and reliable entity-component system.
Mixin type used to add signal support to storage types.
auto on_update() noexcept
Returns a sink object.
typename underlying_type::entity_type entity_type
Underlying entity identifier.
auto on_construct() noexcept
Returns a sink object.
const registry_type & registry() const noexcept
Returns a pointer to the underlying registry, if any.
decltype(auto) patch(const entity_type entt, Func &&...func)
Patches the given instance for an entity.
auto emplace()
Emplace elements into a storage.
typename underlying_type::allocator_type allocator_type
Allocator type.
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
Move assignment operator.
basic_sigh_mixin(const allocator_type &allocator)
Constructs an empty storage with a given allocator.
owner_type registry_type
Expected registry type.
basic_sigh_mixin()
Default constructor.
registry_type & registry() noexcept
Returns a pointer to the underlying registry, if any.
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
Move constructor.
~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.
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator)
Allocator-extended move constructor.
auto on_destroy() noexcept
Returns a sink object.
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.
entity
Default entity identifier.
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
std::uint32_t id_type
Alias declaration for type identifiers.
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.