Array.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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 allocator_type = Allocator;
  30. using size_type = size_t;
  31. using difference_type = typename Allocator::difference_type;
  32. using pointer = T *;
  33. using const_pointer = const T *;
  34. using reference = T &;
  35. using const_reference = const T &;
  36. using const_iterator = const T *;
  37. using iterator = T *;
  38. /// An iterator that traverses the array in reverse order
  39. class rev_it
  40. {
  41. public:
  42. /// Constructor
  43. rev_it() = default;
  44. explicit rev_it(T *inValue) : mValue(inValue) { }
  45. /// Copying
  46. rev_it(const rev_it &) = default;
  47. rev_it & operator = (const rev_it &) = default;
  48. /// Comparison
  49. bool operator == (const rev_it &inRHS) const { return mValue == inRHS.mValue; }
  50. bool operator != (const rev_it &inRHS) const { return mValue != inRHS.mValue; }
  51. /// Arithmetics
  52. rev_it & operator ++ () { --mValue; return *this; }
  53. rev_it operator ++ (int) { return rev_it(mValue--); }
  54. rev_it & operator -- () { ++mValue; return *this; }
  55. rev_it operator -- (int) { return rev_it(mValue++); }
  56. rev_it operator + (int inValue) const { return rev_it(mValue - inValue); }
  57. rev_it operator - (int inValue) const { return rev_it(mValue + inValue); }
  58. rev_it & operator += (int inValue) { mValue -= inValue; return *this; }
  59. rev_it & operator -= (int inValue) { mValue += inValue; return *this; }
  60. /// Access
  61. T & operator * () const { return *mValue; }
  62. T & operator -> () const { return *mValue; }
  63. private:
  64. T * mValue;
  65. };
  66. /// A const iterator that traverses the array in reverse order
  67. class crev_it
  68. {
  69. public:
  70. /// Constructor
  71. crev_it() = default;
  72. explicit crev_it(const T *inValue) : mValue(inValue) { }
  73. /// Copying
  74. crev_it(const crev_it &) = default;
  75. explicit crev_it(const rev_it &inValue) : mValue(inValue.mValue) { }
  76. crev_it & operator = (const crev_it &) = default;
  77. crev_it & operator = (const rev_it &inRHS) { mValue = inRHS.mValue; return *this; }
  78. /// Comparison
  79. bool operator == (const crev_it &inRHS) const { return mValue == inRHS.mValue; }
  80. bool operator != (const crev_it &inRHS) const { return mValue != inRHS.mValue; }
  81. /// Arithmetics
  82. crev_it & operator ++ () { --mValue; return *this; }
  83. crev_it operator ++ (int) { return crev_it(mValue--); }
  84. crev_it & operator -- () { ++mValue; return *this; }
  85. crev_it operator -- (int) { return crev_it(mValue++); }
  86. crev_it operator + (int inValue) { return crev_it(mValue - inValue); }
  87. crev_it operator - (int inValue) { return crev_it(mValue + inValue); }
  88. crev_it & operator += (int inValue) { mValue -= inValue; return *this; }
  89. crev_it & operator -= (int inValue) { mValue += inValue; return *this; }
  90. /// Access
  91. const T & operator * () const { return *mValue; }
  92. const T & operator -> () const { return *mValue; }
  93. private:
  94. const T * mValue;
  95. };
  96. using reverse_iterator = rev_it;
  97. using const_reverse_iterator = crev_it;
  98. private:
  99. /// Move elements from one location to another
  100. inline void move(pointer inDestination, pointer inSource, size_type inCount)
  101. {
  102. if constexpr (std::is_trivially_copyable<T>())
  103. memmove(inDestination, inSource, inCount * sizeof(T));
  104. else
  105. {
  106. if (inDestination < inSource)
  107. {
  108. for (T *destination_end = inDestination + inCount; inDestination < destination_end; ++inDestination, ++inSource)
  109. {
  110. new (inDestination) T(std::move(*inSource));
  111. inSource->~T();
  112. }
  113. }
  114. else
  115. {
  116. for (T *destination = inDestination + inCount - 1, *source = inSource + inCount - 1; destination >= inDestination; --destination, --source)
  117. {
  118. new (destination) T(std::move(*source));
  119. source->~T();
  120. }
  121. }
  122. }
  123. }
  124. /// Reallocate the data block to inNewCapacity
  125. inline void reallocate(size_type inNewCapacity)
  126. {
  127. JPH_ASSERT(inNewCapacity > 0 && inNewCapacity >= mSize);
  128. pointer ptr;
  129. if constexpr (AllocatorHasReallocate<Allocator>::sValue)
  130. {
  131. // Reallocate data block
  132. ptr = get_allocator().reallocate(mElements, mCapacity, inNewCapacity);
  133. }
  134. else
  135. {
  136. // Copy data to a new location
  137. ptr = get_allocator().allocate(inNewCapacity);
  138. if (mElements != nullptr)
  139. {
  140. move(ptr, mElements, mSize);
  141. get_allocator().deallocate(mElements, mCapacity);
  142. }
  143. }
  144. mElements = ptr;
  145. mCapacity = inNewCapacity;
  146. }
  147. /// Destruct elements [inStart, inEnd - 1]
  148. inline void destruct(size_type inStart, size_type inEnd)
  149. {
  150. if constexpr (!std::is_trivially_destructible<T>())
  151. if (inStart < inEnd)
  152. for (T *element = mElements + inStart, *element_end = mElements + inEnd; element < element_end; ++element)
  153. element->~T();
  154. }
  155. public:
  156. /// Reserve array space
  157. inline void reserve(size_type inNewSize)
  158. {
  159. if (mCapacity < inNewSize)
  160. reallocate(inNewSize);
  161. }
  162. /// Resize array to new length
  163. inline void resize(size_type inNewSize)
  164. {
  165. destruct(inNewSize, mSize);
  166. reserve(inNewSize);
  167. if constexpr (!std::is_trivially_constructible<T>())
  168. for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
  169. new (element) T;
  170. mSize = inNewSize;
  171. }
  172. /// Resize array to new length and initialize all elements with inValue
  173. inline void resize(size_type inNewSize, const T &inValue)
  174. {
  175. JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to resize");
  176. destruct(inNewSize, mSize);
  177. reserve(inNewSize);
  178. for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
  179. new (element) T(inValue);
  180. mSize = inNewSize;
  181. }
  182. /// Destruct all elements and set length to zero
  183. inline void clear()
  184. {
  185. destruct(0, mSize);
  186. mSize = 0;
  187. }
  188. private:
  189. /// Grow the array by at least inAmount elements
  190. inline void grow(size_type inAmount = 1)
  191. {
  192. size_type min_size = mSize + inAmount;
  193. if (min_size > mCapacity)
  194. {
  195. size_type new_capacity = max(min_size, mCapacity * 2);
  196. reserve(new_capacity);
  197. }
  198. }
  199. /// Free memory
  200. inline void deallocate()
  201. {
  202. get_allocator().deallocate(mElements, mCapacity);
  203. mElements = nullptr;
  204. mCapacity = 0;
  205. }
  206. /// Destroy all elements and free memory
  207. inline void destroy()
  208. {
  209. if (mElements != nullptr)
  210. {
  211. clear();
  212. deallocate();
  213. }
  214. }
  215. public:
  216. /// Replace the contents of this array with inBegin .. inEnd
  217. template <class Iterator>
  218. inline void assign(Iterator inBegin, Iterator inEnd)
  219. {
  220. clear();
  221. reserve(size_type(std::distance(inBegin, inEnd)));
  222. for (Iterator element = inBegin; element != inEnd; ++element)
  223. new (&mElements[mSize++]) T(*element);
  224. }
  225. /// Replace the contents of this array with inList
  226. inline void assign(std::initializer_list<T> inList)
  227. {
  228. clear();
  229. reserve(size_type(inList.size()));
  230. for (const T &v : inList)
  231. new (&mElements[mSize++]) T(v);
  232. }
  233. /// Default constructor
  234. Array() = default;
  235. /// Constructor with allocator
  236. explicit inline Array(const Allocator &inAllocator) :
  237. Allocator(inAllocator)
  238. {
  239. }
  240. /// Constructor with length
  241. explicit inline Array(size_type inLength, const Allocator &inAllocator = { }) :
  242. Allocator(inAllocator)
  243. {
  244. resize(inLength);
  245. }
  246. /// Constructor with length and value
  247. inline Array(size_type inLength, const T &inValue, const Allocator &inAllocator = { }) :
  248. Allocator(inAllocator)
  249. {
  250. resize(inLength, inValue);
  251. }
  252. /// Constructor from initializer list
  253. inline Array(std::initializer_list<T> inList, const Allocator &inAllocator = { }) :
  254. Allocator(inAllocator)
  255. {
  256. assign(inList);
  257. }
  258. /// Constructor from iterator
  259. inline Array(const_iterator inBegin, const_iterator inEnd, const Allocator &inAllocator = { }) :
  260. Allocator(inAllocator)
  261. {
  262. assign(inBegin, inEnd);
  263. }
  264. /// Copy constructor
  265. inline Array(const Array<T, Allocator> &inRHS) :
  266. Allocator(inRHS.get_allocator())
  267. {
  268. assign(inRHS.begin(), inRHS.end());
  269. }
  270. /// Move constructor
  271. inline Array(Array<T, Allocator> &&inRHS) noexcept :
  272. Allocator(std::move(inRHS.get_allocator())),
  273. mSize(inRHS.mSize),
  274. mCapacity(inRHS.mCapacity),
  275. mElements(inRHS.mElements)
  276. {
  277. inRHS.mSize = 0;
  278. inRHS.mCapacity = 0;
  279. inRHS.mElements = nullptr;
  280. }
  281. /// Destruct all elements
  282. inline ~Array()
  283. {
  284. destroy();
  285. }
  286. /// Get the allocator
  287. inline Allocator & get_allocator()
  288. {
  289. return *this;
  290. }
  291. inline const Allocator &get_allocator() const
  292. {
  293. return *this;
  294. }
  295. /// Add element to the back of the array
  296. inline void push_back(const T &inValue)
  297. {
  298. JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to push_back");
  299. grow();
  300. T *element = mElements + mSize++;
  301. new (element) T(inValue);
  302. }
  303. inline void push_back(T &&inValue)
  304. {
  305. grow();
  306. T *element = mElements + mSize++;
  307. new (element) T(std::move(inValue));
  308. }
  309. /// Construct element at the back of the array
  310. template <class... A>
  311. inline T & emplace_back(A &&... inValue)
  312. {
  313. grow();
  314. T *element = mElements + mSize++;
  315. new (element) T(std::forward<A>(inValue)...);
  316. return *element;
  317. }
  318. /// Remove element from the back of the array
  319. inline void pop_back()
  320. {
  321. JPH_ASSERT(mSize > 0);
  322. mElements[--mSize].~T();
  323. }
  324. /// Returns true if there are no elements in the array
  325. inline bool empty() const
  326. {
  327. return mSize == 0;
  328. }
  329. /// Returns amount of elements in the array
  330. inline size_type size() const
  331. {
  332. return mSize;
  333. }
  334. /// Returns maximum amount of elements the array can hold
  335. inline size_type capacity() const
  336. {
  337. return mCapacity;
  338. }
  339. /// Reduce the capacity of the array to match its size
  340. void shrink_to_fit()
  341. {
  342. if (mElements != nullptr)
  343. {
  344. if (mSize == 0)
  345. deallocate();
  346. else if (mCapacity > mSize)
  347. reallocate(mSize);
  348. }
  349. }
  350. /// Swap the contents of two arrays
  351. void swap(Array<T, Allocator> &inRHS) noexcept
  352. {
  353. std::swap(get_allocator(), inRHS.get_allocator());
  354. std::swap(mSize, inRHS.mSize);
  355. std::swap(mCapacity, inRHS.mCapacity);
  356. std::swap(mElements, inRHS.mElements);
  357. }
  358. template <class Iterator>
  359. void insert(const_iterator inPos, Iterator inBegin, Iterator inEnd)
  360. {
  361. size_type num_elements = size_type(std::distance(inBegin, inEnd));
  362. if (num_elements > 0)
  363. {
  364. // After grow() inPos may be invalid
  365. size_type first_element = inPos - mElements;
  366. grow(num_elements);
  367. T *element_begin = mElements + first_element;
  368. T *element_end = element_begin + num_elements;
  369. move(element_end, element_begin, mSize - first_element);
  370. for (T *element = element_begin; element < element_end; ++element, ++inBegin)
  371. new (element) T(*inBegin);
  372. mSize += num_elements;
  373. }
  374. }
  375. void insert(const_iterator inPos, const T &inValue)
  376. {
  377. JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to insert");
  378. // After grow() inPos may be invalid
  379. size_type first_element = inPos - mElements;
  380. grow();
  381. T *element = mElements + first_element;
  382. move(element + 1, element, mSize - first_element);
  383. new (element) T(inValue);
  384. mSize++;
  385. }
  386. /// Remove one element from the array
  387. iterator erase(const_iterator inIter)
  388. {
  389. size_type p = size_type(inIter - begin());
  390. JPH_ASSERT(p < mSize);
  391. mElements[p].~T();
  392. if (p + 1 < mSize)
  393. move(mElements + p, mElements + p + 1, mSize - p - 1);
  394. --mSize;
  395. return const_cast<iterator>(inIter);
  396. }
  397. /// Remove multiple element from the array
  398. iterator erase(const_iterator inBegin, const_iterator inEnd)
  399. {
  400. size_type p = size_type(inBegin - begin());
  401. size_type n = size_type(inEnd - inBegin);
  402. JPH_ASSERT(inEnd <= end());
  403. destruct(p, p + n);
  404. if (p + n < mSize)
  405. move(mElements + p, mElements + p + n, mSize - p - n);
  406. mSize -= n;
  407. return const_cast<iterator>(inBegin);
  408. }
  409. /// Iterators
  410. inline const_iterator begin() const
  411. {
  412. return mElements;
  413. }
  414. inline const_iterator end() const
  415. {
  416. return mElements + mSize;
  417. }
  418. inline crev_it rbegin() const
  419. {
  420. return crev_it(mElements + mSize - 1);
  421. }
  422. inline crev_it rend() const
  423. {
  424. return crev_it(mElements - 1);
  425. }
  426. inline const_iterator cbegin() const
  427. {
  428. return begin();
  429. }
  430. inline const_iterator cend() const
  431. {
  432. return end();
  433. }
  434. inline crev_it crbegin() const
  435. {
  436. return rbegin();
  437. }
  438. inline crev_it crend() const
  439. {
  440. return rend();
  441. }
  442. inline iterator begin()
  443. {
  444. return mElements;
  445. }
  446. inline iterator end()
  447. {
  448. return mElements + mSize;
  449. }
  450. inline rev_it rbegin()
  451. {
  452. return rev_it(mElements + mSize - 1);
  453. }
  454. inline rev_it rend()
  455. {
  456. return rev_it(mElements - 1);
  457. }
  458. inline const T * data() const
  459. {
  460. return mElements;
  461. }
  462. inline T * data()
  463. {
  464. return mElements;
  465. }
  466. /// Access element
  467. inline T & operator [] (size_type inIdx)
  468. {
  469. JPH_ASSERT(inIdx < mSize);
  470. return mElements[inIdx];
  471. }
  472. inline const T & operator [] (size_type inIdx) const
  473. {
  474. JPH_ASSERT(inIdx < mSize);
  475. return mElements[inIdx];
  476. }
  477. /// Access element
  478. inline T & at(size_type inIdx)
  479. {
  480. JPH_ASSERT(inIdx < mSize);
  481. return mElements[inIdx];
  482. }
  483. inline const T & at(size_type inIdx) const
  484. {
  485. JPH_ASSERT(inIdx < mSize);
  486. return mElements[inIdx];
  487. }
  488. /// First element in the array
  489. inline const T & front() const
  490. {
  491. JPH_ASSERT(mSize > 0);
  492. return mElements[0];
  493. }
  494. inline T & front()
  495. {
  496. JPH_ASSERT(mSize > 0);
  497. return mElements[0];
  498. }
  499. /// Last element in the array
  500. inline const T & back() const
  501. {
  502. JPH_ASSERT(mSize > 0);
  503. return mElements[mSize - 1];
  504. }
  505. inline T & back()
  506. {
  507. JPH_ASSERT(mSize > 0);
  508. return mElements[mSize - 1];
  509. }
  510. /// Assignment operator
  511. Array<T, Allocator> & operator = (const Array<T, Allocator> &inRHS)
  512. {
  513. if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
  514. assign(inRHS.begin(), inRHS.end());
  515. return *this;
  516. }
  517. /// Assignment move operator
  518. Array<T, Allocator> & operator = (Array<T, Allocator> &&inRHS) noexcept
  519. {
  520. if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
  521. {
  522. destroy();
  523. get_allocator() = std::move(inRHS.get_allocator());
  524. mSize = inRHS.mSize;
  525. mCapacity = inRHS.mCapacity;
  526. mElements = inRHS.mElements;
  527. inRHS.mSize = 0;
  528. inRHS.mCapacity = 0;
  529. inRHS.mElements = nullptr;
  530. }
  531. return *this;
  532. }
  533. /// Assignment operator
  534. Array<T, Allocator> & operator = (std::initializer_list<T> inRHS)
  535. {
  536. assign(inRHS);
  537. return *this;
  538. }
  539. /// Comparing arrays
  540. bool operator == (const Array<T, Allocator> &inRHS) const
  541. {
  542. if (mSize != inRHS.mSize)
  543. return false;
  544. for (size_type i = 0; i < mSize; ++i)
  545. if (!(mElements[i] == inRHS.mElements[i]))
  546. return false;
  547. return true;
  548. }
  549. bool operator != (const Array<T, Allocator> &inRHS) const
  550. {
  551. if (mSize != inRHS.mSize)
  552. return true;
  553. for (size_type i = 0; i < mSize; ++i)
  554. if (mElements[i] != inRHS.mElements[i])
  555. return true;
  556. return false;
  557. }
  558. /// Get hash for this array
  559. uint64 GetHash() const
  560. {
  561. // Hash length first
  562. uint64 ret = Hash<uint32> { } (uint32(size()));
  563. // Then hash elements
  564. for (const T *element = mElements, *element_end = mElements + mSize; element < element_end; ++element)
  565. HashCombine(ret, *element);
  566. return ret;
  567. }
  568. private:
  569. size_type mSize = 0;
  570. size_type mCapacity = 0;
  571. T * mElements = nullptr;
  572. };
  573. JPH_NAMESPACE_END
  574. JPH_SUPPRESS_WARNING_PUSH
  575. JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
  576. namespace std
  577. {
  578. /// Declare std::hash for Array
  579. template <class T, class Allocator>
  580. struct hash<JPH::Array<T, Allocator>>
  581. {
  582. size_t operator () (const JPH::Array<T, Allocator> &inRHS) const
  583. {
  584. return std::size_t(inRHS.GetHash());
  585. }
  586. };
  587. }
  588. JPH_SUPPRESS_WARNING_POP
  589. #endif // JPH_USE_STD_VECTOR