StaticArray.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Core/HashCombine.h>
  6. JPH_NAMESPACE_BEGIN
  7. /// Simple variable length array backed by a fixed size buffer
  8. template <class T, uint N>
  9. class [[nodiscard]] StaticArray
  10. {
  11. public:
  12. using value_type = T;
  13. using size_type = uint;
  14. static constexpr uint Capacity = N;
  15. /// Default constructor
  16. StaticArray() = default;
  17. /// Constructor from initializer list
  18. explicit StaticArray(std::initializer_list<T> inList)
  19. {
  20. JPH_ASSERT(inList.size() <= N);
  21. for (const T &v : inList)
  22. ::new (reinterpret_cast<T *>(&mElements[mSize++])) T(v);
  23. }
  24. /// Copy constructor
  25. StaticArray(const StaticArray<T, N> &inRHS)
  26. {
  27. while (mSize < inRHS.mSize)
  28. {
  29. ::new (&mElements[mSize]) T(inRHS[mSize]);
  30. ++mSize;
  31. }
  32. }
  33. /// Destruct all elements
  34. ~StaticArray()
  35. {
  36. if constexpr (!is_trivially_destructible<T>())
  37. for (T *e = reinterpret_cast<T *>(mElements), *end = e + mSize; e < end; ++e)
  38. e->~T();
  39. }
  40. /// Destruct all elements and set length to zero
  41. void clear()
  42. {
  43. if constexpr (!is_trivially_destructible<T>())
  44. for (T *e = reinterpret_cast<T *>(mElements), *end = e + mSize; e < end; ++e)
  45. e->~T();
  46. mSize = 0;
  47. }
  48. /// Add element to the back of the array
  49. void push_back(const T &inElement)
  50. {
  51. JPH_ASSERT(mSize < N);
  52. ::new (&mElements[mSize++]) T(inElement);
  53. }
  54. /// Construct element at the back of the array
  55. template <class... A>
  56. void emplace_back(A &&... inElement)
  57. {
  58. JPH_ASSERT(mSize < N);
  59. ::new (&mElements[mSize++]) T(std::forward<A>(inElement)...);
  60. }
  61. /// Remove element from the back of the array
  62. void pop_back()
  63. {
  64. JPH_ASSERT(mSize > 0);
  65. reinterpret_cast<T &>(mElements[--mSize]).~T();
  66. }
  67. /// Returns true if there are no elements in the array
  68. bool empty() const
  69. {
  70. return mSize == 0;
  71. }
  72. /// Returns amount of elements in the array
  73. size_type size() const
  74. {
  75. return mSize;
  76. }
  77. /// Returns maximum amount of elements the array can hold
  78. size_type capacity() const
  79. {
  80. return N;
  81. }
  82. /// Resize array to new length
  83. void resize(size_type inNewSize)
  84. {
  85. JPH_ASSERT(inNewSize <= N);
  86. if constexpr (!is_trivially_constructible<T>())
  87. for (T *element = reinterpret_cast<T *>(mElements) + mSize, *element_end = reinterpret_cast<T *>(mElements) + inNewSize; element < element_end; ++element)
  88. ::new (element) T;
  89. if constexpr (!is_trivially_destructible<T>())
  90. for (T *element = reinterpret_cast<T *>(mElements) + inNewSize, *element_end = reinterpret_cast<T *>(mElements) + mSize; element < element_end; ++element)
  91. element->~T();
  92. mSize = inNewSize;
  93. }
  94. using const_iterator = const T *;
  95. /// Iterators
  96. const_iterator begin() const
  97. {
  98. return reinterpret_cast<const T *>(mElements);
  99. }
  100. const_iterator end() const
  101. {
  102. return reinterpret_cast<const T *>(mElements + mSize);
  103. }
  104. using iterator = T *;
  105. iterator begin()
  106. {
  107. return reinterpret_cast<T *>(mElements);
  108. }
  109. iterator end()
  110. {
  111. return reinterpret_cast<T *>(mElements + mSize);
  112. }
  113. const T * data() const
  114. {
  115. return reinterpret_cast<const T *>(mElements);
  116. }
  117. T * data()
  118. {
  119. return reinterpret_cast<T *>(mElements);
  120. }
  121. /// Access element
  122. T & operator [] (size_type inIdx)
  123. {
  124. JPH_ASSERT(inIdx < mSize);
  125. return reinterpret_cast<T &>(mElements[inIdx]);
  126. }
  127. const T & operator [] (size_type inIdx) const
  128. {
  129. JPH_ASSERT(inIdx < mSize);
  130. return reinterpret_cast<const T &>(mElements[inIdx]);
  131. }
  132. /// Access element
  133. T & at(size_type inIdx)
  134. {
  135. JPH_ASSERT(inIdx < mSize);
  136. return reinterpret_cast<T &>(mElements[inIdx]);
  137. }
  138. const T & at(size_type inIdx) const
  139. {
  140. JPH_ASSERT(inIdx < mSize);
  141. return reinterpret_cast<const T &>(mElements[inIdx]);
  142. }
  143. /// First element in the array
  144. const T & front() const
  145. {
  146. JPH_ASSERT(mSize > 0);
  147. return reinterpret_cast<const T &>(mElements[0]);
  148. }
  149. T & front()
  150. {
  151. JPH_ASSERT(mSize > 0);
  152. return reinterpret_cast<T &>(mElements[0]);
  153. }
  154. /// Last element in the array
  155. const T & back() const
  156. {
  157. JPH_ASSERT(mSize > 0);
  158. return reinterpret_cast<const T &>(mElements[mSize - 1]);
  159. }
  160. T & back()
  161. {
  162. JPH_ASSERT(mSize > 0);
  163. return reinterpret_cast<T &>(mElements[mSize - 1]);
  164. }
  165. /// Remove one element from the array
  166. void erase(const_iterator inIter)
  167. {
  168. size_type p = size_type(inIter - begin());
  169. JPH_ASSERT(p < mSize);
  170. reinterpret_cast<T &>(mElements[p]).~T();
  171. if (p + 1 < mSize)
  172. memmove(mElements + p, mElements + p + 1, (mSize - p - 1) * sizeof(T));
  173. --mSize;
  174. }
  175. /// Remove multiple element from the array
  176. void erase(const_iterator inBegin, const_iterator inEnd)
  177. {
  178. size_type p = size_type(inBegin - begin());
  179. size_type n = size_type(inEnd - inBegin);
  180. JPH_ASSERT(inEnd <= end());
  181. for (size_type i = 0; i < n; ++i)
  182. reinterpret_cast<T &>(mElements[p + i]).~T();
  183. if (p + n < mSize)
  184. memmove(mElements + p, mElements + p + n, (mSize - p - n) * sizeof(T));
  185. mSize -= n;
  186. }
  187. /// Assignment operator
  188. StaticArray<T, N> & operator = (const StaticArray<T, N> &inRHS)
  189. {
  190. size_type rhs_size = inRHS.size();
  191. if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
  192. {
  193. clear();
  194. while (mSize < rhs_size)
  195. {
  196. ::new (&mElements[mSize]) T(inRHS[mSize]);
  197. ++mSize;
  198. }
  199. }
  200. return *this;
  201. }
  202. /// Assignment operator with static array of different max length
  203. template <uint M>
  204. StaticArray<T, N> & operator = (const StaticArray<T, M> &inRHS)
  205. {
  206. size_type rhs_size = inRHS.size();
  207. JPH_ASSERT(rhs_size <= N);
  208. if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
  209. {
  210. clear();
  211. while (mSize < rhs_size)
  212. {
  213. ::new (&mElements[mSize]) T(inRHS[mSize]);
  214. ++mSize;
  215. }
  216. }
  217. return *this;
  218. }
  219. /// Comparing arrays
  220. bool operator == (const StaticArray<T, N> &inRHS) const
  221. {
  222. if (mSize != inRHS.mSize)
  223. return false;
  224. for (size_type i = 0; i < mSize; ++i)
  225. if (!(reinterpret_cast<const T &>(mElements[i]) == reinterpret_cast<const T &>(inRHS.mElements[i])))
  226. return false;
  227. return true;
  228. }
  229. bool operator != (const StaticArray<T, N> &inRHS) const
  230. {
  231. if (mSize != inRHS.mSize)
  232. return true;
  233. for (size_type i = 0; i < mSize; ++i)
  234. if (reinterpret_cast<const T &>(mElements[i]) != reinterpret_cast<const T &>(inRHS.mElements[i]))
  235. return true;
  236. return false;
  237. }
  238. protected:
  239. struct alignas(T) Storage
  240. {
  241. uint8 mData[sizeof(T)];
  242. };
  243. static_assert(sizeof(T) == sizeof(Storage), "Mismatch in size");
  244. static_assert(alignof(T) == alignof(Storage), "Mismatch in alignment");
  245. size_type mSize = 0;
  246. Storage mElements[N];
  247. };
  248. JPH_NAMESPACE_END
  249. JPH_SUPPRESS_WARNING_PUSH
  250. JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
  251. namespace std
  252. {
  253. /// Declare std::hash for StaticArray
  254. template <class T, JPH::uint N>
  255. struct hash<JPH::StaticArray<T, N>>
  256. {
  257. size_t operator () (const JPH::StaticArray<T, N> &inRHS) const
  258. {
  259. std::size_t ret = 0;
  260. // Hash length first
  261. JPH::HashCombine(ret, inRHS.size());
  262. // Then hash elements
  263. for (const T &t : inRHS)
  264. JPH::HashCombine(ret, t);
  265. return ret;
  266. }
  267. };
  268. }
  269. JPH_SUPPRESS_WARNING_POP