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