entt  2.3.0
sparse_set.hpp
1 #ifndef ENTT_ENTITY_SPARSE_SET_HPP
2 #define ENTT_ENTITY_SPARSE_SET_HPP
3 
4 
5 #include <algorithm>
6 #include <numeric>
7 #include <utility>
8 #include <vector>
9 #include <cstddef>
10 #include <cassert>
11 #include <type_traits>
12 #include "traits.hpp"
13 
14 
15 namespace entt {
16 
17 
24 template<typename...>
25 class SparseSet;
26 
27 
55 template<typename Entity>
58 
59  struct Iterator {
60  using value_type = Entity;
61 
62  Iterator(const std::vector<Entity> *direct, std::size_t pos)
63  : direct{direct}, pos{pos}
64  {}
65 
66  Iterator & operator++() noexcept {
67  return --pos, *this;
68  }
69 
70  Iterator operator++(int) noexcept {
71  Iterator orig = *this;
72  return ++(*this), orig;
73  }
74 
75  bool operator==(const Iterator &other) const noexcept {
76  return other.pos == pos && other.direct == direct;
77  }
78 
79  bool operator!=(const Iterator &other) const noexcept {
80  return !(*this == other);
81  }
82 
83  value_type operator*() const noexcept {
84  return (*direct)[pos-1];
85  }
86 
87  private:
88  const std::vector<Entity> *direct;
89  std::size_t pos;
90  };
91 
92  static constexpr Entity in_use = (Entity{1} << traits_type::entity_shift);
93 
94 public:
96  using entity_type = Entity;
100  using size_type = std::size_t;
102  using iterator_type = Iterator;
103 
105  SparseSet() noexcept = default;
106 
108  virtual ~SparseSet() noexcept = default;
109 
111  SparseSet(const SparseSet &) = delete;
113  SparseSet(SparseSet &&) = default;
114 
116  SparseSet & operator=(const SparseSet &) = delete;
118  SparseSet & operator=(SparseSet &&) = default;
119 
130  size_type size() const noexcept {
131  return direct.size();
132  }
133 
138  bool empty() const noexcept {
139  return direct.empty();
140  }
141 
157  const entity_type * data() const noexcept {
158  return direct.data();
159  }
160 
173  iterator_type begin() const noexcept {
174  return Iterator{&direct, direct.size()};
175  }
176 
190  iterator_type end() const noexcept {
191  return Iterator{&direct, 0};
192  }
193 
199  bool has(entity_type entity) const noexcept {
200  using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
201  // explicit promotion to avoid warnings with std::uint16_t
202  const auto entt = promotion_type{entity} & traits_type::entity_mask;
203  // the in-use control bit permits to avoid accessing the direct vector
204  return (entt < reverse.size()) && (reverse[entt] & in_use);
205  }
206 
219  pos_type get(entity_type entity) const noexcept {
220  assert(has(entity));
221  const auto entt = entity & traits_type::entity_mask;
222  // we must get rid of the in-use bit for it's not part of the position
223  return reverse[entt] & ~in_use;
224  }
225 
237  void construct(entity_type entity) {
238  assert(!has(entity));
239  using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
240  // explicit promotion to avoid warnings with std::uint16_t
241  const auto entt = promotion_type{entity} & traits_type::entity_mask;
242 
243  if(!(entt < reverse.size())) {
244  reverse.resize(entt+1, pos_type{});
245  }
246 
247  // we exploit the fact that pos_type is equal to entity_type and pos has
248  // traits_type::version_mask bits unused we can use to mark it as in-use
249  reverse[entt] = pos_type(direct.size()) | in_use;
250  direct.emplace_back(entity);
251  }
252 
264  virtual void destroy(entity_type entity) {
265  assert(has(entity));
266  const auto entt = entity & traits_type::entity_mask;
267  const auto back = direct.back() & traits_type::entity_mask;
268  const auto pos = reverse[entt] & ~in_use;
269  // the order matters: if back and entt are the same (for the sparse set
270  // has size 1), switching the two lines below doesn't work as expected
271  reverse[back] = pos | in_use;
272  reverse[entt] = pos;
273  // swapping isn't required here, we are getting rid of the last element
274  direct[pos] = direct.back();
275  direct.pop_back();
276  }
277 
293  void swap(pos_type lhs, pos_type rhs) noexcept {
294  assert(lhs < direct.size());
295  assert(rhs < direct.size());
296  std::swap(reverse[direct[lhs]], reverse[direct[rhs]]);
297  std::swap(direct[lhs], direct[rhs]);
298  }
299 
319  virtual void respect(const SparseSet<Entity> &other) noexcept {
320  auto from = other.begin();
321  auto to = other.end();
322 
323  pos_type pos = direct.size() - 1;
324 
325  while(pos > 0 && from != to) {
326  if(has(*from)) {
327  if(*from != direct[pos]) {
328  swap(pos, get(*from));
329  }
330 
331  --pos;
332  }
333 
334  ++from;
335  }
336  }
337 
341  virtual void reset() {
342  reverse.clear();
343  direct.clear();
344  }
345 
346 private:
347  std::vector<pos_type> reverse;
348  std::vector<entity_type> direct;
349 };
350 
351 
374 template<typename Entity, typename Type>
377 
378 public:
380  using object_type = Type;
389 
391  SparseSet() noexcept = default;
392 
394  SparseSet(const SparseSet &) = delete;
396  SparseSet(SparseSet &&) = default;
397 
399  SparseSet & operator=(const SparseSet &) = delete;
401  SparseSet & operator=(SparseSet &&) = default;
402 
418  const object_type * raw() const noexcept {
419  return instances.data();
420  }
421 
437  object_type * raw() noexcept {
438  return instances.data();
439  }
440 
453  const object_type & get(entity_type entity) const noexcept {
454  return instances[underlying_type::get(entity)];
455  }
456 
469  object_type & get(entity_type entity) noexcept {
470  return const_cast<object_type &>(const_cast<const SparseSet *>(this)->get(entity));
471  }
472 
487  template<typename... Args>
488  object_type & construct(entity_type entity, Args&&... args) {
489  underlying_type::construct(entity);
490  // emplace_back doesn't work well with PODs because of its placement new
491  instances.push_back({ std::forward<Args>(args)... });
492  return instances.back();
493  }
494 
506  void destroy(entity_type entity) override {
507  // swapping isn't required here, we are getting rid of the last element
508  instances[underlying_type::get(entity)] = std::move(instances.back());
509  instances.pop_back();
510  underlying_type::destroy(entity);
511  }
512 
535  template<typename Compare>
536  void sort(Compare compare) {
537  std::vector<pos_type> copy(instances.size());
538  std::iota(copy.begin(), copy.end(), 0);
539 
540  std::sort(copy.begin(), copy.end(), [this, compare = std::move(compare)](auto lhs, auto rhs) {
541  return compare(const_cast<const object_type &>(instances[rhs]), const_cast<const object_type &>(instances[lhs]));
542  });
543 
544  for(pos_type i = 0; i < copy.size(); ++i) {
545  auto curr = i;
546  auto next = copy[curr];
547 
548  while(curr != next) {
549  auto lhs = copy[curr];
550  auto rhs = copy[next];
551  std::swap(instances[lhs], instances[rhs]);
552  underlying_type::swap(lhs, rhs);
553  copy[curr] = curr;
554  curr = next;
555  next = copy[curr];
556  }
557  }
558  }
559 
582  void respect(const SparseSet<Entity> &other) noexcept override {
583  auto from = other.begin();
584  auto to = other.end();
585 
586  pos_type pos = underlying_type::size() - 1;
587  const auto *direct = underlying_type::data();
588 
589  while(pos > 0 && from != to) {
590  if(underlying_type::has(*from)) {
591  if(*from != *(direct + pos)) {
592  auto candidate = underlying_type::get(*from);
593  std::swap(instances[pos], instances[candidate]);
594  underlying_type::swap(pos, candidate);
595  }
596 
597  --pos;
598  }
599 
600  ++from;
601  }
602  }
603 
607  void reset() override {
608  underlying_type::reset();
609  instances.clear();
610  }
611 
612 private:
613  std::vector<object_type> instances;
614 };
615 
616 
617 }
618 
619 
620 #endif // ENTT_ENTITY_SPARSE_SET_HPP
void sort(Compare compare)
Sort components according to the given comparison function.
Definition: sparse_set.hpp:536
virtual void reset()
Resets a sparse set.
Definition: sparse_set.hpp:341
EnTT default namespace.
Definition: family.hpp:9
void reset() override
Resets a sparse set.
Definition: sparse_set.hpp:607
bool empty() const noexcept
Checks whether a sparse set is empty.
Definition: sparse_set.hpp:138
void respect(const SparseSet< Entity > &other) noexcept override
Sort components according to the order of the entities in another sparse set.
Definition: sparse_set.hpp:582
Sparse set.
Definition: sparse_set.hpp:25
std::size_t size_type
Unsigned integer type.
Definition: sparse_set.hpp:100
Extended sparse set implementation.
Definition: sparse_set.hpp:375
void destroy(entity_type entity) override
Removes an entity from a sparse set and destroies its object.
Definition: sparse_set.hpp:506
Entity entity_type
Underlying entity identifier.
Definition: sparse_set.hpp:96
Iterator iterator_type
Input iterator type.
Definition: sparse_set.hpp:102
Basic sparse set implementation.
Definition: sparse_set.hpp:56
bool has(entity_type entity) const noexcept
Checks if a sparse set contains an entity.
Definition: sparse_set.hpp:199
entity_type pos_type
Entity dependent position type.
Definition: sparse_set.hpp:98
Type object_type
Type of the objects associated to the entities.
Definition: sparse_set.hpp:380
const entity_type * data() const noexcept
Direct access to the internal packed array.
Definition: sparse_set.hpp:157
iterator_type end() const noexcept
Returns an iterator to the end.
Definition: sparse_set.hpp:190
virtual void destroy(entity_type entity)
Removes an entity from a sparse set.
Definition: sparse_set.hpp:264
iterator_type begin() const noexcept
Returns an iterator to the beginning.
Definition: sparse_set.hpp:173
void construct(entity_type entity)
Assigns an entity to a sparse set.
Definition: sparse_set.hpp:237
object_type & construct(entity_type entity, Args &&... args)
Assigns an entity to a sparse set and constructs its object.
Definition: sparse_set.hpp:488
constexpr bool operator!=(const HashedString &lhs, const HashedString &rhs) noexcept
Compares two hashed strings.
virtual void respect(const SparseSet< Entity > &other) noexcept
Sort entities according to their order in another sparse set.
Definition: sparse_set.hpp:319
object_type * raw() noexcept
Direct access to the array of objects.
Definition: sparse_set.hpp:437
void swap(pos_type lhs, pos_type rhs) noexcept
Swaps the position of two entities in the internal packed array.
Definition: sparse_set.hpp:293
Entity traits.
Definition: traits.hpp:18