7#ifndef PXR_BASE_TF_SMALL_VECTOR_H
8#define PXR_BASE_TF_SMALL_VECTOR_H
19#include <initializer_list>
26PXR_NAMESPACE_OPEN_SCOPE
30class TfSmallVectorBase
36 using _SizeMemberType = std::uint32_t;
39 template <
size_t Size,
size_t Align,
size_t NumLocal>
44 template <
class ValueType,
size_t NumLocal>
45 using _Data = _DataUnion<
sizeof(ValueType),
alignof(ValueType), NumLocal>;
48 using size_type = std::size_t;
49 using difference_type = std::ptrdiff_t;
56 static constexpr size_type ComputeSerendipitousLocalCapacity() {
57 return (
alignof(U) <=
alignof(_Data<U, 0>))
58 ?
sizeof(_Data<U, 0>) /
sizeof(U)
67 template<
typename _ForwardIterator>
68 using _EnableIfForwardIterator =
70 std::is_convertible_v<
71 typename std::iterator_traits<
72 _ForwardIterator>::iterator_category,
73 std::forward_iterator_tag
79 template <
typename Iterator>
80 static Iterator _UninitializedMove(
81 Iterator first, Iterator last, Iterator dest) {
82 return std::uninitialized_copy(
83 std::make_move_iterator(first),
84 std::make_move_iterator(last),
91 static void _MoveConstruct(U *p, U *src) {
92 new (p) U(std::move(*src));
98 template <
size_t Size,
size_t Align,
size_t NumLocal>
103 static constexpr bool HasLocal = NumLocal != 0;
105 void *GetLocalStorage() {
106 return HasLocal ? _local :
nullptr;
108 const void *GetLocalStorage()
const {
109 return HasLocal ? _local :
nullptr;
112 void *GetRemoteStorage() {
115 const void *GetRemoteStorage()
const {
119 void SetRemoteStorage(
void *p) {
126 alignas(NumLocal == 0 ? std::alignment_of_v<void *> : Align)
127 char _local[std::max<size_t>(Size * NumLocal,
sizeof(_remote))];
153template <
typename T, u
int32_t N>
168 typedef T value_type;
169 typedef T& reference;
170 typedef const T& const_reference;
178 using const_iterator =
const T*;
179 typedef std::reverse_iterator<iterator> reverse_iterator;
180 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
193 value_type *d =
data();
194 for (size_type i = 0; i < n; ++i) {
195 new (d + i) value_type();
204 std::uninitialized_fill_n(
data(), n, v);
213 value_type *d =
data();
214 for (size_type i = 0; i < n; ++i) {
215 new (d + i) value_type;
222 _InitStorage(rhs.
size());
223 std::uninitialized_copy(rhs.begin(), rhs.end(), begin());
231 if (rhs.size() > N) {
232 _SetRemoteStorage(rhs._GetRemoteStorage());
233 std::swap(_capacity, rhs._capacity);
241 _UninitializedMove(rhs.begin(), rhs.end(), begin());
244 std::swap(_size, rhs._size);
254 template<
typename ForwardIterator,
255 typename = _EnableIfForwardIterator<ForwardIterator>>
258 _InitStorage(std::distance(first, last));
259 std::uninitialized_copy(first, last, begin());
273 assign(rhs.begin(), rhs.end());
290 assign(ilist.begin(), ilist.end());
298 if (_IsLocal() && rhs._IsLocal()) {
303 std::swap_ranges(smaller->begin(), smaller->end(), larger->begin());
307 for (size_type i = smaller->
size(); i < larger->
size(); ++i) {
308 _MoveConstruct(smaller->
data() + i, &(*larger)[i]);
309 (*larger)[i].~value_type();
313 std::swap(smaller->_size, larger->_size);
318 else if (!_IsLocal() && !rhs._IsLocal()) {
319 value_type *tmp = _GetRemoteStorage();
320 _SetRemoteStorage(rhs._GetRemoteStorage());
321 rhs._SetRemoteStorage(tmp);
323 std::swap(_size, rhs._size);
324 std::swap(_capacity, rhs._capacity);
335 value_type *remoteStorage = remote->_GetStorage();
343 for (size_type i = 0; i < local->
size(); ++i) {
344 _MoveConstruct(remote->_GetLocalStorage() + i, &(*local)[i]);
345 (*local)[i].~value_type();
350 local->_SetRemoteStorage(remoteStorage);
353 std::swap(remote->_size, local->_size);
354 std::swap(remote->_capacity, local->_capacity);
361 iterator
insert(const_iterator it, value_type &&v) {
362 return _Insert(it, std::move(v));
367 iterator
insert(const_iterator it,
const value_type &v) {
368 return _Insert(it, v);
374 return erase(it, it + 1);
379 iterator
erase(const_iterator it, const_iterator last) {
380 value_type *p =
const_cast<value_type *
>(&*it);
381 value_type *q =
const_cast<value_type *
>(&*last);
388 const size_type num = std::distance(p, q);
395 for (value_type *i = (e - num); i != e; ++i) {
413 _GrowStorage(newCapacity);
419 void resize(size_type newSize,
const value_type &v = value_type()) {
422 if (newSize <
size()) {
429 else if (newSize >
size()) {
431 std::uninitialized_fill(
data() +
size(),
data() + newSize, v);
447 template<
typename ForwardIterator,
448 typename = _EnableIfForwardIterator<ForwardIterator>>
449 void assign(ForwardIterator first, ForwardIterator last) {
451 const size_type newSize = std::distance(first, last);
453 std::uninitialized_copy(first, last, begin());
459 void assign(std::initializer_list<T> ilist) {
460 assign(ilist.begin(), ilist.end());
465 template <
typename... Args >
468 _GrowStorage(_NextCapacity());
470 new (
data() +
size()) value_type(std::forward<Args>(args)...);
489 template <
typename ForwardIterator>
490 void insert(iterator pos, ForwardIterator first, ForwardIterator last)
494 typename std::iterator_traits<ForwardIterator>::iterator_category,
495 std::forward_iterator_tag>::value,
496 "Input Iterators not supported.");
501 const bool insertAtEnd = pos == end();
503 const long numNewElems = std::distance(first, last);
504 const size_type neededCapacity =
size() + numNewElems;
505 const size_type nextCapacity =
506 std::max(_NextCapacity(), neededCapacity);
518 _GrowStorage(nextCapacity);
520 std::uninitialized_copy(first, last, end());
521 _size += numNewElems;
530 const size_type posI = std::distance(begin(), pos);
531 value_type *newStorage = _Allocate(nextCapacity);
533 iterator newPrefixBegin = iterator(newStorage);
534 iterator newPos = newPrefixBegin + posI;
535 iterator newSuffixBegin = newPos + numNewElems;
536 _UninitializedMove(begin(), pos, newPrefixBegin);
537 std::uninitialized_copy(first, last, newPos);
538 _UninitializedMove(pos, end(), newSuffixBegin);
543 _SetRemoteStorage(newStorage);
544 _capacity = nextCapacity;
557 const long numMoveElems = std::distance(pos, end());
558 const long numUninitMoves = std::min(numNewElems, numMoveElems);
559 const long numInitMoves = numMoveElems - numUninitMoves;
560 const long numUninitNews = numNewElems - numUninitMoves;
561 const long numInitNews = numNewElems - numUninitNews;
564 iterator umSrc = pos + numInitMoves;
565 iterator umDst = end() + numUninitNews;
566 _UninitializedMove(umSrc, end(), umDst);
567 std::copy_backward(pos, umSrc, umDst);
570 for (
long i=0; i<numInitNews; ++i, ++first, ++pos) {
573 std::uninitialized_copy(first, last, end());
576 _size += numNewElems;
581 void insert(iterator pos, std::initializer_list<T> ilist) {
582 insert(pos, ilist.begin(), ilist.end());
588 back().~value_type();
601 return std::numeric_limits<_SizeMemberType>::max();
631 return iterator(_GetStorage());
634 const_iterator begin()
const {
635 return const_iterator(_GetStorage());
638 const_iterator cbegin()
const {
648 return iterator(_GetStorage() +
size());
651 const_iterator end()
const {
652 return const_iterator(_GetStorage() +
size());
655 const_iterator cend()
const {
664 reverse_iterator rbegin() {
665 return reverse_iterator(end());
668 const_reverse_iterator rbegin()
const {
669 return const_reverse_iterator(end());
672 const_reverse_iterator crbegin()
const {
681 reverse_iterator rend() {
682 return reverse_iterator(begin());
685 const_reverse_iterator rend()
const {
686 return const_reverse_iterator(begin());
689 const_reverse_iterator crend()
const {
734 return _GetStorage();
739 const value_type *
data()
const {
740 return _GetStorage();
746 return size() == rhs.
size() && std::equal(begin(), end(), rhs.begin());
758 value_type *_GetLocalStorage() {
759 return static_cast<value_type *
>(_data.GetLocalStorage());
761 const value_type *_GetLocalStorage()
const {
762 return static_cast<const value_type *
>(_data.GetLocalStorage());
765 value_type *_GetRemoteStorage() {
766 return static_cast<value_type *
>(_data.GetRemoteStorage());
768 const value_type *_GetRemoteStorage()
const {
769 return static_cast<const value_type *
>(_data.GetRemoteStorage());
772 void _SetRemoteStorage(value_type *p) {
773 _data.SetRemoteStorage(
static_cast<void *
>(p));
777 bool _IsLocal()
const {
778 return _capacity <= N;
783 value_type *_GetStorage() {
784 return _IsLocal() ? _GetLocalStorage() : _GetRemoteStorage();
789 const value_type *_GetStorage()
const {
790 return _IsLocal() ? _GetLocalStorage() : _GetRemoteStorage();
794 void _FreeStorage() {
796 free(_GetRemoteStorage());
802 value_type *b =
data();
803 value_type *e = b +
size();
804 for (value_type *p = b; p != e; ++p) {
810 static value_type *_Allocate(size_type
size) {
811 return static_cast<value_type *
>(malloc(
sizeof(value_type) *
size));
815 void _InitStorage(size_type
size) {
817 _SetRemoteStorage(_Allocate(
size));
825 void _GrowStorage(
const size_type newCapacity) {
826 value_type *newStorage = _Allocate(newCapacity);
827 _UninitializedMove(begin(), end(), iterator(newStorage));
830 _SetRemoteStorage(newStorage);
831 _capacity = newCapacity;
837 size_type _NextCapacity()
const {
839 return cap + (cap / 2) + 1;
848 template <
typename U >
849 iterator _Insert(const_iterator it, U &&v) {
850 value_type *newEntry;
862 const size_type newCapacity = _NextCapacity();
863 value_type *newStorage = _Allocate(newCapacity);
865 value_type *i =
const_cast<value_type *
>(&*it);
866 value_type *curData =
data();
867 newEntry = _UninitializedMove(curData, i, newStorage);
869 new (newEntry) value_type(std::forward<U>(v));
871 _UninitializedMove(i, curData +
size(), newEntry + 1);
876 _SetRemoteStorage(newStorage);
877 _capacity = newCapacity;
884 newEntry =
const_cast<value_type *
>(&*it);
885 value_type *last =
const_cast<value_type *
>(&
back());
886 new (
data() +
size()) value_type(std::move(*last));
887 std::move_backward(newEntry, last, last + 1);
890 newEntry->~value_type();
891 new (newEntry) value_type(std::forward<U>(v));
896 return iterator(newEntry);
901 _Data<value_type, N> _data;
904 _SizeMemberType _size;
908 _SizeMemberType _capacity;
913template <
typename T, u
int32_t N >
921PXR_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.