Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/templates/local_vector.h
21204 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/string/print_string.h"
36
#include "core/templates/sort_array.h"
37
#include "core/templates/vector.h"
38
39
#include <initializer_list>
40
#include <type_traits>
41
42
// If tight, it grows strictly as much as needed.
43
// Otherwise, it grows exponentially (the default and what you want in most cases).
44
template <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
45
class LocalVector {
46
static_assert(!force_trivial, "force_trivial is no longer supported. Use resize_uninitialized instead.");
47
48
private:
49
U count = 0;
50
U capacity = 0;
51
T *data = nullptr;
52
53
template <bool p_init>
54
void _resize(U p_size) {
55
if (p_size < count) {
56
if constexpr (!std::is_trivially_destructible_v<T>) {
57
for (U i = p_size; i < count; i++) {
58
data[i].~T();
59
}
60
}
61
count = p_size;
62
} else if (p_size > count) {
63
reserve(p_size);
64
if constexpr (p_init) {
65
memnew_arr_placement(data + count, p_size - count);
66
} else {
67
static_assert(std::is_trivially_destructible_v<T>, "T must be trivially destructible to resize uninitialized");
68
}
69
count = p_size;
70
}
71
}
72
73
public:
74
_FORCE_INLINE_ T *ptr() { return data; }
75
_FORCE_INLINE_ const T *ptr() const { return data; }
76
_FORCE_INLINE_ U size() const { return count; }
77
78
_FORCE_INLINE_ Span<T> span() const { return Span(data, count); }
79
_FORCE_INLINE_ operator Span<T>() const { return span(); }
80
81
// Must take a copy instead of a reference (see GH-31736).
82
_FORCE_INLINE_ void push_back(T p_elem) {
83
if (unlikely(count == capacity)) {
84
reserve(count + 1);
85
}
86
87
memnew_placement(&data[count++], T(std::move(p_elem)));
88
}
89
90
void remove_at(U p_index) {
91
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
92
count--;
93
for (U i = p_index; i < count; i++) {
94
data[i] = std::move(data[i + 1]);
95
}
96
data[count].~T();
97
}
98
99
/// Removes the item copying the last value into the position of the one to
100
/// remove. It's generally faster than `remove_at`.
101
void remove_at_unordered(U p_index) {
102
ERR_FAIL_INDEX(p_index, count);
103
count--;
104
if (count > p_index) {
105
data[p_index] = std::move(data[count]);
106
}
107
data[count].~T();
108
}
109
110
_FORCE_INLINE_ bool erase(const T &p_val) {
111
int64_t idx = find(p_val);
112
if (idx >= 0) {
113
remove_at(idx);
114
return true;
115
}
116
return false;
117
}
118
119
bool erase_unordered(const T &p_val) {
120
int64_t idx = find(p_val);
121
if (idx >= 0) {
122
remove_at_unordered(idx);
123
return true;
124
}
125
return false;
126
}
127
128
U erase_multiple_unordered(const T &p_val) {
129
U from = 0;
130
U occurrences = 0;
131
while (true) {
132
int64_t idx = find(p_val, from);
133
134
if (idx == -1) {
135
break;
136
}
137
remove_at_unordered(idx);
138
from = idx;
139
occurrences++;
140
}
141
return occurrences;
142
}
143
144
void reverse() {
145
for (U i = 0; i < count / 2; i++) {
146
SWAP(data[i], data[count - i - 1]);
147
}
148
}
149
#ifndef DISABLE_DEPRECATED
150
[[deprecated("Use reverse() instead")]] void invert() { reverse(); }
151
#endif
152
153
_FORCE_INLINE_ void clear() { resize(0); }
154
_FORCE_INLINE_ void reset() {
155
clear();
156
if (data) {
157
memfree(data);
158
data = nullptr;
159
capacity = 0;
160
}
161
}
162
_FORCE_INLINE_ bool is_empty() const { return count == 0; }
163
_FORCE_INLINE_ U get_capacity() const { return capacity; }
164
void reserve(U p_size) {
165
if (p_size > capacity) {
166
if (tight) {
167
capacity = p_size;
168
} else {
169
// Try 1.5x the current capacity.
170
// This ratio was chosen because it is close to the ideal growth rate of the golden ratio.
171
// See https://archive.ph/Z2R8w for details.
172
capacity = MAX((U)2, capacity + ((1 + capacity) >> 1));
173
// If 1.5x growth isn't enough, just use the needed size exactly.
174
if (p_size > capacity) {
175
capacity = p_size;
176
}
177
}
178
data = (T *)memrealloc(data, capacity * sizeof(T));
179
CRASH_COND_MSG(!data, "Out of memory");
180
} else if (p_size < count) {
181
WARN_VERBOSE("reserve() called with a capacity smaller than the current size. This is likely a mistake.");
182
}
183
}
184
185
/// Resize the vector.
186
/// Elements are initialized (or not) depending on what the default C++ behavior for T is.
187
/// Note: If force_trivial is set, this will behave like resize_uninitialized instead.
188
void resize(U p_size) {
189
// Don't init when trivially constructible.
190
_resize<!std::is_trivially_constructible_v<T>>(p_size);
191
}
192
193
/// Resize and set all values to 0 / false / nullptr.
194
_FORCE_INLINE_ void resize_initialized(U p_size) { _resize<true>(p_size); }
195
196
/// Resize and keep memory uninitialized.
197
/// This means that any newly added elements have an unknown value, and are expected to be set after the `resize_uninitialized` call.
198
/// This is only available for trivially destructible types (otherwise, trivial resize might be UB).
199
_FORCE_INLINE_ void resize_uninitialized(U p_size) { _resize<false>(p_size); }
200
201
_FORCE_INLINE_ const T &operator[](U p_index) const {
202
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
203
return data[p_index];
204
}
205
_FORCE_INLINE_ T &operator[](U p_index) {
206
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
207
return data[p_index];
208
}
209
210
struct Iterator {
211
_FORCE_INLINE_ T &operator*() const {
212
return *elem_ptr;
213
}
214
_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
215
_FORCE_INLINE_ Iterator &operator++() {
216
elem_ptr++;
217
return *this;
218
}
219
_FORCE_INLINE_ Iterator &operator--() {
220
elem_ptr--;
221
return *this;
222
}
223
224
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
225
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
226
227
Iterator(T *p_ptr) { elem_ptr = p_ptr; }
228
Iterator() {}
229
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
230
231
private:
232
T *elem_ptr = nullptr;
233
};
234
235
struct ConstIterator {
236
_FORCE_INLINE_ const T &operator*() const {
237
return *elem_ptr;
238
}
239
_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
240
_FORCE_INLINE_ ConstIterator &operator++() {
241
elem_ptr++;
242
return *this;
243
}
244
_FORCE_INLINE_ ConstIterator &operator--() {
245
elem_ptr--;
246
return *this;
247
}
248
249
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
250
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
251
252
ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
253
ConstIterator() {}
254
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
255
256
private:
257
const T *elem_ptr = nullptr;
258
};
259
260
_FORCE_INLINE_ Iterator begin() {
261
return Iterator(data);
262
}
263
_FORCE_INLINE_ Iterator end() {
264
return Iterator(data + size());
265
}
266
267
_FORCE_INLINE_ ConstIterator begin() const {
268
return ConstIterator(ptr());
269
}
270
_FORCE_INLINE_ ConstIterator end() const {
271
return ConstIterator(ptr() + size());
272
}
273
274
void insert(U p_pos, T p_val) {
275
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
276
if (p_pos == count) {
277
push_back(std::move(p_val));
278
} else {
279
resize(count + 1);
280
for (U i = count - 1; i > p_pos; i--) {
281
data[i] = std::move(data[i - 1]);
282
}
283
data[p_pos] = std::move(p_val);
284
}
285
}
286
287
int64_t find(const T &p_val, int64_t p_from = 0) const {
288
if (p_from < 0) {
289
p_from = size() + p_from;
290
}
291
if (p_from < 0 || p_from >= size()) {
292
return -1;
293
}
294
return span().find(p_val, p_from);
295
}
296
297
bool has(const T &p_val) const {
298
return find(p_val) != -1;
299
}
300
301
template <typename C>
302
void sort_custom() {
303
U len = count;
304
if (len == 0) {
305
return;
306
}
307
308
SortArray<T, C> sorter;
309
sorter.sort(data, len);
310
}
311
312
void sort() {
313
sort_custom<Comparator<T>>();
314
}
315
316
void ordered_insert(T p_val) {
317
U i;
318
for (i = 0; i < count; i++) {
319
if (p_val < data[i]) {
320
break;
321
}
322
}
323
insert(i, p_val);
324
}
325
326
explicit operator Vector<T>() const {
327
Vector<T> ret;
328
ret.resize(count);
329
T *w = ret.ptrw();
330
if (w) {
331
copy_arr_placement(w, data, count);
332
}
333
return ret;
334
}
335
336
Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
337
Vector<uint8_t> ret;
338
ret.resize(count * sizeof(T));
339
uint8_t *w = ret.ptrw();
340
if (w) {
341
memcpy(w, data, sizeof(T) * count);
342
}
343
return ret;
344
}
345
346
_FORCE_INLINE_ LocalVector() {}
347
_FORCE_INLINE_ LocalVector(std::initializer_list<T> p_init) {
348
reserve(p_init.size());
349
for (const T &element : p_init) {
350
push_back(element);
351
}
352
}
353
_FORCE_INLINE_ explicit LocalVector(const LocalVector &p_from) {
354
resize(p_from.size());
355
for (U i = 0; i < p_from.count; i++) {
356
data[i] = p_from.data[i];
357
}
358
}
359
_FORCE_INLINE_ LocalVector(LocalVector &&p_from) {
360
data = p_from.data;
361
count = p_from.count;
362
capacity = p_from.capacity;
363
364
p_from.data = nullptr;
365
p_from.count = 0;
366
p_from.capacity = 0;
367
}
368
369
inline void operator=(const LocalVector &p_from) {
370
resize(p_from.size());
371
for (U i = 0; i < p_from.count; i++) {
372
data[i] = p_from.data[i];
373
}
374
}
375
inline void operator=(const Vector<T> &p_from) {
376
resize(p_from.size());
377
for (U i = 0; i < count; i++) {
378
data[i] = p_from[i];
379
}
380
}
381
inline void operator=(LocalVector &&p_from) {
382
if (unlikely(this == &p_from)) {
383
return;
384
}
385
reset();
386
387
data = p_from.data;
388
count = p_from.count;
389
capacity = p_from.capacity;
390
391
p_from.data = nullptr;
392
p_from.count = 0;
393
p_from.capacity = 0;
394
}
395
inline void operator=(Vector<T> &&p_from) {
396
resize(p_from.size());
397
for (U i = 0; i < count; i++) {
398
data[i] = std::move(p_from[i]);
399
}
400
}
401
402
_FORCE_INLINE_ ~LocalVector() {
403
if (data) {
404
reset();
405
}
406
}
407
};
408
409
template <typename T, typename U = uint32_t>
410
using TightLocalVector = LocalVector<T, U, false, true>;
411
412
// Zero-constructing LocalVector initializes count, capacity and data to 0 and thus empty.
413
template <typename T, typename U, bool force_trivial, bool tight>
414
struct is_zero_constructible<LocalVector<T, U, force_trivial, tight>> : std::true_type {};
415
416