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