EnTT 3.12.0
Loading...
Searching...
No Matches
sparse_set.hpp
1#ifndef ENTT_ENTITY_SPARSE_SET_HPP
2#define ENTT_ENTITY_SPARSE_SET_HPP
3
4#include <cstddef>
5#include <iterator>
6#include <memory>
7#include <type_traits>
8#include <utility>
9#include <vector>
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"
15#include "entity.hpp"
16#include "fwd.hpp"
17
18namespace entt {
19
25namespace internal {
26
27template<typename Container>
28struct 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;
34
35 constexpr sparse_set_iterator() noexcept
36 : packed{},
37 offset{} {}
38
39 constexpr sparse_set_iterator(const Container &ref, const difference_type idx) noexcept
40 : packed{std::addressof(ref)},
41 offset{idx} {}
42
43 constexpr sparse_set_iterator &operator++() noexcept {
44 return --offset, *this;
45 }
46
47 constexpr sparse_set_iterator operator++(int) noexcept {
48 sparse_set_iterator orig = *this;
49 return ++(*this), orig;
50 }
51
52 constexpr sparse_set_iterator &operator--() noexcept {
53 return ++offset, *this;
54 }
55
56 constexpr sparse_set_iterator operator--(int) noexcept {
57 sparse_set_iterator orig = *this;
58 return operator--(), orig;
59 }
60
61 constexpr sparse_set_iterator &operator+=(const difference_type value) noexcept {
62 offset -= value;
63 return *this;
64 }
65
66 constexpr sparse_set_iterator operator+(const difference_type value) const noexcept {
67 sparse_set_iterator copy = *this;
68 return (copy += value);
69 }
70
71 constexpr sparse_set_iterator &operator-=(const difference_type value) noexcept {
72 return (*this += -value);
73 }
74
75 constexpr sparse_set_iterator operator-(const difference_type value) const noexcept {
76 return (*this + -value);
77 }
78
79 [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
80 return packed->data()[index() - value];
81 }
82
83 [[nodiscard]] constexpr pointer operator->() const noexcept {
84 return packed->data() + index();
85 }
86
87 [[nodiscard]] constexpr reference operator*() const noexcept {
88 return *operator->();
89 }
90
91 [[nodiscard]] constexpr pointer data() const noexcept {
92 return packed ? packed->data() : nullptr;
93 }
94
95 [[nodiscard]] constexpr difference_type index() const noexcept {
96 return offset - 1;
97 }
98
99private:
100 const Container *packed;
101 difference_type offset;
102};
103
104template<typename Container>
105[[nodiscard]] constexpr std::ptrdiff_t operator-(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
106 return rhs.index() - lhs.index();
107}
108
109template<typename Container>
110[[nodiscard]] constexpr bool operator==(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
111 return lhs.index() == rhs.index();
112}
113
114template<typename Container>
115[[nodiscard]] constexpr bool operator!=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
116 return !(lhs == rhs);
117}
118
119template<typename Container>
120[[nodiscard]] constexpr bool operator<(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
121 return lhs.index() > rhs.index();
122}
123
124template<typename Container>
125[[nodiscard]] constexpr bool operator>(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
126 return rhs < lhs;
127}
128
129template<typename Container>
130[[nodiscard]] constexpr bool operator<=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
131 return !(lhs > rhs);
132}
133
134template<typename Container>
135[[nodiscard]] constexpr bool operator>=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
136 return !(lhs < rhs);
137}
138
139} // namespace internal
140
165template<typename Entity, typename Allocator>
167 using alloc_traits = std::allocator_traits<Allocator>;
168 static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
169 using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
170 using packed_container_type = std::vector<Entity, Allocator>;
171
172 [[nodiscard]] auto sparse_ptr(const Entity entt) const {
173 const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
174 const auto page = pos / traits_type::page_size;
175 return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod(pos, traits_type::page_size)) : nullptr;
176 }
177
178 [[nodiscard]] auto &sparse_ref(const Entity entt) const {
179 ENTT_ASSERT(sparse_ptr(entt), "Invalid element");
180 const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
181 return sparse[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
182 }
183
184 [[nodiscard]] auto to_iterator(const Entity entt) const {
185 return --(end() - index(entt));
186 }
187
188 [[nodiscard]] auto &assure_at_least(const Entity entt) {
189 const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
190 const auto page = pos / traits_type::page_size;
191
192 if(!(page < sparse.size())) {
193 sparse.resize(page + 1u, nullptr);
194 }
195
196 if(!sparse[page]) {
197 auto page_allocator{packed.get_allocator()};
198 sparse[page] = alloc_traits::allocate(page_allocator, traits_type::page_size);
199 std::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, null);
200 }
201
202 auto &elem = sparse[page][fast_mod(pos, traits_type::page_size)];
203 ENTT_ASSERT(elem == null, "Slot not available");
204 return elem;
205 }
206
207 void release_sparse_pages() {
208 auto page_allocator{packed.get_allocator()};
209
210 for(auto &&page: sparse) {
211 if(page != nullptr) {
212 std::destroy(page, page + traits_type::page_size);
213 alloc_traits::deallocate(page_allocator, page, traits_type::page_size);
214 page = nullptr;
215 }
216 }
217 }
218
219private:
220 virtual const void *get_at(const std::size_t) const {
221 return nullptr;
222 }
223
224 virtual void swap_or_move(const std::size_t, const std::size_t) {}
225
226protected:
228 using basic_iterator = internal::sparse_set_iterator<packed_container_type>;
229
235 void swap_at(const std::size_t lhs, const std::size_t rhs) {
236 const auto entity = static_cast<typename traits_type::entity_type>(lhs);
237 const auto other = static_cast<typename traits_type::entity_type>(rhs);
238
239 sparse_ref(packed[lhs]) = traits_type::combine(other, traits_type::to_integral(packed[lhs]));
240 sparse_ref(packed[rhs]) = traits_type::combine(entity, traits_type::to_integral(packed[rhs]));
241
242 using std::swap;
243 swap(packed[lhs], packed[rhs]);
244 }
245
251 ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatched");
252 auto &self = sparse_ref(*it);
253 const auto entt = traits_type::to_entity(self);
254 sparse_ref(packed.back()) = traits_type::combine(entt, traits_type::to_integral(packed.back()));
255 packed[static_cast<size_type>(entt)] = packed.back();
256 // unnecessary but it helps to detect nasty bugs
257 ENTT_ASSERT((packed.back() = null, true), "");
258 // lazy self-assignment guard
259 self = null;
260 packed.pop_back();
261 }
262
268 ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatched");
269 const auto entt = traits_type::to_entity(std::exchange(sparse_ref(*it), null));
270 packed[static_cast<size_type>(entt)] = std::exchange(free_list, traits_type::combine(entt, tombstone));
271 }
272
273protected:
279 virtual void pop(basic_iterator first, basic_iterator last) {
281 for(; first != last; ++first) {
282 swap_and_pop(first);
283 }
284 } else {
285 for(; first != last; ++first) {
286 in_place_pop(first);
287 }
288 }
289 }
290
292 virtual void pop_all() {
293 if(const auto prev = std::exchange(free_list, tombstone); prev == null) {
294 for(auto first = begin(); !(first.index() < 0); ++first) {
295 sparse_ref(*first) = null;
296 }
297 } else {
298 for(auto first = begin(); !(first.index() < 0); ++first) {
299 if(*first != tombstone) {
300 sparse_ref(*first) = null;
301 }
302 }
303 }
304
305 packed.clear();
306 }
307
314 virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) {
315 ENTT_ASSERT(!contains(entt), "Set already contains entity");
316
317 if(auto &elem = assure_at_least(entt); free_list == null || force_back) {
318 packed.push_back(entt);
319 elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
320 return begin();
321 } else {
322 const auto pos = static_cast<size_type>(traits_type::to_entity(free_list));
324 free_list = std::exchange(packed[pos], entt);
325 return --(end() - pos);
326 }
327 }
328
329public:
337 using size_type = std::size_t;
339 using allocator_type = Allocator;
341 using pointer = typename packed_container_type::const_pointer;
347 using reverse_iterator = std::reverse_iterator<iterator>;
349 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
350
353 : basic_sparse_set{type_id<void>()} {}
354
359 explicit basic_sparse_set(const allocator_type &allocator)
360 : basic_sparse_set{type_id<void>(), deletion_policy::swap_and_pop, allocator} {}
361
367 explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {})
368 : basic_sparse_set{type_id<void>(), pol, allocator} {}
369
378 : sparse{allocator},
379 packed{allocator},
380 info{&elem},
381 free_list{tombstone},
382 mode{pol} {}
383
389 : sparse{std::move(other.sparse)},
390 packed{std::move(other.packed)},
391 info{other.info},
392 free_list{std::exchange(other.free_list, tombstone)},
393 mode{other.mode} {}
394
400 basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) noexcept
401 : sparse{std::move(other.sparse), allocator},
402 packed{std::move(other.packed), allocator},
403 info{other.info},
404 free_list{std::exchange(other.free_list, tombstone)},
405 mode{other.mode} {
406 ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
407 }
408
411 release_sparse_pages();
412 }
413
420 ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
421
422 release_sparse_pages();
423 sparse = std::move(other.sparse);
424 packed = std::move(other.packed);
425 info = other.info;
426 free_list = std::exchange(other.free_list, tombstone);
427 mode = other.mode;
428 return *this;
429 }
430
435 void swap(basic_sparse_set &other) {
436 using std::swap;
437 swap(sparse, other.sparse);
438 swap(packed, other.packed);
439 swap(info, other.info);
440 swap(free_list, other.free_list);
441 swap(mode, other.mode);
442 }
443
448 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
449 return packed.get_allocator();
450 }
451
456 [[nodiscard]] deletion_policy policy() const noexcept {
457 return mode;
458 }
459
468 virtual void reserve(const size_type cap) {
469 packed.reserve(cap);
470 }
471
477 [[nodiscard]] virtual size_type capacity() const noexcept {
478 return packed.capacity();
479 }
480
482 virtual void shrink_to_fit() {
483 packed.shrink_to_fit();
484 }
485
496 [[nodiscard]] size_type extent() const noexcept {
497 return sparse.size() * traits_type::page_size;
498 }
499
510 [[nodiscard]] size_type size() const noexcept {
511 return packed.size();
512 }
513
518 [[nodiscard]] bool empty() const noexcept {
519 return packed.empty();
520 }
521
526 [[nodiscard]] bool contiguous() const noexcept {
527 return (free_list == null);
528 }
529
534 [[nodiscard]] pointer data() const noexcept {
535 return packed.data();
536 }
537
546 [[nodiscard]] const_iterator begin() const noexcept {
547 const auto pos = static_cast<typename iterator::difference_type>(packed.size());
548 return iterator{packed, pos};
549 }
550
552 [[nodiscard]] const_iterator cbegin() const noexcept {
553 return begin();
554 }
555
561 [[nodiscard]] iterator end() const noexcept {
562 return iterator{packed, {}};
563 }
564
566 [[nodiscard]] const_iterator cend() const noexcept {
567 return end();
568 }
569
579 [[nodiscard]] const_reverse_iterator rbegin() const noexcept {
580 return std::make_reverse_iterator(end());
581 }
582
584 [[nodiscard]] const_reverse_iterator crbegin() const noexcept {
585 return rbegin();
586 }
587
593 [[nodiscard]] reverse_iterator rend() const noexcept {
594 return std::make_reverse_iterator(begin());
595 }
596
598 [[nodiscard]] const_reverse_iterator crend() const noexcept {
599 return rend();
600 }
601
608 [[nodiscard]] iterator find(const entity_type entt) const noexcept {
609 return contains(entt) ? to_iterator(entt) : end();
610 }
611
617 [[nodiscard]] bool contains(const entity_type entt) const noexcept {
618 const auto elem = sparse_ptr(entt);
619 constexpr auto cap = traits_type::to_entity(null);
620 // testing versions permits to avoid accessing the packed array
621 return elem && (((~cap & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap);
622 }
623
630 [[nodiscard]] version_type current(const entity_type entt) const noexcept {
631 const auto elem = sparse_ptr(entt);
632 constexpr auto fallback = traits_type::to_version(tombstone);
633 return elem ? traits_type::to_version(*elem) : fallback;
634 }
635
646 [[nodiscard]] size_type index(const entity_type entt) const noexcept {
647 ENTT_ASSERT(contains(entt), "Set does not contain entity");
648 return static_cast<size_type>(traits_type::to_entity(sparse_ref(entt)));
649 }
650
656 [[nodiscard]] entity_type at(const size_type pos) const noexcept {
657 return pos < packed.size() ? packed[pos] : null;
658 }
659
665 [[nodiscard]] entity_type operator[](const size_type pos) const noexcept {
666 ENTT_ASSERT(pos < packed.size(), "Position is out of bounds");
667 return packed[pos];
668 }
669
680 [[nodiscard]] const void *value(const entity_type entt) const noexcept {
681 return get_at(index(entt));
682 }
683
685 [[nodiscard]] void *value(const entity_type entt) noexcept {
686 return const_cast<void *>(std::as_const(*this).value(entt));
687 }
688
701 iterator push(const entity_type entt, const void *elem = nullptr) {
702 return try_emplace(entt, false, elem);
703 }
704
718 template<typename It>
719 iterator push(It first, It last) {
720 for(auto it = first; it != last; ++it) {
721 try_emplace(*it, true);
722 }
723
724 return first == last ? end() : find(*first);
725 }
726
738 auto &entity = sparse_ref(entt);
739 ENTT_ASSERT(entt != tombstone && entity != null, "Cannot set the required version");
741 packed[static_cast<size_type>(traits_type::to_entity(entity))] = entt;
743 }
744
754 void erase(const entity_type entt) {
755 const auto it = to_iterator(entt);
756 pop(it, it + 1u);
757 }
758
768 template<typename It>
769 void erase(It first, It last) {
770 if constexpr(std::is_same_v<It, basic_iterator>) {
771 pop(first, last);
772 } else {
773 for(; first != last; ++first) {
774 erase(*first);
775 }
776 }
777 }
778
784 bool remove(const entity_type entt) {
785 return contains(entt) && (erase(entt), true);
786 }
787
795 template<typename It>
796 size_type remove(It first, It last) {
797 size_type count{};
798
799 if constexpr(std::is_same_v<It, basic_iterator>) {
800 while(first != last) {
801 while(first != last && !contains(*first)) {
802 ++first;
803 }
804
805 const auto it = first;
806
807 while(first != last && contains(*first)) {
808 ++first;
809 }
810
811 count += std::distance(it, first);
812 erase(it, first);
813 }
814 } else {
815 for(; first != last; ++first) {
816 count += remove(*first);
817 }
818 }
819
820 return count;
821 }
822
824 void compact() {
825 size_type from = packed.size();
826 for(; from && packed[from - 1u] == tombstone; --from) {}
827
828 for(auto *it = &free_list; *it != null && from; it = std::addressof(packed[traits_type::to_entity(*it)])) {
829 if(const size_type to = traits_type::to_entity(*it); to < from) {
830 --from;
831 swap_or_move(from, to);
832
833 packed[to] = std::exchange(packed[from], tombstone);
834 const auto entity = static_cast<typename traits_type::entity_type>(to);
835 sparse_ref(packed[to]) = traits_type::combine(entity, traits_type::to_integral(packed[to]));
836
837 *it = traits_type::combine(static_cast<typename traits_type::entity_type>(from), tombstone);
838 for(; from && packed[from - 1u] == tombstone; --from) {}
839 }
840 }
841
842 free_list = tombstone;
843 packed.resize(from);
844 }
845
859 void swap_elements(const entity_type lhs, const entity_type rhs) {
860 const auto from = index(lhs);
861 const auto to = index(rhs);
862
863 // basic no-leak guarantee if swapping throws
864 swap_or_move(from, to);
865 swap_at(from, to);
866 }
867
898 template<typename Compare, typename Sort = std_sort, typename... Args>
899 void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) {
900 ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements");
901 ENTT_ASSERT(free_list == null, "Partial sorting with tombstones is not supported");
902
903 algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward<Args>(args)...);
904
905 for(size_type pos{}; pos < length; ++pos) {
906 auto curr = pos;
907 auto next = index(packed[curr]);
908
909 while(curr != next) {
910 const auto idx = index(packed[next]);
911 const auto entt = packed[curr];
912
913 swap_or_move(next, idx);
914 const auto entity = static_cast<typename traits_type::entity_type>(curr);
915 sparse_ref(entt) = traits_type::combine(entity, traits_type::to_integral(packed[curr]));
916 curr = std::exchange(next, idx);
917 }
918 }
919 }
920
933 template<typename Compare, typename Sort = std_sort, typename... Args>
934 void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
935 compact();
936 sort_n(packed.size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
937 }
938
949 void sort_as(const basic_sparse_set &other) {
950 compact();
951
952 const auto to = other.end();
953 auto from = other.begin();
954
955 for(auto it = begin(); it.index() && from != to; ++from) {
956 if(const auto curr = *from; contains(curr)) {
957 if(const auto entt = *it; entt != curr) {
958 // basic no-leak guarantee (with invalid state) if swapping throws
959 swap_elements(entt, curr);
960 }
961
962 ++it;
963 }
964 }
965 }
966
968 void clear() {
969 pop_all();
970 // sanity check to avoid subtle issues due to storage classes
971 ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set");
972 free_list = tombstone;
973 packed.clear();
974 }
975
980 const type_info &type() const noexcept {
981 return *info;
982 }
983
985 virtual void bind(any) noexcept {}
986
987private:
988 sparse_container_type sparse;
989 packed_container_type packed;
990 const type_info *info;
991 entity_type free_list;
992 deletion_policy mode;
993};
994
995} // namespace entt
996
997#endif
typename Traits::entity_type entity_type
Underlying entity type.
Definition: entity.hpp:84
static constexpr entity_type to_integral(const value_type value) noexcept
Converts an entity to its underlying type.
Definition: entity.hpp:98
static constexpr entity_type to_entity(const value_type value) noexcept
Returns the entity part once converted to the underlying type.
Definition: entity.hpp:107
typename Traits::value_type value_type
Value type.
Definition: entity.hpp:82
typename Traits::version_type version_type
Underlying version type.
Definition: entity.hpp:86
static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept
Combines two identifiers in a single one.
Definition: entity.hpp:154
static constexpr version_type to_version(const value_type value) noexcept
Returns the version part once converted to the underlying type.
Definition: entity.hpp:116
Basic sparse set implementation.
Definition: sparse_set.hpp:166
void erase(const entity_type entt)
Erases an entity from a sparse set.
Definition: sparse_set.hpp:754
void swap(basic_sparse_set &other)
Exchanges the contents with those of a given sparse set.
Definition: sparse_set.hpp:435
typename traits_type::version_type version_type
Underlying version type.
Definition: sparse_set.hpp:335
virtual size_type capacity() const noexcept
Returns the number of elements that a sparse set has currently allocated space for.
Definition: sparse_set.hpp:477
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition: sparse_set.hpp:552
basic_sparse_set(const allocator_type &allocator)
Constructs an empty container with a given allocator.
Definition: sparse_set.hpp:359
virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void *=nullptr)
Assigns an entity to a sparse set.
Definition: sparse_set.hpp:314
virtual void pop_all()
Erases all entities of a sparse set.
Definition: sparse_set.hpp:292
void erase(It first, It last)
Erases entities from a set.
Definition: sparse_set.hpp:769
std::reverse_iterator< const_iterator > const_reverse_iterator
Constant reverse iterator type.
Definition: sparse_set.hpp:349
void swap_elements(const entity_type lhs, const entity_type rhs)
Swaps two entities in a sparse set.
Definition: sparse_set.hpp:859
void swap_and_pop(const basic_iterator it)
Erases an entity from a sparse set.
Definition: sparse_set.hpp:250
std::size_t size_type
Unsigned integer type.
Definition: sparse_set.hpp:337
iterator end() const noexcept
Returns an iterator to the end.
Definition: sparse_set.hpp:561
void * value(const entity_type entt) noexcept
Returns the element assigned to an entity, if any.
Definition: sparse_set.hpp:685
const_reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition: sparse_set.hpp:579
iterator const_iterator
Constant random access iterator type.
Definition: sparse_set.hpp:345
reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition: sparse_set.hpp:593
iterator push(It first, It last)
Assigns one or more entities to a sparse set.
Definition: sparse_set.hpp:719
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.
Definition: sparse_set.hpp:899
pointer data() const noexcept
Direct access to the internal packed array.
Definition: sparse_set.hpp:534
basic_sparse_set & operator=(basic_sparse_set &&other) noexcept
Move assignment operator.
Definition: sparse_set.hpp:419
virtual void reserve(const size_type cap)
Increases the capacity of a sparse set.
Definition: sparse_set.hpp:468
void clear()
Clears a sparse set.
Definition: sparse_set.hpp:968
size_type size() const noexcept
Returns the number of elements in a sparse set.
Definition: sparse_set.hpp:510
basic_iterator iterator
Random access iterator type.
Definition: sparse_set.hpp:343
bool contiguous() const noexcept
Checks whether a sparse set is fully packed.
Definition: sparse_set.hpp:526
version_type bump(const entity_type entt)
Bump the version number of an entity.
Definition: sparse_set.hpp:737
void sort_as(const basic_sparse_set &other)
Sort entities according to their order in another sparse set.
Definition: sparse_set.hpp:949
virtual void shrink_to_fit()
Requests the removal of unused capacity.
Definition: sparse_set.hpp:482
size_type extent() const noexcept
Returns the extent of a sparse set.
Definition: sparse_set.hpp:496
typename packed_container_type::const_pointer pointer
Pointer type to contained entities.
Definition: sparse_set.hpp:341
basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) noexcept
Allocator-extended move constructor.
Definition: sparse_set.hpp:400
iterator push(const entity_type entt, const void *elem=nullptr)
Assigns an entity to a sparse set.
Definition: sparse_set.hpp:701
basic_sparse_set(deletion_policy pol, const allocator_type &allocator={})
Constructs an empty container with the given policy and allocator.
Definition: sparse_set.hpp:367
virtual void pop(basic_iterator first, basic_iterator last)
Erases entities from a sparse set.
Definition: sparse_set.hpp:279
deletion_policy policy() const noexcept
Returns the deletion policy of a sparse set.
Definition: sparse_set.hpp:456
version_type current(const entity_type entt) const noexcept
Returns the contained version for an identifier.
Definition: sparse_set.hpp:630
bool contains(const entity_type entt) const noexcept
Checks if a sparse set contains an entity.
Definition: sparse_set.hpp:617
virtual void bind(any) noexcept
Forwards variables to derived classes, if any.
Definition: sparse_set.hpp:985
const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: sparse_set.hpp:566
void in_place_pop(const basic_iterator it)
Erases an entity from a sparse set.
Definition: sparse_set.hpp:267
basic_sparse_set(basic_sparse_set &&other) noexcept
Move constructor.
Definition: sparse_set.hpp:388
const_reverse_iterator crend() const noexcept
Returns a reverse iterator to the end.
Definition: sparse_set.hpp:598
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Definition: sparse_set.hpp:448
size_type remove(It first, It last)
Removes entities from a sparse set if they exist.
Definition: sparse_set.hpp:796
const void * value(const entity_type entt) const noexcept
Returns the element assigned to an entity, if any.
Definition: sparse_set.hpp:680
entity_type operator[](const size_type pos) const noexcept
Returns the entity at specified location, without bounds checking.
Definition: sparse_set.hpp:665
internal::sparse_set_iterator< packed_container_type > basic_iterator
Random access iterator type.
Definition: sparse_set.hpp:228
virtual ~basic_sparse_set()
Default destructor.
Definition: sparse_set.hpp:410
entity_type at(const size_type pos) const noexcept
Returns the entity at specified location, with bounds checking.
Definition: sparse_set.hpp:656
const_reverse_iterator crbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition: sparse_set.hpp:584
bool empty() const noexcept
Checks whether a sparse set is empty.
Definition: sparse_set.hpp:518
size_type index(const entity_type entt) const noexcept
Returns the position of an entity in a sparse set.
Definition: sparse_set.hpp:646
const type_info & type() const noexcept
Returned value type, if any.
Definition: sparse_set.hpp:980
void sort(Compare compare, Sort algo=Sort{}, Args &&...args)
Sort all elements according to the given comparison function.
Definition: sparse_set.hpp:934
typename traits_type::value_type entity_type
Underlying entity identifier.
Definition: sparse_set.hpp:333
void swap_at(const std::size_t lhs, const std::size_t rhs)
Swaps two items at specific locations.
Definition: sparse_set.hpp:235
bool remove(const entity_type entt)
Removes an entity from a sparse set if it exists.
Definition: sparse_set.hpp:784
void compact()
Removes all tombstones from a sparse set.
Definition: sparse_set.hpp:824
basic_sparse_set(const type_info &elem, deletion_policy pol=deletion_policy::swap_and_pop, const allocator_type &allocator={})
Constructs an empty container with the given value type, policy and allocator.
Definition: sparse_set.hpp:377
const_iterator begin() const noexcept
Returns an iterator to the beginning.
Definition: sparse_set.hpp:546
Allocator allocator_type
Allocator type.
Definition: sparse_set.hpp:339
iterator find(const entity_type entt) const noexcept
Finds an entity.
Definition: sparse_set.hpp:608
basic_sparse_set()
Default constructor.
Definition: sparse_set.hpp:352
std::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Definition: sparse_set.hpp:347
EnTT default namespace.
Definition: dense_map.hpp:21
entity
Default entity identifier.
Definition: fwd.hpp:13
constexpr null_t null
Compile-time constant for null entities.
Definition: entity.hpp:366
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
Definition: entity.hpp:375
constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) noexcept
Fast module utility function (powers of two only).
Definition: memory.hpp:45
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.
deletion_policy
Storage deletion policy.
Definition: fwd.hpp:16
@ swap_and_pop
Swap-and-pop deletion policy.
@ in_place
In-place deletion policy.
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.
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
Definition: type_info.hpp:257
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.
Entity traits.
Definition: entity.hpp:165
static constexpr std::size_t page_size
Page size, default is ENTT_SPARSE_PAGE.
Definition: entity.hpp:169
Function object to wrap std::sort in a class type.
Definition: algorithm.hpp:21
Implementation specific information about a type.
Definition: type_info.hpp:141