SparseArray.h 10 KB

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