id_array.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * Copyright (c) 2012-2014 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/taylor001/crown/blob/master/LICENSE
  4. */
  5. #pragma once
  6. #include "assert.h"
  7. #include "types.h"
  8. #include "container_types.h"
  9. namespace crown
  10. {
  11. /// Packed array of objects with lookup table.
  12. ///
  13. /// @ingroup Containers
  14. template <uint32_t MAX, typename T>
  15. struct IdArray
  16. {
  17. /// Creates the table for tracking exactly @a MAX - 1 unique Ids.
  18. IdArray();
  19. /// Random access by index.
  20. T& operator[](uint32_t i);
  21. /// Random access by index.
  22. const T& operator[](uint32_t i) const;
  23. // The index of the first unused id
  24. uint16_t _freelist;
  25. // Next available unique id
  26. uint16_t _next_id;
  27. uint16_t _size;
  28. // The last valid id is reserved and cannot be used to
  29. // refer to Ids from the outside
  30. Id _sparse[MAX];
  31. uint16_t _sparse_to_dense[MAX];
  32. uint16_t _dense_to_sparse[MAX];
  33. T _objects[MAX];
  34. };
  35. /// Functions to manipulate IdArray.
  36. ///
  37. /// @ingroup Containers
  38. namespace id_array
  39. {
  40. /// Creates a new @a object in the array @a a and returns its id.
  41. template <uint32_t MAX, typename T> Id create(IdArray<MAX, T>& a, const T& object);
  42. /// Destroys the object with the given @a id.
  43. template <uint32_t MAX, typename T> void destroy(IdArray<MAX, T>& a, Id id);
  44. /// Returns whether the table has the object with the given @a id.
  45. template <uint32_t MAX, typename T> bool has(const IdArray<MAX, T>& a, Id id);
  46. /// Returns the number of objects in the array.
  47. template <uint32_t MAX, typename T> uint32_t size(const IdArray<MAX, T>& a);
  48. /// Returns the object with the given @a id.
  49. template <uint32_t MAX, typename T> T& get(const Id& id);
  50. template <uint32_t MAX, typename T> T* begin(IdArray<MAX, T>& a);
  51. template <uint32_t MAX, typename T> const T* begin(const IdArray<MAX, T>& a);
  52. template <uint32_t MAX, typename T> T* end(IdArray<MAX, T>& a);
  53. template <uint32_t MAX, typename T> const T* end(const IdArray<MAX, T>& a);
  54. } // namespace id_array
  55. namespace id_array
  56. {
  57. template <uint32_t MAX, typename T>
  58. inline Id create(IdArray<MAX, T>& a, const T& object)
  59. {
  60. CE_ASSERT(a._size < MAX, "Object list full");
  61. // Obtain a new id
  62. Id id;
  63. id.id = a._next_id++;
  64. // Recycle slot if there are any
  65. if (a._freelist != INVALID_ID)
  66. {
  67. id.index = a._freelist;
  68. a._freelist = a._sparse[a._freelist].index;
  69. }
  70. else
  71. {
  72. id.index = a._size;
  73. }
  74. a._sparse[id.index] = id;
  75. a._sparse_to_dense[id.index] = a._size;
  76. a._dense_to_sparse[a._size] = id.index;
  77. a._objects[a._size] = object;
  78. a._size++;
  79. return id;
  80. }
  81. template <uint32_t MAX, typename T>
  82. inline void destroy(IdArray<MAX, T>& a, Id id)
  83. {
  84. CE_ASSERT(has(a, id), "IdArray does not have ID: %d,%d", id.id, id.index);
  85. a._sparse[id.index].id = INVALID_ID;
  86. a._sparse[id.index].index = a._freelist;
  87. a._freelist = id.index;
  88. // Swap with last element
  89. const uint32_t last = a._size - 1;
  90. CE_ASSERT(last >= a._sparse_to_dense[id.index], "Swapping with previous item");
  91. a._objects[a._sparse_to_dense[id.index]] = a._objects[last];
  92. // Update tables
  93. uint16_t std = a._sparse_to_dense[id.index];
  94. uint16_t dts = a._dense_to_sparse[last];
  95. a._sparse_to_dense[dts] = std;
  96. a._dense_to_sparse[std] = dts;
  97. a._size--;
  98. }
  99. template <uint32_t MAX, typename T>
  100. inline T& get(IdArray<MAX, T>& a, const Id& id)
  101. {
  102. CE_ASSERT(has(a, id), "IdArray does not have ID: %d,%d", id.id, id.index);
  103. return a._objects[a._sparse_to_dense[id.index]];
  104. }
  105. template <uint32_t MAX, typename T>
  106. inline bool has(const IdArray<MAX, T>& a, Id id)
  107. {
  108. return id.index < MAX && a._sparse[id.index].id == id.id;
  109. }
  110. template <uint32_t MAX, typename T>
  111. inline uint32_t size(const IdArray<MAX, T>& a)
  112. {
  113. return a._size;
  114. }
  115. template <uint32_t MAX, typename T>
  116. inline T* begin(IdArray<MAX, T>& a)
  117. {
  118. return a._objects;
  119. }
  120. template <uint32_t MAX, typename T>
  121. inline const T* begin(const IdArray<MAX, T>& a)
  122. {
  123. return a._objects;
  124. }
  125. template <uint32_t MAX, typename T>
  126. inline T* end(IdArray<MAX, T>& a)
  127. {
  128. return a._objects + a._size;
  129. }
  130. template <uint32_t MAX, typename T>
  131. inline const T* end(const IdArray<MAX, T>& a)
  132. {
  133. return a._objects + a._size;
  134. }
  135. } // namespace id_array
  136. template <uint32_t MAX, typename T>
  137. inline IdArray<MAX, T>::IdArray()
  138. : _freelist(INVALID_ID)
  139. , _next_id(0)
  140. , _size(0)
  141. {
  142. for (uint32_t i = 0; i < MAX; i++)
  143. {
  144. _sparse[i].id = INVALID_ID;
  145. }
  146. }
  147. template <uint32_t MAX, typename T>
  148. inline T& IdArray<MAX, T>::operator[](uint32_t i)
  149. {
  150. CE_ASSERT(i < _size, "Index out of bounds");
  151. return _objects[i];
  152. }
  153. template <uint32_t MAX, typename T>
  154. inline const T& IdArray<MAX, T>::operator[](uint32_t i) const
  155. {
  156. CE_ASSERT(i < _size, "Index out of bounds");
  157. return _objects[i];
  158. }
  159. } // namespace crown