Array.h 13 KB

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