Loading...
Searching...
No Matches
smallVector.h
Go to the documentation of this file.
1//
2// Copyright 2019 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_TF_SMALL_VECTOR_H
8#define PXR_BASE_TF_SMALL_VECTOR_H
9
12
13#include "pxr/pxr.h"
14
15#include <algorithm>
16#include <cstddef>
17#include <cstdint>
18#include <cstdlib>
19#include <initializer_list>
20#include <iterator>
21#include <limits>
22#include <memory>
23#include <new>
24#include <type_traits>
25
26PXR_NAMESPACE_OPEN_SCOPE
27
28// Contains parts of the small vector implementation that do not depend on
29// *all* of TfSmallVector's template parameters.
30class TfSmallVectorBase
31{
32protected:
33 // We present the public size_type and difference_type as std::size_t and
34 // std::ptrdiff_t to match std::vector, but internally we store size &
35 // capacity as uint32_t.
36 using _SizeMemberType = std::uint32_t;
37
38 // Union type containing local storage or a pointer to heap storage.
39 template <size_t Size, size_t Align, size_t NumLocal>
40 union _DataUnion;
41
42 // Helper alias to produce the right _DataUnion instantiation for a given
43 // ValueType and NumLocal elements.
44 template <class ValueType, size_t NumLocal>
45 using _Data = _DataUnion<sizeof(ValueType), alignof(ValueType), NumLocal>;
46
47public:
48 using size_type = std::size_t;
49 using difference_type = std::ptrdiff_t;
50
51 // Returns the local capacity that may be used without increasing the size
52 // of the TfSmallVector. TfSmallVector<T, N> will never use more local
53 // capacity than is specified by N but clients that wish to maximize local
54 // occupancy in a generic way can compute N using this function.
55 template <typename U>
56 static constexpr size_type ComputeSerendipitousLocalCapacity() {
57 return (alignof(U) <= alignof(_Data<U, 0>))
58 ? sizeof(_Data<U, 0>) / sizeof(U)
59 : 0;
60 }
61
62protected:
63
64 // Enabler used to disambiguate the range-based constructor (begin, end)
65 // from the n-copies constructor (size_t n, value_type const &value)
66 // when the value_type is integral.
67 template<typename _ForwardIterator>
68 using _EnableIfForwardIterator =
69 std::enable_if_t<
70 std::is_convertible_v<
71 typename std::iterator_traits<
72 _ForwardIterator>::iterator_category,
73 std::forward_iterator_tag
74 >
75 >;
76
77 // Invoke std::uninitialized_copy that either moves or copies entries,
78 // depending on whether the type is move constructible or not.
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),
85 dest);
86 }
87
88 // Invokes either the move or copy constructor (via placement new),
89 // depending on whether U is move constructible or not.
90 template <typename U>
91 static void _MoveConstruct(U *p, U *src) {
92 new (p) U(std::move(*src));
93 }
94
95 // The data storage, which is a union of both the local storage, as well
96 // as a pointer, holding the address to the remote storage on the heap, if
97 // used.
98 template <size_t Size, size_t Align, size_t NumLocal>
99 union _DataUnion {
100 public:
101 // XXX: Could in principle assert in calls to GetLocalStorage() when
102 // HasLocal is false. Add dependency on tf/diagnostic.h?
103 static constexpr bool HasLocal = NumLocal != 0;
104
105 void *GetLocalStorage() {
106 return HasLocal ? _local : nullptr;
107 }
108 const void *GetLocalStorage() const {
109 return HasLocal ? _local : nullptr;
110 }
111
112 void *GetRemoteStorage() {
113 return _remote;
114 }
115 const void *GetRemoteStorage() const {
116 return _remote;
117 }
118
119 void SetRemoteStorage(void *p) {
120 _remote = p;
121 }
122 private:
123 // Pointer to heap storage.
124 void *_remote;
125 // Local storage -- min size is sizeof(_remote).
126 alignas(NumLocal == 0 ? std::alignment_of_v<void *> : Align)
127 char _local[std::max<size_t>(Size * NumLocal, sizeof(_remote))];
128 };
129};
130
153template <typename T, uint32_t N>
154class TfSmallVector : public TfSmallVectorBase
155{
156public:
157
164
167
168 typedef T value_type;
169 typedef T& reference;
170 typedef const T& const_reference;
171
173
176
177 using iterator = T*;
178 using const_iterator = const T*;
179 typedef std::reverse_iterator<iterator> reverse_iterator;
180 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
181
183
186 TfSmallVector() : _size(0), _capacity(N) {}
187
190 explicit TfSmallVector(size_type n) :
191 _capacity(N) {
192 _InitStorage(n);
193 value_type *d = data();
194 for (size_type i = 0; i < n; ++i) {
195 new (d + i) value_type();
196 }
197 }
198
201 TfSmallVector(size_type n, const value_type &v) :
202 _capacity(N) {
203 _InitStorage(n);
204 std::uninitialized_fill_n(data(), n, v);
205 }
206
209 enum DefaultInitTag { DefaultInit };
210 TfSmallVector(size_type n, DefaultInitTag) :
211 _capacity(N) {
212 _InitStorage(n);
213 value_type *d = data();
214 for (size_type i = 0; i < n; ++i) {
215 new (d + i) value_type;
216 }
217 }
218
221 TfSmallVector(const TfSmallVector &rhs) : _capacity(N) {
222 _InitStorage(rhs.size());
223 std::uninitialized_copy(rhs.begin(), rhs.end(), begin());
224 }
225
228 TfSmallVector(TfSmallVector &&rhs) : _size(0), _capacity(N) {
229 // If rhs can not be stored locally, take rhs's remote storage and
230 // reset rhs to empty.
231 if (rhs.size() > N) {
232 _SetRemoteStorage(rhs._GetRemoteStorage());
233 std::swap(_capacity, rhs._capacity);
234 }
235
236 // If rhs is stored locally, it's faster to simply move the entries
237 // into this vector's storage, destruct the entries at rhs, and swap
238 // sizes. Note that capacities will be the same in this case, so no
239 // need to swap those.
240 else {
241 _UninitializedMove(rhs.begin(), rhs.end(), begin());
242 rhs._Destruct();
243 }
244 std::swap(_size, rhs._size);
245 }
246
248 TfSmallVector(std::initializer_list<T> values)
249 : TfSmallVector(values.begin(), values.end()) {
250 }
251
254 template<typename ForwardIterator,
255 typename = _EnableIfForwardIterator<ForwardIterator>>
256 TfSmallVector(ForwardIterator first, ForwardIterator last) : _capacity(N)
257 {
258 _InitStorage(std::distance(first, last));
259 std::uninitialized_copy(first, last, begin());
260 }
261
265 _Destruct();
266 _FreeStorage();
267 }
268
272 if (this != &rhs) {
273 assign(rhs.begin(), rhs.end());
274 }
275 return *this;
276 }
277
281 if (this != &rhs) {
282 swap(rhs);
283 }
284 return *this;
285 }
286
289 TfSmallVector &operator=(std::initializer_list<T> ilist) {
290 assign(ilist.begin(), ilist.end());
291 return *this;
292 }
293
296 void swap(TfSmallVector &rhs) {
297 // Both this vector and rhs are stored locally.
298 if (_IsLocal() && rhs._IsLocal()) {
299 TfSmallVector *smaller = size() < rhs.size() ? this : &rhs;
300 TfSmallVector *larger = size() < rhs.size() ? &rhs : this;
301
302 // Swap all the entries up to the size of the smaller vector.
303 std::swap_ranges(smaller->begin(), smaller->end(), larger->begin());
304
305 // Move the tail end of the entries, and destruct them at the
306 // source vector.
307 for (size_type i = smaller->size(); i < larger->size(); ++i) {
308 _MoveConstruct(smaller->data() + i, &(*larger)[i]);
309 (*larger)[i].~value_type();
310 }
311
312 // Swap sizes. Capacities are already equal in this case.
313 std::swap(smaller->_size, larger->_size);
314 }
315
316 // Both this vector and rhs are stored remotely. Simply swap the
317 // pointers, as well as size and capacity.
318 else if (!_IsLocal() && !rhs._IsLocal()) {
319 value_type *tmp = _GetRemoteStorage();
320 _SetRemoteStorage(rhs._GetRemoteStorage());
321 rhs._SetRemoteStorage(tmp);
322
323 std::swap(_size, rhs._size);
324 std::swap(_capacity, rhs._capacity);
325 }
326
327 // Either this vector or rhs is stored remotely, whereas the other
328 // one is stored locally.
329 else {
330 TfSmallVector *remote = _IsLocal() ? &rhs : this;
331 TfSmallVector *local = _IsLocal() ? this : &rhs;
332
333 // Get a pointer to the remote storage. We'll be overwriting the
334 // pointer value below, so gotta retain it first.
335 value_type *remoteStorage = remote->_GetStorage();
336
337 // Move all the entries from the vector with the local storage, to
338 // the other vector's local storage. This will overwrite the pointer
339 // to the other vectors remote storage. Note that we will have to
340 // also destruct the elements at the source's local storage. The
341 // source will become the one with the remote storage, so those
342 // entries will be essentially freed.
343 for (size_type i = 0; i < local->size(); ++i) {
344 _MoveConstruct(remote->_GetLocalStorage() + i, &(*local)[i]);
345 (*local)[i].~value_type();
346 }
347
348 // Swap the remote storage into the vector which previously had the
349 // local storage. It's been properly cleaned up now.
350 local->_SetRemoteStorage(remoteStorage);
351
352 // Swap sizes and capacities. Easy peasy.
353 std::swap(remote->_size, local->_size);
354 std::swap(remote->_capacity, local->_capacity);
355 }
356
357 }
358
361 iterator insert(const_iterator it, value_type &&v) {
362 return _Insert(it, std::move(v));
363 }
364
367 iterator insert(const_iterator it, const value_type &v) {
368 return _Insert(it, v);
369 }
370
373 iterator erase(const_iterator it) {
374 return erase(it, it + 1);
375 }
376
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);
382
383 // If we're not removing anything, bail out.
384 if (p == q) {
385 return iterator(p);
386 }
387
388 const size_type num = std::distance(p, q);
389
390 // Move entries starting at last, down a few slots to starting a it.
391 value_type *e = data() + size();
392 std::move(q, e, p);
393
394 // Destruct all the freed up slots at the end of the vector.
395 for (value_type *i = (e - num); i != e; ++i) {
396 i->~value_type();
397 }
398
399 // Bump down the size.
400 _size -= num;
401
402 // Return an iterator to the next entry.
403 return iterator(p);
404 }
405
408 void reserve(size_type newCapacity) {
409 // Only reserve storage if the new capacity would grow past the local
410 // storage, or the currently allocated storage. We'll grow to
411 // accommodate exactly newCapacity entries.
412 if (newCapacity > capacity()) {
413 _GrowStorage(newCapacity);
414 }
415 }
416
419 void resize(size_type newSize, const value_type &v = value_type()) {
420 // If the new size is smaller than the current size, let go of some
421 // entries at the tail.
422 if (newSize < size()) {
423 erase(const_iterator(data() + newSize),
424 const_iterator(data() + size()));
425 }
426
427 // Otherwise, lets grow and fill: Reserve some storage, fill the tail
428 // end with copies of v, and update the new size.
429 else if (newSize > size()) {
430 reserve(newSize);
431 std::uninitialized_fill(data() + size(), data() + newSize, v);
432 _size = newSize;
433 }
434 }
435
439 void clear() {
440 _Destruct();
441 _size = 0;
442 }
443
447 template<typename ForwardIterator,
448 typename = _EnableIfForwardIterator<ForwardIterator>>
449 void assign(ForwardIterator first, ForwardIterator last) {
450 clear();
451 const size_type newSize = std::distance(first, last);
452 reserve(newSize);
453 std::uninitialized_copy(first, last, begin());
454 _size = newSize;
455 }
456
459 void assign(std::initializer_list<T> ilist) {
460 assign(ilist.begin(), ilist.end());
461 }
462
465 template < typename... Args >
466 void emplace_back(Args&&... args) {
467 if (size() == capacity()) {
468 _GrowStorage(_NextCapacity());
469 }
470 new (data() + size()) value_type(std::forward<Args>(args)...);
471 _size += 1;
472 }
473
476 void push_back(const value_type &v) {
477 emplace_back(v);
478 }
479
482 void push_back(value_type &&v) {
483 emplace_back(std::move(v));
484 }
485
489 template <typename ForwardIterator>
490 void insert(iterator pos, ForwardIterator first, ForwardIterator last)
491 {
492 static_assert(
493 std::is_convertible<
494 typename std::iterator_traits<ForwardIterator>::iterator_category,
495 std::forward_iterator_tag>::value,
496 "Input Iterators not supported.");
497
498 // Check for the insert-at-end special case as the very first thing so
499 // that we give the compiler the best possible opportunity to
500 // eliminate the general case code.
501 const bool insertAtEnd = pos == end();
502
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);
507
508 // Insertions at the end would be handled correctly by the code below
509 // without this special case. However, insert(end(), f, l) is an
510 // extremely common operation so we provide this fast path both to
511 // avoid unneeded work and to make it easier for the compiler to
512 // eliminate dead code when pos == end().
513 if (insertAtEnd) {
514 // The reallocation here is not a simple reserve. We want to grow
515 // the storage only when there are too many new elements but the
516 // desired size is based on the growth factor.
517 if (neededCapacity > capacity()) {
518 _GrowStorage(nextCapacity);
519 }
520 std::uninitialized_copy(first, last, end());
521 _size += numNewElems;
522 return;
523 }
524
525 if (neededCapacity > capacity()) {
526 // Because we need to realloc, we can do the insertion by copying
527 // each range, [begin(), pos), [first, last), [pos, end()), into
528 // the new storage.
529
530 const size_type posI = std::distance(begin(), pos);
531 value_type *newStorage = _Allocate(nextCapacity);
532
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);
539
540 // Destroy old data and set up this new buffer.
541 _Destruct();
542 _FreeStorage();
543 _SetRemoteStorage(newStorage);
544 _capacity = nextCapacity;
545 }
546 else {
547 // Insert in-place requires handling four ranges.
548 //
549 // For both the range-to-move [pos, end()) and the range-to-insert
550 // [first, last), there are two subranges: the subrange to copy
551 // and the subrange to uinitialized_copy. Note that only three of
552 // these ranges may be non-empty: either there is a non-empty
553 // prefix of [pos, end()) that needs to be copied over existing
554 // elements or there is a non-empty suffix of [first, last) that
555 // needs to be placed in uninitialized storage.
556
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;
562
563 // Move our existing elements out of the way of new elements.
564 iterator umSrc = pos + numInitMoves;
565 iterator umDst = end() + numUninitNews;
566 _UninitializedMove(umSrc, end(), umDst);
567 std::copy_backward(pos, umSrc, umDst);
568
569 // Copy new elements into place.
570 for (long i=0; i<numInitNews; ++i, ++first, ++pos) {
571 *pos = *first;
572 }
573 std::uninitialized_copy(first, last, end());
574 }
575
576 _size += numNewElems;
577 }
578
581 void insert(iterator pos, std::initializer_list<T> ilist) {
582 insert(pos, ilist.begin(), ilist.end());
583 }
584
587 void pop_back() {
588 back().~value_type();
589 _size -= 1;
590 }
591
594 size_type size() const {
595 return _size;
596 }
597
600 static constexpr size_type max_size() {
601 return std::numeric_limits<_SizeMemberType>::max();
602 }
603
606 bool empty() const {
607 return size() == 0;
608 }
609
615 size_type capacity() const {
616 return _capacity;
617 }
618
623 static constexpr size_type internal_capacity() {
624 return N;
625 }
626
629
630 iterator begin() {
631 return iterator(_GetStorage());
632 }
633
634 const_iterator begin() const {
635 return const_iterator(_GetStorage());
636 }
637
638 const_iterator cbegin() const {
639 return begin();
640 }
641
643
646
647 iterator end() {
648 return iterator(_GetStorage() + size());
649 }
650
651 const_iterator end() const {
652 return const_iterator(_GetStorage() + size());
653 }
654
655 const_iterator cend() const {
656 return end();
657 }
658
660
663
664 reverse_iterator rbegin() {
665 return reverse_iterator(end());
666 }
667
668 const_reverse_iterator rbegin() const {
669 return const_reverse_iterator(end());
670 }
671
672 const_reverse_iterator crbegin() const {
673 return rbegin();
674 }
675
677
680
681 reverse_iterator rend() {
682 return reverse_iterator(begin());
683 }
684
685 const_reverse_iterator rend() const {
686 return const_reverse_iterator(begin());
687 }
688
689 const_reverse_iterator crend() const {
690 return rend();
691 }
692
694
697 reference front() {
698 return *begin();
699 }
700
703 const_reference front() const {
704 return *begin();
705 }
706
709 reference back() {
710 return data()[size() - 1];
711 }
712
715 const_reference back() const {
716 return data()[size() - 1];
717 }
718
721 reference operator[](size_type i) {
722 return data()[i];
723 }
724
727 const_reference operator[](size_type i) const {
728 return data()[i];
729 }
730
733 value_type *data() {
734 return _GetStorage();
735 }
736
739 const value_type *data() const {
740 return _GetStorage();
741 }
742
745 bool operator==(const TfSmallVector &rhs) const {
746 return size() == rhs.size() && std::equal(begin(), end(), rhs.begin());
747 }
748
751 bool operator!=(const TfSmallVector &rhs) const {
752 return !operator==(rhs);
753 }
754
755private:
756
757 // Raw data access.
758 value_type *_GetLocalStorage() {
759 return static_cast<value_type *>(_data.GetLocalStorage());
760 }
761 const value_type *_GetLocalStorage() const {
762 return static_cast<const value_type *>(_data.GetLocalStorage());
763 }
764
765 value_type *_GetRemoteStorage() {
766 return static_cast<value_type *>(_data.GetRemoteStorage());
767 }
768 const value_type *_GetRemoteStorage() const {
769 return static_cast<const value_type *>(_data.GetRemoteStorage());
770 }
771
772 void _SetRemoteStorage(value_type *p) {
773 _data.SetRemoteStorage(static_cast<void *>(p));
774 }
775
776 // Returns true if the local storage is used.
777 bool _IsLocal() const {
778 return _capacity <= N;
779 }
780
781 // Return a pointer to the storage, which is either local or remote
782 // depending on the current capacity.
783 value_type *_GetStorage() {
784 return _IsLocal() ? _GetLocalStorage() : _GetRemoteStorage();
785 }
786
787 // Return a const pointer to the storage, which is either local or remote
788 // depending on the current capacity.
789 const value_type *_GetStorage() const {
790 return _IsLocal() ? _GetLocalStorage() : _GetRemoteStorage();
791 }
792
793 // Free the remotely allocated storage.
794 void _FreeStorage() {
795 if (!_IsLocal()) {
796 free(_GetRemoteStorage());
797 }
798 }
799
800 // Destructs all the elements stored in this vector.
801 void _Destruct() {
802 value_type *b = data();
803 value_type *e = b + size();
804 for (value_type *p = b; p != e; ++p) {
805 p->~value_type();
806 }
807 }
808
809 // Allocate a buffer on the heap.
810 static value_type *_Allocate(size_type size) {
811 return static_cast<value_type *>(malloc(sizeof(value_type) * size));
812 }
813
814 // Initialize the vector with new storage, updating the capacity and size.
815 void _InitStorage(size_type size) {
816 if (size > capacity()) {
817 _SetRemoteStorage(_Allocate(size));
818 _capacity = size;
819 }
820 _size = size;
821 }
822
823 // Grow the storage to be able to accommodate newCapacity entries. This
824 // always allocates remote storage.
825 void _GrowStorage(const size_type newCapacity) {
826 value_type *newStorage = _Allocate(newCapacity);
827 _UninitializedMove(begin(), end(), iterator(newStorage));
828 _Destruct();
829 _FreeStorage();
830 _SetRemoteStorage(newStorage);
831 _capacity = newCapacity;
832 }
833
834 // Returns the next capacity to use for vector growth. The growth factor
835 // here is 1.5. A constant 1 is added so that we do not have to special
836 // case initial capacities of 0 and 1.
837 size_type _NextCapacity() const {
838 const size_type cap = capacity();
839 return cap + (cap / 2) + 1;
840 }
841
842 // Insert the value v at iterator it. We use this method that takes a
843 // universal reference to de-duplicate the logic required for the insert
844 // overloads, one taking an rvalue reference, and the other one taking a
845 // const reference. This way, we can take the most optimal code path (
846 // move, or copy without making redundant copies) based on whether v is
847 // a rvalue reference or const reference.
848 template < typename U >
849 iterator _Insert(const_iterator it, U &&v) {
850 value_type *newEntry;
851
852 // If the iterator points to the end, simply push back.
853 if (it == end()) {
854 push_back(std::forward<U>(v));
855 return end() - 1;
856 }
857
858 // Grow the remote storage, if we need to. This invalidates iterators,
859 // so special care must be taken in order to return a new, valid
860 // iterator.
861 else if (size() == capacity()) {
862 const size_type newCapacity = _NextCapacity();
863 value_type *newStorage = _Allocate(newCapacity);
864
865 value_type *i = const_cast<value_type *>(&*it);
866 value_type *curData = data();
867 newEntry = _UninitializedMove(curData, i, newStorage);
868
869 new (newEntry) value_type(std::forward<U>(v));
870
871 _UninitializedMove(i, curData + size(), newEntry + 1);
872
873 _Destruct();
874 _FreeStorage();
875
876 _SetRemoteStorage(newStorage);
877 _capacity = newCapacity;
878 }
879
880 // Our current capacity is big enough to allow us to simply shift
881 // elements up one slot and insert v at it.
882 else {
883 // Move all the elements after it up by one slot.
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);
888
889 // Move v into the slot at the supplied iterator position.
890 newEntry->~value_type();
891 new (newEntry) value_type(std::forward<U>(v));
892 }
893
894 // Bump size and return an iterator to the newly inserted entry.
895 ++_size;
896 return iterator(newEntry);
897 }
898
899 // The vector storage, which is a union of the local storage and a pointer
900 // to the heap memory, if allocated.
901 _Data<value_type, N> _data;
902
903 // The current size of the vector, i.e. how many entries it contains.
904 _SizeMemberType _size;
905
906 // The current capacity of the vector, i.e. how big the currently allocated
907 // storage space is.
908 _SizeMemberType _capacity;
909};
910
912
913template < typename T, uint32_t N >
915{
916 a.swap(b);
917}
918
920
921PXR_NAMESPACE_CLOSE_SCOPE
922
923#endif
This is a small-vector class with local storage optimization, the local storage can be specified via ...
Definition: smallVector.h:155
void push_back(const value_type &v)
Copy an entry to the back of the vector,.
Definition: smallVector.h:476
void pop_back()
Remove the entry at the back of the vector.
Definition: smallVector.h:587
const_reference front() const
Returns the first element in the vector.
Definition: smallVector.h:703
reference operator[](size_type i)
Access the specified element.
Definition: smallVector.h:721
void assign(ForwardIterator first, ForwardIterator last)
Clears any previously held entries, and copies entries between [ first, last ) to this vector.
Definition: smallVector.h:449
void reserve(size_type newCapacity)
Reserve storage for newCapacity entries.
Definition: smallVector.h:408
iterator erase(const_iterator it)
Erase an entry at the given iterator.
Definition: smallVector.h:373
TfSmallVector(ForwardIterator first, ForwardIterator last)
Creates a new vector containing copies of the data between first and last.
Definition: smallVector.h:256
void assign(std::initializer_list< T > ilist)
Replace existing contents with the contents of ilist.
Definition: smallVector.h:459
TfSmallVector(std::initializer_list< T > values)
Construct a new vector from initializer list.
Definition: smallVector.h:248
~TfSmallVector()
Destructor.
Definition: smallVector.h:264
bool operator!=(const TfSmallVector &rhs) const
Lexicographically compares the elements in the vectors for inequality.
Definition: smallVector.h:751
size_type size() const
Returns the current size of the vector.
Definition: smallVector.h:594
const_reference back() const
Returns the last elements in the vector.
Definition: smallVector.h:715
iterator erase(const_iterator it, const_iterator last)
Erase entries between [ first, last ) from the vector.
Definition: smallVector.h:379
TfSmallVector & operator=(std::initializer_list< T > ilist)
Replace existing contents with the contents of ilist.
Definition: smallVector.h:289
TfSmallVector(size_type n)
Construct a vector holding n value-initialized elements.
Definition: smallVector.h:190
bool empty() const
Returns true if this vector is empty.
Definition: smallVector.h:606
reference front()
Returns the first element in the vector.
Definition: smallVector.h:697
static constexpr size_type max_size()
Returns the maximum size of this vector.
Definition: smallVector.h:600
TfSmallVector(size_type n, const value_type &v)
Construct a vector holding n copies of v.
Definition: smallVector.h:201
bool operator==(const TfSmallVector &rhs) const
Lexicographically compares the elements in the vectors for equality.
Definition: smallVector.h:745
void swap(TfSmallVector &rhs)
Swap two vector instances.
Definition: smallVector.h:296
void resize(size_type newSize, const value_type &v=value_type())
Resize the vector to newSize and insert copies of \v.
Definition: smallVector.h:419
const value_type * data() const
Direct access to the underlying array.
Definition: smallVector.h:739
DefaultInitTag
Construct a vector holding n default-initialized elements.
Definition: smallVector.h:209
TfSmallVector(const TfSmallVector &rhs)
Copy constructor.
Definition: smallVector.h:221
const_reference operator[](size_type i) const
Access the specified element.
Definition: smallVector.h:727
TfSmallVector & operator=(const TfSmallVector &rhs)
Assignment operator.
Definition: smallVector.h:271
static constexpr size_type internal_capacity()
Returns the local storage capacity.
Definition: smallVector.h:623
void insert(iterator pos, ForwardIterator first, ForwardIterator last)
Copy the range denoted by [first, last) into this vector before pos.
Definition: smallVector.h:490
void emplace_back(Args &&... args)
Emplace an entry at the back of the vector.
Definition: smallVector.h:466
void clear()
Clear the entries in the vector.
Definition: smallVector.h:439
iterator insert(const_iterator it, value_type &&v)
Insert an rvalue-reference entry at the given iterator position.
Definition: smallVector.h:361
TfSmallVector & operator=(TfSmallVector &&rhs)
Move assignment operator.
Definition: smallVector.h:280
size_type capacity() const
Returns the current capacity of this vector.
Definition: smallVector.h:615
TfSmallVector(TfSmallVector &&rhs)
Move constructor.
Definition: smallVector.h:228
void insert(iterator pos, std::initializer_list< T > ilist)
Insert elements from ilist starting at position pos.
Definition: smallVector.h:581
value_type * data()
Direct access to the underlying array.
Definition: smallVector.h:733
iterator insert(const_iterator it, const value_type &v)
Insert an entry at the given iterator.
Definition: smallVector.h:367
reference back()
Returns the last element in the vector.
Definition: smallVector.h:709
void push_back(value_type &&v)
Move an entry to the back of the vector.
Definition: smallVector.h:482