Blender V5.0
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#if defined(__GNUC__) && !defined(__clang__)
137# pragma GCC diagnostic push
138# pragma GCC diagnostic ignored "-Warray-bounds"
139#endif
140 uninitialized_fill_n(data_, size, value);
141#if defined(__GNUC__) && !defined(__clang__)
142# pragma GCC diagnostic pop
143#endif
144 size_ = size;
145 }
146
161 {
162 BLI_assert(size >= 0);
163 data_ = this->get_buffer_for_size(size);
164 size_ = size;
165 }
166
167 Array(const Array &other) : Array(other.as_span(), other.allocator_) {}
168
169 Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>)
170 : Array(NoExceptConstructor(), other.allocator_)
171 {
172 if (other.data_ == other.inline_buffer_) {
173#if defined(__GNUC__) && !defined(__clang__)
174# pragma GCC diagnostic push
175# pragma GCC diagnostic ignored "-Warray-bounds"
176#endif
177 uninitialized_relocate_n(other.data_, other.size_, data_);
178#if defined(__GNUC__) && !defined(__clang__)
179# pragma GCC diagnostic pop
180#endif
181 }
182 else {
183 data_ = other.data_;
184 }
185 size_ = other.size_;
186
187 other.data_ = other.inline_buffer_;
188 other.size_ = 0;
189 }
190
192 {
193 destruct_n(data_, size_);
194 this->deallocate_if_not_inline(data_);
195 }
196
197 Array &operator=(const Array &other)
198 {
199 return copy_assign_container(*this, other);
200 }
201
202 Array &operator=(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>)
203 {
204 return move_assign_container(*this, std::move(other));
205 }
206
208 {
209 BLI_assert(index >= 0);
210 BLI_assert(index < size_);
211 return data_[index];
212 }
213
214 const T &operator[](int64_t index) const
215 {
216 BLI_assert(index >= 0);
217 BLI_assert(index < size_);
218 return data_[index];
219 }
220
221 operator Span<T>() const
222 {
223 return Span<T>(data_, size_);
224 }
225
226 operator MutableSpan<T>()
227 {
228 return MutableSpan<T>(data_, size_);
229 }
230
231 template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
232 operator Span<U>() const
233 {
234 return Span<U>(data_, size_);
235 }
236
237 template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
238 operator MutableSpan<U>()
239 {
240 return MutableSpan<U>(data_, size_);
241 }
242
244 {
245 return *this;
246 }
247
249 {
250 return *this;
251 }
252
256 int64_t size() const
257 {
258 return size_;
259 }
260
264 bool is_empty() const
265 {
266 return size_ == 0;
267 }
268
272 void fill(const T &value) const
273 {
274 initialized_fill_n(data_, size_, value);
275 }
276
281 const T &first() const
282 {
283 BLI_assert(size_ > 0);
284 return *data_;
285 }
287 {
288 BLI_assert(size_ > 0);
289 return *data_;
290 }
291
296 const T &last(const int64_t n = 0) const
297 {
298 BLI_assert(n >= 0);
299 BLI_assert(n < size_);
300 return *(data_ + size_ - 1 - n);
301 }
302 T &last(const int64_t n = 0)
303 {
304 BLI_assert(n >= 0);
305 BLI_assert(n < size_);
306 return *(data_ + size_ - 1 - n);
307 }
308
312 const T *data() const
313 {
314 return data_;
315 }
317 {
318 return data_;
319 }
320
321 const T *begin() const
322 {
323 return data_;
324 }
325 const T *end() const
326 {
327 return data_ + size_;
328 }
329
331 {
332 return data_;
333 }
335 {
336 return data_ + size_;
337 }
338
339 std::reverse_iterator<T *> rbegin()
340 {
341 return std::reverse_iterator<T *>(this->end());
342 }
343 std::reverse_iterator<T *> rend()
344 {
345 return std::reverse_iterator<T *>(this->begin());
346 }
347
348 std::reverse_iterator<const T *> rbegin() const
349 {
350 return std::reverse_iterator<T *>(this->end());
351 }
352 std::reverse_iterator<const T *> rend() const
353 {
354 return std::reverse_iterator<T *>(this->begin());
355 }
356
361 {
362 return IndexRange(size_);
363 }
364
366 {
367 return this->as_span().hash();
368 }
369
370 static uint64_t hash_as(const Span<T> values)
371 {
372 return values.hash();
373 }
374
375 friend bool operator==(const Array &a, const Array &b)
376 {
377 return a.as_span() == b.as_span();
378 }
379
380 friend bool operator!=(const Array &a, const Array &b)
381 {
382 return !(a == b);
383 }
384
390 {
391 size_ = 0;
392 }
393
397 Allocator &allocator()
398 {
399 return allocator_;
400 }
401 const Allocator &allocator() const
402 {
403 return allocator_;
404 }
405
411 {
412 return InlineBufferCapacity;
413 }
414
419 void reinitialize(const int64_t new_size)
420 {
421 BLI_assert(new_size >= 0);
422 int64_t old_size = size_;
423
424 destruct_n(data_, size_);
425 size_ = 0;
426
427 if (new_size <= old_size) {
428 default_construct_n(data_, new_size);
429 }
430 else {
431 T *new_data = this->get_buffer_for_size(new_size);
432 try {
433 default_construct_n(new_data, new_size);
434 }
435 catch (...) {
436 this->deallocate_if_not_inline(new_data);
437 throw;
438 }
439 this->deallocate_if_not_inline(data_);
440 data_ = new_data;
441 }
442
443 size_ = new_size;
444 }
445
446 private:
447 T *get_buffer_for_size(int64_t size)
448 {
449 if (size <= InlineBufferCapacity) {
450 return inline_buffer_;
451 }
452 return this->allocate(size);
453 }
454
455 T *allocate(int64_t size)
456 {
457 return static_cast<T *>(allocator_.allocate(size_t(size) * sizeof(T), alignof(T), AT));
458 }
459
460 void deallocate_if_not_inline(T *ptr)
461 {
462 if (ptr != inline_buffer_) {
463 allocator_.deallocate(ptr);
464 }
465 }
466};
467
468} // 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
unsigned long long int uint64_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:169
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:339
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
friend bool operator!=(const Array &a, const Array &b)
Definition BLI_array.hh:380
const T * end() const
Definition BLI_array.hh:325
const T & operator[](int64_t index) const
Definition BLI_array.hh:214
const T & last(const int64_t n=0) const
Definition BLI_array.hh:296
Array(Allocator allocator={}) noexcept
Definition BLI_array.hh:78
static int64_t inline_buffer_capacity()
Definition BLI_array.hh:410
T & operator[](int64_t index)
Definition BLI_array.hh:207
const T * data() const
Definition BLI_array.hh:312
Array(int64_t size, const T &value, Allocator allocator={})
Definition BLI_array.hh:131
std::reverse_iterator< T * > rend()
Definition BLI_array.hh:343
static uint64_t hash_as(const Span< T > values)
Definition BLI_array.hh:370
IndexRange index_range() const
Definition BLI_array.hh:360
const Allocator & allocator() const
Definition BLI_array.hh:401
std::reverse_iterator< const T * > rend() const
Definition BLI_array.hh:352
T & last(const int64_t n=0)
Definition BLI_array.hh:302
int64_t size_type
Definition BLI_array.hh:59
std::reverse_iterator< const T * > rbegin() const
Definition BLI_array.hh:348
const T & first() const
Definition BLI_array.hh:281
Array(int64_t size, NoInitialization, Allocator allocator={})
Definition BLI_array.hh:159
void fill(const T &value) const
Definition BLI_array.hh:272
friend bool operator==(const Array &a, const Array &b)
Definition BLI_array.hh:375
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:419
const T * const_iterator
Definition BLI_array.hh:58
const T * begin() const
Definition BLI_array.hh:321
const T * const_pointer
Definition BLI_array.hh:54
Array & operator=(const Array &other)
Definition BLI_array.hh:197
void clear_without_destruct()
Definition BLI_array.hh:389
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:202
uint64_t hash() const
Definition BLI_array.hh:365
Array(const Array &other)
Definition BLI_array.hh:167
Array(const std::initializer_list< T > &values, Allocator allocator={})
Definition BLI_array.hh:107
bool is_empty() const
Definition BLI_array.hh:264
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr uint64_t hash() const
Definition BLI_span.hh:406
#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:4238