Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Common/include/Luau/SmallVector.h
2727 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#pragma once
3
4
#include "Luau/Common.h"
5
6
#include <initializer_list>
7
#include <new>
8
#include <memory>
9
#include <type_traits>
10
#include <utility>
11
12
namespace Luau
13
{
14
15
template<typename T, unsigned N>
16
class SmallVector
17
{
18
static_assert(std::is_nothrow_move_constructible<T>::value, "T must be nothrow move constructible");
19
20
public:
21
using iterator = T*;
22
using const_iterator = const T*;
23
using value_type = T;
24
using reference = T&;
25
using const_reference = const T&;
26
27
SmallVector()
28
{
29
ptr = reinterpret_cast<T*>(storage);
30
}
31
32
SmallVector(std::initializer_list<T> init)
33
: SmallVector()
34
{
35
LUAU_ASSERT(unsigned(init.size()) == init.size());
36
37
reserve(unsigned(init.size()));
38
39
std::uninitialized_copy(init.begin(), init.end(), ptr);
40
count = unsigned(init.size());
41
}
42
43
SmallVector(const SmallVector& other)
44
: SmallVector()
45
{
46
reserve(other.count);
47
48
std::uninitialized_copy(other.begin(), other.end(), ptr);
49
count = other.count;
50
}
51
52
SmallVector(SmallVector&& other) noexcept
53
: SmallVector()
54
{
55
if (!other.is_heap())
56
{
57
std::uninitialized_move(other.begin(), other.end(), ptr);
58
count = other.count;
59
60
other.clear();
61
}
62
else
63
{
64
ptr = other.ptr;
65
max = other.max;
66
count = other.count;
67
68
other.ptr = reinterpret_cast<T*>(other.storage);
69
other.max = N;
70
other.count = 0;
71
}
72
}
73
74
~SmallVector()
75
{
76
clear();
77
78
if (is_heap())
79
::operator delete(ptr);
80
}
81
82
SmallVector& operator=(const SmallVector& other)
83
{
84
if (this == &other)
85
return *this;
86
87
if (other.count <= count)
88
{
89
std::copy(other.begin(), other.end(), begin());
90
91
while (count > other.count)
92
ptr[--count].~T();
93
}
94
else
95
{
96
std::copy(other.begin(), other.begin() + count, begin());
97
98
reserve(other.count);
99
100
std::uninitialized_copy(other.begin() + count, other.end(), ptr + count);
101
count = other.count;
102
}
103
104
return *this;
105
}
106
107
SmallVector& operator=(SmallVector&& other) noexcept
108
{
109
if (this != &other)
110
{
111
clear();
112
113
if (!other.is_heap())
114
{
115
std::uninitialized_move(other.begin(), other.end(), begin());
116
count = other.count;
117
118
other.clear();
119
}
120
else
121
{
122
if (is_heap())
123
::operator delete(ptr);
124
125
ptr = other.ptr;
126
max = other.max;
127
count = other.count;
128
129
other.ptr = reinterpret_cast<T*>(other.storage);
130
other.max = N;
131
other.count = 0;
132
}
133
}
134
135
return *this;
136
}
137
138
template<typename... Args>
139
reference emplace_back(Args&&... args)
140
{
141
if (count == max)
142
grow(count + 1);
143
144
new (&ptr[count]) T(std::forward<Args>(args)...);
145
return ptr[count++];
146
}
147
148
void push_back(const T& val)
149
{
150
if (count == max)
151
grow(count + 1);
152
153
new (&ptr[count]) T(val);
154
count++;
155
}
156
157
void push_back(T&& val)
158
{
159
if (count == max)
160
grow(count + 1);
161
162
new (&ptr[count]) T(std::move(val));
163
count++;
164
}
165
166
T& front()
167
{
168
LUAU_ASSERT(count > 0);
169
return ptr[0];
170
}
171
172
const T& front() const
173
{
174
LUAU_ASSERT(count > 0);
175
return ptr[0];
176
}
177
178
T& back()
179
{
180
LUAU_ASSERT(count > 0);
181
return ptr[count - 1];
182
}
183
184
const T& back() const
185
{
186
LUAU_ASSERT(count > 0);
187
return ptr[count - 1];
188
}
189
190
bool empty() const noexcept
191
{
192
return count == 0;
193
}
194
195
unsigned size() const noexcept
196
{
197
return count;
198
}
199
200
unsigned capacity() const noexcept
201
{
202
return max;
203
}
204
205
void pop_back()
206
{
207
LUAU_ASSERT(count > 0);
208
ptr[--count].~T();
209
}
210
211
void clear()
212
{
213
while (count > 0)
214
ptr[--count].~T();
215
}
216
217
T* begin()
218
{
219
return ptr;
220
}
221
222
const T* begin() const
223
{
224
return ptr;
225
}
226
227
T* end()
228
{
229
return ptr + count;
230
}
231
232
const T* end() const
233
{
234
return ptr + count;
235
}
236
237
T* data()
238
{
239
return ptr;
240
}
241
const T* data() const
242
{
243
return ptr;
244
}
245
246
T& operator[](size_t index)
247
{
248
LUAU_ASSERT(index < count);
249
250
return ptr[index];
251
}
252
253
const T& operator[](size_t index) const
254
{
255
LUAU_ASSERT(index < count);
256
257
return ptr[index];
258
}
259
260
void resize(unsigned newSize)
261
{
262
if (newSize > count)
263
{
264
if (newSize > max)
265
grow(newSize);
266
267
for (unsigned i = count; i < newSize; ++i)
268
new (&ptr[i]) T();
269
}
270
else
271
{
272
while (count > newSize)
273
ptr[--count].~T();
274
}
275
276
count = newSize;
277
}
278
279
void reserve(unsigned reserveSize)
280
{
281
if (reserveSize > max)
282
grow(reserveSize);
283
}
284
285
private:
286
bool is_heap() const
287
{
288
return ptr != reinterpret_cast<const T*>(storage);
289
}
290
291
void grow(unsigned newSize)
292
{
293
if (max + (max >> 1) > newSize)
294
newSize = max + (max >> 1);
295
else
296
newSize += 4;
297
298
LUAU_ASSERT(newSize < 0x40000000);
299
300
void* raw = ::operator new(newSize * sizeof(T));
301
T* newData = static_cast<T*>(raw);
302
303
std::uninitialized_move(ptr, ptr + count, newData);
304
305
for (unsigned i = 0; i < count; ++i)
306
ptr[i].~T();
307
308
if (is_heap())
309
::operator delete(ptr);
310
311
ptr = newData;
312
max = newSize;
313
}
314
315
T* ptr = nullptr;
316
unsigned count = 0;
317
unsigned max = N;
318
319
alignas(T) unsigned char storage[N * sizeof(T)];
320
};
321
322
} // namespace Luau
323
324