Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/templates/local_vector.h
9973 views
1
/**************************************************************************/
2
/* local_vector.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/error/error_macros.h"
34
#include "core/os/memory.h"
35
#include "core/templates/sort_array.h"
36
#include "core/templates/vector.h"
37
38
#include <initializer_list>
39
#include <type_traits>
40
41
// If tight, it grows strictly as much as needed.
42
// Otherwise, it grows exponentially (the default and what you want in most cases).
43
template <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
44
class LocalVector {
45
static_assert(!force_trivial, "force_trivial is no longer supported. Use resize_uninitialized instead.");
46
47
private:
48
U count = 0;
49
U capacity = 0;
50
T *data = nullptr;
51
52
template <bool p_init>
53
void _resize(U p_size) {
54
if (p_size < count) {
55
if constexpr (!std::is_trivially_destructible_v<T>) {
56
for (U i = p_size; i < count; i++) {
57
data[i].~T();
58
}
59
}
60
count = p_size;
61
} else if (p_size > count) {
62
reserve(p_size);
63
if constexpr (p_init) {
64
memnew_arr_placement(data + count, p_size - count);
65
} else {
66
static_assert(std::is_trivially_destructible_v<T>, "T must be trivially destructible to resize uninitialized");
67
}
68
count = p_size;
69
}
70
}
71
72
public:
73
_FORCE_INLINE_ T *ptr() { return data; }
74
_FORCE_INLINE_ const T *ptr() const { return data; }
75
_FORCE_INLINE_ U size() const { return count; }
76
77
_FORCE_INLINE_ Span<T> span() const { return Span(data, count); }
78
_FORCE_INLINE_ operator Span<T>() const { return span(); }
79
80
// Must take a copy instead of a reference (see GH-31736).
81
_FORCE_INLINE_ void push_back(T p_elem) {
82
if (unlikely(count == capacity)) {
83
reserve(count + 1);
84
}
85
86
memnew_placement(&data[count++], T(std::move(p_elem)));
87
}
88
89
void remove_at(U p_index) {
90
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
91
count--;
92
for (U i = p_index; i < count; i++) {
93
data[i] = std::move(data[i + 1]);
94
}
95
data[count].~T();
96
}
97
98
/// Removes the item copying the last value into the position of the one to
99
/// remove. It's generally faster than `remove_at`.
100
void remove_at_unordered(U p_index) {
101
ERR_FAIL_INDEX(p_index, count);
102
count--;
103
if (count > p_index) {
104
data[p_index] = std::move(data[count]);
105
}
106
data[count].~T();
107
}
108
109
_FORCE_INLINE_ bool erase(const T &p_val) {
110
int64_t idx = find(p_val);
111
if (idx >= 0) {
112
remove_at(idx);
113
return true;
114
}
115
return false;
116
}
117
118
bool erase_unordered(const T &p_val) {
119
int64_t idx = find(p_val);
120
if (idx >= 0) {
121
remove_at_unordered(idx);
122
return true;
123
}
124
return false;
125
}
126
127
U erase_multiple_unordered(const T &p_val) {
128
U from = 0;
129
U occurrences = 0;
130
while (true) {
131
int64_t idx = find(p_val, from);
132
133
if (idx == -1) {
134
break;
135
}
136
remove_at_unordered(idx);
137
from = idx;
138
occurrences++;
139
}
140
return occurrences;
141
}
142
143
void reverse() {
144
for (U i = 0; i < count / 2; i++) {
145
SWAP(data[i], data[count - i - 1]);
146
}
147
}
148
#ifndef DISABLE_DEPRECATED
149
[[deprecated("Use reverse() instead")]] void invert() { reverse(); }
150
#endif
151
152
_FORCE_INLINE_ void clear() { resize(0); }
153
_FORCE_INLINE_ void reset() {
154
clear();
155
if (data) {
156
memfree(data);
157
data = nullptr;
158
capacity = 0;
159
}
160
}
161
_FORCE_INLINE_ bool is_empty() const { return count == 0; }
162
_FORCE_INLINE_ U get_capacity() const { return capacity; }
163
void reserve(U p_size) {
164
ERR_FAIL_COND_MSG(p_size < size(), "reserve() called with a capacity smaller than the current size. This is likely a mistake.");
165
if (p_size > capacity) {
166
if (tight) {
167
capacity = p_size;
168
} else {
169
capacity = MAX((U)2, capacity + ((1 + capacity) >> 1));
170
if (p_size > capacity) {
171
capacity = p_size;
172
}
173
}
174
data = (T *)memrealloc(data, capacity * sizeof(T));
175
CRASH_COND_MSG(!data, "Out of memory");
176
}
177
}
178
179
/// Resize the vector.
180
/// Elements are initialized (or not) depending on what the default C++ behavior for T is.
181
/// Note: If force_trivial is set, this will behave like resize_uninitialized instead.
182
void resize(U p_size) {
183
// Don't init when trivially constructible.
184
_resize<!std::is_trivially_constructible_v<T>>(p_size);
185
}
186
187
/// Resize and set all values to 0 / false / nullptr.
188
_FORCE_INLINE_ void resize_initialized(U p_size) { _resize<true>(p_size); }
189
190
/// Resize and set all values to 0 / false / nullptr.
191
/// This is only available for trivially destructible types (otherwise, trivial resize might be UB).
192
_FORCE_INLINE_ void resize_uninitialized(U p_size) { _resize<false>(p_size); }
193
194
_FORCE_INLINE_ const T &operator[](U p_index) const {
195
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
196
return data[p_index];
197
}
198
_FORCE_INLINE_ T &operator[](U p_index) {
199
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
200
return data[p_index];
201
}
202
203
struct Iterator {
204
_FORCE_INLINE_ T &operator*() const {
205
return *elem_ptr;
206
}
207
_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
208
_FORCE_INLINE_ Iterator &operator++() {
209
elem_ptr++;
210
return *this;
211
}
212
_FORCE_INLINE_ Iterator &operator--() {
213
elem_ptr--;
214
return *this;
215
}
216
217
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
218
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
219
220
Iterator(T *p_ptr) { elem_ptr = p_ptr; }
221
Iterator() {}
222
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
223
224
private:
225
T *elem_ptr = nullptr;
226
};
227
228
struct ConstIterator {
229
_FORCE_INLINE_ const T &operator*() const {
230
return *elem_ptr;
231
}
232
_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
233
_FORCE_INLINE_ ConstIterator &operator++() {
234
elem_ptr++;
235
return *this;
236
}
237
_FORCE_INLINE_ ConstIterator &operator--() {
238
elem_ptr--;
239
return *this;
240
}
241
242
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
243
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
244
245
ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
246
ConstIterator() {}
247
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
248
249
private:
250
const T *elem_ptr = nullptr;
251
};
252
253
_FORCE_INLINE_ Iterator begin() {
254
return Iterator(data);
255
}
256
_FORCE_INLINE_ Iterator end() {
257
return Iterator(data + size());
258
}
259
260
_FORCE_INLINE_ ConstIterator begin() const {
261
return ConstIterator(ptr());
262
}
263
_FORCE_INLINE_ ConstIterator end() const {
264
return ConstIterator(ptr() + size());
265
}
266
267
void insert(U p_pos, T p_val) {
268
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
269
if (p_pos == count) {
270
push_back(std::move(p_val));
271
} else {
272
resize(count + 1);
273
for (U i = count - 1; i > p_pos; i--) {
274
data[i] = std::move(data[i - 1]);
275
}
276
data[p_pos] = std::move(p_val);
277
}
278
}
279
280
int64_t find(const T &p_val, int64_t p_from = 0) const {
281
if (p_from < 0) {
282
p_from = size() + p_from;
283
}
284
if (p_from < 0 || p_from >= size()) {
285
return -1;
286
}
287
return span().find(p_val, p_from);
288
}
289
290
bool has(const T &p_val) const {
291
return find(p_val) != -1;
292
}
293
294
template <typename C>
295
void sort_custom() {
296
U len = count;
297
if (len == 0) {
298
return;
299
}
300
301
SortArray<T, C> sorter;
302
sorter.sort(data, len);
303
}
304
305
void sort() {
306
sort_custom<Comparator<T>>();
307
}
308
309
void ordered_insert(T p_val) {
310
U i;
311
for (i = 0; i < count; i++) {
312
if (p_val < data[i]) {
313
break;
314
}
315
}
316
insert(i, p_val);
317
}
318
319
operator Vector<T>() const {
320
Vector<T> ret;
321
ret.resize(count);
322
T *w = ret.ptrw();
323
if (w) {
324
if constexpr (std::is_trivially_copyable_v<T>) {
325
memcpy(w, data, sizeof(T) * count);
326
} else {
327
for (U i = 0; i < count; i++) {
328
w[i] = data[i];
329
}
330
}
331
}
332
return ret;
333
}
334
335
Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
336
Vector<uint8_t> ret;
337
ret.resize(count * sizeof(T));
338
uint8_t *w = ret.ptrw();
339
if (w) {
340
memcpy(w, data, sizeof(T) * count);
341
}
342
return ret;
343
}
344
345
_FORCE_INLINE_ LocalVector() {}
346
_FORCE_INLINE_ LocalVector(std::initializer_list<T> p_init) {
347
reserve(p_init.size());
348
for (const T &element : p_init) {
349
push_back(element);
350
}
351
}
352
_FORCE_INLINE_ LocalVector(const LocalVector &p_from) {
353
resize(p_from.size());
354
for (U i = 0; i < p_from.count; i++) {
355
data[i] = p_from.data[i];
356
}
357
}
358
_FORCE_INLINE_ LocalVector(LocalVector &&p_from) {
359
data = p_from.data;
360
count = p_from.count;
361
capacity = p_from.capacity;
362
363
p_from.data = nullptr;
364
p_from.count = 0;
365
p_from.capacity = 0;
366
}
367
368
inline void operator=(const LocalVector &p_from) {
369
resize(p_from.size());
370
for (U i = 0; i < p_from.count; i++) {
371
data[i] = p_from.data[i];
372
}
373
}
374
inline void operator=(const Vector<T> &p_from) {
375
resize(p_from.size());
376
for (U i = 0; i < count; i++) {
377
data[i] = p_from[i];
378
}
379
}
380
inline void operator=(LocalVector &&p_from) {
381
if (unlikely(this == &p_from)) {
382
return;
383
}
384
reset();
385
386
data = p_from.data;
387
count = p_from.count;
388
capacity = p_from.capacity;
389
390
p_from.data = nullptr;
391
p_from.count = 0;
392
p_from.capacity = 0;
393
}
394
inline void operator=(Vector<T> &&p_from) {
395
resize(p_from.size());
396
for (U i = 0; i < count; i++) {
397
data[i] = std::move(p_from[i]);
398
}
399
}
400
401
_FORCE_INLINE_ ~LocalVector() {
402
if (data) {
403
reset();
404
}
405
}
406
};
407
408
template <typename T, typename U = uint32_t>
409
using TightLocalVector = LocalVector<T, U, false, true>;
410
411
// Zero-constructing LocalVector initializes count, capacity and data to 0 and thus empty.
412
template <typename T, typename U, bool force_trivial, bool tight>
413
struct is_zero_constructible<LocalVector<T, U, force_trivial, tight>> : std::true_type {};
414
415