Blender V5.0
BLI_vector.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
26
27#include <algorithm>
28
29#include "BLI_allocator.hh"
30#include "BLI_index_range.hh"
31#include "BLI_memory_utils.hh"
32#include "BLI_span.hh"
33#include "BLI_utildefines.h"
34
35namespace blender {
36
37namespace internal {
38void vector_print_stats(const char *name,
39 const void *address,
41 int64_t capacity,
42 int64_t inlineCapacity,
43 int64_t memorySize);
44}
45
50template<typename T, typename Allocator> struct VectorData {
51 T *data = nullptr;
55};
56
57template<
61 typename T,
70 int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T)),
75 typename Allocator = GuardedAllocator>
76class Vector {
77 public:
78 using value_type = T;
79 using pointer = T *;
80 using const_pointer = const T *;
81 using reference = T &;
82 using const_reference = const T &;
83 using iterator = T *;
84 using const_iterator = const T *;
86 using allocator_type = Allocator;
87
88 private:
95 T *begin_;
96 T *end_;
97 T *capacity_end_;
98
100 BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
101
104
110#ifndef NDEBUG
111 int64_t debug_size_;
112# define UPDATE_VECTOR_SIZE(ptr) (ptr)->debug_size_ = int64_t((ptr)->end_ - (ptr)->begin_)
113#else
114# define UPDATE_VECTOR_SIZE(ptr) ((void)0)
115#endif
116
121 template<typename OtherT, int64_t OtherInlineBufferCapacity, typename OtherAllocator>
122 friend class Vector;
123
125 static constexpr bool is_nothrow_move_constructible()
126 {
127 if constexpr (InlineBufferCapacity == 0) {
128 return true;
129 }
130 else {
131 return std::is_nothrow_move_constructible_v<T>;
132 }
133 }
134
135 public:
140 Vector(Allocator allocator = {}) noexcept : allocator_(allocator)
141 {
142 begin_ = inline_buffer_;
143 end_ = begin_;
144 capacity_end_ = begin_ + InlineBufferCapacity;
145 UPDATE_VECTOR_SIZE(this);
146 }
147
148 Vector(NoExceptConstructor, Allocator allocator = {}) noexcept : Vector(allocator) {}
149
155 explicit Vector(int64_t size, Allocator allocator = {})
156 : Vector(NoExceptConstructor(), allocator)
157 {
158 this->resize(size);
159 }
160
164 Vector(int64_t size, const T &value, Allocator allocator = {})
165 : Vector(NoExceptConstructor(), allocator)
166 {
167 this->resize(size, value);
168 }
169
173 template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
174 Vector(Span<U> values, Allocator allocator = {}) : Vector(NoExceptConstructor(), allocator)
175 {
176 const int64_t size = values.size();
177 this->reserve(size);
178 uninitialized_convert_n<U, T>(values.data(), size, begin_);
179 this->increase_size_by_unchecked(size);
180 }
181
182 template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
183 explicit Vector(MutableSpan<U> values, Allocator allocator = {})
184 : Vector(values.as_span(), allocator)
185 {
186 }
187
194 template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
195 Vector(const std::initializer_list<U> &values) : Vector(Span<U>(values))
196 {
197 }
198
199 Vector(const std::initializer_list<T> &values) : Vector(Span<T>(values)) {}
200
201 template<typename U, size_t N, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
202 Vector(const std::array<U, N> &values) : Vector(Span(values))
203 {
204 }
205
206 template<typename InputIt,
207 /* This constructor should not be called with e.g. Vector(3, 10), because that is
208 * expected to produce the vector (10, 10, 10). */
209 BLI_ENABLE_IF((!std::is_convertible_v<InputIt, int>))>
210 Vector(InputIt first, InputIt last, Allocator allocator = {})
211 : Vector(NoExceptConstructor(), allocator)
212 {
213 for (InputIt current = first; current != last; ++current) {
214 this->append(*current);
215 }
216 }
217
222 Vector(const Vector &other) : Vector(other.as_span(), other.allocator_) {}
223
228 template<int64_t OtherInlineBufferCapacity>
230 : Vector(other.as_span(), other.allocator_)
231 {
232 }
233
238 template<int64_t OtherInlineBufferCapacity>
240 is_nothrow_move_constructible())
241 : Vector(NoExceptConstructor(), other.allocator_)
242 {
243 if (other.is_inline()) {
244 const int64_t size = other.size();
245
246 /* Optimize the case by copying the full inline buffer. */
247 constexpr bool other_is_same_type = std::is_same_v<Vector, std::decay_t<decltype(other)>>;
248 constexpr size_t max_full_copy_size = 32;
249 if constexpr (other_is_same_type && std::is_trivial_v<T> &&
250 sizeof(inline_buffer_) <= max_full_copy_size)
251 {
252 /* This check is technically optional. However, benchmarking shows that skipping work
253 * for empty vectors (which is a common case) is worth the extra check even in the case
254 * when the vector is not empty. */
255 if (size > 0) {
256 /* Copy the full inline buffer instead of only the used parts. This may copy
257 * uninitialized values but allows producing more optimal code than when the copy size
258 * would depend on a dynamic value. */
259 memcpy(inline_buffer_, other.inline_buffer_, sizeof(inline_buffer_));
260 this->increase_size_by_unchecked(size);
261 /* Reset other vector. */
262 other.end_ = other.inline_buffer_;
263 }
264 }
265 else {
266 /* This first check is not strictly necessary, but improves performance because it can be
267 * done at compile time and makes the size check at run-time unnecessary. */
268 if (OtherInlineBufferCapacity <= InlineBufferCapacity || size <= InlineBufferCapacity) {
269 /* Copy between inline buffers. */
270 uninitialized_relocate_n(other.begin_, size, begin_);
271 end_ = begin_ + size;
272 }
273 else {
274 /* Copy from inline buffer to newly allocated buffer. */
275 const int64_t capacity = size;
276 begin_ = static_cast<T *>(
277 allocator_.allocate(sizeof(T) * size_t(capacity), alignof(T), AT));
278 capacity_end_ = begin_ + capacity;
279 uninitialized_relocate_n(other.begin_, size, begin_);
280 end_ = begin_ + size;
281 }
282 /* Reset other vector. */
283 other.end_ = other.inline_buffer_;
284 }
285 }
286 else {
287 /* Steal the pointer. */
288 begin_ = other.begin_;
289 end_ = other.end_;
290 capacity_end_ = other.capacity_end_;
291
292 /* Reset other vector. */
293 other.begin_ = other.inline_buffer_;
294 other.end_ = other.inline_buffer_;
295 other.capacity_end_ = other.inline_buffer_ + OtherInlineBufferCapacity;
296 }
297
298 UPDATE_VECTOR_SIZE(this);
299 UPDATE_VECTOR_SIZE(&other);
300 }
301
308 {
309 BLI_assert(data.capacity == 0 || data.data != nullptr);
310 BLI_assert(data.size >= 0);
311 BLI_assert(data.size <= data.capacity);
312 /* Don't use the passed in buffer if it is null. Use the inline-buffer instead which is already
313 * initialized by the constructor call above. */
314 if (data.data != nullptr) {
315 /* Take ownership of the array. */
316 begin_ = data.data;
317 end_ = data.data + data.size;
318 capacity_end_ = data.data + data.capacity;
319 UPDATE_VECTOR_SIZE(this);
320 }
321 }
322
324 {
325 destruct_n(begin_, this->size());
326 if (!this->is_inline()) {
327 allocator_.deallocate(begin_);
328 }
329 }
330
331 Vector &operator=(const Vector &other)
332 {
333 return copy_assign_container(*this, other);
334 }
335
337 {
338 return move_assign_container(*this, std::move(other));
339 }
340
345 const T &operator[](int64_t index) const
346 {
347 BLI_assert(index >= 0);
348 BLI_assert(index < this->size());
349 return begin_[index];
350 }
351
353 {
354 BLI_assert(index >= 0);
355 BLI_assert(index < this->size());
356 return begin_[index];
357 }
358
359 operator Span<T>() const
360 {
361 return Span<T>(begin_, this->size());
362 }
363
364 operator MutableSpan<T>()
365 {
366 return MutableSpan<T>(begin_, this->size());
367 }
368
369 template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
370 operator Span<U>() const
371 {
372 return Span<U>(begin_, this->size());
373 }
374
375 template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
376 operator MutableSpan<U>()
377 {
378 return MutableSpan<U>(begin_, this->size());
379 }
380
382 {
383 return *this;
384 }
385
387 {
388 return *this;
389 }
390
396 void reserve(const int64_t min_capacity)
397 {
398 if (min_capacity > this->capacity()) {
399 this->realloc_to_at_least(min_capacity);
400 }
401 }
402
409 void resize(const int64_t new_size)
410 {
411 BLI_assert(new_size >= 0);
412 const int64_t old_size = this->size();
413 if (new_size > old_size) {
414 this->reserve(new_size);
415 default_construct_n(begin_ + old_size, new_size - old_size);
416 }
417 else {
418 destruct_n(begin_ + new_size, old_size - new_size);
419 }
420 end_ = begin_ + new_size;
421 UPDATE_VECTOR_SIZE(this);
422 }
423
430 void resize(const int64_t new_size, const T &value)
431 {
432 BLI_assert(new_size >= 0);
433 const int64_t old_size = this->size();
434 if (new_size > old_size) {
435 this->reserve(new_size);
436 uninitialized_fill_n(begin_ + old_size, new_size - old_size, value);
437 }
438 else {
439 destruct_n(begin_ + new_size, old_size - new_size);
440 }
441 end_ = begin_ + new_size;
442 UPDATE_VECTOR_SIZE(this);
443 }
444
449 void reinitialize(const int64_t new_size)
450 {
451 this->clear();
452 this->resize(new_size);
453 }
454
459 void clear()
460 {
461 destruct_n(begin_, this->size());
462 end_ = begin_;
463 UPDATE_VECTOR_SIZE(this);
464 }
465
471 {
472 destruct_n(begin_, this->size());
473 if (!this->is_inline()) {
474 allocator_.deallocate(begin_);
475 }
476
477 begin_ = inline_buffer_;
478 end_ = begin_;
479 capacity_end_ = begin_ + InlineBufferCapacity;
480 UPDATE_VECTOR_SIZE(this);
481 }
482
489 void append(const T &value)
490 {
491 this->append_as(value);
492 }
493 void append(T &&value)
494 {
495 this->append_as(std::move(value));
496 }
497 /* This is similar to `std::vector::emplace_back`. */
498 template<typename... ForwardValue> void append_as(ForwardValue &&...value)
499 {
500 this->ensure_space_for_one();
501 this->append_unchecked_as(std::forward<ForwardValue>(value)...);
502 }
503
509 {
510 return this->append_and_get_index_as(value);
511 }
513 {
514 return this->append_and_get_index_as(std::move(value));
515 }
516 template<typename... ForwardValue> int64_t append_and_get_index_as(ForwardValue &&...value)
517 {
518 const int64_t index = this->size();
519 this->append_as(std::forward<ForwardValue>(value)...);
520 return index;
521 }
522
528 void append_non_duplicates(const T &value)
529 {
530 if (!this->contains(value)) {
531 this->append(value);
532 }
533 }
534
540 void append_unchecked(const T &value)
541 {
542 this->append_unchecked_as(value);
543 }
544 void append_unchecked(T &&value)
545 {
546 this->append_unchecked_as(std::move(value));
547 }
548 template<typename... ForwardT> void append_unchecked_as(ForwardT &&...value)
549 {
550 BLI_assert(end_ < capacity_end_);
551 new (end_) T(std::forward<ForwardT>(value)...);
552 end_++;
553 UPDATE_VECTOR_SIZE(this);
554 }
555
560 void append_n_times(const T &value, const int64_t n)
561 {
562 BLI_assert(n >= 0);
563 this->reserve(this->size() + n);
564 uninitialized_fill_n(end_, n, value);
566 }
567
574 void increase_size_by_unchecked(const int64_t n) noexcept
575 {
576 BLI_assert(end_ + n <= capacity_end_);
577 end_ += n;
578 UPDATE_VECTOR_SIZE(this);
579 }
580
587 {
588 this->extend(array.data(), array.size());
589 }
590 void extend(const T *start, int64_t amount)
591 {
592 this->reserve(this->size() + amount);
593 this->extend_unchecked(start, amount);
594 }
595
604 template<int64_t OtherInlineBufferCapacity>
606 {
607 BLI_assert(this != &other);
608 this->extend(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
609 other.clear();
610 }
611
618 {
619 for (const T &value : array) {
620 this->append_non_duplicates(value);
621 }
622 }
623
629 {
630 this->extend_unchecked(array.data(), array.size());
631 }
632 void extend_unchecked(const T *start, int64_t amount)
633 {
634 BLI_assert(amount >= 0);
635 BLI_assert(begin_ + amount <= capacity_end_);
636 uninitialized_copy_n(start, amount, end_);
637 end_ += amount;
638 UPDATE_VECTOR_SIZE(this);
639 }
640
641 template<typename InputIt> void extend(InputIt first, InputIt last)
642 {
643 this->insert(this->end(), first, last);
644 }
645
651 void insert(const int64_t insert_index, const T &value)
652 {
653 this->insert(insert_index, Span<T>(&value, 1));
654 }
655 void insert(const int64_t insert_index, T &&value)
656 {
657 this->insert(
658 insert_index, std::make_move_iterator(&value), std::make_move_iterator(&value + 1));
659 }
660 void insert(const int64_t insert_index, Span<T> array)
661 {
662 this->insert(begin_ + insert_index, array.begin(), array.end());
663 }
664 template<typename InputIt> void insert(const T *insert_position, InputIt first, InputIt last)
665 {
666 const int64_t insert_index = insert_position - begin_;
667 this->insert(insert_index, first, last);
668 }
669 template<typename InputIt> void insert(const int64_t insert_index, InputIt first, InputIt last)
670 {
671 BLI_assert(insert_index >= 0);
672 BLI_assert(insert_index <= this->size());
673
674 const int64_t insert_amount = std::distance(first, last);
675 const int64_t old_size = this->size();
676 const int64_t new_size = old_size + insert_amount;
677 const int64_t move_amount = old_size - insert_index;
678
679 this->reserve(new_size);
680 for (int64_t i = 0; i < move_amount; i++) {
681 const int64_t src_index = insert_index + move_amount - i - 1;
682 const int64_t dst_index = new_size - i - 1;
683 try {
684 new (static_cast<void *>(begin_ + dst_index)) T(std::move(begin_[src_index]));
685 }
686 catch (...) {
687 /* Destruct all values that have been moved already. */
688 destruct_n(begin_ + dst_index + 1, i);
689 end_ = begin_ + src_index + 1;
690 UPDATE_VECTOR_SIZE(this);
691 throw;
692 }
693 begin_[src_index].~T();
694 }
695
696 try {
697 if constexpr (std::is_rvalue_reference_v<decltype(*first)>) {
698 std::uninitialized_move_n(first, insert_amount, begin_ + insert_index);
699 }
700 else {
701 std::uninitialized_copy_n(first, insert_amount, begin_ + insert_index);
702 }
703 }
704 catch (...) {
705 /* Destruct all values that have been moved. */
706 destruct_n(begin_ + new_size - move_amount, move_amount);
707 end_ = begin_ + insert_index;
708 UPDATE_VECTOR_SIZE(this);
709 throw;
710 }
711 end_ = begin_ + new_size;
712 UPDATE_VECTOR_SIZE(this);
713 }
714
719 void prepend(const T &value)
720 {
721 this->insert(0, value);
722 }
723 void prepend(T &&value)
724 {
725 this->insert(0, std::move(value));
726 }
727 void prepend(Span<T> values)
728 {
729 this->insert(0, values);
730 }
731 template<typename InputIt> void prepend(InputIt first, InputIt last)
732 {
733 this->insert(0, first, last);
734 }
735
740 const T &last(const int64_t n = 0) const
741 {
742 BLI_assert(n >= 0);
743 BLI_assert(n < this->size());
744 return *(end_ - 1 - n);
745 }
746 T &last(const int64_t n = 0)
747 {
748 BLI_assert(n >= 0);
749 BLI_assert(n < this->size());
750 return *(end_ - 1 - n);
751 }
752
757 const T &first() const
758 {
759 BLI_assert(this->size() > 0);
760 return *begin_;
761 }
763 {
764 BLI_assert(this->size() > 0);
765 return *begin_;
766 }
767
771 int64_t size() const
772 {
773 const int64_t current_size = int64_t(end_ - begin_);
774 BLI_assert(debug_size_ == current_size);
775 return current_size;
776 }
777
783 bool is_empty() const
784 {
785 return begin_ == end_;
786 }
787
793 {
794 BLI_assert(!this->is_empty());
795 end_--;
796 end_->~T();
797 UPDATE_VECTOR_SIZE(this);
798 }
799
807 {
808 BLI_assert(!this->is_empty());
809 T value = std::move(*(end_ - 1));
810 end_--;
811 end_->~T();
812 UPDATE_VECTOR_SIZE(this);
813 return value;
814 }
815
820 void remove_and_reorder(const int64_t index)
821 {
822 BLI_assert(index >= 0);
823 BLI_assert(index < this->size());
824 T *element_to_remove = begin_ + index;
825 T *last_element = end_ - 1;
826 if (element_to_remove < last_element) {
827 *element_to_remove = std::move(*last_element);
828 }
829 end_ = last_element;
830 last_element->~T();
831 UPDATE_VECTOR_SIZE(this);
832 }
833
839 {
840 const int64_t index = this->first_index_of(value);
841 this->remove_and_reorder(index);
842 }
843
851 void remove(const int64_t index)
852 {
853 BLI_assert(index >= 0);
854 BLI_assert(index < this->size());
855 const int64_t last_index = this->size() - 1;
856 for (int64_t i = index; i < last_index; i++) {
857 begin_[i] = std::move(begin_[i + 1]);
858 }
859 begin_[last_index].~T();
860 end_--;
861 UPDATE_VECTOR_SIZE(this);
862 }
863
870 void remove(const int64_t start_index, const int64_t amount)
871 {
872 const int64_t old_size = this->size();
873 BLI_assert(start_index >= 0);
874 BLI_assert(amount >= 0);
875 BLI_assert(start_index + amount <= old_size);
876 const int64_t move_amount = old_size - start_index - amount;
877 for (int64_t i = 0; i < move_amount; i++) {
878 begin_[start_index + i] = std::move(begin_[start_index + amount + i]);
879 }
880 destruct_n(end_ - amount, amount);
881 end_ -= amount;
882 UPDATE_VECTOR_SIZE(this);
883 }
884
891 template<typename Predicate> int64_t remove_if(Predicate &&predicate)
892 {
893 const T *prev_end = this->end();
894 end_ = std::remove_if(this->begin(), this->end(), predicate);
895 destruct_n(end_, prev_end - end_);
896 UPDATE_VECTOR_SIZE(this);
897 return int64_t(prev_end - end_);
898 }
899
904 int64_t first_index_of_try(const T &value) const
905 {
906 for (const T *current = begin_; current != end_; current++) {
907 if (*current == value) {
908 return int64_t(current - begin_);
909 }
910 }
911 return -1;
912 }
913
918 int64_t first_index_of(const T &value) const
919 {
920 const int64_t index = this->first_index_of_try(value);
921 BLI_assert(index >= 0);
922 return index;
923 }
924
929 bool contains(const T &value) const
930 {
931 return this->first_index_of_try(value) != -1;
932 }
933
937 void fill(const T &value) const
938 {
939 initialized_fill_n(begin_, this->size(), value);
940 }
941
946 {
947 return begin_;
948 }
949
953 const T *data() const
954 {
955 return begin_;
956 }
957
959 {
960 return begin_;
961 }
963 {
964 return end_;
965 }
966
967 const T *begin() const
968 {
969 return begin_;
970 }
971 const T *end() const
972 {
973 return end_;
974 }
975
976 std::reverse_iterator<T *> rbegin()
977 {
978 return std::reverse_iterator<T *>(this->end());
979 }
980 std::reverse_iterator<T *> rend()
981 {
982 return std::reverse_iterator<T *>(this->begin());
983 }
984
985 std::reverse_iterator<const T *> rbegin() const
986 {
987 return std::reverse_iterator<const T *>(this->end());
988 }
989 std::reverse_iterator<const T *> rend() const
990 {
991 return std::reverse_iterator<const T *>(this->begin());
992 }
993
999 {
1000 return int64_t(capacity_end_ - begin_);
1001 }
1002
1003 bool is_at_capacity() const
1004 {
1005 return end_ == capacity_end_;
1006 }
1007
1018 {
1019 return IndexRange(this->size());
1020 }
1021
1023 {
1024 return this->as_span().hash();
1025 }
1026
1027 static uint64_t hash_as(const Span<T> values)
1028 {
1029 return values.hash();
1030 }
1031
1032 friend bool operator==(const Vector &a, const Vector &b)
1033 {
1034 return a.as_span() == b.as_span();
1035 }
1036
1037 friend bool operator!=(const Vector &a, const Vector &b)
1038 {
1039 return !(a == b);
1040 }
1041
1052 {
1053 if (this->is_inline()) {
1054 if (this->is_empty()) {
1055 /* No need to make an allocation that does not contain any data. */
1056 return {};
1057 }
1058 /* Make an new allocation, because it's not possible to transfer ownership of the inline
1059 * buffer to the caller. */
1060 const int64_t size = this->size();
1061 T *data = static_cast<T *>(
1062 allocator_.allocate(size_t(size) * sizeof(T), alignof(T), __func__));
1063 try {
1065 }
1066 catch (...) {
1067 allocator_.deallocate(data);
1068 throw;
1069 }
1070 begin_ = data;
1071 end_ = begin_ + size;
1072 capacity_end_ = end_;
1073 }
1074
1076 data.data = begin_;
1077 data.size = end_ - begin_;
1078 data.capacity = capacity_end_ - begin_;
1079 data.allocator = allocator_;
1080
1081 /* Reset #Vector to use empty inline buffer again. */
1082 begin_ = inline_buffer_;
1083 end_ = begin_;
1084 capacity_end_ = begin_ + InlineBufferCapacity;
1085 UPDATE_VECTOR_SIZE(this);
1086
1087 return data;
1088 }
1089
1093 void print_stats(const char *name) const
1094 {
1096 name, this, this->size(), capacity_end_ - begin_, InlineBufferCapacity, sizeof(*this));
1097 }
1098
1099 bool is_inline() const
1100 {
1101 return begin_ == inline_buffer_;
1102 }
1103
1104 private:
1105 void ensure_space_for_one()
1106 {
1107 if (UNLIKELY(end_ >= capacity_end_)) {
1108 this->realloc_to_at_least(this->size() + 1);
1109 }
1110 }
1111
1112 BLI_NOINLINE void realloc_to_at_least(const int64_t min_capacity)
1113 {
1114 if (this->capacity() >= min_capacity) {
1115 return;
1116 }
1117
1118 /* At least double the size of the previous allocation. Otherwise consecutive calls to grow can
1119 * cause a reallocation every time even though min_capacity only increments. */
1120 const int64_t min_new_capacity = this->capacity() * 2;
1121
1122 const int64_t new_capacity = std::max(min_capacity, min_new_capacity);
1123 const int64_t size = this->size();
1124
1125 T *new_array = static_cast<T *>(
1126 allocator_.allocate(size_t(new_capacity) * sizeof(T), alignof(T), AT));
1127 try {
1128 uninitialized_relocate_n(begin_, size, new_array);
1129 }
1130 catch (...) {
1131 allocator_.deallocate(new_array);
1132 throw;
1133 }
1134
1135 if (!this->is_inline()) {
1136 allocator_.deallocate(begin_);
1137 }
1138
1139 begin_ = new_array;
1140 end_ = begin_ + size;
1141 capacity_end_ = begin_ + new_capacity;
1142 }
1143};
1144
1145#undef UPDATE_VECTOR_SIZE
1146
1151template<typename T, int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T))>
1153
1154template<typename T> static constexpr bool is_Vector_v = false;
1155template<typename T, int64_t InlineBufferCapacity, typename Allocator>
1157
1158} /* namespace blender */
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_NOINLINE
void BLI_kdtree_nd_ insert(KDTree *tree, int index, const float co[KD_DIMS]) ATTR_NONNULL(1
#define BLI_ENABLE_IF(condition)
#define UNLIKELY(x)
#define AT
#define BLI_NO_UNIQUE_ADDRESS
#define UPDATE_VECTOR_SIZE(ptr)
#define U
iter begin(iter)
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void remove_and_reorder(const int64_t index)
bool contains(const T &value) const
void append(const T &value)
void append_unchecked_as(ForwardT &&...value)
bool is_empty() const
int64_t append_and_get_index_as(ForwardValue &&...value)
void resize(const int64_t new_size)
int64_t first_index_of(const T &value) const
void extend_unchecked(Span< T > array)
void reserve(const int64_t min_capacity)
void extend(Span< T > array)
void append_non_duplicates(const T &value)
T * end()
Span< T > as_span() const
bool is_inline() const
void append_as(ForwardValue &&...value)
void increase_size_by_unchecked(const int64_t n) noexcept
int64_t capacity() const
int64_t first_index_of_try(const T &value) const
size_t size() const
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
void insert(const int64_t insert_index, T &&value)
std::reverse_iterator< const T * > rbegin() const
std::reverse_iterator< T * > rbegin()
void remove_and_reorder(const int64_t index)
Vector(const Vector< T, OtherInlineBufferCapacity, Allocator > &other)
void print_stats(const char *name) const
int64_t remove_if(Predicate &&predicate)
Vector(const Vector &other)
Vector(Allocator allocator={}) noexcept
int64_t append_and_get_index(const T &value)
void prepend(const T &value)
bool contains(const T &value) const
Vector & operator=(Vector &&other)
bool is_at_capacity() const
void append(const T &value)
void insert(const int64_t insert_index, const T &value)
friend bool operator==(const Vector &a, const Vector &b)
void prepend(T &&value)
const SubdivCCGCoord & last(const int64_t n=0) const
Vector(InputIt first, InputIt last, Allocator allocator={})
void append_unchecked_as(ForwardT &&...value)
void remove(const int64_t index)
uint64_t hash() const
friend class Vector
bool is_empty() const
void resize(const int64_t new_size, const T &value)
void remove_first_occurrence_and_reorder(const T &value)
IndexRange index_range() const
int64_t append_and_get_index_as(ForwardValue &&...value)
void prepend(InputIt first, InputIt last)
Vector(const VectorData< T, Allocator > &data)
void resize(const int64_t new_size)
int64_t first_index_of(const T &value) const
MutableSpan< T > as_mutable_span()
void extend_unchecked(Span< T > array)
T & operator[](int64_t index)
void append_unchecked(const T &value)
void prepend(Span< T > values)
void extend(Vector< T, OtherInlineBufferCapacity, Allocator > &&other)
static uint64_t hash_as(const Span< T > values)
Vector(NoExceptConstructor, Allocator allocator={}) noexcept
const T & operator[](int64_t index) const
Vector(Span< U > values, Allocator allocator={})
void reserve(const int64_t min_capacity)
const SubdivCCGCoord & const_reference
Definition BLI_vector.hh:82
const T * end() const
std::reverse_iterator< T * > rend()
void remove(const int64_t start_index, const int64_t amount)
void extend(Span< T > array)
void append(T &&value)
std::reverse_iterator< const T * > rend() const
void insert(const T *insert_position, InputIt first, InputIt last)
void append_unchecked(T &&value)
void extend_non_duplicates(Span< T > array)
Vector & operator=(const Vector &other)
void reinitialize(const int64_t new_size)
Vector(int64_t size, const T &value, Allocator allocator={})
void append_non_duplicates(const T &value)
void fill(const T &value) const
void insert(const int64_t insert_index, InputIt first, InputIt last)
Vector(const std::array< U, N > &values)
Span< T > as_span() const
bool is_inline() const
const T * data() const
Vector(int64_t size, Allocator allocator={})
const SubdivCCGCoord * const_pointer
Definition BLI_vector.hh:80
const SubdivCCGCoord & first() const
T & last(const int64_t n=0)
void insert(const int64_t insert_index, Span< T > array)
Vector(Vector< T, OtherInlineBufferCapacity, Allocator > &&other) noexcept(is_nothrow_move_constructible())
void append_as(ForwardValue &&...value)
int64_t append_and_get_index(T &&value)
void extend(InputIt first, InputIt last)
void extend(const T *start, int64_t amount)
Vector(const std::initializer_list< U > &values)
void clear_and_shrink()
friend bool operator!=(const Vector &a, const Vector &b)
VectorData< T, Allocator > release()
void extend_unchecked(const T *start, int64_t amount)
void increase_size_by_unchecked(const int64_t n) noexcept
int64_t capacity() const
Vector(MutableSpan< U > values, Allocator allocator={})
const T * begin() const
int64_t first_index_of_try(const T &value) const
void append_n_times(const T &value, const int64_t n)
const SubdivCCGCoord * const_iterator
Definition BLI_vector.hh:84
Vector(const std::initializer_list< T > &values)
#define T
static void clear(Message &msg)
Definition msgfmt.cc:213
void vector_print_stats(const char *name, const void *address, int64_t size, int64_t capacity, int64_t inlineCapacity, int64_t memorySize)
Definition vector.cc:14
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 >)
Vector< T, InlineBufferCapacity, RawAllocator > RawVector
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)
static constexpr bool is_Vector_v
void uninitialized_convert_n(const From *src, int64_t n, To *dst)
void destruct_n(T *ptr, int64_t n)
void uninitialized_copy_n(const T *src, int64_t n, T *dst)
const char * name
BLI_NO_UNIQUE_ADDRESS Allocator allocator
Definition BLI_vector.hh:54
i
Definition text_draw.cc:230