Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Core/Array.h
9906 views
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
7
#include <Jolt/Core/STLAllocator.h>
8
#include <Jolt/Core/HashCombine.h>
9
10
#ifdef JPH_USE_STD_VECTOR
11
12
JPH_SUPPRESS_WARNINGS_STD_BEGIN
13
#include <vector>
14
JPH_SUPPRESS_WARNINGS_STD_END
15
16
JPH_NAMESPACE_BEGIN
17
18
template <class T, class Allocator = STLAllocator<T>> using Array = std::vector<T, Allocator>;
19
20
JPH_NAMESPACE_END
21
22
#else
23
24
JPH_NAMESPACE_BEGIN
25
26
/// Simple replacement for std::vector
27
///
28
/// Major differences:
29
/// - Memory is not initialized to zero (this was causing a lot of page faults when deserializing large MeshShapes / HeightFieldShapes)
30
/// - Iterators are simple pointers (for now)
31
/// - No exception safety
32
/// - No specialization like std::vector<bool> has
33
/// - Not all functions have been implemented
34
template <class T, class Allocator = STLAllocator<T>>
35
class [[nodiscard]] Array : private Allocator
36
{
37
public:
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
50
/// An iterator that traverses the array in reverse order
51
class rev_it
52
{
53
public:
54
/// Constructor
55
rev_it() = default;
56
explicit rev_it(T *inValue) : mValue(inValue) { }
57
58
/// Copying
59
rev_it(const rev_it &) = default;
60
rev_it & operator = (const rev_it &) = default;
61
62
/// Comparison
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
66
/// Arithmetics
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
78
/// Access
79
T & operator * () const { return *mValue; }
80
T & operator -> () const { return *mValue; }
81
82
private:
83
T * mValue;
84
};
85
86
/// A const iterator that traverses the array in reverse order
87
class crev_it
88
{
89
public:
90
/// Constructor
91
crev_it() = default;
92
explicit crev_it(const T *inValue) : mValue(inValue) { }
93
94
/// Copying
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
100
/// Comparison
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
104
/// Arithmetics
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
116
/// Access
117
const T & operator * () const { return *mValue; }
118
const T & operator -> () const { return *mValue; }
119
120
private:
121
const T * mValue;
122
};
123
124
using reverse_iterator = rev_it;
125
using const_reverse_iterator = crev_it;
126
127
private:
128
/// Move elements from one location to another
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
154
/// Reallocate the data block to inNewCapacity
155
inline void reallocate(size_type inNewCapacity)
156
{
157
JPH_ASSERT(inNewCapacity > 0 && inNewCapacity >= mSize);
158
159
pointer ptr;
160
if constexpr (AllocatorHasReallocate<Allocator>::sValue)
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
179
/// Destruct elements [inStart, inEnd - 1]
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
188
public:
189
/// Reserve array space
190
inline void reserve(size_type inNewSize)
191
{
192
if (mCapacity < inNewSize)
193
reallocate(inNewSize);
194
}
195
196
/// Resize array to new length
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
208
/// Resize array to new length and initialize all elements with inValue
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
221
/// Destruct all elements and set length to zero
222
inline void clear()
223
{
224
destruct(0, mSize);
225
mSize = 0;
226
}
227
228
private:
229
/// Grow the array by at least inAmount elements
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
240
/// Free memory
241
inline void free()
242
{
243
get_allocator().deallocate(mElements, mCapacity);
244
mElements = nullptr;
245
mCapacity = 0;
246
}
247
248
/// Destroy all elements and free memory
249
inline void destroy()
250
{
251
if (mElements != nullptr)
252
{
253
clear();
254
free();
255
}
256
}
257
258
public:
259
/// Replace the contents of this array with inBegin .. inEnd
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
270
/// Replace the contents of this array with inList
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
280
/// Default constructor
281
Array() = default;
282
283
/// Constructor with allocator
284
explicit inline Array(const Allocator &inAllocator) :
285
Allocator(inAllocator)
286
{
287
}
288
289
/// Constructor with length
290
explicit inline Array(size_type inLength, const Allocator &inAllocator = { }) :
291
Allocator(inAllocator)
292
{
293
resize(inLength);
294
}
295
296
/// Constructor with length and value
297
inline Array(size_type inLength, const T &inValue, const Allocator &inAllocator = { }) :
298
Allocator(inAllocator)
299
{
300
resize(inLength, inValue);
301
}
302
303
/// Constructor from initializer list
304
inline Array(std::initializer_list<T> inList, const Allocator &inAllocator = { }) :
305
Allocator(inAllocator)
306
{
307
assign(inList);
308
}
309
310
/// Constructor from iterator
311
inline Array(const_iterator inBegin, const_iterator inEnd, const Allocator &inAllocator = { }) :
312
Allocator(inAllocator)
313
{
314
assign(inBegin, inEnd);
315
}
316
317
/// Copy constructor
318
inline Array(const Array<T, Allocator> &inRHS) :
319
Allocator(inRHS.get_allocator())
320
{
321
assign(inRHS.begin(), inRHS.end());
322
}
323
324
/// Move constructor
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
336
/// Destruct all elements
337
inline ~Array()
338
{
339
destroy();
340
}
341
342
/// Get the allocator
343
inline Allocator & get_allocator()
344
{
345
return *this;
346
}
347
348
inline const Allocator &get_allocator() const
349
{
350
return *this;
351
}
352
353
/// Add element to the back of the array
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
372
/// Construct element at the back of the array
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
383
/// Remove element from the back of the array
384
inline void pop_back()
385
{
386
JPH_ASSERT(mSize > 0);
387
mElements[--mSize].~T();
388
}
389
390
/// Returns true if there are no elements in the array
391
inline bool empty() const
392
{
393
return mSize == 0;
394
}
395
396
/// Returns amount of elements in the array
397
inline size_type size() const
398
{
399
return mSize;
400
}
401
402
/// Returns maximum amount of elements the array can hold
403
inline size_type capacity() const
404
{
405
return mCapacity;
406
}
407
408
/// Reduce the capacity of the array to match its size
409
void shrink_to_fit()
410
{
411
if (mElements != nullptr)
412
{
413
if (mSize == 0)
414
free();
415
else if (mCapacity > mSize)
416
reallocate(mSize);
417
}
418
}
419
420
/// Swap the contents of two arrays
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
467
/// Remove one element from the array
468
iterator erase(const_iterator inIter)
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
479
/// Remove multiple element from the array
480
iterator erase(const_iterator inBegin, const_iterator inEnd)
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
492
/// Iterators
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
533
inline iterator begin()
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
563
/// Access element
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
576
/// Access element
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
589
/// First element in the array
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
602
/// Last element in the array
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
615
/// Assignment operator
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
624
/// Assignment move operator
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
645
/// Assignment operator
646
Array<T, Allocator> & operator = (std::initializer_list<T> inRHS)
647
{
648
assign(inRHS);
649
650
return *this;
651
}
652
653
/// Comparing arrays
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
674
/// Get hash for this array
675
uint64 GetHash() const
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
687
private:
688
size_type mSize = 0;
689
size_type mCapacity = 0;
690
T * mElements = nullptr;
691
};
692
693
JPH_NAMESPACE_END
694
695
JPH_SUPPRESS_WARNING_PUSH
696
JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
697
698
namespace std
699
{
700
/// Declare std::hash for Array
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
711
JPH_SUPPRESS_WARNING_POP
712
713
#endif // JPH_USE_STD_VECTOR
714
715