entt  2.4.1
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 
128  void reserve(size_type cap) {
129  reverse.reserve(cap);
130  direct.reserve(cap);
131  }
132 
143  size_type size() const noexcept {
144  return direct.size();
145  }
146 
151  bool empty() const noexcept {
152  return direct.empty();
153  }
154 
170  const entity_type * data() const noexcept {
171  return direct.data();
172  }
173 
186  iterator_type begin() const noexcept {
187  return Iterator{&direct, direct.size()};
188  }
189 
203  iterator_type end() const noexcept {
204  return Iterator{&direct, 0};
205  }
206 
212  bool has(entity_type entity) const noexcept {
213  using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
214  // explicit promotion to avoid warnings with std::uint16_t
215  const auto entt = promotion_type{entity} & traits_type::entity_mask;
216  // the in-use control bit permits to avoid accessing the direct vector
217  return (entt < reverse.size()) && (reverse[entt] & in_use);
218  }
219 
232  pos_type get(entity_type entity) const noexcept {
233  assert(has(entity));
234  const auto entt = entity & traits_type::entity_mask;
235  // we must get rid of the in-use bit for it's not part of the position
236  return reverse[entt] & ~in_use;
237  }
238 
250  void construct(entity_type entity) {
251  assert(!has(entity));
252  using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
253  // explicit promotion to avoid warnings with std::uint16_t
254  const auto entt = promotion_type{entity} & traits_type::entity_mask;
255 
256  if(!(entt < reverse.size())) {
257  reverse.resize(entt+1, pos_type{});
258  }
259 
260  // we exploit the fact that pos_type is equal to entity_type and pos has
261  // traits_type::version_mask bits unused we can use to mark it as in-use
262  reverse[entt] = pos_type(direct.size()) | in_use;
263  direct.emplace_back(entity);
264  }
265 
277  virtual void destroy(entity_type entity) {
278  assert(has(entity));
279  const auto entt = entity & traits_type::entity_mask;
280  const auto back = direct.back() & traits_type::entity_mask;
281  const auto pos = reverse[entt] & ~in_use;
282  // the order matters: if back and entt are the same (for the sparse set
283  // has size 1), switching the two lines below doesn't work as expected
284  reverse[back] = pos | in_use;
285  reverse[entt] = pos;
286  // swapping isn't required here, we are getting rid of the last element
287  direct[pos] = direct.back();
288  direct.pop_back();
289  }
290 
306  void swap(pos_type lhs, pos_type rhs) noexcept {
307  assert(lhs < direct.size());
308  assert(rhs < direct.size());
309  const auto src = direct[lhs] & traits_type::entity_mask;
310  const auto dst = direct[rhs] & traits_type::entity_mask;
311  std::swap(reverse[src], reverse[dst]);
312  std::swap(direct[lhs], direct[rhs]);
313  }
314 
334  virtual void respect(const SparseSet<Entity> &other) noexcept {
335  auto from = other.begin();
336  auto to = other.end();
337 
338  pos_type pos = direct.size() - 1;
339 
340  while(pos > 0 && from != to) {
341  if(has(*from)) {
342  if(*from != direct[pos]) {
343  swap(pos, get(*from));
344  }
345 
346  --pos;
347  }
348 
349  ++from;
350  }
351  }
352 
356  virtual void reset() {
357  reverse.clear();
358  direct.clear();
359  }
360 
361 private:
362  std::vector<pos_type> reverse;
363  std::vector<entity_type> direct;
364 };
365 
366 
389 template<typename Entity, typename Type>
392 
393 public:
395  using object_type = Type;
404 
406  SparseSet() noexcept = default;
407 
409  SparseSet(const SparseSet &) = delete;
411  SparseSet(SparseSet &&) = default;
412 
414  SparseSet & operator=(const SparseSet &) = delete;
416  SparseSet & operator=(SparseSet &&) = default;
417 
426  void reserve(size_type cap) {
427  underlying_type::reserve(cap);
428  instances.reserve(cap);
429  }
430 
446  const object_type * raw() const noexcept {
447  return instances.data();
448  }
449 
465  object_type * raw() noexcept {
466  return instances.data();
467  }
468 
481  const object_type & get(entity_type entity) const noexcept {
482  return instances[underlying_type::get(entity)];
483  }
484 
497  object_type & get(entity_type entity) noexcept {
498  return const_cast<object_type &>(const_cast<const SparseSet *>(this)->get(entity));
499  }
500 
515  template<typename... Args>
516  object_type & construct(entity_type entity, Args&&... args) {
517  underlying_type::construct(entity);
518  // emplace_back doesn't work well with PODs because of its placement new
519  instances.push_back({ std::forward<Args>(args)... });
520  return instances.back();
521  }
522 
534  void destroy(entity_type entity) override {
535  // swapping isn't required here, we are getting rid of the last element
536  instances[underlying_type::get(entity)] = std::move(instances.back());
537  instances.pop_back();
538  underlying_type::destroy(entity);
539  }
540 
563  template<typename Compare>
564  void sort(Compare compare) {
565  std::vector<pos_type> copy(instances.size());
566  std::iota(copy.begin(), copy.end(), 0);
567 
568  std::sort(copy.begin(), copy.end(), [this, compare = std::move(compare)](auto lhs, auto rhs) {
569  return compare(const_cast<const object_type &>(instances[rhs]), const_cast<const object_type &>(instances[lhs]));
570  });
571 
572  for(pos_type pos = 0, last = copy.size(); pos < last; ++pos) {
573  auto curr = pos;
574  auto next = copy[curr];
575 
576  while(curr != next) {
577  auto lhs = copy[curr];
578  auto rhs = copy[next];
579  std::swap(instances[lhs], instances[rhs]);
580  underlying_type::swap(lhs, rhs);
581  copy[curr] = curr;
582  curr = next;
583  next = copy[curr];
584  }
585  }
586  }
587 
610  void respect(const SparseSet<Entity> &other) noexcept override {
611  auto from = other.begin();
612  auto to = other.end();
613 
614  pos_type pos = underlying_type::size() - 1;
615  const auto *direct = underlying_type::data();
616 
617  while(pos > 0 && from != to) {
618  if(underlying_type::has(*from)) {
619  if(*from != *(direct + pos)) {
620  auto candidate = underlying_type::get(*from);
621  std::swap(instances[pos], instances[candidate]);
622  underlying_type::swap(pos, candidate);
623  }
624 
625  --pos;
626  }
627 
628  ++from;
629  }
630  }
631 
635  void reset() override {
636  underlying_type::reset();
637  instances.clear();
638  }
639 
640 private:
641  std::vector<object_type> instances;
642 };
643 
644 
645 }
646 
647 
648 #endif // ENTT_ENTITY_SPARSE_SET_HPP
void sort(Compare compare)
Sort components according to the given comparison function.
Definition: sparse_set.hpp:564
virtual void reset()
Resets a sparse set.
Definition: sparse_set.hpp:356
EnTT default namespace.
Definition: family.hpp:9
void reset() override
Resets a sparse set.
Definition: sparse_set.hpp:635
const object_type * raw() const noexcept
Direct access to the array of objects.
Definition: sparse_set.hpp:446
bool empty() const noexcept
Checks whether a sparse set is empty.
Definition: sparse_set.hpp:151
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:610
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:390
void destroy(entity_type entity) override
Removes an entity from a sparse set and destroies its object.
Definition: sparse_set.hpp:534
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:212
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:395
const entity_type * data() const noexcept
Direct access to the internal packed array.
Definition: sparse_set.hpp:170
iterator_type end() const noexcept
Returns an iterator to the end.
Definition: sparse_set.hpp:203
virtual void destroy(entity_type entity)
Removes an entity from a sparse set.
Definition: sparse_set.hpp:277
iterator_type begin() const noexcept
Returns an iterator to the beginning.
Definition: sparse_set.hpp:186
void construct(entity_type entity)
Assigns an entity to a sparse set.
Definition: sparse_set.hpp:250
object_type & construct(entity_type entity, Args &&... args)
Assigns an entity to a sparse set and constructs its object.
Definition: sparse_set.hpp:516
size_type size() const noexcept
Returns the number of elements in a sparse set.
Definition: sparse_set.hpp:143
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:334
object_type * raw() noexcept
Direct access to the array of objects.
Definition: sparse_set.hpp:465
void swap(pos_type lhs, pos_type rhs) noexcept
Swaps the position of two entities in the internal packed array.
Definition: sparse_set.hpp:306
Entity traits.
Definition: traits.hpp:18