1 #ifndef ENTT_ENTITY_SPARSE_SET_HPP
2 #define ENTT_ENTITY_SPARSE_SET_HPP
10 #include "../config/config.h"
11 #include "../core/algorithm.hpp"
12 #include "../core/any.hpp"
13 #include "../core/memory.hpp"
14 #include "../core/type_info.hpp"
27 template<
typename Container>
28 struct sparse_set_iterator final {
29 using value_type =
typename Container::value_type;
30 using pointer =
typename Container::const_pointer;
31 using reference =
typename Container::const_reference;
32 using difference_type =
typename Container::difference_type;
33 using iterator_category = std::random_access_iterator_tag;
35 sparse_set_iterator() ENTT_NOEXCEPT = default;
37 sparse_set_iterator(const Container &ref, const difference_type idx) ENTT_NOEXCEPT
38 : packed{std::addressof(ref)},
41 sparse_set_iterator &operator++() ENTT_NOEXCEPT {
42 return --offset, *
this;
45 sparse_set_iterator operator++(
int) ENTT_NOEXCEPT {
46 sparse_set_iterator orig = *
this;
47 return ++(*this), orig;
50 sparse_set_iterator &operator--() ENTT_NOEXCEPT {
51 return ++offset, *
this;
54 sparse_set_iterator operator--(
int) ENTT_NOEXCEPT {
55 sparse_set_iterator orig = *
this;
56 return operator--(), orig;
59 sparse_set_iterator &operator+=(
const difference_type value) ENTT_NOEXCEPT {
64 sparse_set_iterator
operator+(
const difference_type value)
const ENTT_NOEXCEPT {
65 sparse_set_iterator copy = *
this;
66 return (copy += value);
69 sparse_set_iterator &operator-=(
const difference_type value) ENTT_NOEXCEPT {
70 return (*
this += -value);
73 sparse_set_iterator operator-(
const difference_type value)
const ENTT_NOEXCEPT {
74 return (*
this + -value);
77 [[nodiscard]] reference operator[](
const difference_type value)
const {
78 const auto pos = offset - value - 1;
79 return packed->data()[pos];
82 [[nodiscard]] pointer operator->()
const {
83 const auto pos = offset - 1;
84 return packed->data() + pos;
87 [[nodiscard]] reference operator*()
const {
91 [[nodiscard]] difference_type index() const ENTT_NOEXCEPT {
96 const Container *packed;
97 difference_type offset;
100 template<
typename Type,
typename Other>
101 [[nodiscard]]
auto operator-(
const sparse_set_iterator<Type> &lhs,
const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
102 return rhs.index() - lhs.index();
105 template<
typename Type,
typename Other>
106 [[nodiscard]]
bool operator==(
const sparse_set_iterator<Type> &lhs,
const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
107 return lhs.index() == rhs.index();
110 template<
typename Type,
typename Other>
111 [[nodiscard]]
bool operator!=(
const sparse_set_iterator<Type> &lhs,
const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
112 return !(lhs == rhs);
115 template<
typename Type,
typename Other>
116 [[nodiscard]]
bool operator<(
const sparse_set_iterator<Type> &lhs,
const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
117 return lhs.index() > rhs.index();
120 template<
typename Type,
typename Other>
121 [[nodiscard]]
bool operator>(
const sparse_set_iterator<Type> &lhs,
const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
122 return lhs.index() < rhs.index();
125 template<
typename Type,
typename Other>
126 [[nodiscard]]
bool operator<=(
const sparse_set_iterator<Type> &lhs,
const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
130 template<
typename Type,
typename Other>
131 [[nodiscard]]
bool operator>=(
const sparse_set_iterator<Type> &lhs,
const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
173 template<
typename Entity,
typename Allocator>
175 using allocator_traits = std::allocator_traits<Allocator>;
176 using alloc =
typename allocator_traits::template rebind_alloc<Entity>;
177 using alloc_traits =
typename std::allocator_traits<alloc>;
180 using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
181 using packed_container_type = std::vector<Entity, alloc>;
183 [[nodiscard]]
auto sparse_ptr(
const Entity
entt)
const {
189 [[nodiscard]]
auto &sparse_ref(
const Entity
entt)
const {
190 ENTT_ASSERT(sparse_ptr(
entt),
"Invalid element");
195 void release_sparse_pages() {
196 auto page_allocator{packed.get_allocator()};
198 for(
auto &&page: sparse) {
199 if(page !=
nullptr) {
212 virtual const void *
get_at(
const std::size_t)
const ENTT_NOEXCEPT {
217 virtual void swap_at(
const std::size_t,
const std::size_t) {}
227 auto &ref = sparse_ref(
entt);
229 ENTT_ASSERT(packed[pos] ==
entt,
"Invalid identifier");
231 packed[pos] = packed.back();
232 auto &elem = sparse_ref(packed.back());
237 ENTT_ASSERT((packed.back() =
tombstone,
true),
"");
246 auto &ref = sparse_ref(
entt);
248 ENTT_ASSERT(packed[pos] ==
entt,
"Invalid identifier");
263 if(!(page < sparse.size())) {
264 sparse.resize(page + 1u,
nullptr);
268 auto page_allocator{packed.get_allocator()};
276 if(free_list ==
null) {
278 packed.push_back(
entt);
293 using size_type =
typename packed_container_type::size_type;
295 using pointer =
typename packed_container_type::const_pointer;
297 using iterator = internal::sparse_set_iterator<packed_container_type>;
342 : sparse{std::move(other.sparse)},
343 packed{std::move(other.packed)},
345 free_list{std::exchange(other.free_list,
tombstone)},
354 : sparse{std::move(other.sparse), allocator},
355 packed{std::move(other.packed), allocator},
357 free_list{std::exchange(other.free_list,
tombstone)},
359 ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(),
"Copying a sparse set is not allowed");
364 release_sparse_pages();
373 ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(),
"Copying a sparse set is not allowed");
375 release_sparse_pages();
376 sparse = std::move(other.sparse);
377 packed = std::move(other.packed);
379 free_list = std::exchange(other.free_list,
tombstone);
390 swap(sparse, other.sparse);
391 swap(packed, other.packed);
392 swap(info, other.info);
393 swap(free_list, other.free_list);
394 swap(mode, other.mode);
402 return packed.get_allocator();
439 return packed.capacity();
444 packed.shrink_to_fit();
472 return packed.size();
479 [[nodiscard]]
bool empty() const ENTT_NOEXCEPT {
480 return packed.empty();
488 return packed.data();
501 const auto pos =
static_cast<typename iterator::difference_type
>(packed.size());
540 return std::make_reverse_iterator(
end());
559 return std::make_reverse_iterator(
begin());
583 const auto elem = sparse_ptr(
entt);
596 const auto elem = sparse_ptr(
entt);
612 ENTT_ASSERT(
contains(
entt),
"Set does not contain entity");
622 return pos < packed.size() ? packed[pos] :
null;
631 ENTT_ASSERT(pos < packed.size(),
"Position is out of bounds");
646 ENTT_ASSERT(
contains(
entt),
"Set does not contain entity");
652 return const_cast<void *
>(std::as_const(*this).get(
entt));
667 ENTT_ASSERT(
contains(
entt),
"Emplace did not take place");
681 template<
typename It>
683 for(; first != last && free_list !=
null; ++first) {
687 reserve(packed.size() + std::distance(first, last));
689 for(; first != last; ++first) {
704 ENTT_ASSERT(
contains(
entt),
"Set does not contain entity");
706 ENTT_ASSERT(!
contains(
entt),
"Destruction did not take place");
718 template<
typename It>
720 for(; first != last; ++first) {
741 template<
typename It>
745 for(; first != last; ++first) {
755 for(; next && packed[next - 1u] ==
tombstone; --next) {}
761 std::swap(packed[next], packed[pos]);
765 for(; next && packed[next - 1u] ==
tombstone; --next) {}
787 ENTT_ASSERT(
contains(lhs) &&
contains(rhs),
"Set does not contain entities");
789 auto &
entt = sparse_ref(lhs);
790 auto &other = sparse_ref(rhs);
799 std::swap(packed[from], packed[to]);
832 template<
typename Compare,
typename Sort =
std_sort,
typename... Args>
833 void sort_n(
const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) {
834 ENTT_ASSERT(!(length > packed.size()),
"Length exceeds the number of elements");
835 ENTT_ASSERT(free_list ==
null,
"Partial sorting with tombstones is not supported");
837 algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward<Args>(args)...);
839 for(
size_type pos{}; pos < length; ++pos) {
841 auto next =
index(packed[curr]);
843 while(curr != next) {
844 const auto idx =
index(packed[next]);
845 const auto entt = packed[curr];
850 curr = std::exchange(next, idx);
867 template<
typename Compare,
typename Sort = std_sort,
typename... Args>
868 void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
870 sort_n(packed.size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
891 const auto to = other.
end();
892 auto from = other.
begin();
894 for(
size_type pos = packed.size() - 1; pos && from != to; ++from) {
896 if(*from != packed[pos]) {
908 for(
auto &&
entity: *
this) {
926 sparse_container_type sparse;
927 packed_container_type packed;
Basic sparse set implementation.
deletion_policy policy() const
Returns the deletion policy of a sparse set.
void erase(const entity_type entt)
Erases an entity from a sparse set.
void swap(basic_sparse_set &other)
Exchanges the contents with those of a given sparse set.
const_reverse_iterator crbegin() const
Returns a reverse iterator to the beginning.
void insert(It first, It last)
Assigns one or more entities to a sparse set.
size_type index(const entity_type entt) const
Returns the position of an entity in a sparse set.
basic_sparse_set(const allocator_type &allocator)
Constructs an empty container with a given allocator.
reverse_iterator rend() const
Returns a reverse iterator to the end.
void erase(It first, It last)
Erases entities from a set.
const_reverse_iterator crend() const
Returns a reverse iterator to the end.
void swap_elements(const entity_type lhs, const entity_type rhs)
Swaps two entities in a sparse set.
iterator end() const
Returns an iterator to the end.
bool empty() const
Checks whether a sparse set is empty.
iterator const_iterator
Constant random access iterator type.
size_type slot() const
Returns the next slot available for insertion.
entity_type operator[](const size_type pos) const
Returns the entity at specified location, without bounds checking.
virtual void bind(any)
Forwards variables to mixins, if any.
virtual void swap_and_pop(const Entity entt)
Erase an entity from a sparse set.
basic_sparse_set(const type_info &value, deletion_policy pol=deletion_policy::swap_and_pop, const allocator_type &allocator={})
Constructs an empty container with the given policy and allocator.
void sort_n(const size_type length, Compare compare, Sort algo=Sort{}, Args &&...args)
Sort the first count elements according to the given comparison function.
virtual const void * get_at(const std::size_t) const
Returns the element assigned to an entity.
reverse_iterator const_reverse_iterator
Constant reverse iterator type.
version_type current(const entity_type entt) const
Returns the contained version for an identifier.
void emplace(const entity_type entt, const void *value=nullptr)
Assigns an entity to a sparse set.
virtual void reserve(const size_type cap)
Increases the capacity of a sparse set.
const void * get(const entity_type entt) const
Returns the element assigned to an entity, if any.
void clear()
Clears a sparse set.
typename packed_container_type::size_type size_type
Unsigned integer type.
size_type size() const
Returns the number of elements in a sparse set.
virtual void swap_at(const std::size_t, const std::size_t)
Swaps two entities in a sparse set.
internal::sparse_set_iterator< packed_container_type > iterator
Random access iterator type.
virtual void shrink_to_fit()
Requests the removal of unused capacity.
iterator find(const entity_type entt) const
Finds an entity.
typename packed_container_type::const_pointer pointer
Pointer type to contained entities.
basic_sparse_set(deletion_policy pol, const allocator_type &allocator={})
Constructs an empty container with the given policy and allocator.
typename entity_traits::version_type version_type
Underlying version type.
Entity entity_type
Underlying entity identifier.
basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator)
Allocator-extended move constructor.
size_type extent() const
Returns the extent of a sparse set.
entity_type at(const size_type pos) const
Returns the entity at specified location, with bounds checking.
const_iterator begin() const
Returns an iterator to the beginning.
const_iterator cbegin() const
Returns an iterator to the beginning.
size_type remove(It first, It last)
Removes entities from a sparse set if they exist.
basic_sparse_set(basic_sparse_set &&other)
Move constructor.
virtual void move_and_pop(const std::size_t, const std::size_t)
Moves an entity in a sparse set.
virtual void in_place_pop(const Entity entt)
Erase an entity from a sparse set.
const type_info & type() const
Returned value type, if any.
virtual size_type capacity() const
Returns the number of elements that a sparse set has currently allocated space for.
virtual ~basic_sparse_set()
Default destructor.
bool contains(const entity_type entt) const
Checks if a sparse set contains an entity.
virtual void try_emplace(const Entity entt, const void *=nullptr)
Assigns an entity to a sparse set.
void respect(const basic_sparse_set &other)
Sort entities according to their order in another sparse set.
pointer data() const
Direct access to the internal packed array.
constexpr allocator_type get_allocator() const
Returns the associated allocator.
void sort(Compare compare, Sort algo=Sort{}, Args &&...args)
Sort all elements according to the given comparison function.
const_reverse_iterator rbegin() const
Returns a reverse iterator to the beginning.
const_iterator cend() const
Returns an iterator to the end.
bool remove(const entity_type entt)
Removes an entity from a sparse set if it exists.
void * get(const entity_type entt)
Returns the element assigned to an entity, if any.
void compact()
Removes all tombstones from the packed array of a sparse set.
Allocator allocator_type
Allocator type.
basic_sparse_set()
Default constructor.
basic_sparse_set & operator=(basic_sparse_set &&other)
Move assignment operator.
std::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
static constexpr auto page_size
Page size, default is ENTT_SPARSE_PAGE.
typename base_type::entity_type entity_type
Underlying entity type.
static constexpr entity_type reserved
Reserved identifier.
static constexpr entity_type to_integral(const value_type value)
Converts an entity to its underlying type.
static constexpr entity_type to_entity(const value_type value)
Returns the entity part once converted to the underlying type.
static constexpr value_type combine(const entity_type lhs, const entity_type rhs)
Combines two identifiers in a single one.
typename base_type::version_type version_type
Underlying version type.
static constexpr version_type to_version(const value_type value)
Returns the version part once converted to the underlying type.
Implementation specific information about a type.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
entity
Default entity identifier.
constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod)
Fast module utility function (powers of two only).
const type_info & type_id()
Returns the type info object associated to a given type.
constexpr bool operator<=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
constexpr bool operator>=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
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)
Compares two hashed strings.
deletion_policy
Sparse set deletion policy.
@ swap_and_pop
Swap-and-pop deletion policy.
@ in_place
In-place deletion policy.
bool operator!=(const basic_any< Len, Align > &lhs, const basic_any< Len, Align > &rhs)
Checks if two wrappers differ in their content.
constexpr bool operator>(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
Function object to wrap std::sort in a class type.