EnTT  3.2.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 <numeric>
12 #include <type_traits>
13 #include "../config/config.h"
14 #include "../core/algorithm.hpp"
15 #include "entity.hpp"
16 #include "fwd.hpp"
17 
18 
19 namespace entt {
20 
21 
49 template<typename Entity>
50 class sparse_set {
52 
53  static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0));
54  static constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(typename traits_type::entity_type);
55 
56  class iterator {
57  friend class sparse_set<Entity>;
58 
59  using direct_type = const std::vector<Entity>;
60  using index_type = typename traits_type::difference_type;
61 
62  iterator(direct_type *ref, const index_type idx) ENTT_NOEXCEPT
63  : direct{ref}, index{idx}
64  {}
65 
66  public:
67  using difference_type = index_type;
68  using value_type = Entity;
69  using pointer = const value_type *;
70  using reference = const value_type &;
71  using iterator_category = std::random_access_iterator_tag;
72 
73  iterator() ENTT_NOEXCEPT = default;
74 
75  iterator & operator++() ENTT_NOEXCEPT {
76  return --index, *this;
77  }
78 
79  iterator operator++(int) ENTT_NOEXCEPT {
80  iterator orig = *this;
81  return ++(*this), orig;
82  }
83 
84  iterator & operator--() ENTT_NOEXCEPT {
85  return ++index, *this;
86  }
87 
88  iterator operator--(int) ENTT_NOEXCEPT {
89  iterator orig = *this;
90  return --(*this), orig;
91  }
92 
93  iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
94  index -= value;
95  return *this;
96  }
97 
98  iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
99  return iterator{direct, index-value};
100  }
101 
102  iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
103  return (*this += -value);
104  }
105 
106  iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
107  return (*this + -value);
108  }
109 
110  difference_type operator-(const iterator &other) const ENTT_NOEXCEPT {
111  return other.index - index;
112  }
113 
114  reference operator[](const difference_type value) const ENTT_NOEXCEPT {
115  const auto pos = size_type(index-value-1);
116  return (*direct)[pos];
117  }
118 
119  bool operator==(const iterator &other) const ENTT_NOEXCEPT {
120  return other.index == index;
121  }
122 
123  bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
124  return !(*this == other);
125  }
126 
127  bool operator<(const iterator &other) const ENTT_NOEXCEPT {
128  return index > other.index;
129  }
130 
131  bool operator>(const iterator &other) const ENTT_NOEXCEPT {
132  return index < other.index;
133  }
134 
135  bool operator<=(const iterator &other) const ENTT_NOEXCEPT {
136  return !(*this > other);
137  }
138 
139  bool operator>=(const iterator &other) const ENTT_NOEXCEPT {
140  return !(*this < other);
141  }
142 
143  pointer operator->() const ENTT_NOEXCEPT {
144  const auto pos = size_type(index-1);
145  return &(*direct)[pos];
146  }
147 
148  reference operator*() const ENTT_NOEXCEPT {
149  return *operator->();
150  }
151 
152  private:
153  direct_type *direct;
154  index_type index;
155  };
156 
157  void assure(const std::size_t page) {
158  if(!(page < reverse.size())) {
159  reverse.resize(page+1);
160  }
161 
162  if(!reverse[page]) {
163  reverse[page] = std::make_unique<entity_type[]>(entt_per_page);
164  // null is safe in all cases for our purposes
165  std::fill_n(reverse[page].get(), entt_per_page, null);
166  }
167  }
168 
169  auto map(const Entity entt) const ENTT_NOEXCEPT {
170  const auto identifier = to_integer(entt) & traits_type::entity_mask;
171  const auto page = size_type(identifier / entt_per_page);
172  const auto offset = size_type(identifier & (entt_per_page - 1));
173  return std::make_pair(page, offset);
174  }
175 
176 public:
178  using entity_type = Entity;
180  using size_type = std::size_t;
182  using iterator_type = iterator;
183 
185  sparse_set() = default;
186 
191  sparse_set(const sparse_set &other)
192  : reverse{},
193  direct{other.direct}
194  {
195  for(size_type pos{}, last = other.reverse.size(); pos < last; ++pos) {
196  if(other.reverse[pos]) {
197  assure(pos);
198  std::copy_n(other.reverse[pos].get(), entt_per_page, reverse[pos].get());
199  }
200  }
201  }
202 
204  sparse_set(sparse_set &&) = default;
205 
207  virtual ~sparse_set() ENTT_NOEXCEPT = default;
208 
214  sparse_set & operator=(const sparse_set &other) {
215  if(&other != this) {
216  auto tmp{other};
217  *this = std::move(tmp);
218  }
219 
220  return *this;
221  }
222 
224  sparse_set & operator=(sparse_set &&) = default;
225 
234  void reserve(const size_type cap) {
235  direct.reserve(cap);
236  }
237 
243  size_type capacity() const ENTT_NOEXCEPT {
244  return direct.capacity();
245  }
246 
248  void shrink_to_fit() {
249  // conservative approach
250  if(direct.empty()) {
251  reverse.clear();
252  }
253 
254  reverse.shrink_to_fit();
255  direct.shrink_to_fit();
256  }
257 
268  size_type extent() const ENTT_NOEXCEPT {
269  return reverse.size() * entt_per_page;
270  }
271 
282  size_type size() const ENTT_NOEXCEPT {
283  return direct.size();
284  }
285 
290  bool empty() const ENTT_NOEXCEPT {
291  return direct.empty();
292  }
293 
309  const entity_type * data() const ENTT_NOEXCEPT {
310  return direct.data();
311  }
312 
326  iterator_type begin() const ENTT_NOEXCEPT {
327  const typename traits_type::difference_type pos = direct.size();
328  return iterator_type{&direct, pos};
329  }
330 
345  iterator_type end() const ENTT_NOEXCEPT {
346  return iterator_type{&direct, {}};
347  }
348 
355  iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
356  return has(entt) ? --(end() - index(entt)) : end();
357  }
358 
364  bool has(const entity_type entt) const ENTT_NOEXCEPT {
365  auto [page, offset] = map(entt);
366  // testing against null permits to avoid accessing the direct vector
367  return (page < reverse.size() && reverse[page] && reverse[page][offset] != null);
368  }
369 
382  size_type index(const entity_type entt) const ENTT_NOEXCEPT {
383  ENTT_ASSERT(has(entt));
384  auto [page, offset] = map(entt);
385  return size_type(reverse[page][offset]);
386  }
387 
399  void construct(const entity_type entt) {
400  ENTT_ASSERT(!has(entt));
401  auto [page, offset] = map(entt);
402  assure(page);
403  reverse[page][offset] = entity_type(direct.size());
404  direct.push_back(entt);
405  }
406 
420  template<typename It>
421  void batch(It first, It last) {
422  std::for_each(first, last, [this, next = direct.size()](const auto entt) mutable {
423  ENTT_ASSERT(!has(entt));
424  auto [page, offset] = map(entt);
425  assure(page);
426  reverse[page][offset] = entity_type(next++);
427  });
428 
429  direct.insert(direct.end(), first, last);
430  }
431 
443  void destroy(const entity_type entt) {
444  ENTT_ASSERT(has(entt));
445  auto [from_page, from_offset] = map(entt);
446  auto [to_page, to_offset] = map(direct.back());
447  direct[size_type(reverse[from_page][from_offset])] = entity_type(direct.back());
448  reverse[to_page][to_offset] = reverse[from_page][from_offset];
449  reverse[from_page][from_offset] = null;
450  direct.pop_back();
451  }
452 
468  virtual void swap(const entity_type lhs, const entity_type rhs) ENTT_NOEXCEPT {
469  auto [src_page, src_offset] = map(lhs);
470  auto [dst_page, dst_offset] = map(rhs);
471  auto &from = reverse[src_page][src_offset];
472  auto &to = reverse[dst_page][dst_offset];
473  std::swap(direct[size_type(from)], direct[size_type(to)]);
474  std::swap(from, to);
475  }
476 
516  template<typename Compare, typename Sort = std_sort, typename... Args>
517  void sort(iterator_type first, iterator_type last, Compare compare, Sort algo = Sort{}, Args &&... args) {
518  ENTT_ASSERT(!(last < first));
519  ENTT_ASSERT(!(last > end()));
520 
521  const auto length = std::distance(first, last);
522  const auto skip = std::distance(last, end());
523  const auto to = direct.rend() - skip;
524  const auto from = to - length;
525 
526  algo(from, to, std::move(compare), std::forward<Args>(args)...);
527 
528  for(size_type pos = skip, end = skip+length; pos < end; ++pos) {
529  auto [page, offset] = map(direct[pos]);
530  reverse[page][offset] = entity_type(pos);
531  }
532  }
533 
561  template<typename Apply, typename Compare, typename Sort = std_sort, typename... Args>
562  void arrange(iterator_type first, iterator_type last, Apply apply, Compare compare, Sort algo = Sort{}, Args &&... args) {
563  ENTT_ASSERT(!(last < first));
564  ENTT_ASSERT(!(last > end()));
565 
566  const auto length = std::distance(first, last);
567  const auto skip = std::distance(last, end());
568  const auto to = direct.rend() - skip;
569  const auto from = to - length;
570 
571  algo(from, to, std::move(compare), std::forward<Args>(args)...);
572 
573  for(size_type pos = skip, end = skip+length; pos < end; ++pos) {
574  auto curr = pos;
575  auto next = index(direct[curr]);
576 
577  while(curr != next) {
578  apply(direct[curr], direct[next]);
579  auto [page, offset] = map(direct[curr]);
580  reverse[page][offset] = entity_type(curr);
581 
582  curr = next;
583  next = index(direct[curr]);
584  }
585  }
586  }
587 
608  void respect(const sparse_set &other) ENTT_NOEXCEPT {
609  const auto to = other.end();
610  auto from = other.begin();
611 
612  size_type pos = direct.size() - 1;
613 
614  while(pos && from != to) {
615  if(has(*from)) {
616  if(*from != direct[pos]) {
617  swap(direct[pos], *from);
618  }
619 
620  --pos;
621  }
622 
623  ++from;
624  }
625  }
626 
630  void reset() {
631  reverse.clear();
632  direct.clear();
633  }
634 
635 private:
636  std::vector<std::unique_ptr<entity_type[]>> reverse;
637  std::vector<entity_type> direct;
638 };
639 
640 
641 }
642 
643 
644 #endif // ENTT_ENTITY_SPARSE_SET_HPP
entt::sparse_set::~sparse_set
virtual ~sparse_set() ENTT_NOEXCEPT=default
Default destructor.
entt::sparse_set::begin
iterator_type begin() const ENTT_NOEXCEPT
Returns an iterator to the beginning.
Definition: sparse_set.hpp:326
entt::sparse_set::end
iterator_type end() const ENTT_NOEXCEPT
Returns an iterator to the end.
Definition: sparse_set.hpp:345
entt::sparse_set::find
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT
Finds an entity.
Definition: sparse_set.hpp:355
entt::sparse_set
Basic sparse set implementation.
Definition: sparse_set.hpp:50
entt::get
constexpr get_t< Type... > get
Variable template for lists of observed components.
Definition: utility.hpp:40
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:517
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:268
entt::sparse_set::shrink_to_fit
void shrink_to_fit()
Requests the removal of unused capacity.
Definition: sparse_set.hpp:248
entt::sparse_set::destroy
void destroy(const entity_type entt)
Removes an entity from a sparse set.
Definition: sparse_set.hpp:443
entt::sparse_set::empty
bool empty() const ENTT_NOEXCEPT
Checks whether a sparse set is empty.
Definition: sparse_set.hpp:290
entt
EnTT default namespace.
Definition: algorithm.hpp:12
entt::sparse_set::sparse_set
sparse_set(const sparse_set &other)
Copy constructor.
Definition: sparse_set.hpp:191
entt::sparse_set::data
const entity_type * data() const ENTT_NOEXCEPT
Direct access to the internal packed array.
Definition: sparse_set.hpp:309
entt::sparse_set::index
size_type index(const entity_type entt) const ENTT_NOEXCEPT
Returns the position of an entity in a sparse set.
Definition: sparse_set.hpp:382
entt::sparse_set::size_type
std::size_t size_type
Unsigned integer type.
Definition: sparse_set.hpp:180
entt::sparse_set::construct
void construct(const entity_type entt)
Assigns an entity to a sparse set.
Definition: sparse_set.hpp:399
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:217
entt::sparse_set::size
size_type size() const ENTT_NOEXCEPT
Returns the number of elements in a sparse set.
Definition: sparse_set.hpp:282
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:243
entt::identifier
Types identifiers.
Definition: ident.hpp:42
entt::sparse_set::has
bool has(const entity_type entt) const ENTT_NOEXCEPT
Checks if a sparse set contains an entity.
Definition: sparse_set.hpp:364
entt::sparse_set::batch
void batch(It first, It last)
Assigns one or more entities to a sparse set.
Definition: sparse_set.hpp:421
entt::sparse_set::respect
void respect(const sparse_set &other) ENTT_NOEXCEPT
Sort entities according to their order in another sparse set.
Definition: sparse_set.hpp:608
entt::sparse_set::reset
void reset()
Resets a sparse set.
Definition: sparse_set.hpp:630
entt::entt_traits
Entity traits.
Definition: entity.hpp:20
entt::sparse_set::operator=
sparse_set & operator=(const sparse_set &other)
Copy assignment operator.
Definition: sparse_set.hpp:214
entt::sparse_set::reserve
void reserve(const size_type cap)
Increases the capacity of a sparse set.
Definition: sparse_set.hpp:234
entt::sparse_set< entity_type >::entity_type
entity_type entity_type
Underlying entity identifier.
Definition: sparse_set.hpp:178
entt::sparse_set< entity_type >::iterator_type
iterator iterator_type
Random access iterator type.
Definition: sparse_set.hpp:182
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:562
entt::sparse_set::swap
virtual void swap(const entity_type lhs, const entity_type rhs) ENTT_NOEXCEPT
Swaps two entities in the internal packed array.
Definition: sparse_set.hpp:468
entt::std_sort
Function object to wrap std::sort in a class type.
Definition: algorithm.hpp:23