Array.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2024 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Core/STLAllocator.h>
  6. #include <Jolt/Core/HashCombine.h>
  7. #ifdef JPH_USE_STD_VECTOR
  8. JPH_SUPPRESS_WARNINGS_STD_BEGIN
  9. #include <vector>
  10. JPH_SUPPRESS_WARNINGS_STD_END
  11. JPH_NAMESPACE_BEGIN
  12. template <class T, class Allocator = STLAllocator<T>> using Array = std::vector<T, Allocator>;
  13. JPH_NAMESPACE_END
  14. #else
  15. JPH_NAMESPACE_BEGIN
  16. /// Simple replacement for std::vector
  17. ///
  18. /// Major differences:
  19. /// - Memory is not initialized to zero (this was causing a lot of page faults when deserializing large MeshShapes / HeightFieldShapes)
  20. /// - Iterators are simple pointers (for now)
  21. /// - No exception safety
  22. /// - No specialization like std::vector<bool> has
  23. /// - Not all functions have been implemented
  24. template <class T, class Allocator = STLAllocator<T>>
  25. class [[nodiscard]] Array : private Allocator
  26. {
  27. public:
  28. using value_type = T;
  29. using size_type = size_t;
  30. using pointer = T *;
  31. using const_pointer = const T *;
  32. using reference = T &;
  33. using const_reference = const T &;
  34. using const_iterator = const T *;
  35. using iterator = T *;
  36. private:
  37. /// Move elements from one location to another
  38. inline void move(pointer inDestination, pointer inSource, size_type inCount)
  39. {
  40. if constexpr (std::is_trivially_copyable<T>())
  41. memmove(inDestination, inSource, inCount * sizeof(T));
  42. else
  43. {
  44. if (inDestination < inSource)
  45. {
  46. for (T *destination_end = inDestination + inCount; inDestination < destination_end; ++inDestination, ++inSource)
  47. {
  48. ::new (inDestination) T(std::move(*inSource));
  49. inSource->~T();
  50. }
  51. }
  52. else
  53. {
  54. for (T *destination = inDestination + inCount - 1, *source = inSource + inCount - 1; destination >= inDestination; --destination, --source)
  55. {
  56. ::new (destination) T(std::move(*source));
  57. source->~T();
  58. }
  59. }
  60. }
  61. }
  62. /// Destruct elements [inStart, inEnd - 1]
  63. inline void destruct(size_type inStart, size_type inEnd)
  64. {
  65. if constexpr (!is_trivially_destructible<T>())
  66. if (inStart < inEnd)
  67. for (T *element = mElements + inStart, *element_end = mElements + inEnd; element < element_end; ++element)
  68. element->~T();
  69. }
  70. public:
  71. /// Reserve array space
  72. inline void reserve(size_type inNewSize)
  73. {
  74. if (mCapacity < inNewSize)
  75. {
  76. pointer pointer;
  77. if constexpr (std::is_trivially_copyable<T>() && !std::is_same<Allocator, std::allocator<T>>())
  78. {
  79. pointer = get_allocator().reallocate(mElements, mCapacity, inNewSize);
  80. }
  81. else
  82. {
  83. pointer = get_allocator().allocate(inNewSize);
  84. if (mElements != nullptr)
  85. {
  86. move(pointer, mElements, mSize);
  87. get_allocator().deallocate(mElements, mCapacity);
  88. }
  89. }
  90. mElements = pointer;
  91. mCapacity = inNewSize;
  92. }
  93. }
  94. /// Resize array to new length
  95. inline void resize(size_type inNewSize)
  96. {
  97. destruct(inNewSize, mSize);
  98. reserve(inNewSize);
  99. if constexpr (!is_trivially_constructible<T>())
  100. for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
  101. ::new (element) T;
  102. mSize = inNewSize;
  103. }
  104. /// Resize array to new length and initialize all elements with inValue
  105. inline void resize(size_type inNewSize, const T &inValue)
  106. {
  107. JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to resize");
  108. destruct(inNewSize, mSize);
  109. reserve(inNewSize);
  110. for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
  111. ::new (element) T(inValue);
  112. mSize = inNewSize;
  113. }
  114. /// Destruct all elements and set length to zero
  115. inline void clear()
  116. {
  117. destruct(0, mSize);
  118. mSize = 0;
  119. }
  120. private:
  121. /// Grow the array by at least inAmount elements
  122. inline void grow(size_type inAmount = 1)
  123. {
  124. size_type min_size = mSize + inAmount;
  125. if (min_size > mCapacity)
  126. {
  127. size_type new_capacity = max(min_size, mCapacity * 2);
  128. reserve(new_capacity);
  129. }
  130. }
  131. /// Destroy all elements and free memory
  132. inline void destroy()
  133. {
  134. if (mElements != nullptr)
  135. {
  136. clear();
  137. get_allocator().deallocate(mElements, mCapacity);
  138. mElements = nullptr;
  139. mCapacity = 0;
  140. }
  141. }
  142. public:
  143. /// Replace the contents of this array with inBegin .. inEnd
  144. template <class Iterator>
  145. inline void assign(Iterator inBegin, Iterator inEnd)
  146. {
  147. clear();
  148. reserve(size_type(std::distance(inBegin, inEnd)));
  149. for (Iterator element = inBegin; element != inEnd; ++element)
  150. ::new (&mElements[mSize++]) T(*element);
  151. }
  152. /// Replace the contents of this array with inList
  153. inline void assign(std::initializer_list<T> inList)
  154. {
  155. clear();
  156. reserve(size_type(inList.size()));
  157. for (typename std::initializer_list<T>::iterator i = inList.begin(); i != inList.end(); ++i)
  158. ::new (&mElements[mSize++]) T(*i);
  159. }
  160. /// Default constructor
  161. Array() = default;
  162. /// Constructor with allocator
  163. explicit inline Array(const Allocator &inAllocator) :
  164. Allocator(inAllocator)
  165. {
  166. }
  167. /// Constructor with length
  168. explicit inline Array(size_type inLength, const Allocator &inAllocator = { }) :
  169. Allocator(inAllocator)
  170. {
  171. resize(inLength);
  172. }
  173. /// Constructor with length and value
  174. inline Array(size_type inLength, const T &inValue, const Allocator &inAllocator = { }) :
  175. Allocator(inAllocator)
  176. {
  177. resize(inLength, inValue);
  178. }
  179. /// Constructor from initializer list
  180. inline Array(std::initializer_list<T> inList, const Allocator &inAllocator = { }) :
  181. Allocator(inAllocator)
  182. {
  183. assign(inList);
  184. }
  185. /// Constructor from iterator
  186. inline Array(const_iterator inBegin, const_iterator inEnd, const Allocator &inAllocator = { }) :
  187. Allocator(inAllocator)
  188. {
  189. assign(inBegin, inEnd);
  190. }
  191. /// Copy constructor
  192. inline Array(const Array<T, Allocator> &inRHS) :
  193. Allocator(inRHS.get_allocator())
  194. {
  195. assign(inRHS.begin(), inRHS.end());
  196. }
  197. /// Move constructor
  198. inline Array(Array<T, Allocator> &&inRHS) noexcept :
  199. Allocator(std::move(inRHS.get_allocator())),
  200. mSize(inRHS.mSize),
  201. mCapacity(inRHS.mCapacity),
  202. mElements(inRHS.mElements)
  203. {
  204. inRHS.mSize = 0;
  205. inRHS.mCapacity = 0;
  206. inRHS.mElements = nullptr;
  207. }
  208. /// Destruct all elements
  209. inline ~Array()
  210. {
  211. destroy();
  212. }
  213. /// Get the allocator
  214. inline Allocator & get_allocator()
  215. {
  216. return *this;
  217. }
  218. inline const Allocator &get_allocator() const
  219. {
  220. return *this;
  221. }
  222. /// Add element to the back of the array
  223. inline void push_back(const T &inValue)
  224. {
  225. JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to push_back");
  226. grow();
  227. T *element = mElements + mSize++;
  228. ::new (element) T(inValue);
  229. }
  230. inline void push_back(T &&inValue)
  231. {
  232. grow();
  233. T *element = mElements + mSize++;
  234. ::new (element) T(std::move(inValue));
  235. }
  236. /// Construct element at the back of the array
  237. template <class... A>
  238. inline T & emplace_back(A &&... inValue)
  239. {
  240. grow();
  241. T *element = mElements + mSize++;
  242. ::new (element) T(std::forward<A>(inValue)...);
  243. return *element;
  244. }
  245. /// Remove element from the back of the array
  246. inline void pop_back()
  247. {
  248. JPH_ASSERT(mSize > 0);
  249. mElements[--mSize].~T();
  250. }
  251. /// Returns true if there are no elements in the array
  252. inline bool empty() const
  253. {
  254. return mSize == 0;
  255. }
  256. /// Returns amount of elements in the array
  257. inline size_type size() const
  258. {
  259. return mSize;
  260. }
  261. /// Returns maximum amount of elements the array can hold
  262. inline size_type capacity() const
  263. {
  264. return mCapacity;
  265. }
  266. /// Reduce the capacity of the array to match its size
  267. void shrink_to_fit()
  268. {
  269. if (mSize == 0)
  270. {
  271. // Free memory block
  272. if (mElements != nullptr)
  273. {
  274. get_allocator().deallocate(mElements, mCapacity);
  275. mElements = nullptr;
  276. mCapacity = 0;
  277. }
  278. }
  279. else if (mCapacity > mSize)
  280. {
  281. // Reallocate memory block
  282. pointer pointer = get_allocator().allocate(mSize);
  283. move(pointer, mElements, mSize);
  284. get_allocator().deallocate(mElements, mCapacity);
  285. mElements = pointer;
  286. mCapacity = mSize;
  287. }
  288. }
  289. /// Swap the contents of two arrays
  290. void swap(Array<T, Allocator> &inRHS) noexcept
  291. {
  292. std::swap(get_allocator(), inRHS.get_allocator());
  293. std::swap(mSize, inRHS.mSize);
  294. std::swap(mCapacity, inRHS.mCapacity);
  295. std::swap(mElements, inRHS.mElements);
  296. }
  297. template <class Iterator>
  298. void insert(const_iterator inPos, Iterator inBegin, Iterator inEnd)
  299. {
  300. size_type num_elements = size_type(std::distance(inBegin, inEnd));
  301. if (num_elements > 0)
  302. {
  303. // After grow() inPos may be invalid
  304. size_type first_element = inPos - mElements;
  305. grow(num_elements);
  306. T *element_begin = mElements + first_element;
  307. T *element_end = element_begin + num_elements;
  308. move(element_end, element_begin, mSize - first_element);
  309. for (T *element = element_begin; element < element_end; ++element, ++inBegin)
  310. ::new (element) T(*inBegin);
  311. mSize += num_elements;
  312. }
  313. }
  314. void insert(const_iterator inPos, const T &inValue)
  315. {
  316. JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to insert");
  317. // After grow() inPos may be invalid
  318. size_type first_element = inPos - mElements;
  319. grow();
  320. T *element = mElements + first_element;
  321. move(element + 1, element, mSize - first_element);
  322. ::new (element) T(inValue);
  323. mSize++;
  324. }
  325. /// Remove one element from the array
  326. void erase(const_iterator inIter)
  327. {
  328. size_type p = size_type(inIter - begin());
  329. JPH_ASSERT(p < mSize);
  330. mElements[p].~T();
  331. if (p + 1 < mSize)
  332. move(mElements + p, mElements + p + 1, mSize - p - 1);
  333. --mSize;
  334. }
  335. /// Remove multiple element from the array
  336. void erase(const_iterator inBegin, const_iterator inEnd)
  337. {
  338. size_type p = size_type(inBegin - begin());
  339. size_type n = size_type(inEnd - inBegin);
  340. JPH_ASSERT(inEnd <= end());
  341. destruct(p, p + n);
  342. if (p + n < mSize)
  343. move(mElements + p, mElements + p + n, mSize - p - n);
  344. mSize -= n;
  345. }
  346. /// Iterators
  347. inline const_iterator begin() const
  348. {
  349. return mElements;
  350. }
  351. inline const_iterator end() const
  352. {
  353. return mElements + mSize;
  354. }
  355. inline const_iterator cbegin() const
  356. {
  357. return mElements;
  358. }
  359. inline const_iterator cend() const
  360. {
  361. return mElements + mSize;
  362. }
  363. inline iterator begin()
  364. {
  365. return mElements;
  366. }
  367. inline iterator end()
  368. {
  369. return mElements + mSize;
  370. }
  371. inline const T * data() const
  372. {
  373. return mElements;
  374. }
  375. inline T * data()
  376. {
  377. return mElements;
  378. }
  379. /// Access element
  380. inline T & operator [] (size_type inIdx)
  381. {
  382. JPH_ASSERT(inIdx < mSize);
  383. return mElements[inIdx];
  384. }
  385. inline const T & operator [] (size_type inIdx) const
  386. {
  387. JPH_ASSERT(inIdx < mSize);
  388. return mElements[inIdx];
  389. }
  390. /// Access element
  391. inline T & at(size_type inIdx)
  392. {
  393. JPH_ASSERT(inIdx < mSize);
  394. return mElements[inIdx];
  395. }
  396. inline const T & at(size_type inIdx) const
  397. {
  398. JPH_ASSERT(inIdx < mSize);
  399. return mElements[inIdx];
  400. }
  401. /// First element in the array
  402. inline const T & front() const
  403. {
  404. JPH_ASSERT(mSize > 0);
  405. return mElements[0];
  406. }
  407. inline T & front()
  408. {
  409. JPH_ASSERT(mSize > 0);
  410. return mElements[0];
  411. }
  412. /// Last element in the array
  413. inline const T & back() const
  414. {
  415. JPH_ASSERT(mSize > 0);
  416. return mElements[mSize - 1];
  417. }
  418. inline T & back()
  419. {
  420. JPH_ASSERT(mSize > 0);
  421. return mElements[mSize - 1];
  422. }
  423. /// Assignment operator
  424. Array<T, Allocator> & operator = (const Array<T, Allocator> &inRHS)
  425. {
  426. if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
  427. assign(inRHS.begin(), inRHS.end());
  428. return *this;
  429. }
  430. /// Assignment move operator
  431. Array<T, Allocator> & operator = (Array<T, Allocator> &&inRHS) noexcept
  432. {
  433. if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
  434. {
  435. destroy();
  436. get_allocator() = std::move(inRHS.get_allocator());
  437. mSize = inRHS.mSize;
  438. mCapacity = inRHS.mCapacity;
  439. mElements = inRHS.mElements;
  440. inRHS.mSize = 0;
  441. inRHS.mCapacity = 0;
  442. inRHS.mElements = nullptr;
  443. }
  444. return *this;
  445. }
  446. /// Assignment operator
  447. Array<T, Allocator> & operator = (std::initializer_list<T> inRHS)
  448. {
  449. assign(inRHS);
  450. return *this;
  451. }
  452. /// Comparing arrays
  453. bool operator == (const Array<T, Allocator> &inRHS) const
  454. {
  455. if (mSize != inRHS.mSize)
  456. return false;
  457. for (size_type i = 0; i < mSize; ++i)
  458. if (!(mElements[i] == inRHS.mElements[i]))
  459. return false;
  460. return true;
  461. }
  462. bool operator != (const Array<T, Allocator> &inRHS) const
  463. {
  464. if (mSize != inRHS.mSize)
  465. return true;
  466. for (size_type i = 0; i < mSize; ++i)
  467. if (mElements[i] != inRHS.mElements[i])
  468. return true;
  469. return false;
  470. }
  471. private:
  472. size_type mSize = 0;
  473. size_type mCapacity = 0;
  474. T * mElements = nullptr;
  475. };
  476. JPH_NAMESPACE_END
  477. JPH_SUPPRESS_WARNING_PUSH
  478. JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
  479. namespace std
  480. {
  481. /// Declare std::hash for Array
  482. template <class T, class Allocator>
  483. struct hash<JPH::Array<T, Allocator>>
  484. {
  485. size_t operator () (const JPH::Array<T, Allocator> &inRHS) const
  486. {
  487. std::size_t ret = 0;
  488. // Hash length first
  489. JPH::HashCombine(ret, inRHS.size());
  490. // Then hash elements
  491. for (const T &t : inRHS)
  492. JPH::HashCombine(ret, t);
  493. return ret;
  494. }
  495. };
  496. }
  497. JPH_SUPPRESS_WARNING_POP
  498. #endif // JPH_USE_STD_VECTOR