Blender  V2.93
BLI_array.hh
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #pragma once
18 
40 #include "BLI_allocator.hh"
41 #include "BLI_index_range.hh"
42 #include "BLI_memory_utils.hh"
43 #include "BLI_span.hh"
44 #include "BLI_utildefines.h"
45 
46 namespace blender {
47 
48 template<
52  typename T,
56  int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T)),
61  typename Allocator = GuardedAllocator>
62 class Array {
63  public:
64  using value_type = T;
65  using pointer = T *;
66  using const_pointer = const T *;
67  using reference = T &;
68  using const_reference = const T &;
69  using iterator = T *;
70  using const_iterator = const T *;
71  using size_type = int64_t;
72 
73  private:
75  T *data_;
76 
78  int64_t size_;
79 
81  Allocator allocator_;
82 
85 
86  public:
90  Array(Allocator allocator = {}) noexcept : allocator_(allocator)
91  {
92  data_ = inline_buffer_;
93  size_ = 0;
94  }
95 
96  Array(NoExceptConstructor, Allocator allocator = {}) noexcept : Array(allocator)
97  {
98  }
99 
103  template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
105  {
106  const int64_t size = values.size();
107  data_ = this->get_buffer_for_size(size);
108  uninitialized_convert_n<U, T>(values.data(), size, data_);
109  size_ = size;
110  }
111 
115  template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
116  Array(const std::initializer_list<U> &values, Allocator allocator = {})
117  : Array(Span<U>(values), allocator)
118  {
119  }
120 
121  Array(const std::initializer_list<T> &values, Allocator allocator = {})
122  : Array(Span<T>(values), allocator)
123  {
124  }
125 
135  {
136  data_ = this->get_buffer_for_size(size);
137  default_construct_n(data_, size);
138  size_ = size;
139  }
140 
145  Array(int64_t size, const T &value, Allocator allocator = {})
147  {
148  BLI_assert(size >= 0);
149  data_ = this->get_buffer_for_size(size);
150  uninitialized_fill_n(data_, size, value);
151  size_ = size;
152  }
153 
168  {
169  BLI_assert(size >= 0);
170  data_ = this->get_buffer_for_size(size);
171  size_ = size;
172  }
173 
174  Array(const Array &other) : Array(other.as_span(), other.allocator_)
175  {
176  }
177 
178  Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>)
179  : Array(NoExceptConstructor(), other.allocator_)
180  {
181  if (other.data_ == other.inline_buffer_) {
182  uninitialized_relocate_n(other.data_, other.size_, data_);
183  }
184  else {
185  data_ = other.data_;
186  }
187  size_ = other.size_;
188 
189  other.data_ = other.inline_buffer_;
190  other.size_ = 0;
191  }
192 
194  {
195  destruct_n(data_, size_);
196  this->deallocate_if_not_inline(data_);
197  }
198 
199  Array &operator=(const Array &other)
200  {
201  return copy_assign_container(*this, other);
202  }
203 
204  Array &operator=(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>)
205  {
206  return move_assign_container(*this, std::move(other));
207  }
208 
210  {
211  BLI_assert(index >= 0);
212  BLI_assert(index < size_);
213  return data_[index];
214  }
215 
216  const T &operator[](int64_t index) const
217  {
218  BLI_assert(index >= 0);
219  BLI_assert(index < size_);
220  return data_[index];
221  }
222 
223  operator Span<T>() const
224  {
225  return Span<T>(data_, size_);
226  }
227 
228  operator MutableSpan<T>()
229  {
230  return MutableSpan<T>(data_, size_);
231  }
232 
233  template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
234  operator Span<U>() const
235  {
236  return Span<U>(data_, size_);
237  }
238 
239  template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
240  operator MutableSpan<U>()
241  {
242  return MutableSpan<U>(data_, size_);
243  }
244 
245  Span<T> as_span() const
246  {
247  return *this;
248  }
249 
251  {
252  return *this;
253  }
254 
258  int64_t size() const
259  {
260  return size_;
261  }
262 
266  bool is_empty() const
267  {
268  return size_ == 0;
269  }
270 
274  void fill(const T &value) const
275  {
276  initialized_fill_n(data_, size_, value);
277  }
278 
283  const T &last() const
284  {
285  BLI_assert(size_ > 0);
286  return *(data_ + size_ - 1);
287  }
288  T &last()
289  {
290  BLI_assert(size_ > 0);
291  return *(data_ + size_ - 1);
292  }
293 
297  const T *data() const
298  {
299  return data_;
300  }
301  T *data()
302  {
303  return data_;
304  }
305 
306  const T *begin() const
307  {
308  return data_;
309  }
310  const T *end() const
311  {
312  return data_ + size_;
313  }
314 
315  T *begin()
316  {
317  return data_;
318  }
319  T *end()
320  {
321  return data_ + size_;
322  }
323 
324  std::reverse_iterator<T *> rbegin()
325  {
326  return std::reverse_iterator<T *>(this->end());
327  }
328  std::reverse_iterator<T *> rend()
329  {
330  return std::reverse_iterator<T *>(this->begin());
331  }
332 
333  std::reverse_iterator<const T *> rbegin() const
334  {
335  return std::reverse_iterator<T *>(this->end());
336  }
337  std::reverse_iterator<const T *> rend() const
338  {
339  return std::reverse_iterator<T *>(this->begin());
340  }
341 
346  {
347  return IndexRange(size_);
348  }
349 
355  {
356  size_ = 0;
357  }
358 
362  Allocator &allocator()
363  {
364  return allocator_;
365  }
366  const Allocator &allocator() const
367  {
368  return allocator_;
369  }
370 
376  {
377  return InlineBufferCapacity;
378  }
379 
384  void reinitialize(const int64_t new_size)
385  {
386  BLI_assert(new_size >= 0);
387  int64_t old_size = size_;
388 
389  destruct_n(data_, size_);
390  size_ = 0;
391 
392  if (new_size <= old_size) {
393  default_construct_n(data_, new_size);
394  }
395  else {
396  T *new_data = this->get_buffer_for_size(new_size);
397  try {
398  default_construct_n(new_data, new_size);
399  }
400  catch (...) {
401  this->deallocate_if_not_inline(new_data);
402  throw;
403  }
404  this->deallocate_if_not_inline(data_);
405  data_ = new_data;
406  }
407 
408  size_ = new_size;
409  }
410 
411  private:
412  T *get_buffer_for_size(int64_t size)
413  {
414  if (size <= InlineBufferCapacity) {
415  return inline_buffer_;
416  }
417  else {
418  return this->allocate(size);
419  }
420  }
421 
422  T *allocate(int64_t size)
423  {
424  return static_cast<T *>(
425  allocator_.allocate(static_cast<size_t>(size) * sizeof(T), alignof(T), AT));
426  }
427 
428  void deallocate_if_not_inline(T *ptr)
429  {
430  if (ptr != inline_buffer_) {
431  allocator_.deallocate(ptr);
432  }
433  }
434 };
435 
440 template<typename T, int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T))>
442 
443 } // namespace blender
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define AT
int64_t size() const
Definition: BLI_array.hh:258
Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v< T >)
Definition: BLI_array.hh:178
const T & last() const
Definition: BLI_array.hh:283
Array(Span< U > values, Allocator allocator={})
Definition: BLI_array.hh:104
Array(NoExceptConstructor, Allocator allocator={}) noexcept
Definition: BLI_array.hh:96
Array & operator=(Array &&other) noexcept(std::is_nothrow_move_constructible_v< T >)
Definition: BLI_array.hh:204
Array(Allocator allocator={}) noexcept
Definition: BLI_array.hh:90
Allocator & allocator()
Definition: BLI_array.hh:362
static int64_t inline_buffer_capacity()
Definition: BLI_array.hh:375
std::reverse_iterator< const T * > rend() const
Definition: BLI_array.hh:337
Array(int64_t size, const T &value, Allocator allocator={})
Definition: BLI_array.hh:145
std::reverse_iterator< T * > rbegin()
Definition: BLI_array.hh:324
const T * data() const
Definition: BLI_array.hh:297
const T & operator[](int64_t index) const
Definition: BLI_array.hh:216
IndexRange index_range() const
Definition: BLI_array.hh:345
Span< T > as_span() const
Definition: BLI_array.hh:245
int64_t size_type
Definition: BLI_array.hh:71
Array(int64_t size, NoInitialization, Allocator allocator={})
Definition: BLI_array.hh:166
void fill(const T &value) const
Definition: BLI_array.hh:274
std::reverse_iterator< const T * > rbegin() const
Definition: BLI_array.hh:333
Array(const std::initializer_list< U > &values, Allocator allocator={})
Definition: BLI_array.hh:116
const T & const_reference
Definition: BLI_array.hh:68
const T * begin() const
Definition: BLI_array.hh:306
void reinitialize(const int64_t new_size)
Definition: BLI_array.hh:384
const T * const_iterator
Definition: BLI_array.hh:70
const Allocator & allocator() const
Definition: BLI_array.hh:366
const T * const_pointer
Definition: BLI_array.hh:66
Array & operator=(const Array &other)
Definition: BLI_array.hh:199
T & operator[](int64_t index)
Definition: BLI_array.hh:209
void clear_without_destruct()
Definition: BLI_array.hh:354
Array(int64_t size, Allocator allocator={})
Definition: BLI_array.hh:134
Array(const Array &other)
Definition: BLI_array.hh:174
std::reverse_iterator< T * > rend()
Definition: BLI_array.hh:328
MutableSpan< T > as_mutable_span()
Definition: BLI_array.hh:250
const T * end() const
Definition: BLI_array.hh:310
Array(const std::initializer_list< T > &values, Allocator allocator={})
Definition: BLI_array.hh:121
bool is_empty() const
Definition: BLI_array.hh:266
constexpr const T * data() const
Definition: BLI_span.hh:217
constexpr int64_t size() const
Definition: BLI_span.hh:254
T * data_
#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:92
PointerRNA * ptr
Definition: wm_files.c:3157