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