7#ifndef PXR_BASE_TF_SMALL_VECTOR_H
8#define PXR_BASE_TF_SMALL_VECTOR_H
15#include "pxr/base/arch/defines.h"
21#include <initializer_list>
28PXR_NAMESPACE_OPEN_SCOPE
32class TfSmallVectorBase
38 using _SizeMemberType = std::uint32_t;
41 template <
size_t Size,
size_t Align,
size_t NumLocal>
46 template <
class ValueType,
size_t NumLocal>
47 using _Data = _DataUnion<
sizeof(ValueType),
alignof(ValueType), NumLocal>;
50 using size_type = std::size_t;
51 using difference_type = std::ptrdiff_t;
58 static constexpr size_type ComputeSerendipitousLocalCapacity() {
59 return (
alignof(U) <=
alignof(_Data<U, 0>))
60 ?
sizeof(_Data<U, 0>) /
sizeof(U)
69 template<
typename _ForwardIterator>
70 using _EnableIfForwardIterator =
72 std::is_convertible_v<
73 typename std::iterator_traits<
74 _ForwardIterator>::iterator_category,
75 std::forward_iterator_tag
81 template <
typename Iterator>
82 static Iterator _UninitializedMove(
83 Iterator first, Iterator last, Iterator dest) {
84 return std::uninitialized_copy(
85 std::make_move_iterator(first),
86 std::make_move_iterator(last),
93 static void _MoveConstruct(U *p, U *src) {
94 new (p) U(std::move(*src));
100 template <
size_t Size,
size_t Align,
size_t NumLocal>
105 static constexpr bool HasLocal = NumLocal != 0;
107 void *GetLocalStorage() {
108 return HasLocal ? _local :
nullptr;
110 const void *GetLocalStorage()
const {
111 return HasLocal ? _local :
nullptr;
114 void *GetRemoteStorage() {
117 const void *GetRemoteStorage()
const {
121 void SetRemoteStorage(
void *p) {
128 alignas(NumLocal == 0 ? std::alignment_of_v<void *> : Align)
129 char _local[std::max<size_t>(Size * NumLocal,
sizeof(_remote))];
155template <
typename T, u
int32_t N>
169 typedef T value_type;
170 typedef T& reference;
171 typedef const T& const_reference;
179 using const_iterator =
const T*;
180 typedef std::reverse_iterator<iterator> reverse_iterator;
181 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
194 value_type *d =
data();
195 for (size_type i = 0; i < n; ++i) {
196 new (d + i) value_type();
205 std::uninitialized_fill_n(
data(), n, v);
214 value_type *d =
data();
215 for (size_type i = 0; i < n; ++i) {
216 new (d + i) value_type;
223 _InitStorage(rhs.
size());
224 std::uninitialized_copy(rhs.begin(), rhs.end(), begin());
232 if (rhs.size() > N) {
233 _SetRemoteStorage(rhs._GetRemoteStorage());
234 std::swap(_capacity, rhs._capacity);
245 if constexpr (N > 0) {
246 _UninitializedMove(rhs.begin(), rhs.end(), begin());
250 std::swap(_size, rhs._size);
260 template<
typename ForwardIterator,
261 typename = _EnableIfForwardIterator<ForwardIterator>>
264 _InitStorage(std::distance(first, last));
265 std::uninitialized_copy(first, last, begin());
279 assign(rhs.begin(), rhs.end());
296 assign(ilist.begin(), ilist.end());
304 if (_IsLocal() && rhs._IsLocal()) {
309 std::swap_ranges(smaller->begin(), smaller->end(), larger->begin());
313 for (size_type i = smaller->
size(); i < larger->size(); ++i) {
314 _MoveConstruct(smaller->
data() + i, &(*larger)[i]);
315 (*larger)[i].~value_type();
319 std::swap(smaller->_size, larger->_size);
324 else if (!_IsLocal() && !rhs._IsLocal()) {
325 value_type *tmp = _GetRemoteStorage();
326 _SetRemoteStorage(rhs._GetRemoteStorage());
327 rhs._SetRemoteStorage(tmp);
329 std::swap(_size, rhs._size);
330 std::swap(_capacity, rhs._capacity);
341 value_type *remoteStorage = remote->_GetStorage();
349 for (size_type i = 0; i < local->
size(); ++i) {
350 _MoveConstruct(remote->_GetLocalStorage() + i, &(*local)[i]);
351 (*local)[i].~value_type();
356 local->_SetRemoteStorage(remoteStorage);
359 std::swap(remote->_size, local->_size);
360 std::swap(remote->_capacity, local->_capacity);
367 iterator
insert(const_iterator it, value_type &&v) {
368 return _Insert(it, std::move(v));
373 iterator
insert(const_iterator it,
const value_type &v) {
374 return _Insert(it, v);
380 return erase(it, it + 1);
385 iterator
erase(const_iterator it, const_iterator last) {
386 value_type *p =
const_cast<value_type *
>(&*it);
387 value_type *q =
const_cast<value_type *
>(&*last);
394 const size_type num = std::distance(p, q);
397 value_type *e = data() + size();
401 for (value_type *i = (e - num); i != e; ++i) {
418 if (newCapacity > capacity()) {
419 _GrowStorage(newCapacity);
425 void resize(size_type newSize,
const value_type &v = value_type()) {
428 if (newSize < size()) {
429 erase(const_iterator(data() + newSize),
430 const_iterator(data() + size()));
435 else if (newSize > size()) {
437 std::uninitialized_fill(data() + size(), data() + newSize, v);
453 template<
typename ForwardIterator,
454 typename = _EnableIfForwardIterator<ForwardIterator>>
455 void assign(ForwardIterator first, ForwardIterator last) {
457 const size_type newSize = std::distance(first, last);
459 std::uninitialized_copy(first, last, begin());
465 void assign(std::initializer_list<T> ilist) {
466 assign(ilist.begin(), ilist.end());
471 template <
typename... Args >
473 if (size() == capacity()) {
474 _GrowStorage(_NextCapacity());
476 new (data() + size()) value_type(std::forward<Args>(args)...);
489 emplace_back(std::move(v));
495 template <
typename ForwardIterator>
496 void insert(iterator pos, ForwardIterator first, ForwardIterator last)
500 typename std::iterator_traits<ForwardIterator>::iterator_category,
501 std::forward_iterator_tag>::value,
502 "Input Iterators not supported.");
507 const bool insertAtEnd = pos == end();
509 const long numNewElems = std::distance(first, last);
510 const size_type neededCapacity = size() + numNewElems;
511 const size_type nextCapacity =
512 std::max(_NextCapacity(), neededCapacity);
523 if (neededCapacity > capacity()) {
524 _GrowStorage(nextCapacity);
526 std::uninitialized_copy(first, last, end());
527 _size += numNewElems;
531 if (neededCapacity > capacity()) {
536 const size_type posI = std::distance(begin(), pos);
537 value_type *newStorage = _Allocate(nextCapacity);
539 iterator newPrefixBegin = iterator(newStorage);
540 iterator newPos = newPrefixBegin + posI;
541 iterator newSuffixBegin = newPos + numNewElems;
542 _UninitializedMove(begin(), pos, newPrefixBegin);
543 std::uninitialized_copy(first, last, newPos);
544 _UninitializedMove(pos, end(), newSuffixBegin);
549 _SetRemoteStorage(newStorage);
550 _capacity = nextCapacity;
563 const long numMoveElems = std::distance(pos, end());
564 const long numUninitMoves = std::min(numNewElems, numMoveElems);
565 const long numInitMoves = numMoveElems - numUninitMoves;
566 const long numUninitNews = numNewElems - numUninitMoves;
567 const long numInitNews = numNewElems - numUninitNews;
570 iterator umSrc = pos + numInitMoves;
571 iterator umDst = end() + numUninitNews;
572 _UninitializedMove(umSrc, end(), umDst);
573 std::copy_backward(pos, umSrc, umDst);
576 for (
long i=0; i<numInitNews; ++i, ++first, ++pos) {
579 std::uninitialized_copy(first, last, end());
582 _size += numNewElems;
587 void insert(iterator pos, std::initializer_list<T> ilist) {
588 insert(pos, ilist.begin(), ilist.end());
594 back().~value_type();
607 return std::numeric_limits<_SizeMemberType>::max();
637 return iterator(_GetStorage());
640 const_iterator begin()
const {
641 return const_iterator(_GetStorage());
644 const_iterator cbegin()
const {
654 return iterator(_GetStorage() + size());
657 const_iterator end()
const {
658 return const_iterator(_GetStorage() + size());
661 const_iterator cend()
const {
670 reverse_iterator rbegin() {
671 return reverse_iterator(end());
674 const_reverse_iterator rbegin()
const {
675 return const_reverse_iterator(end());
678 const_reverse_iterator crbegin()
const {
687 reverse_iterator rend() {
688 return reverse_iterator(begin());
691 const_reverse_iterator rend()
const {
692 return const_reverse_iterator(begin());
695 const_reverse_iterator crend()
const {
716 return data()[size() - 1];
722 return data()[size() - 1];
740 return _GetStorage();
745 const value_type *
data()
const {
746 return _GetStorage();
752 return size() == rhs.
size() && std::equal(begin(), end(), rhs.begin());
758 return !operator==(rhs);
764 value_type *_GetLocalStorage() {
765 return static_cast<value_type *
>(_data.GetLocalStorage());
767 const value_type *_GetLocalStorage()
const {
768 return static_cast<const value_type *
>(_data.GetLocalStorage());
771 value_type *_GetRemoteStorage() {
772 return static_cast<value_type *
>(_data.GetRemoteStorage());
774 const value_type *_GetRemoteStorage()
const {
775 return static_cast<const value_type *
>(_data.GetRemoteStorage());
778 void _SetRemoteStorage(value_type *p) {
779 _data.SetRemoteStorage(
static_cast<void *
>(p));
783 bool _IsLocal()
const {
784 return _capacity <= N;
789 value_type *_GetStorage() {
790 return _IsLocal() ? _GetLocalStorage() : _GetRemoteStorage();
795 const value_type *_GetStorage()
const {
796 return _IsLocal() ? _GetLocalStorage() : _GetRemoteStorage();
800 void _FreeStorage() {
802 ::operator
delete(_data.GetRemoteStorage(), std::nothrow);
808 value_type *b = data();
809 value_type *e = b + size();
810 for (value_type *p = b; p != e; ++p) {
816 static value_type *_Allocate(size_type size) {
817 return static_cast<value_type *
>(
818 ::operator
new(
sizeof(value_type) * size, std::nothrow));
822 void _InitStorage(size_type size) {
823 if (size > capacity()) {
824 _SetRemoteStorage(_Allocate(size));
827#if defined(ARCH_COMPILER_GCC) && ARCH_COMPILER_GCC_MAJOR < 11
828 else if constexpr (!_data.HasLocal) {
836 _data.SetRemoteStorage(
nullptr);
844 void _GrowStorage(
const size_type newCapacity) {
845 value_type *newStorage = _Allocate(newCapacity);
846 _UninitializedMove(begin(), end(), iterator(newStorage));
849 _SetRemoteStorage(newStorage);
850 _capacity = newCapacity;
856 size_type _NextCapacity()
const {
857 const size_type cap = capacity();
858 return cap + (cap / 2) + 1;
867 template <
typename U >
868 iterator _Insert(const_iterator it, U &&v) {
869 value_type *newEntry;
873 push_back(std::forward<U>(v));
880 else if (size() == capacity()) {
881 const size_type newCapacity = _NextCapacity();
882 value_type *newStorage = _Allocate(newCapacity);
884 value_type *i =
const_cast<value_type *
>(&*it);
885 value_type *curData = data();
886 newEntry = _UninitializedMove(curData, i, newStorage);
888 new (newEntry) value_type(std::forward<U>(v));
890 _UninitializedMove(i, curData + size(), newEntry + 1);
895 _SetRemoteStorage(newStorage);
896 _capacity = newCapacity;
903 newEntry =
const_cast<value_type *
>(&*it);
904 value_type *last =
const_cast<value_type *
>(&back());
905 new (data() + size()) value_type(std::move(*last));
906 std::move_backward(newEntry, last, last + 1);
909 newEntry->~value_type();
910 new (newEntry) value_type(std::forward<U>(v));
915 return iterator(newEntry);
920 _Data<value_type, N> _data;
923 _SizeMemberType _size;
927 _SizeMemberType _capacity;
932template <
typename T, u
int32_t N >
942template <
class T,
size_t SizeOf>
944TfComputeSmallVectorLocalCapacityForTotalSize()
952 constexpr size_t LocalCap = SizeOfOne > SizeOf ? 0
953 : ((SizeOf - SizeOfOne) /
sizeof(T)) + 1;
954 constexpr size_t LocalCapMax = std::numeric_limits<uint32_t>::max();
955 constexpr uint32_t LocalCap32 =
static_cast<uint32_t
>(
956 LocalCap > LocalCapMax ? LocalCapMax : LocalCap);
961PXR_NAMESPACE_CLOSE_SCOPE
This is a small-vector class with local storage optimization, the local storage can be specified via ...
void push_back(const value_type &v)
Copy an entry to the back of the vector,.
void pop_back()
Remove the entry at the back of the vector.
const_reference front() const
Returns the first element in the vector.
reference operator[](size_type i)
Access the specified element.
void assign(ForwardIterator first, ForwardIterator last)
Clears any previously held entries, and copies entries between [ first, last ) to this vector.
void reserve(size_type newCapacity)
Reserve storage for newCapacity entries.
iterator erase(const_iterator it)
Erase an entry at the given iterator.
TfSmallVector(ForwardIterator first, ForwardIterator last)
Creates a new vector containing copies of the data between first and last.
void assign(std::initializer_list< T > ilist)
Replace existing contents with the contents of ilist.
TfSmallVector(std::initializer_list< T > values)
Construct a new vector from initializer list.
~TfSmallVector()
Destructor.
bool operator!=(const TfSmallVector &rhs) const
Lexicographically compares the elements in the vectors for inequality.
size_type size() const
Returns the current size of the vector.
const_reference back() const
Returns the last elements in the vector.
iterator erase(const_iterator it, const_iterator last)
Erase entries between [ first, last ) from the vector.
TfSmallVector & operator=(std::initializer_list< T > ilist)
Replace existing contents with the contents of ilist.
TfSmallVector(size_type n)
Construct a vector holding n value-initialized elements.
bool empty() const
Returns true if this vector is empty.
reference front()
Returns the first element in the vector.
static constexpr size_type max_size()
Returns the maximum size of this vector.
TfSmallVector(size_type n, const value_type &v)
Construct a vector holding n copies of v.
bool operator==(const TfSmallVector &rhs) const
Lexicographically compares the elements in the vectors for equality.
void swap(TfSmallVector &rhs)
Swap two vector instances.
void resize(size_type newSize, const value_type &v=value_type())
Resize the vector to newSize and insert copies of \v.
const value_type * data() const
Direct access to the underlying array.
DefaultInitTag
Construct a vector holding n default-initialized elements.
TfSmallVector(const TfSmallVector &rhs)
Copy constructor.
const_reference operator[](size_type i) const
Access the specified element.
TfSmallVector & operator=(const TfSmallVector &rhs)
Assignment operator.
static constexpr size_type internal_capacity()
Returns the local storage capacity.
void insert(iterator pos, ForwardIterator first, ForwardIterator last)
Copy the range denoted by [first, last) into this vector before pos.
void emplace_back(Args &&... args)
Emplace an entry at the back of the vector.
void clear()
Clear the entries in the vector.
iterator insert(const_iterator it, value_type &&v)
Insert an rvalue-reference entry at the given iterator position.
TfSmallVector & operator=(TfSmallVector &&rhs)
Move assignment operator.
size_type capacity() const
Returns the current capacity of this vector.
TfSmallVector(TfSmallVector &&rhs)
Move constructor.
void insert(iterator pos, std::initializer_list< T > ilist)
Insert elements from ilist starting at position pos.
value_type * data()
Direct access to the underlying array.
iterator insert(const_iterator it, const value_type &v)
Insert an entry at the given iterator.
reference back()
Returns the last element in the vector.
void push_back(value_type &&v)
Move an entry to the back of the vector.