Blender  V3.3
BLI_array.hh
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #pragma once
4 
26 #include "BLI_allocator.hh"
27 #include "BLI_index_range.hh"
28 #include "BLI_memory_utils.hh"
29 #include "BLI_span.hh"
30 #include "BLI_utildefines.h"
31 
32 namespace blender {
33 
34 template<
38  typename T,
42  int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T)),
47  typename Allocator = GuardedAllocator>
48 class Array {
49  public:
50  using value_type = T;
51  using pointer = T *;
52  using const_pointer = const T *;
53  using reference = T &;
54  using const_reference = const T &;
55  using iterator = T *;
56  using const_iterator = const T *;
57  using size_type = int64_t;
58 
59  private:
61  T *data_;
62 
64  int64_t size_;
65 
67  BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
68 
71 
72  public:
76  Array(Allocator allocator = {}) noexcept : allocator_(allocator)
77  {
78  data_ = inline_buffer_;
79  size_ = 0;
80  }
81 
82  Array(NoExceptConstructor, Allocator allocator = {}) noexcept : Array(allocator)
83  {
84  }
85 
89  template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
90  Array(Span<U> values, Allocator allocator = {}) : Array(NoExceptConstructor(), allocator)
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);
123  default_construct_n(data_, 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  }
163 
164  Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>)
165  : Array(NoExceptConstructor(), other.allocator_)
166  {
167  if (other.data_ == other.inline_buffer_) {
168  uninitialized_relocate_n(other.data_, other.size_, data_);
169  }
170  else {
171  data_ = other.data_;
172  }
173  size_ = other.size_;
174 
175  other.data_ = other.inline_buffer_;
176  other.size_ = 0;
177  }
178 
180  {
181  destruct_n(data_, size_);
182  this->deallocate_if_not_inline(data_);
183  }
184 
185  Array &operator=(const Array &other)
186  {
187  return copy_assign_container(*this, other);
188  }
189 
190  Array &operator=(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>)
191  {
192  return move_assign_container(*this, std::move(other));
193  }
194 
196  {
197  BLI_assert(index >= 0);
198  BLI_assert(index < size_);
199  return data_[index];
200  }
201 
202  const T &operator[](int64_t index) const
203  {
204  BLI_assert(index >= 0);
205  BLI_assert(index < size_);
206  return data_[index];
207  }
208 
209  operator Span<T>() const
210  {
211  return Span<T>(data_, size_);
212  }
213 
214  operator MutableSpan<T>()
215  {
216  return MutableSpan<T>(data_, size_);
217  }
218 
219  template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
220  operator Span<U>() const
221  {
222  return Span<U>(data_, size_);
223  }
224 
225  template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
226  operator MutableSpan<U>()
227  {
228  return MutableSpan<U>(data_, size_);
229  }
230 
231  Span<T> as_span() const
232  {
233  return *this;
234  }
235 
237  {
238  return *this;
239  }
240 
244  int64_t size() const
245  {
246  return size_;
247  }
248 
252  bool is_empty() const
253  {
254  return size_ == 0;
255  }
256 
260  void fill(const T &value) const
261  {
262  initialized_fill_n(data_, size_, value);
263  }
264 
269  const T &first() const
270  {
271  BLI_assert(size_ > 0);
272  return *data_;
273  }
274  T &first()
275  {
276  BLI_assert(size_ > 0);
277  return *data_;
278  }
279 
284  const T &last(const int64_t n = 0) const
285  {
286  BLI_assert(n >= 0);
287  BLI_assert(n < size_);
288  return *(data_ + size_ - 1 - n);
289  }
290  T &last(const int64_t n = 0)
291  {
292  BLI_assert(n >= 0);
293  BLI_assert(n < size_);
294  return *(data_ + size_ - 1 - n);
295  }
296 
300  const T *data() const
301  {
302  return data_;
303  }
304  T *data()
305  {
306  return data_;
307  }
308 
309  const T *begin() const
310  {
311  return data_;
312  }
313  const T *end() const
314  {
315  return data_ + size_;
316  }
317 
318  T *begin()
319  {
320  return data_;
321  }
322  T *end()
323  {
324  return data_ + size_;
325  }
326 
327  std::reverse_iterator<T *> rbegin()
328  {
329  return std::reverse_iterator<T *>(this->end());
330  }
331  std::reverse_iterator<T *> rend()
332  {
333  return std::reverse_iterator<T *>(this->begin());
334  }
335 
336  std::reverse_iterator<const T *> rbegin() const
337  {
338  return std::reverse_iterator<T *>(this->end());
339  }
340  std::reverse_iterator<const T *> rend() const
341  {
342  return std::reverse_iterator<T *>(this->begin());
343  }
344 
349  {
350  return IndexRange(size_);
351  }
352 
358  {
359  size_ = 0;
360  }
361 
365  Allocator &allocator()
366  {
367  return allocator_;
368  }
369  const Allocator &allocator() const
370  {
371  return allocator_;
372  }
373 
379  {
380  return InlineBufferCapacity;
381  }
382 
387  void reinitialize(const int64_t new_size)
388  {
389  BLI_assert(new_size >= 0);
390  int64_t old_size = size_;
391 
392  destruct_n(data_, size_);
393  size_ = 0;
394 
395  if (new_size <= old_size) {
396  default_construct_n(data_, new_size);
397  }
398  else {
399  T *new_data = this->get_buffer_for_size(new_size);
400  try {
401  default_construct_n(new_data, new_size);
402  }
403  catch (...) {
404  this->deallocate_if_not_inline(new_data);
405  throw;
406  }
407  this->deallocate_if_not_inline(data_);
408  data_ = new_data;
409  }
410 
411  size_ = new_size;
412  }
413 
414  private:
415  T *get_buffer_for_size(int64_t size)
416  {
417  if (size <= InlineBufferCapacity) {
418  return inline_buffer_;
419  }
420  else {
421  return this->allocate(size);
422  }
423  }
424 
425  T *allocate(int64_t size)
426  {
427  return static_cast<T *>(
428  allocator_.allocate(static_cast<size_t>(size) * sizeof(T), alignof(T), AT));
429  }
430 
431  void deallocate_if_not_inline(T *ptr)
432  {
433  if (ptr != inline_buffer_) {
434  allocator_.deallocate(ptr);
435  }
436  }
437 };
438 
443 template<typename T, int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T))>
445 
446 } // namespace blender
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define AT
#define BLI_NO_UNIQUE_ADDRESS
const T & first() const
Definition: BLI_array.hh:269
int64_t size() const
Definition: BLI_array.hh:244
const T & last(const int64_t n=0) const
Definition: BLI_array.hh:284
Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v< T >)
Definition: BLI_array.hh:164
Array(Span< U > values, Allocator allocator={})
Definition: BLI_array.hh:90
Array(NoExceptConstructor, Allocator allocator={}) noexcept
Definition: BLI_array.hh:82
Array & operator=(Array &&other) noexcept(std::is_nothrow_move_constructible_v< T >)
Definition: BLI_array.hh:190
Array(Allocator allocator={}) noexcept
Definition: BLI_array.hh:76
Allocator & allocator()
Definition: BLI_array.hh:365
static int64_t inline_buffer_capacity()
Definition: BLI_array.hh:378
std::reverse_iterator< const T * > rend() const
Definition: BLI_array.hh:340
Array(int64_t size, const T &value, Allocator allocator={})
Definition: BLI_array.hh:131
std::reverse_iterator< T * > rbegin()
Definition: BLI_array.hh:327
const T * data() const
Definition: BLI_array.hh:300
const T & operator[](int64_t index) const
Definition: BLI_array.hh:202
IndexRange index_range() const
Definition: BLI_array.hh:348
Span< T > as_span() const
Definition: BLI_array.hh:231
int64_t size_type
Definition: BLI_array.hh:57
T & last(const int64_t n=0)
Definition: BLI_array.hh:290
Array(int64_t size, NoInitialization, Allocator allocator={})
Definition: BLI_array.hh:152
void fill(const T &value) const
Definition: BLI_array.hh:260
std::reverse_iterator< const T * > rbegin() const
Definition: BLI_array.hh:336
Array(const std::initializer_list< U > &values, Allocator allocator={})
Definition: BLI_array.hh:102
const T & const_reference
Definition: BLI_array.hh:54
const T * begin() const
Definition: BLI_array.hh:309
void reinitialize(const int64_t new_size)
Definition: BLI_array.hh:387
const T * const_iterator
Definition: BLI_array.hh:56
const Allocator & allocator() const
Definition: BLI_array.hh:369
const T * const_pointer
Definition: BLI_array.hh:52
Array & operator=(const Array &other)
Definition: BLI_array.hh:185
T & operator[](int64_t index)
Definition: BLI_array.hh:195
void clear_without_destruct()
Definition: BLI_array.hh:357
Array(int64_t size, Allocator allocator={})
Definition: BLI_array.hh:120
Array(const Array &other)
Definition: BLI_array.hh:160
std::reverse_iterator< T * > rend()
Definition: BLI_array.hh:331
MutableSpan< T > as_mutable_span()
Definition: BLI_array.hh:236
const T * end() const
Definition: BLI_array.hh:313
Array(const std::initializer_list< T > &values, Allocator allocator={})
Definition: BLI_array.hh:107
bool is_empty() const
Definition: BLI_array.hh:252
constexpr const T * data() const
Definition: BLI_span.hh:203
constexpr int64_t size() const
Definition: BLI_span.hh:240
T * data_
Definition: eval_output.h:163
#define T
Container & move_assign_container(Container &dst, Container &&src) noexcept(std::is_nothrow_move_constructible_v< Container >)
void default_construct_n(T *ptr, int64_t n)
Container & copy_assign_container(Container &dst, const Container &src)
void initialized_fill_n(T *dst, int64_t n, const T &value)
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_relocate_n(T *src, int64_t n, T *dst)
void destruct_n(T *ptr, int64_t n)
__int64 int64_t
Definition: stdint.h:89
PointerRNA * ptr
Definition: wm_files.c:3480