EnTT  3.3.2
sparse_set.hpp
1 #ifndef ENTT_ENTITY_SPARSE_SET_HPP
2 #define ENTT_ENTITY_SPARSE_SET_HPP
3 
4 
5 #include <algorithm>
6 #include <iterator>
7 #include <utility>
8 #include <vector>
9 #include <memory>
10 #include <cstddef>
11 #include <type_traits>
12 #include "../config/config.h"
13 #include "../core/algorithm.hpp"
14 #include "entity.hpp"
15 #include "fwd.hpp"
16 
17 
18 namespace entt {
19 
20 
48 template<typename Entity>
49 class sparse_set {
51 
52  static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0));
53  static constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(typename traits_type::entity_type);
54 
55  class iterator {
56  friend class sparse_set<Entity>;
57 
58  using direct_type = std::vector<Entity>;
59  using index_type = typename traits_type::difference_type;
60 
61  iterator(const direct_type *ref, const index_type idx) ENTT_NOEXCEPT
62  : direct{ref}, index{idx}
63  {}
64 
65  public:
66  using difference_type = index_type;
67  using value_type = Entity;
68  using pointer = const value_type *;
69  using reference = const value_type &;
70  using iterator_category = std::random_access_iterator_tag;
71 
72  iterator() ENTT_NOEXCEPT = default;
73 
74  iterator & operator++() ENTT_NOEXCEPT {
75  return --index, *this;
76  }
77 
78  iterator operator++(int) ENTT_NOEXCEPT {
79  iterator orig = *this;
80  return operator++(), orig;
81  }
82 
83  iterator & operator--() ENTT_NOEXCEPT {
84  return ++index, *this;
85  }
86 
87  iterator operator--(int) ENTT_NOEXCEPT {
88  iterator orig = *this;
89  return operator--(), orig;
90  }
91 
92  iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
93  index -= value;
94  return *this;
95  }
96 
97  iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
98  return iterator{direct, index-value};
99  }
100 
101  iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
102  return (*this += -value);
103  }
104 
105  iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
106  return (*this + -value);
107  }
108 
109  difference_type operator-(const iterator &other) const ENTT_NOEXCEPT {
110  return other.index - index;
111  }
112 
113  reference operator[](const difference_type value) const {
114  const auto pos = size_type(index-value-1);
115  return (*direct)[pos];
116  }
117 
118  bool operator==(const iterator &other) const ENTT_NOEXCEPT {
119  return other.index == index;
120  }
121 
122  bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
123  return !(*this == other);
124  }
125 
126  bool operator<(const iterator &other) const ENTT_NOEXCEPT {
127  return index > other.index;
128  }
129 
130  bool operator>(const iterator &other) const ENTT_NOEXCEPT {
131  return index < other.index;
132  }
133 
134  bool operator<=(const iterator &other) const ENTT_NOEXCEPT {
135  return !(*this > other);
136  }
137 
138  bool operator>=(const iterator &other) const ENTT_NOEXCEPT {
139  return !(*this < other);
140  }
141 
142  pointer operator->() const {
143  const auto pos = size_type(index-1);
144  return &(*direct)[pos];
145  }
146 
147  reference operator*() const {
148  return *operator->();
149  }
150 
151  private:
152  const direct_type *direct;
153  index_type index;
154  };
155 
156  auto page(const Entity entt) const ENTT_NOEXCEPT {
157  return std::size_t{(to_integral(entt) & traits_type::entity_mask) / entt_per_page};
158  }
159 
160  auto offset(const Entity entt) const ENTT_NOEXCEPT {
161  return std::size_t{to_integral(entt) & (entt_per_page - 1)};
162  }
163 
164  Entity * assure(const std::size_t pos) {
165  if(!(pos < reverse.size())) {
166  reverse.resize(pos+1);
167  }
168 
169  if(!reverse[pos]) {
170  reverse[pos] = std::make_unique<entity_type[]>(entt_per_page);
171  // null is safe in all cases for our purposes
172  std::fill_n(reverse[pos].get(), entt_per_page, null);
173  }
174 
175  return reverse[pos].get();
176  }
177 
178 public:
180  using entity_type = Entity;
182  using size_type = std::size_t;
184  using iterator_type = iterator;
185 
187  sparse_set() = default;
188 
190  sparse_set(sparse_set &&) = default;
191 
193  virtual ~sparse_set() = default;
194 
196  sparse_set & operator=(sparse_set &&) = default;
197 
206  void reserve(const size_type cap) {
207  direct.reserve(cap);
208  }
209 
215  size_type capacity() const ENTT_NOEXCEPT {
216  return direct.capacity();
217  }
218 
220  void shrink_to_fit() {
221  // conservative approach
222  if(direct.empty()) {
223  reverse.clear();
224  }
225 
226  reverse.shrink_to_fit();
227  direct.shrink_to_fit();
228  }
229 
240  size_type extent() const ENTT_NOEXCEPT {
241  return reverse.size() * entt_per_page;
242  }
243 
254  size_type size() const ENTT_NOEXCEPT {
255  return direct.size();
256  }
257 
262  bool empty() const ENTT_NOEXCEPT {
263  return direct.empty();
264  }
265 
281  const entity_type * data() const ENTT_NOEXCEPT {
282  return direct.data();
283  }
284 
298  iterator_type begin() const ENTT_NOEXCEPT {
299  const typename traits_type::difference_type pos = direct.size();
300  return iterator_type{&direct, pos};
301  }
302 
317  iterator_type end() const ENTT_NOEXCEPT {
318  return iterator_type{&direct, {}};
319  }
320 
328  return has(entt) ? --(end() - index(entt)) : end();
329  }
330 
336  bool has(const entity_type entt) const {
337  const auto curr = page(entt);
338  // testing against null permits to avoid accessing the direct vector
339  return (curr < reverse.size() && reverse[curr] && reverse[curr][offset(entt)] != null);
340  }
341 
355  ENTT_ASSERT(has(entt));
356  return size_type(reverse[page(entt)][offset(entt)]);
357  }
358 
370  void construct(const entity_type entt) {
371  ENTT_ASSERT(!has(entt));
372  assure(page(entt))[offset(entt)] = entity_type(direct.size());
373  direct.push_back(entt);
374  }
375 
389  template<typename It>
390  void construct(It first, It last) {
391  std::for_each(first, last, [this, next = direct.size()](const auto entt) mutable {
392  ENTT_ASSERT(!has(entt));
393  assure(page(entt))[offset(entt)] = entity_type(next++);
394  });
395 
396  direct.insert(direct.end(), first, last);
397  }
398 
410  void destroy(const entity_type entt) {
411  ENTT_ASSERT(has(entt));
412  const auto curr = page(entt);
413  const auto pos = offset(entt);
414  direct[size_type(reverse[curr][pos])] = entity_type(direct.back());
415  reverse[page(direct.back())][offset(direct.back())] = reverse[curr][pos];
416  reverse[curr][pos] = null;
417  direct.pop_back();
418  }
419 
435  virtual void swap(const entity_type lhs, const entity_type rhs) {
436  auto &from = reverse[page(lhs)][offset(lhs)];
437  auto &to = reverse[page(rhs)][offset(rhs)];
438  std::swap(direct[size_type(from)], direct[size_type(to)]);
439  std::swap(from, to);
440  }
441 
481  template<typename Compare, typename Sort = std_sort, typename... Args>
482  void sort(iterator_type first, iterator_type last, Compare compare, Sort algo = Sort{}, Args &&... args) {
483  ENTT_ASSERT(!(last < first));
484  ENTT_ASSERT(!(last > end()));
485 
486  const auto length = std::distance(first, last);
487  const auto skip = std::distance(last, end());
488  const auto to = direct.rend() - skip;
489  const auto from = to - length;
490 
491  algo(from, to, std::move(compare), std::forward<Args>(args)...);
492 
493  for(size_type pos = skip, end = skip+length; pos < end; ++pos) {
494  reverse[page(direct[pos])][offset(direct[pos])] = entity_type(pos);
495  }
496  }
497 
525  template<typename Apply, typename Compare, typename Sort = std_sort, typename... Args>
526  void arrange(iterator_type first, iterator_type last, Apply apply, Compare compare, Sort algo = Sort{}, Args &&... args) {
527  ENTT_ASSERT(!(last < first));
528  ENTT_ASSERT(!(last > end()));
529 
530  const auto length = std::distance(first, last);
531  const auto skip = std::distance(last, end());
532  const auto to = direct.rend() - skip;
533  const auto from = to - length;
534 
535  algo(from, to, std::move(compare), std::forward<Args>(args)...);
536 
537  for(size_type pos = skip, end = skip+length; pos < end; ++pos) {
538  auto curr = pos;
539  auto next = index(direct[curr]);
540 
541  while(curr != next) {
542  apply(direct[curr], direct[next]);
543  reverse[page(direct[curr])][offset(direct[curr])] = entity_type(curr);
544 
545  curr = next;
546  next = index(direct[curr]);
547  }
548  }
549  }
550 
571  void respect(const sparse_set &other) {
572  const auto to = other.end();
573  auto from = other.begin();
574 
575  size_type pos = direct.size() - 1;
576 
577  while(pos && from != to) {
578  if(has(*from)) {
579  if(*from != direct[pos]) {
580  swap(direct[pos], *from);
581  }
582 
583  --pos;
584  }
585 
586  ++from;
587  }
588  }
589 
593  void clear() ENTT_NOEXCEPT {
594  reverse.clear();
595  direct.clear();
596  }
597 
598 private:
599  std::vector<std::unique_ptr<entity_type[]>> reverse;
600  std::vector<entity_type> direct;
601 };
602 
603 
604 }
605 
606 
607 #endif
entt::sparse_set::swap
virtual void swap(const entity_type lhs, const entity_type rhs)
Swaps two entities in the internal packed array.
Definition: sparse_set.hpp:435
entt::sparse_set::find
iterator_type find(const entity_type entt) const
Finds an entity.
Definition: sparse_set.hpp:327
entt::sparse_set::begin
iterator_type begin() const ENTT_NOEXCEPT
Returns an iterator to the beginning.
Definition: sparse_set.hpp:298
entt::sparse_set::end
iterator_type end() const ENTT_NOEXCEPT
Returns an iterator to the end.
Definition: sparse_set.hpp:317
entt::sparse_set::respect
void respect(const sparse_set &other)
Sort entities according to their order in another sparse set.
Definition: sparse_set.hpp:571
entt::sparse_set::~sparse_set
virtual ~sparse_set()=default
Default destructor.
entt::sparse_set
Basic sparse set implementation.
Definition: sparse_set.hpp:49
entt::get
constexpr get_t< Type... > get
Variable template for lists of observed components.
Definition: fwd.hpp:41
entt::sparse_set::has
bool has(const entity_type entt) const
Checks if a sparse set contains an entity.
Definition: sparse_set.hpp:336
entt::sparse_set::sort
void sort(iterator_type first, iterator_type last, Compare compare, Sort algo=Sort{}, Args &&... args)
Sort elements according to the given comparison function.
Definition: sparse_set.hpp:482
entt::sparse_set::construct
void construct(It first, It last)
Assigns one or more entities to a sparse set.
Definition: sparse_set.hpp:390
entt::sparse_set::sparse_set
sparse_set()=default
Default constructor.
entt::sparse_set::extent
size_type extent() const ENTT_NOEXCEPT
Returns the extent of a sparse set.
Definition: sparse_set.hpp:240
entt::sparse_set::shrink_to_fit
void shrink_to_fit()
Requests the removal of unused capacity.
Definition: sparse_set.hpp:220
entt::sparse_set::destroy
void destroy(const entity_type entt)
Removes an entity from a sparse set.
Definition: sparse_set.hpp:410
entt::sparse_set::empty
bool empty() const ENTT_NOEXCEPT
Checks whether a sparse set is empty.
Definition: sparse_set.hpp:262
entt
EnTT default namespace.
Definition: algorithm.hpp:13
entt::sparse_set::clear
void clear() ENTT_NOEXCEPT
Clears a sparse set.
Definition: sparse_set.hpp:593
entt::sparse_set::data
const entity_type * data() const ENTT_NOEXCEPT
Direct access to the internal packed array.
Definition: sparse_set.hpp:281
entt::sparse_set::size_type
std::size_t size_type
Unsigned integer type.
Definition: sparse_set.hpp:182
entt::sparse_set::construct
void construct(const entity_type entt)
Assigns an entity to a sparse set.
Definition: sparse_set.hpp:370
entt::operator!=
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) ENTT_NOEXCEPT
Compares two hashed strings.
Definition: hashed_string.hpp:226
entt::sparse_set::index
size_type index(const entity_type entt) const
Returns the position of an entity in a sparse set.
Definition: sparse_set.hpp:354
entt::sparse_set::size
size_type size() const ENTT_NOEXCEPT
Returns the number of elements in a sparse set.
Definition: sparse_set.hpp:254
entt::sparse_set::capacity
size_type capacity() const ENTT_NOEXCEPT
Returns the number of elements that a sparse set has currently allocated space for.
Definition: sparse_set.hpp:215
entt::sparse_set::operator=
sparse_set & operator=(sparse_set &&)=default
Default move assignment operator.
entt::entt_traits
Entity traits.
Definition: entity.hpp:21
entt::sparse_set::reserve
void reserve(const size_type cap)
Increases the capacity of a sparse set.
Definition: sparse_set.hpp:206
entt::sparse_set< entity_type >::entity_type
entity_type entity_type
Underlying entity identifier.
Definition: sparse_set.hpp:180
entt::sparse_set< entity_type >::iterator_type
iterator iterator_type
Random access iterator type.
Definition: sparse_set.hpp:184
entt::sparse_set::arrange
void arrange(iterator_type first, iterator_type last, Apply apply, Compare compare, Sort algo=Sort{}, Args &&... args)
Sort elements according to the given comparison function.
Definition: sparse_set.hpp:526
entt::std_sort
Function object to wrap std::sort in a class type.
Definition: algorithm.hpp:24