SparseArray.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Util/StdTypes.h>
  7. #include <AnKi/Util/Assert.h>
  8. #include <AnKi/Util/Array.h>
  9. #include <AnKi/Util/Allocator.h>
  10. #include <utility>
  11. namespace anki {
  12. /// @addtogroup util_containers
  13. /// @{
  14. /// Sparse array iterator.
  15. template<typename TValuePointer, typename TValueReference, typename TSparseArrayPtr>
  16. class SparseArrayIterator
  17. {
  18. template<typename, typename>
  19. friend class SparseArray;
  20. private:
  21. using Index = typename RemovePointer<TSparseArrayPtr>::Type::Index;
  22. public:
  23. /// Default constructor.
  24. SparseArrayIterator()
  25. : m_array(nullptr)
  26. , m_elementIdx(getMaxNumericLimit<Index>())
  27. #if ANKI_EXTRA_CHECKS
  28. , m_iteratorVer(MAX_U32)
  29. #endif
  30. {
  31. }
  32. /// Copy.
  33. SparseArrayIterator(const SparseArrayIterator& b)
  34. : m_array(b.m_array)
  35. , m_elementIdx(b.m_elementIdx)
  36. #if ANKI_EXTRA_CHECKS
  37. , m_iteratorVer(b.m_iteratorVer)
  38. #endif
  39. {
  40. }
  41. /// Allow conversion from iterator to const iterator.
  42. template<typename YValuePointer, typename YValueReference, typename YSparseArrayPtr>
  43. SparseArrayIterator(const SparseArrayIterator<YValuePointer, YValueReference, YSparseArrayPtr>& b)
  44. : m_array(b.m_array)
  45. , m_elementIdx(b.m_elementIdx)
  46. #if ANKI_EXTRA_CHECKS
  47. , m_iteratorVer(b.m_iteratorVer)
  48. #endif
  49. {
  50. }
  51. SparseArrayIterator(TSparseArrayPtr arr, Index modIdx
  52. #if ANKI_EXTRA_CHECKS
  53. ,
  54. U32 ver
  55. #endif
  56. )
  57. : m_array(arr)
  58. , m_elementIdx(modIdx)
  59. #if ANKI_EXTRA_CHECKS
  60. , m_iteratorVer(ver)
  61. #endif
  62. {
  63. ANKI_ASSERT(arr);
  64. }
  65. SparseArrayIterator& operator=(const SparseArrayIterator& b)
  66. {
  67. m_array = b.m_array;
  68. m_elementIdx = b.m_elementIdx;
  69. #if ANKI_EXTRA_CHECKS
  70. m_iteratorVer = b.m_iteratorVer;
  71. #endif
  72. return *this;
  73. }
  74. TValueReference operator*() const
  75. {
  76. check();
  77. return m_array->m_elements[m_elementIdx];
  78. }
  79. TValuePointer operator->() const
  80. {
  81. check();
  82. return &m_array->m_elements[m_elementIdx];
  83. }
  84. SparseArrayIterator& operator++()
  85. {
  86. check();
  87. m_elementIdx = m_array->iterate(m_elementIdx, 1);
  88. return *this;
  89. }
  90. SparseArrayIterator operator++(int)
  91. {
  92. check();
  93. SparseArrayIterator out = *this;
  94. ++(*this);
  95. return out;
  96. }
  97. SparseArrayIterator operator+(Index n) const
  98. {
  99. check();
  100. Index pos = m_array->iterate(m_elementIdx, n);
  101. return SparseArrayIterator(m_array, pos);
  102. }
  103. SparseArrayIterator& operator+=(Index n)
  104. {
  105. check();
  106. m_elementIdx = m_array->iterate(m_elementIdx, n);
  107. return *this;
  108. }
  109. Bool operator==(const SparseArrayIterator& b) const
  110. {
  111. ANKI_ASSERT(m_array == b.m_array);
  112. ANKI_ASSERT(m_iteratorVer == b.m_iteratorVer);
  113. return m_elementIdx == b.m_elementIdx;
  114. }
  115. Bool operator!=(const SparseArrayIterator& b) const
  116. {
  117. return !(*this == b);
  118. }
  119. U32 getKey() const
  120. {
  121. check();
  122. return m_elementIdx;
  123. }
  124. private:
  125. TSparseArrayPtr m_array;
  126. Index m_elementIdx;
  127. #if ANKI_EXTRA_CHECKS
  128. U32 m_iteratorVer; ///< See SparseArray::m_iteratorVer.
  129. #endif
  130. void check() const
  131. {
  132. ANKI_ASSERT(m_array);
  133. ANKI_ASSERT(m_elementIdx != getMaxNumericLimit<Index>());
  134. ANKI_ASSERT(m_array->m_metadata[m_elementIdx].m_alive);
  135. ANKI_ASSERT(m_array->m_iteratorVer == m_iteratorVer);
  136. }
  137. };
  138. /// Sparse array.
  139. /// @tparam T The type of the valut it will hold.
  140. /// @tparam TIndex Indicates the max size of the sparse indices it can accept. Can be U32 or U64.
  141. template<typename T, typename TIndex = U32>
  142. class SparseArray
  143. {
  144. template<typename, typename, typename>
  145. friend class SparseArrayIterator;
  146. public:
  147. // Typedefs
  148. using Value = T;
  149. using Iterator = SparseArrayIterator<T*, T&, SparseArray*>;
  150. using ConstIterator = SparseArrayIterator<const T*, const T&, const SparseArray*>;
  151. using Index = TIndex;
  152. // Consts
  153. static constexpr Index INITIAL_STORAGE_SIZE = 64; ///< The initial storage size of the array.
  154. static constexpr U32 LINEAR_PROBING_COUNT = 8; ///< The number of linear probes.
  155. static constexpr F32 MAX_LOAD_FACTOR = 0.8f; ///< Load factor.
  156. /// Constructor.
  157. /// @param initialStorageSize The initial size of the array.
  158. /// @param probeCount The number of probe queries. It's the linear probe count the sparse array is using.
  159. /// @param maxLoadFactor If storage is loaded more than maxLoadFactor then increase it.
  160. SparseArray(Index initialStorageSize = INITIAL_STORAGE_SIZE, U32 probeCount = LINEAR_PROBING_COUNT,
  161. F32 maxLoadFactor = MAX_LOAD_FACTOR)
  162. : m_initialStorageSize(initialStorageSize)
  163. , m_probeCount(probeCount)
  164. , m_maxLoadFactor(maxLoadFactor)
  165. {
  166. ANKI_ASSERT(initialStorageSize > 0 && isPowerOfTwo(initialStorageSize));
  167. ANKI_ASSERT(probeCount > 0 && probeCount < initialStorageSize);
  168. ANKI_ASSERT(maxLoadFactor > 0.5f && maxLoadFactor < 1.0f);
  169. }
  170. /// Non-copyable.
  171. SparseArray(const SparseArray&) = delete;
  172. /// Move constructor.
  173. SparseArray(SparseArray&& b)
  174. {
  175. *this = std::move(b);
  176. }
  177. /// Destroy.
  178. ~SparseArray()
  179. {
  180. ANKI_ASSERT(m_elements == nullptr && m_metadata == nullptr && "Forgot to call destroy");
  181. }
  182. /// Non-copyable.
  183. SparseArray& operator=(const SparseArray&) = delete;
  184. /// Move operator.
  185. SparseArray& operator=(SparseArray&& b)
  186. {
  187. ANKI_ASSERT(m_elements == nullptr && m_metadata == nullptr && "Forgot to call destroy");
  188. m_elements = b.m_elements;
  189. m_metadata = b.m_metadata;
  190. m_elementCount = b.m_elementCount;
  191. m_capacity = b.m_capacity;
  192. m_initialStorageSize = b.m_initialStorageSize;
  193. m_probeCount = b.m_probeCount;
  194. m_maxLoadFactor = b.m_maxLoadFactor;
  195. #if ANKI_EXTRA_CHECKS
  196. ++m_iteratorVer;
  197. #endif
  198. b.resetMembers();
  199. return *this;
  200. }
  201. /// Get begin.
  202. Iterator getBegin()
  203. {
  204. return Iterator(this, findFirstAlive()
  205. #if ANKI_EXTRA_CHECKS
  206. ,
  207. m_iteratorVer
  208. #endif
  209. );
  210. }
  211. /// Get begin.
  212. ConstIterator getBegin() const
  213. {
  214. return ConstIterator(this, findFirstAlive()
  215. #if ANKI_EXTRA_CHECKS
  216. ,
  217. m_iteratorVer
  218. #endif
  219. );
  220. }
  221. /// Get end.
  222. Iterator getEnd()
  223. {
  224. return Iterator(this, getMaxNumericLimit<Index>()
  225. #if ANKI_EXTRA_CHECKS
  226. ,
  227. m_iteratorVer
  228. #endif
  229. );
  230. }
  231. /// Get end.
  232. ConstIterator getEnd() const
  233. {
  234. return ConstIterator(this, getMaxNumericLimit<Index>()
  235. #if ANKI_EXTRA_CHECKS
  236. ,
  237. m_iteratorVer
  238. #endif
  239. );
  240. }
  241. /// Get begin.
  242. Iterator begin()
  243. {
  244. return getBegin();
  245. }
  246. /// Get begin.
  247. ConstIterator begin() const
  248. {
  249. return getBegin();
  250. }
  251. /// Get end.
  252. Iterator end()
  253. {
  254. return getEnd();
  255. }
  256. /// Get end.
  257. ConstIterator end() const
  258. {
  259. return getEnd();
  260. }
  261. /// Get the number of elements in the array.
  262. PtrSize getSize() const
  263. {
  264. return m_elementCount;
  265. }
  266. /// Return true if it's empty and false otherwise.
  267. Bool isEmpty() const
  268. {
  269. return m_elementCount == 0;
  270. }
  271. /// Destroy the array and free its elements.
  272. template<typename TAlloc>
  273. void destroy(TAlloc& alloc);
  274. /// Set a value to an index.
  275. template<typename TAlloc, typename... TArgs>
  276. Iterator emplace(TAlloc& alloc, Index idx, TArgs&&... args);
  277. /// Get an iterator.
  278. Iterator find(Index idx)
  279. {
  280. return Iterator(this, findInternal(idx)
  281. #if ANKI_EXTRA_CHECKS
  282. ,
  283. m_iteratorVer
  284. #endif
  285. );
  286. }
  287. /// Get an iterator.
  288. ConstIterator find(Index idx) const
  289. {
  290. return ConstIterator(this, findInternal(idx)
  291. #if ANKI_EXTRA_CHECKS
  292. ,
  293. m_iteratorVer
  294. #endif
  295. );
  296. }
  297. /// Remove an element.
  298. template<typename TAlloc>
  299. void erase(TAlloc& alloc, Iterator it);
  300. /// Check the validity of the array.
  301. void validate() const;
  302. /// Create a copy of this.
  303. template<typename TAlloc>
  304. void clone(TAlloc& alloc, SparseArray& b) const;
  305. protected:
  306. /// Element metadata.
  307. class Metadata
  308. {
  309. public:
  310. Index m_idx;
  311. Bool m_alive;
  312. };
  313. Value* m_elements = nullptr;
  314. Metadata* m_metadata = nullptr;
  315. Index m_elementCount = 0;
  316. Index m_capacity = 0;
  317. Index m_initialStorageSize = 0;
  318. U32 m_probeCount = 0;
  319. F32 m_maxLoadFactor = 0.0f;
  320. #if ANKI_EXTRA_CHECKS
  321. /// Iterators version. Used to check if iterators point to the newest storage. Needs to be changed whenever we need
  322. /// to invalidate iterators.
  323. U32 m_iteratorVer = 0;
  324. #endif
  325. /// Wrap an index.
  326. Index mod(const Index idx) const
  327. {
  328. ANKI_ASSERT(m_capacity > 0);
  329. ANKI_ASSERT(isPowerOfTwo(m_capacity));
  330. return idx & (m_capacity - 1);
  331. }
  332. /// Wrap an index.
  333. static Index mod(const Index idx, Index capacity)
  334. {
  335. ANKI_ASSERT(capacity > 0);
  336. ANKI_ASSERT(isPowerOfTwo(capacity));
  337. return idx & (capacity - 1);
  338. }
  339. F32 calcLoadFactor() const
  340. {
  341. ANKI_ASSERT(m_elementCount <= m_capacity);
  342. ANKI_ASSERT(m_capacity > 0);
  343. return F32(m_elementCount) / F32(m_capacity);
  344. }
  345. /// Insert a value. This method will move the val to a new place.
  346. /// @return One if the idx was a new element or zero if the idx was there already.
  347. template<typename TAlloc>
  348. Index insert(TAlloc& alloc, Index idx, Value& val);
  349. /// Grow the storage and re-insert.
  350. template<typename TAlloc>
  351. void grow(TAlloc& alloc);
  352. /// Compute the distance between a desired position and the current one. This method does a trick with capacity to
  353. /// account for wrapped positions.
  354. Index distanceFromDesired(const Index crntPos, const Index desiredPos) const
  355. {
  356. return mod(crntPos + m_capacity - desiredPos);
  357. }
  358. /// Find the first alive element.
  359. Index findFirstAlive() const
  360. {
  361. if(m_elementCount == 0)
  362. {
  363. return getMaxNumericLimit<Index>();
  364. }
  365. for(Index i = 0; i < m_capacity; ++i)
  366. {
  367. if(m_metadata[i].m_alive)
  368. {
  369. return i;
  370. }
  371. }
  372. ANKI_ASSERT(0);
  373. return getMaxNumericLimit<Index>();
  374. }
  375. /// Find an element and return its position inside m_elements.
  376. Index findInternal(Index idx) const;
  377. /// Reset the class.
  378. void resetMembers()
  379. {
  380. m_elements = nullptr;
  381. m_metadata = nullptr;
  382. m_elementCount = 0;
  383. m_capacity = 0;
  384. invalidateIterators();
  385. }
  386. /// Iterate a number of elements.
  387. Index iterate(Index pos, Index n) const
  388. {
  389. ANKI_ASSERT(pos < m_capacity);
  390. ANKI_ASSERT(n > 0);
  391. ANKI_ASSERT(m_metadata[pos].m_alive);
  392. while(n > 0 && ++pos < m_capacity)
  393. {
  394. ANKI_ASSERT(m_metadata[pos].m_alive == 1 || m_metadata[pos].m_alive == 0);
  395. n -= Index(m_metadata[pos].m_alive);
  396. }
  397. return (pos >= m_capacity) ? getMaxNumericLimit<Index>() : pos;
  398. }
  399. template<typename TAlloc, typename... TArgs>
  400. void emplaceInternal(TAlloc& alloc, Index idx, TArgs&&... args);
  401. void destroyElement(Value& v)
  402. {
  403. v.~Value();
  404. #if ANKI_EXTRA_CHECKS
  405. memset(&v, 0xC, sizeof(v));
  406. #endif
  407. }
  408. void invalidateIterators()
  409. {
  410. #if ANKI_EXTRA_CHECKS
  411. ++m_iteratorVer;
  412. #endif
  413. }
  414. };
  415. /// @}
  416. } // end namespace anki
  417. #include <AnKi/Util/SparseArray.inl.h>