StaticArray.h 6.7 KB

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