Blender V4.5
BLI_array.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
27
28#include "BLI_allocator.hh"
29#include "BLI_index_range.hh"
30#include "BLI_memory_utils.hh"
31#include "BLI_span.hh"
32#include "BLI_utildefines.h"
33
34namespace blender {
35
36template<
40 typename T,
44 int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T)),
49 typename Allocator = GuardedAllocator>
50class Array {
51 public:
52 using value_type = T;
53 using pointer = T *;
54 using const_pointer = const T *;
55 using reference = T &;
56 using const_reference = const T &;
57 using iterator = T *;
58 using const_iterator = const T *;
60
61 private:
63 T *data_;
64
66 int64_t size_;
67
69 BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
70
73
74 public:
78 Array(Allocator allocator = {}) noexcept : allocator_(allocator)
79 {
80 data_ = inline_buffer_;
81 size_ = 0;
82 }
83
84 Array(NoExceptConstructor, Allocator allocator = {}) noexcept : Array(allocator) {}
85
89 template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
91 {
92 const int64_t size = values.size();
93 data_ = this->get_buffer_for_size(size);
94 uninitialized_convert_n<U, T>(values.data(), size, data_);
95 size_ = size;
96 }
97
101 template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
102 Array(const std::initializer_list<U> &values, Allocator allocator = {})
103 : Array(Span<U>(values), allocator)
104 {
105 }
106
107 Array(const std::initializer_list<T> &values, Allocator allocator = {})
108 : Array(Span<T>(values), allocator)
109 {
110 }
111
121 {
122 data_ = this->get_buffer_for_size(size);
124 size_ = size;
125 }
126
131 Array(int64_t size, const T &value, Allocator allocator = {})
133 {
134 BLI_assert(size >= 0);
135 data_ = this->get_buffer_for_size(size);
136 uninitialized_fill_n(data_, size, value);
137 size_ = size;
138 }
139
154 {
155 BLI_assert(size >= 0);
156 data_ = this->get_buffer_for_size(size);
157 size_ = size;
158 }
159
160 Array(const Array &other) : Array(other.as_span(), other.allocator_) {}
161
162 Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>)
163 : Array(NoExceptConstructor(), other.allocator_)
164 {
165 if (other.data_ == other.inline_buffer_) {
166 /* This comparison with #InlineBufferCapacity may look a bit useless, and indeed it is.
167 * However, it helps to quiet a wrong GCC `-Warray-bounds` warning. */
168 const int64_t relocate_num = (InlineBufferCapacity > 0) ? other.size_ : 0;
169 uninitialized_relocate_n(other.data_, relocate_num, data_);
170 }
171 else {
172 data_ = other.data_;
173 }
174 size_ = other.size_;
175
176 other.data_ = other.inline_buffer_;
177 other.size_ = 0;
178 }
179
181 {
182 destruct_n(data_, size_);
183 this->deallocate_if_not_inline(data_);
184 }
185
186 Array &operator=(const Array &other)
187 {
188 return copy_assign_container(*this, other);
189 }
190
191 Array &operator=(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>)
192 {
193 return move_assign_container(*this, std::move(other));
194 }
195
197 {
198 BLI_assert(index >= 0);
199 BLI_assert(index < size_);
200 return data_[index];
201 }
202
203 const T &operator[](int64_t index) const
204 {
205 BLI_assert(index >= 0);
206 BLI_assert(index < size_);
207 return data_[index];
208 }
209
210 operator Span<T>() const
211 {
212 return Span<T>(data_, size_);
213 }
214
215 operator MutableSpan<T>()
216 {
217 return MutableSpan<T>(data_, size_);
218 }
219
220 template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
221 operator Span<U>() const
222 {
223 return Span<U>(data_, size_);
224 }
225
226 template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
227 operator MutableSpan<U>()
228 {
229 return MutableSpan<U>(data_, size_);
230 }
231
233 {
234 return *this;
235 }
236
238 {
239 return *this;
240 }
241
245 int64_t size() const
246 {
247 return size_;
248 }
249
253 bool is_empty() const
254 {
255 return size_ == 0;
256 }
257
261 void fill(const T &value) const
262 {
263 initialized_fill_n(data_, size_, value);
264 }
265
270 const T &first() const
271 {
272 BLI_assert(size_ > 0);
273 return *data_;
274 }
276 {
277 BLI_assert(size_ > 0);
278 return *data_;
279 }
280
285 const T &last(const int64_t n = 0) const
286 {
287 BLI_assert(n >= 0);
288 BLI_assert(n < size_);
289 return *(data_ + size_ - 1 - n);
290 }
291 T &last(const int64_t n = 0)
292 {
293 BLI_assert(n >= 0);
294 BLI_assert(n < size_);
295 return *(data_ + size_ - 1 - n);
296 }
297
301 const T *data() const
302 {
303 return data_;
304 }
306 {
307 return data_;
308 }
309
310 const T *begin() const
311 {
312 return data_;
313 }
314 const T *end() const
315 {
316 return data_ + size_;
317 }
318
320 {
321 return data_;
322 }
324 {
325 return data_ + size_;
326 }
327
328 std::reverse_iterator<T *> rbegin()
329 {
330 return std::reverse_iterator<T *>(this->end());
331 }
332 std::reverse_iterator<T *> rend()
333 {
334 return std::reverse_iterator<T *>(this->begin());
335 }
336
337 std::reverse_iterator<const T *> rbegin() const
338 {
339 return std::reverse_iterator<T *>(this->end());
340 }
341 std::reverse_iterator<const T *> rend() const
342 {
343 return std::reverse_iterator<T *>(this->begin());
344 }
345
350 {
351 return IndexRange(size_);
352 }
353
354 friend bool operator==(const Array &a, const Array &b)
355 {
356 return a.as_span() == b.as_span();
357 }
358
359 friend bool operator!=(const Array &a, const Array &b)
360 {
361 return !(a == b);
362 }
363
369 {
370 size_ = 0;
371 }
372
376 Allocator &allocator()
377 {
378 return allocator_;
379 }
380 const Allocator &allocator() const
381 {
382 return allocator_;
383 }
384
390 {
391 return InlineBufferCapacity;
392 }
393
398 void reinitialize(const int64_t new_size)
399 {
400 BLI_assert(new_size >= 0);
401 int64_t old_size = size_;
402
403 destruct_n(data_, size_);
404 size_ = 0;
405
406 if (new_size <= old_size) {
407 default_construct_n(data_, new_size);
408 }
409 else {
410 T *new_data = this->get_buffer_for_size(new_size);
411 try {
412 default_construct_n(new_data, new_size);
413 }
414 catch (...) {
415 this->deallocate_if_not_inline(new_data);
416 throw;
417 }
418 this->deallocate_if_not_inline(data_);
419 data_ = new_data;
420 }
421
422 size_ = new_size;
423 }
424
425 private:
426 T *get_buffer_for_size(int64_t size)
427 {
428 if (size <= InlineBufferCapacity) {
429 return inline_buffer_;
430 }
431 return this->allocate(size);
432 }
433
434 T *allocate(int64_t size)
435 {
436 return static_cast<T *>(allocator_.allocate(size_t(size) * sizeof(T), alignof(T), AT));
437 }
438
439 void deallocate_if_not_inline(T *ptr)
440 {
441 if (ptr != inline_buffer_) {
442 allocator_.deallocate(ptr);
443 }
444 }
445};
446
447} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:46
#define AT
#define BLI_NO_UNIQUE_ADDRESS
#define U
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
Array(Allocator allocator={}) noexcept
Definition BLI_array.hh:78
Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v< T >)
Definition BLI_array.hh:162
Array(Span< U > values, Allocator allocator={})
Definition BLI_array.hh:90
Array(NoExceptConstructor, Allocator allocator={}) noexcept
Definition BLI_array.hh:84
std::reverse_iterator< T * > rbegin()
Definition BLI_array.hh:328
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
friend bool operator!=(const Array &a, const Array &b)
Definition BLI_array.hh:359
const T * end() const
Definition BLI_array.hh:314
const T & operator[](int64_t index) const
Definition BLI_array.hh:203
const T & last(const int64_t n=0) const
Definition BLI_array.hh:285
Array(Allocator allocator={}) noexcept
Definition BLI_array.hh:78
static int64_t inline_buffer_capacity()
Definition BLI_array.hh:389
T & operator[](int64_t index)
Definition BLI_array.hh:196
const T * data() const
Definition BLI_array.hh:301
Array(int64_t size, const T &value, Allocator allocator={})
Definition BLI_array.hh:131
std::reverse_iterator< T * > rend()
Definition BLI_array.hh:332
IndexRange index_range() const
Definition BLI_array.hh:349
const Allocator & allocator() const
Definition BLI_array.hh:380
std::reverse_iterator< const T * > rend() const
Definition BLI_array.hh:341
T & last(const int64_t n=0)
Definition BLI_array.hh:291
int64_t size_type
Definition BLI_array.hh:59
std::reverse_iterator< const T * > rbegin() const
Definition BLI_array.hh:337
const T & first() const
Definition BLI_array.hh:270
Array(int64_t size, NoInitialization, Allocator allocator={})
Definition BLI_array.hh:152
void fill(const T &value) const
Definition BLI_array.hh:261
friend bool operator==(const Array &a, const Array &b)
Definition BLI_array.hh:354
Array(const std::initializer_list< U > &values, Allocator allocator={})
Definition BLI_array.hh:102
const T & const_reference
Definition BLI_array.hh:56
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
const T * const_iterator
Definition BLI_array.hh:58
const T * begin() const
Definition BLI_array.hh:310
const T * const_pointer
Definition BLI_array.hh:54
Array & operator=(const Array &other)
Definition BLI_array.hh:186
void clear_without_destruct()
Definition BLI_array.hh:368
Array(int64_t size, Allocator allocator={})
Definition BLI_array.hh:120
Array & operator=(Array &&other) noexcept(std::is_nothrow_move_constructible_v< T >)
Definition BLI_array.hh:191
Array(const Array &other)
Definition BLI_array.hh:160
Array(const std::initializer_list< T > &values, Allocator allocator={})
Definition BLI_array.hh:107
bool is_empty() const
Definition BLI_array.hh:253
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
#define T
void default_construct_n(T *ptr, int64_t n)
void initialized_fill_n(T *dst, int64_t n, const T &value)
Container & copy_assign_container(Container &dst, const Container &src)
Container & move_assign_container(Container &dst, Container &&src) noexcept(std::is_nothrow_move_constructible_v< Container >)
constexpr int64_t default_inline_buffer_capacity(size_t element_size)
void uninitialized_fill_n(T *dst, int64_t n, const T &value)
void uninitialized_convert_n(const From *src, int64_t n, To *dst)
void destruct_n(T *ptr, int64_t n)
PointerRNA * ptr
Definition wm_files.cc:4227