1#ifndef ENTT_ENTITY_REGISTRY_HPP
2#define ENTT_ENTITY_REGISTRY_HPP
13#include "../config/config.h"
14#include "../container/dense_map.hpp"
15#include "../core/algorithm.hpp"
16#include "../core/any.hpp"
17#include "../core/fwd.hpp"
18#include "../core/iterator.hpp"
19#include "../core/memory.hpp"
20#include "../core/type_info.hpp"
21#include "../core/type_traits.hpp"
22#include "../core/utility.hpp"
27#include "sparse_set.hpp"
37class registry_storage_iterator final {
38 template<
typename Other>
39 friend class registry_storage_iterator;
41 using mapped_type = std::remove_reference_t<decltype(std::declval<It>()->second)>;
44 using value_type = std::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
45 using pointer = input_iterator_pointer<value_type>;
46 using reference = value_type;
47 using difference_type = std::ptrdiff_t;
48 using iterator_category = std::input_iterator_tag;
49 using iterator_concept = std::random_access_iterator_tag;
51 constexpr registry_storage_iterator() noexcept
54 constexpr registry_storage_iterator(It iter) noexcept
57 template<
typename Other,
typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
58 constexpr registry_storage_iterator(
const registry_storage_iterator<Other> &other) noexcept
59 : registry_storage_iterator{other.it} {}
61 constexpr registry_storage_iterator &operator++() noexcept {
65 constexpr registry_storage_iterator operator++(
int)
noexcept {
66 registry_storage_iterator orig = *
this;
67 return ++(*this), orig;
70 constexpr registry_storage_iterator &operator--() noexcept {
74 constexpr registry_storage_iterator operator--(
int)
noexcept {
75 registry_storage_iterator orig = *
this;
76 return operator--(), orig;
79 constexpr registry_storage_iterator &operator+=(
const difference_type value)
noexcept {
84 constexpr registry_storage_iterator
operator+(
const difference_type value)
const noexcept {
85 registry_storage_iterator copy = *
this;
86 return (copy += value);
89 constexpr registry_storage_iterator &operator-=(
const difference_type value)
noexcept {
90 return (*
this += -value);
93 constexpr registry_storage_iterator operator-(
const difference_type value)
const noexcept {
94 return (*
this + -value);
97 [[nodiscard]]
constexpr reference operator[](
const difference_type value)
const noexcept {
98 return {it[value].first, *it[value].second};
101 [[nodiscard]]
constexpr reference operator*() const noexcept {
102 return {it->first, *it->second};
105 [[nodiscard]]
constexpr pointer operator->() const noexcept {
109 template<
typename Lhs,
typename Rhs>
110 friend constexpr std::ptrdiff_t operator-(
const registry_storage_iterator<Lhs> &,
const registry_storage_iterator<Rhs> &)
noexcept;
112 template<
typename Lhs,
typename Rhs>
113 friend constexpr bool operator==(
const registry_storage_iterator<Lhs> &,
const registry_storage_iterator<Rhs> &)
noexcept;
115 template<
typename Lhs,
typename Rhs>
116 friend constexpr bool operator<(
const registry_storage_iterator<Lhs> &,
const registry_storage_iterator<Rhs> &)
noexcept;
122template<
typename Lhs,
typename Rhs>
123[[nodiscard]]
constexpr std::ptrdiff_t operator-(
const registry_storage_iterator<Lhs> &lhs,
const registry_storage_iterator<Rhs> &rhs)
noexcept {
124 return lhs.it - rhs.it;
127template<
typename Lhs,
typename Rhs>
128[[nodiscard]]
constexpr bool operator==(
const registry_storage_iterator<Lhs> &lhs,
const registry_storage_iterator<Rhs> &rhs)
noexcept {
129 return lhs.it == rhs.it;
132template<
typename Lhs,
typename Rhs>
133[[nodiscard]]
constexpr bool operator!=(
const registry_storage_iterator<Lhs> &lhs,
const registry_storage_iterator<Rhs> &rhs)
noexcept {
134 return !(lhs == rhs);
137template<
typename Lhs,
typename Rhs>
138[[nodiscard]]
constexpr bool operator<(
const registry_storage_iterator<Lhs> &lhs,
const registry_storage_iterator<Rhs> &rhs)
noexcept {
139 return lhs.it < rhs.it;
142template<
typename Lhs,
typename Rhs>
143[[nodiscard]]
constexpr bool operator>(
const registry_storage_iterator<Lhs> &lhs,
const registry_storage_iterator<Rhs> &rhs)
noexcept {
147template<
typename Lhs,
typename Rhs>
148[[nodiscard]]
constexpr bool operator<=(
const registry_storage_iterator<Lhs> &lhs,
const registry_storage_iterator<Rhs> &rhs)
noexcept {
152template<
typename Lhs,
typename Rhs>
153[[nodiscard]]
constexpr bool operator>=(
const registry_storage_iterator<Lhs> &lhs,
const registry_storage_iterator<Rhs> &rhs)
noexcept {
157template<
typename Allocator>
158class registry_context {
159 using alloc_traits = std::allocator_traits<Allocator>;
160 using allocator_type =
typename alloc_traits::template rebind_alloc<std::pair<const id_type, basic_any<0u>>>;
163 explicit registry_context(
const allocator_type &allocator)
166 template<
typename Type,
typename... Args>
167 Type &emplace_as(
const id_type
id, Args &&...args) {
168 return any_cast<Type &>(ctx.try_emplace(
id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
171 template<
typename Type,
typename... Args>
172 Type &emplace(Args &&...args) {
173 return emplace_as<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
176 template<
typename Type>
177 Type &insert_or_assign(
const id_type
id, Type &&value) {
178 return any_cast<std::remove_cv_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(
id, std::forward<Type>(value)).first->second);
181 template<
typename Type>
182 Type &insert_or_assign(Type &&value) {
183 return insert_or_assign(type_id<Type>().hash(), std::forward<Type>(value));
186 template<
typename Type>
187 bool erase(
const id_type
id = type_id<Type>().hash()) {
188 const auto it = ctx.find(
id);
189 return it != ctx.end() && it->second.type() == type_id<Type>() ? (ctx.erase(it),
true) : false;
192 template<
typename Type>
193 [[nodiscard]]
const Type &
get(
const id_type
id = type_id<Type>().hash())
const {
194 return any_cast<const Type &>(ctx.at(
id));
197 template<
typename Type>
198 [[nodiscard]] Type &
get(
const id_type
id = type_id<Type>().hash()) {
199 return any_cast<Type &>(ctx.at(
id));
202 template<
typename Type>
203 [[nodiscard]]
const Type *find(
const id_type
id = type_id<Type>().hash())
const {
204 const auto it = ctx.find(
id);
205 return it != ctx.cend() ? any_cast<const Type>(&it->second) : nullptr;
208 template<
typename Type>
209 [[nodiscard]] Type *find(
const id_type
id = type_id<Type>().hash()) {
210 const auto it = ctx.find(
id);
211 return it != ctx.end() ? any_cast<Type>(&it->second) : nullptr;
214 template<
typename Type>
215 [[nodiscard]]
bool contains(
const id_type
id = type_id<Type>().hash())
const {
216 const auto it = ctx.find(
id);
217 return it != ctx.cend() && it->second.type() == type_id<Type>();
221 dense_map<id_type, basic_any<0u>, identity, std::equal_to<id_type>, allocator_type> ctx;
232template<
typename Entity,
typename Allocator>
236 using alloc_traits = std::allocator_traits<Allocator>;
237 static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>,
"Invalid value type");
243 template<
typename Type>
245 static_assert(std::is_same_v<Type, std::decay_t<Type>>,
"Non-decayed types not allowed");
247 if constexpr(std::is_same_v<Type, entity_type>) {
250 auto &
cpool = pools[id];
254 using alloc_type =
typename storage_type::allocator_type;
256 if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
271 template<
typename Type>
273 static_assert(std::is_same_v<Type, std::decay_t<Type>>,
"Non-decayed types not allowed");
275 if constexpr(std::is_same_v<Type, entity_type>) {
278 if(
const auto it = pools.
find(
id);
it != pools.
cend()) {
290 for(
auto &&
curr: pools) {
309 using context = internal::registry_context<allocator_type>;
319 template<
typename Type>
352 : vars{std::move(
other.vars)},
353 pools{std::move(
other.pools)},
354 groups{std::move(
other.groups)},
355 entities{std::move(
other.entities)} {
365 vars = std::move(
other.vars);
366 pools = std::move(
other.pools);
367 groups = std::move(
other.groups);
368 entities = std::move(
other.entities);
396 return entities.get_allocator();
408 return iterable_adaptor{internal::registry_storage_iterator{pools.
begin()}, internal::registry_storage_iterator{pools.
end()}};
413 return iterable_adaptor{internal::registry_storage_iterator{pools.
cbegin()}, internal::registry_storage_iterator{pools.
cend()}};
422 return const_cast<common_type *
>(std::as_const(*this).storage(
id));
431 const auto it = pools.
find(
id);
441 template<
typename Type>
452 template<
typename Type>
463 return entities.contains(
entt) && (entities.index(
entt) < entities.free_list());
473 return entities.current(
entt);
481 return entities.emplace();
494 return entities.emplace(
hint);
506 template<
typename It>
508 entities.insert(std::move(first), std::move(last));
526 entities.erase(
entt);
527 return entities.current(
entt);
544 const auto elem = traits_type::construct(traits_type::to_entity(
entt),
version);
557 template<
typename It>
559 entities.sort_as(first, last);
561 const auto from = entities.cbegin(0);
562 const auto to =
from + std::distance(first, last);
564 for(
auto &&
curr: pools) {
586 template<
typename Type,
typename...
Args>
602 template<
typename Type,
typename It>
604 assure<Type>().insert(std::move(first), std::move(last), value);
636 template<
typename Type,
typename...
Args>
639 return cpool.patch(
entt, [&
args...](
auto &...curr) { ((
curr = Type{std::forward<Args>(
args)...}), ...); });
664 template<
typename Type,
typename... Func>
684 template<
typename Type,
typename...
Args>
686 return patch<Type>(
entt, [&
args...](
auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
696 template<
typename Type,
typename...
Other>
713 template<
typename Type,
typename...
Other,
typename It>
717 if constexpr(std::is_same_v<It, typename common_type::iterator>) {
721 if constexpr(
sizeof...(Other) != 0
u) {
722 if(
cpools[
pos]->data() == first.data()) {
727 count +=
cpools[
pos]->remove(first, last);
749 template<
typename Type,
typename...
Other>
765 template<
typename Type,
typename...
Other,
typename It>
767 if constexpr(std::is_same_v<It, typename common_type::iterator>) {
771 if constexpr(
sizeof...(Other) != 0
u) {
772 if(
cpools[
pos]->data() == first.data()) {
801 template<
typename Func>
815 template<
typename... Type>
817 if constexpr(
sizeof...(Type) == 0
u) {
818 for(
auto &&
curr: pools) {
819 curr.second->compact();
832 template<
typename... Type>
834 if constexpr(
sizeof...(Type) == 1u) {
849 template<
typename... Type>
865 template<
typename... Type>
867 if constexpr(
sizeof...(Type) == 1u) {
868 return (assure<std::remove_const_t<Type>>()->get(
entt), ...);
875 template<
typename... Type>
877 if constexpr(
sizeof...(Type) == 1u) {
899 template<
typename Type,
typename...
Args>
918 template<
typename... Type>
920 if constexpr(
sizeof...(Type) == 1u) {
929 template<
typename... Type>
931 if constexpr(
sizeof...(Type) == 1u) {
932 return (
const_cast<Type *
>(std::as_const(*this).template
try_get<Type>(
entt)), ...);
942 template<
typename... Type>
944 if constexpr(
sizeof...(Type) == 0
u) {
946 pools.begin()[
pos - 1u].second->clear();
949 const auto elem = entities.each();
950 entities.erase(
elem.begin().base(),
elem.end().base());
962 return std::none_of(pools.cbegin(), pools.cend(), [
entt](
auto &&
curr) { return curr.second->contains(entt); });
984 template<
typename Type>
1008 template<
typename Type>
1032 template<
typename Type>
1044 template<
typename Type,
typename...
Other,
typename...
Exclude>
1047 const auto cpools = std::make_tuple(assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...);
1054 template<
typename Type,
typename...
Other,
typename...
Exclude>
1073 return {*std::static_pointer_cast<handler_type>(
it->second)};
1076 std::shared_ptr<handler_type> handler{};
1078 if constexpr(
sizeof...(Owned) == 0
u) {
1079 handler = std::allocate_shared<handler_type>(get_allocator(), get_allocator(), assure<std::remove_const_t<Get>>()..., assure<std::remove_const_t<Exclude>>()...);
1081 handler = std::allocate_shared<handler_type>(get_allocator(), assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()..., assure<std::remove_const_t<Exclude>>()...);
1083 ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [&
elem](
const auto &data) { return data.second->owned(elem, sizeof...(Owned)) == 0u; }),
"Conflicting groups");
1097 return {*std::static_pointer_cast<handler_type>(
it->second)};
1110 template<
typename Type,
typename...
Other>
1113 return std::any_of(groups.cbegin(), groups.cend(), [&
elem](
auto &&data) { return data.second->owned(elem, 1u + sizeof...(Other)); });
1151 ENTT_ASSERT(!
owned<Type>(),
"Cannot sort owned storage");
1154 if constexpr(std::is_invocable_v<
Compare,
decltype(
cpool.get({})),
decltype(
cpool.get({}))>) {
1175 template<
typename To,
typename From>
1177 ENTT_ASSERT(!
owned<To>(),
"Cannot sort owned storage");
1197 pool_container_type pools;
1198 group_container_type groups;
Fast and reliable entity-component system.
context & ctx() noexcept
Returns the context object, that is, a general purpose container.
auto on_destroy(const id_type id=type_hash< Type >::value())
Returns a sink object for the given component.
bool any_of(const entity_type entt) const
Check if an entity is part of at least one given storage.
typename base_type::traits_type traits_type
Entity traits.
decltype(auto) get_or_emplace(const entity_type entt, Args &&...args)
Returns a reference to the given component for an entity.
bool orphan(const entity_type entt) const
Checks if an entity has components assigned.
decltype(auto) replace(const entity_type entt, Args &&...args)
Replaces the given component for an entity.
basic_registry(const size_type count, const allocator_type &allocator=allocator_type{})
Allocates enough memory upon construction to store count pools.
auto on_update(const id_type id=type_hash< Type >::value())
Returns a sink object for the given component.
const common_type * storage(const id_type id) const
Finds the storage associated with a given name, if any.
auto try_get(const entity_type entt) const
Returns pointers to the given components for an entity.
decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args)
Assigns or replaces the given component for an entity.
iterable storage() noexcept
Returns an iterable object to use to visit a registry.
bool valid(const entity_type entt) const
Checks if an identifier refers to a valid entity.
bool all_of(const entity_type entt) const
Check if an entity is part of all the given storage.
void erase_if(const entity_type entt, Func func)
Erases components satisfying specific criteria from an entity.
version_type destroy(const entity_type entt)
Destroys an entity and releases its identifier.
typename traits_type::version_type version_type
Underlying version type.
entity_type create()
Creates a new entity or recycles a destroyed one.
const context & ctx() const noexcept
Returns the context object, that is, a general purpose container.
void sort()
Sorts two pools of components in the same way.
version_type destroy(const entity_type entt, const version_type version)
Destroys an entity and releases its identifier.
basic_view< get_t< storage_for_type< const Type >, storage_for_type< const Other >... >, exclude_t< storage_for_type< const Exclude >... > > view(exclude_t< Exclude... >=exclude_t{}) const
Returns a view for the given components.
void create(It first, It last)
Assigns each element in a range an identifier.
bool owned() const
Checks whether the given components belong to any group.
size_type remove(It first, It last)
Removes the given components from all the entities in a range.
entity_type create(const entity_type hint)
Creates a new entity or recycles a destroyed one.
void clear()
Clears a whole registry or the pools for the given components.
decltype(auto) patch(const entity_type entt, Func &&...func)
Patches the given component for an entity.
basic_group< owned_t< storage_for_type< const Owned >... >, get_t< storage_for_type< const Get >... >, exclude_t< storage_for_type< const Exclude >... > > group_if_exists(get_t< Get... >=get_t{}, exclude_t< Exclude... >=exclude_t{}) const
Returns a group for the given components.
size_type remove(const entity_type entt)
Removes the given components from an entity.
basic_registry & operator=(basic_registry &&other) noexcept
Move assignment operator.
basic_view< get_t< storage_for_type< Type >, storage_for_type< Other >... >, exclude_t< storage_for_type< Exclude >... > > view(exclude_t< Exclude... >=exclude_t{})
Returns a view for the given components.
auto try_get(const entity_type entt)
Returns pointers to the given components for an entity.
common_type * storage(const id_type id)
Finds the storage associated with a given name, if any.
void destroy(It first, It last)
Destroys all entities in a range and releases their identifiers.
decltype(auto) get(const entity_type entt)
Returns references to the given components for an entity.
typename storage_for< Type, Entity, typename alloc_traits::template rebind_alloc< std::remove_const_t< Type > > >::type storage_for_type
void swap(basic_registry &other)
Exchanges the contents with those of a given registry.
void erase(It first, It last)
Erases the given components from all the entities in a range.
Allocator allocator_type
Allocator type.
void sort(Compare compare, Sort algo=Sort{}, Args &&...args)
Sorts the elements of a given component.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
decltype(auto) emplace(const entity_type entt, Args &&...args)
Assigns the given component to an entity.
basic_registry(const allocator_type &allocator)
Constructs an empty registry with a given allocator.
auto on_construct(const id_type id=type_hash< Type >::value())
Returns a sink object for the given component.
storage_for_type< Type > & storage(const id_type id=type_hash< Type >::value())
Returns the storage for a given component type.
typename traits_type::value_type entity_type
Underlying entity identifier.
decltype(auto) get(const entity_type entt) const
Returns references to the given components for an entity.
std::size_t size_type
Unsigned integer type.
basic_registry(basic_registry &&other) noexcept
Move constructor.
void compact()
Removes all tombstones from a registry or only the pools for the given components.
const_iterable storage() const noexcept
Returns an iterable object to use to visit a registry.
version_type current(const entity_type entt) const
Returns the actual version for an identifier.
basic_group< owned_t< storage_for_type< Owned >... >, get_t< storage_for_type< Get >... >, exclude_t< storage_for_type< Exclude >... > > group(get_t< Get... >=get_t{}, exclude_t< Exclude... >=exclude_t{})
Returns a group for the given components.
void insert(It first, It last, const Type &value={})
Assigns each entity in a range the given component.
const storage_for_type< Type > * storage(const id_type id=type_hash< Type >::value()) const
Returns the storage for a given component type, if any.
void insert(EIt first, EIt last, CIt from)
Assigns each entity in a range the given components.
internal::registry_context< allocator_type > context
Context type.
basic_registry()
Default constructor.
void erase(const entity_type entt)
Erases the given components from an entity.
Basic sparse set implementation.
entt_traits< Entity > traits_type
Entity traits.
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
size_type size() const noexcept
Returns the number of elements in a container.
void reserve(const size_type cnt)
Reserves space for at least the specified number of elements and regenerates the hash table.
const_iterator cend() const noexcept
Returns an iterator to the end.
iterator find(const key_type &key)
Finds an element with a given key.
const_iterator begin() const noexcept
Returns an iterator to the beginning.
const_iterator end() const noexcept
Returns an iterator to the end.
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 components.
constexpr bool operator<=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator<(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr type_list< Type..., Other... > operator+(type_list< Type... >, type_list< Other... >)
Concatenates multiple type lists.
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator>=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator>(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
basic_any< Len, Align > forward_as_any(Type &&value)
Forwards its argument and avoids copies for lvalue references.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
basic_storage< Type > storage
Alias declaration for the most common use case.
Alias for exclusion lists.
Alias for lists of observed components.
Identity function object (waiting for C++20).
Utility class to create an iterable object from a pair of iterators.
Function object to wrap std::sort in a class type.
Provides a common way to define storage types.
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.