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
51 class rev_it
52 {
53 public:
55 rev_it() = default;
56 explicit rev_it(T *inValue) : mValue(inValue) { }
57
59 rev_it(const rev_it &) = default;
60 rev_it & operator = (const rev_it &) = default;
61
63 bool operator == (const rev_it &inRHS) const { return mValue == inRHS.mValue; }
64 bool operator != (const rev_it &inRHS) const { return mValue != inRHS.mValue; }
65
67 rev_it & operator ++ () { --mValue; return *this; }
68 rev_it operator ++ (int) { return rev_it(mValue--); }
69 rev_it & operator -- () { ++mValue; return *this; }
70 rev_it operator -- (int) { return rev_it(mValue++); }
71
72 rev_it operator + (int inValue) { return rev_it(mValue - inValue); }
73 rev_it operator - (int inValue) { return rev_it(mValue + inValue); }
74
75 rev_it & operator += (int inValue) { mValue -= inValue; return *this; }
76 rev_it & operator -= (int inValue) { mValue += inValue; return *this; }
77
79 T & operator * () const { return *mValue; }
80 T & operator -> () const { return *mValue; }
81
82 private:
83 T * mValue;
84 };
85
87 class crev_it
88 {
89 public:
91 crev_it() = default;
92 explicit crev_it(const T *inValue) : mValue(inValue) { }
93
95 crev_it(const crev_it &) = default;
96 explicit crev_it(const rev_it &inValue) : mValue(inValue.mValue) { }
97 crev_it & operator = (const crev_it &) = default;
98 crev_it & operator = (const rev_it &inRHS) { mValue = inRHS.mValue; return *this; }
99
101 bool operator == (const crev_it &inRHS) const { return mValue == inRHS.mValue; }
102 bool operator != (const crev_it &inRHS) const { return mValue != inRHS.mValue; }
103
105 crev_it & operator ++ () { --mValue; return *this; }
106 crev_it operator ++ (int) { return crev_it(mValue--); }
107 crev_it & operator -- () { ++mValue; return *this; }
108 crev_it operator -- (int) { return crev_it(mValue++); }
109
110 crev_it operator + (int inValue) { return crev_it(mValue - inValue); }
111 crev_it operator - (int inValue) { return crev_it(mValue + inValue); }
112
113 crev_it & operator += (int inValue) { mValue -= inValue; return *this; }
114 crev_it & operator -= (int inValue) { mValue += inValue; return *this; }
115
117 const T & operator * () const { return *mValue; }
118 const T & operator -> () const { return *mValue; }
119
120 private:
121 const T * mValue;
122 };
123
126
127private:
129 inline void move(pointer inDestination, pointer inSource, size_type inCount)
130 {
131 if constexpr (std::is_trivially_copyable<T>())
132 memmove(inDestination, inSource, inCount * sizeof(T));
133 else
134 {
135 if (inDestination < inSource)
136 {
137 for (T *destination_end = inDestination + inCount; inDestination < destination_end; ++inDestination, ++inSource)
138 {
139 new (inDestination) T(std::move(*inSource));
140 inSource->~T();
141 }
142 }
143 else
144 {
145 for (T *destination = inDestination + inCount - 1, *source = inSource + inCount - 1; destination >= inDestination; --destination, --source)
146 {
147 new (destination) T(std::move(*source));
148 source->~T();
149 }
150 }
151 }
152 }
153
155 inline void reallocate(size_type inNewCapacity)
156 {
157 JPH_ASSERT(inNewCapacity > 0 && inNewCapacity >= mSize);
158
159 pointer ptr;
161 {
162 // Reallocate data block
163 ptr = get_allocator().reallocate(mElements, mCapacity, inNewCapacity);
164 }
165 else
166 {
167 // Copy data to a new location
168 ptr = get_allocator().allocate(inNewCapacity);
169 if (mElements != nullptr)
170 {
171 move(ptr, mElements, mSize);
172 get_allocator().deallocate(mElements, mCapacity);
173 }
174 }
175 mElements = ptr;
176 mCapacity = inNewCapacity;
177 }
178
180 inline void destruct(size_type inStart, size_type inEnd)
181 {
182 if constexpr (!std::is_trivially_destructible<T>())
183 if (inStart < inEnd)
184 for (T *element = mElements + inStart, *element_end = mElements + inEnd; element < element_end; ++element)
185 element->~T();
186 }
187
188public:
190 inline void reserve(size_type inNewSize)
191 {
192 if (mCapacity < inNewSize)
193 reallocate(inNewSize);
194 }
195
197 inline void resize(size_type inNewSize)
198 {
199 destruct(inNewSize, mSize);
200 reserve(inNewSize);
201
202 if constexpr (!std::is_trivially_constructible<T>())
203 for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
204 new (element) T;
205 mSize = inNewSize;
206 }
207
209 inline void resize(size_type inNewSize, const T &inValue)
210 {
211 JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to resize");
212
213 destruct(inNewSize, mSize);
214 reserve(inNewSize);
215
216 for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
217 new (element) T(inValue);
218 mSize = inNewSize;
219 }
220
222 inline void clear()
223 {
224 destruct(0, mSize);
225 mSize = 0;
226 }
227
228private:
230 inline void grow(size_type inAmount = 1)
231 {
232 size_type min_size = mSize + inAmount;
233 if (min_size > mCapacity)
234 {
235 size_type new_capacity = max(min_size, mCapacity * 2);
236 reserve(new_capacity);
237 }
238 }
239
241 inline void free()
242 {
243 get_allocator().deallocate(mElements, mCapacity);
244 mElements = nullptr;
245 mCapacity = 0;
246 }
247
249 inline void destroy()
250 {
251 if (mElements != nullptr)
252 {
253 clear();
254 free();
255 }
256 }
257
258public:
260 template <class Iterator>
261 inline void assign(Iterator inBegin, Iterator inEnd)
262 {
263 clear();
264 reserve(size_type(std::distance(inBegin, inEnd)));
265
266 for (Iterator element = inBegin; element != inEnd; ++element)
267 new (&mElements[mSize++]) T(*element);
268 }
269
271 inline void assign(std::initializer_list<T> inList)
272 {
273 clear();
274 reserve(size_type(inList.size()));
275
276 for (const T &v : inList)
277 new (&mElements[mSize++]) T(v);
278 }
279
281 Array() = default;
282
284 explicit inline Array(const Allocator &inAllocator) :
285 Allocator(inAllocator)
286 {
287 }
288
290 explicit inline Array(size_type inLength, const Allocator &inAllocator = { }) :
291 Allocator(inAllocator)
292 {
293 resize(inLength);
294 }
295
297 inline Array(size_type inLength, const T &inValue, const Allocator &inAllocator = { }) :
298 Allocator(inAllocator)
299 {
300 resize(inLength, inValue);
301 }
302
304 inline Array(std::initializer_list<T> inList, const Allocator &inAllocator = { }) :
305 Allocator(inAllocator)
306 {
307 assign(inList);
308 }
309
311 inline Array(const_iterator inBegin, const_iterator inEnd, const Allocator &inAllocator = { }) :
312 Allocator(inAllocator)
313 {
314 assign(inBegin, inEnd);
315 }
316
318 inline Array(const Array<T, Allocator> &inRHS) :
319 Allocator(inRHS.get_allocator())
320 {
321 assign(inRHS.begin(), inRHS.end());
322 }
323
325 inline Array(Array<T, Allocator> &&inRHS) noexcept :
326 Allocator(std::move(inRHS.get_allocator())),
327 mSize(inRHS.mSize),
328 mCapacity(inRHS.mCapacity),
329 mElements(inRHS.mElements)
330 {
331 inRHS.mSize = 0;
332 inRHS.mCapacity = 0;
333 inRHS.mElements = nullptr;
334 }
335
337 inline ~Array()
338 {
339 destroy();
340 }
341
343 inline Allocator & get_allocator()
344 {
345 return *this;
346 }
347
348 inline const Allocator &get_allocator() const
349 {
350 return *this;
351 }
352
354 inline void push_back(const T &inValue)
355 {
356 JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to push_back");
357
358 grow();
359
360 T *element = mElements + mSize++;
361 new (element) T(inValue);
362 }
363
364 inline void push_back(T &&inValue)
365 {
366 grow();
367
368 T *element = mElements + mSize++;
369 new (element) T(std::move(inValue));
370 }
371
373 template <class... A>
374 inline T & emplace_back(A &&... inValue)
375 {
376 grow();
377
378 T *element = mElements + mSize++;
379 new (element) T(std::forward<A>(inValue)...);
380 return *element;
381 }
382
384 inline void pop_back()
385 {
386 JPH_ASSERT(mSize > 0);
387 mElements[--mSize].~T();
388 }
389
391 inline bool empty() const
392 {
393 return mSize == 0;
394 }
395
397 inline size_type size() const
398 {
399 return mSize;
400 }
401
403 inline size_type capacity() const
404 {
405 return mCapacity;
406 }
407
410 {
411 if (mElements != nullptr)
412 {
413 if (mSize == 0)
414 free();
415 else if (mCapacity > mSize)
416 reallocate(mSize);
417 }
418 }
419
421 void swap(Array<T, Allocator> &inRHS) noexcept
422 {
423 std::swap(get_allocator(), inRHS.get_allocator());
424 std::swap(mSize, inRHS.mSize);
425 std::swap(mCapacity, inRHS.mCapacity);
426 std::swap(mElements, inRHS.mElements);
427 }
428
429 template <class Iterator>
430 void insert(const_iterator inPos, Iterator inBegin, Iterator inEnd)
431 {
432 size_type num_elements = size_type(std::distance(inBegin, inEnd));
433 if (num_elements > 0)
434 {
435 // After grow() inPos may be invalid
436 size_type first_element = inPos - mElements;
437
438 grow(num_elements);
439
440 T *element_begin = mElements + first_element;
441 T *element_end = element_begin + num_elements;
442 move(element_end, element_begin, mSize - first_element);
443
444 for (T *element = element_begin; element < element_end; ++element, ++inBegin)
445 new (element) T(*inBegin);
446
447 mSize += num_elements;
448 }
449 }
450
451 void insert(const_iterator inPos, const T &inValue)
452 {
453 JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to insert");
454
455 // After grow() inPos may be invalid
456 size_type first_element = inPos - mElements;
457
458 grow();
459
460 T *element = mElements + first_element;
461 move(element + 1, element, mSize - first_element);
462
463 new (element) T(inValue);
464 mSize++;
465 }
466
469 {
470 size_type p = size_type(inIter - begin());
471 JPH_ASSERT(p < mSize);
472 mElements[p].~T();
473 if (p + 1 < mSize)
474 move(mElements + p, mElements + p + 1, mSize - p - 1);
475 --mSize;
476 return const_cast<iterator>(inIter);
477 }
478
481 {
482 size_type p = size_type(inBegin - begin());
483 size_type n = size_type(inEnd - inBegin);
484 JPH_ASSERT(inEnd <= end());
485 destruct(p, p + n);
486 if (p + n < mSize)
487 move(mElements + p, mElements + p + n, mSize - p - n);
488 mSize -= n;
489 return const_cast<iterator>(inBegin);
490 }
491
493 inline const_iterator begin() const
494 {
495 return mElements;
496 }
497
498 inline const_iterator end() const
499 {
500 return mElements + mSize;
501 }
502
503 inline crev_it rbegin() const
504 {
505 return crev_it(mElements + mSize - 1);
506 }
507
508 inline crev_it rend() const
509 {
510 return crev_it(mElements - 1);
511 }
512
513 inline const_iterator cbegin() const
514 {
515 return begin();
516 }
517
518 inline const_iterator cend() const
519 {
520 return end();
521 }
522
523 inline crev_it crbegin() const
524 {
525 return rbegin();
526 }
527
528 inline crev_it crend() const
529 {
530 return rend();
531 }
532
534 {
535 return mElements;
536 }
537
538 inline iterator end()
539 {
540 return mElements + mSize;
541 }
542
543 inline rev_it rbegin()
544 {
545 return rev_it(mElements + mSize - 1);
546 }
547
548 inline rev_it rend()
549 {
550 return rev_it(mElements - 1);
551 }
552
553 inline const T * data() const
554 {
555 return mElements;
556 }
557
558 inline T * data()
559 {
560 return mElements;
561 }
562
564 inline T & operator [] (size_type inIdx)
565 {
566 JPH_ASSERT(inIdx < mSize);
567 return mElements[inIdx];
568 }
569
570 inline const T & operator [] (size_type inIdx) const
571 {
572 JPH_ASSERT(inIdx < mSize);
573 return mElements[inIdx];
574 }
575
577 inline T & at(size_type inIdx)
578 {
579 JPH_ASSERT(inIdx < mSize);
580 return mElements[inIdx];
581 }
582
583 inline const T & at(size_type inIdx) const
584 {
585 JPH_ASSERT(inIdx < mSize);
586 return mElements[inIdx];
587 }
588
590 inline const T & front() const
591 {
592 JPH_ASSERT(mSize > 0);
593 return mElements[0];
594 }
595
596 inline T & front()
597 {
598 JPH_ASSERT(mSize > 0);
599 return mElements[0];
600 }
601
603 inline const T & back() const
604 {
605 JPH_ASSERT(mSize > 0);
606 return mElements[mSize - 1];
607 }
608
609 inline T & back()
610 {
611 JPH_ASSERT(mSize > 0);
612 return mElements[mSize - 1];
613 }
614
616 Array<T, Allocator> & operator = (const Array<T, Allocator> &inRHS)
617 {
618 if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
619 assign(inRHS.begin(), inRHS.end());
620
621 return *this;
622 }
623
625 Array<T, Allocator> & operator = (Array<T, Allocator> &&inRHS) noexcept
626 {
627 if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
628 {
629 destroy();
630
631 get_allocator() = std::move(inRHS.get_allocator());
632
633 mSize = inRHS.mSize;
634 mCapacity = inRHS.mCapacity;
635 mElements = inRHS.mElements;
636
637 inRHS.mSize = 0;
638 inRHS.mCapacity = 0;
639 inRHS.mElements = nullptr;
640 }
641
642 return *this;
643 }
644
646 Array<T, Allocator> & operator = (std::initializer_list<T> inRHS)
647 {
648 assign(inRHS);
649
650 return *this;
651 }
652
654 bool operator == (const Array<T, Allocator> &inRHS) const
655 {
656 if (mSize != inRHS.mSize)
657 return false;
658 for (size_type i = 0; i < mSize; ++i)
659 if (!(mElements[i] == inRHS.mElements[i]))
660 return false;
661 return true;
662 }
663
664 bool operator != (const Array<T, Allocator> &inRHS) const
665 {
666 if (mSize != inRHS.mSize)
667 return true;
668 for (size_type i = 0; i < mSize; ++i)
669 if (mElements[i] != inRHS.mElements[i])
670 return true;
671 return false;
672 }
673
676 {
677 // Hash length first
678 uint64 ret = Hash<uint32> { } (uint32(size()));
679
680 // Then hash elements
681 for (const T *element = mElements, *element_end = mElements + mSize; element < element_end; ++element)
682 HashCombine(ret, *element);
683
684 return ret;
685 }
686
687private:
688 size_type mSize = 0;
689 size_type mCapacity = 0;
690 T * mElements = nullptr;
691};
692
694
695JPH_SUPPRESS_WARNING_PUSH
696JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
697
698namespace std
699{
701 template <class T, class Allocator>
702 struct hash<JPH::Array<T, Allocator>>
703 {
704 size_t operator () (const JPH::Array<T, Allocator> &inRHS) const
705 {
706 return std::size_t(inRHS.GetHash());
707 }
708 };
709}
710
711JPH_SUPPRESS_WARNING_POP
712
713#endif // JPH_USE_STD_VECTOR
#define JPH_SUPPRESS_WARNINGS_STD_BEGIN
Definition Core.h:424
#define JPH_SUPPRESS_WARNINGS_STD_END
Definition Core.h:437
std::uint64_t uint64
Definition Core.h:491
#define JPH_NAMESPACE_END
Definition Core.h:419
#define JPH_CLANG_SUPPRESS_WARNING(w)
Definition Core.h:302
std::uint32_t uint32
Definition Core.h:490
#define JPH_NAMESPACE_BEGIN
Definition Core.h:413
DVec3 operator*(double inV1, DVec3Arg inV2)
Definition DVec3.inl:456
void HashCombine(uint64 &ioSeed, const T &inValue)
Commonly used types.
Definition HashCombine.h:148
#define JPH_ASSERT(...)
Definition IssueReporting.h:33
A const iterator that traverses the array in reverse order.
Definition Array.h:88
crev_it()=default
Constructor.
crev_it(const T *inValue)
Definition Array.h:92
crev_it(const crev_it &)=default
Copying.
crev_it(const rev_it &inValue)
Definition Array.h:96
An iterator that traverses the array in reverse order.
Definition Array.h:52
rev_it(T *inValue)
Definition Array.h:56
rev_it()=default
Constructor.
rev_it(const rev_it &)=default
Copying.
Definition Array.h:36
void resize(size_type inNewSize)
Resize array to new length.
Definition Array.h:197
Array()=default
Default constructor.
crev_it crbegin() const
Definition Array.h:523
void push_back(T &&inValue)
Definition Array.h:364
void pop_back()
Remove element from the back of the array.
Definition Array.h:384
bool empty() const
Returns true if there are no elements in the array.
Definition Array.h:391
size_type capacity() const
Returns maximum amount of elements the array can hold.
Definition Array.h:403
Array(const Allocator &inAllocator)
Constructor with allocator.
Definition Array.h:284
size_t size_type
Definition Array.h:40
~Array()
Destruct all elements.
Definition Array.h:337
const T & back() const
Last element in the array.
Definition Array.h:603
const T * const_iterator
Definition Array.h:47
T * data()
Definition Array.h:558
const_iterator begin() const
Iterators.
Definition Array.h:493
const_iterator cbegin() const
Definition Array.h:513
void insert(const_iterator inPos, Iterator inBegin, Iterator inEnd)
Definition Array.h:430
iterator erase(const_iterator inIter)
Remove one element from the array.
Definition Array.h:468
iterator end()
Definition Array.h:538
crev_it rend() const
Definition Array.h:508
void resize(size_type inNewSize, const T &inValue)
Resize array to new length and initialize all elements with inValue.
Definition Array.h:209
iterator begin()
Definition Array.h:533
const T * const_pointer
Definition Array.h:43
rev_it rend()
Definition Array.h:548
void swap(Array< T, Allocator > &inRHS) noexcept
Swap the contents of two arrays.
Definition Array.h:421
iterator erase(const_iterator inBegin, const_iterator inEnd)
Remove multiple element from the array.
Definition Array.h:480
Array(size_type inLength, const T &inValue, const Allocator &inAllocator={ })
Constructor with length and value.
Definition Array.h:297
const T * data() const
Definition Array.h:553
Array(std::initializer_list< T > inList, const Allocator &inAllocator={ })
Constructor from initializer list.
Definition Array.h:304
rev_it rbegin()
Definition Array.h:543
size_type size() const
Returns amount of elements in the array.
Definition Array.h:397
Array(Array< T, Allocator > &&inRHS) noexcept
Move constructor.
Definition Array.h:325
void shrink_to_fit()
Reduce the capacity of the array to match its size.
Definition Array.h:409
void clear()
Destruct all elements and set length to zero.
Definition Array.h:222
const_iterator cend() const
Definition Array.h:518
uint64 GetHash() const
Get hash for this array.
Definition Array.h:675
const Allocator & get_allocator() const
Definition Array.h:348
T & emplace_back(A &&... inValue)
Construct element at the back of the array.
Definition Array.h:374
crev_it rbegin() const
Definition Array.h:503
T * pointer
Definition Array.h:42
T * iterator
Definition Array.h:48
crev_it crend() const
Definition Array.h:528
Array(size_type inLength, const Allocator &inAllocator={ })
Constructor with length.
Definition Array.h:290
void push_back(const T &inValue)
Add element to the back of the array.
Definition Array.h:354
void insert(const_iterator inPos, const T &inValue)
Definition Array.h:451
T & back()
Definition Array.h:609
const T & const_reference
Definition Array.h:45
T & at(size_type inIdx)
Access element.
Definition Array.h:577
const T & front() const
First element in the array.
Definition Array.h:590
void reserve(size_type inNewSize)
Reserve array space.
Definition Array.h:190
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:261
T value_type
Definition Array.h:38
Allocator & get_allocator()
Get the allocator.
Definition Array.h:343
const_iterator end() const
Definition Array.h:498
T & front()
Definition Array.h:596
T & reference
Definition Array.h:44
const T & at(size_type inIdx) const
Definition Array.h:583
Array(const_iterator inBegin, const_iterator inEnd, const Allocator &inAllocator={ })
Constructor from iterator.
Definition Array.h:311
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:271
Array(const Array< T, Allocator > &inRHS)
Copy constructor.
Definition Array.h:318
Definition Array.h:699
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