Loading...
Searching...
No Matches
smallVector.h
Go to the documentation of this file.
1//
2// Copyright 2019 Pixar
3//
4// Licensed under the Apache License, Version 2.0 (the "Apache License")
5// with the following modification; you may not use this file except in
6// compliance with the Apache License and the following modification to it:
7// Section 6. Trademarks. is deleted and replaced with:
8//
9// 6. Trademarks. This License does not grant permission to use the trade
10// names, trademarks, service marks, or product names of the Licensor
11// and its affiliates, except as required to comply with Section 4(c) of
12// the License and to reproduce the content of the NOTICE file.
13//
14// You may obtain a copy of the Apache License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software
19// distributed under the Apache License with the above modification is
20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21// KIND, either express or implied. See the Apache License for the specific
22// language governing permissions and limitations under the Apache License.
23//
24#ifndef PXR_BASE_TF_SMALL_VECTOR_H
25#define PXR_BASE_TF_SMALL_VECTOR_H
26
29
30#include "pxr/pxr.h"
31
32#include <algorithm>
33#include <cstddef>
34#include <cstdint>
35#include <cstdlib>
36#include <initializer_list>
37#include <iterator>
38#include <limits>
39#include <memory>
40#include <new>
41#include <type_traits>
42
43PXR_NAMESPACE_OPEN_SCOPE
44
45// Contains parts of the small vector implementation that do not depend on
46// *all* of TfSmallVector's template parameters.
47class TfSmallVectorBase
48{
49public:
50 using size_type = std::uint32_t;
51 using difference_type = std::int32_t;
52
53 // Returns the local capacity that may be used without increasing the size
54 // of the TfSmallVector. TfSmallVector<T, N> will never use more local
55 // capacity than is specified by N but clients that wish to maximize local
56 // occupancy in a generic way can compute N using this function.
57 template <typename U>
58 static constexpr size_type ComputeSerendipitousLocalCapacity() {
59 return (alignof(U) <= alignof(_Data<U, 0>))
60 ? sizeof(_Data<U, 0>) / sizeof(U)
61 : 0;
62 }
63
64protected:
65 // Invoke std::uninitialized_copy that either moves or copies entries,
66 // depending on whether the type is move constructible or not.
67 template <typename Iterator>
68 static Iterator _UninitializedMove(
69 Iterator first, Iterator last, Iterator dest) {
70 return std::uninitialized_copy(
71 std::make_move_iterator(first),
72 std::make_move_iterator(last),
73 dest);
74 }
75
76 // Invokes either the move or copy constructor (via placement new),
77 // depending on whether U is move constructible or not.
78 template <typename U>
79 static void _MoveConstruct(U *p, U *src) {
80 new (p) U(std::move(*src));
81 }
82
83 // The data storage, which is a union of both the local storage, as well
84 // as a pointer, holding the address to the remote storage on the heap, if
85 // used.
86 template < typename U, size_type M >
87 union _Data {
88 public:
89
90 U *GetLocalStorage() {
91 return reinterpret_cast<U *>(_local);
92 }
93
94 const U *GetLocalStorage() const {
95 return reinterpret_cast<const U *>(_local);
96 }
97
98 U *GetRemoteStorage() {
99 return _remote;
100 }
101
102 const U *GetRemoteStorage() const {
103 return _remote;
104 }
105
106 void SetRemoteStorage(U *p) {
107 _remote = p;
108 }
109
110 private:
111
112 alignas(U) char _local[sizeof(U)*M];
113 U* _remote;
114
115 };
116
117 // For N == 0 the _Data class has been specialized to elide the local
118 // storage completely. This way we don't have to rely on compiler-specific
119 // support for 0-sized arrays.
120 template < typename U >
121 union _Data<U, 0> {
122 public:
123
124 U *GetLocalStorage() {
125 // XXX: Could assert here. Introduce dependency on tf/diagnostic.h?
126 return nullptr;
127 }
128
129 const U *GetLocalStorage() const {
130 // XXX: Could assert here. Introduce dependency on tf/diagnostic.h?
131 return nullptr;
132 }
133
134 U *GetRemoteStorage() {
135 return _remote;
136 }
137
138 const U *GetRemoteStorage() const {
139 return _remote;
140 }
141
142 void SetRemoteStorage(U *p) {
143 _remote = p;
144 }
145
146 private:
147
148 U* _remote;
149
150 };
151
152};
153
176template < typename T, uint32_t N >
178 : public TfSmallVectorBase
179{
180public:
181
188
191
192 typedef T value_type;
193 typedef T& reference;
194 typedef const T& const_reference;
195
197
200
201 using iterator = T*;
202 using const_iterator = const T*;
203 typedef std::reverse_iterator<iterator> reverse_iterator;
204 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
205
207
210 TfSmallVector() : _size(0), _capacity(N) {}
211
214 explicit TfSmallVector(size_type n) :
215 _capacity(N) {
216 _InitStorage(n);
217 value_type *d = data();
218 for (size_type i = 0; i < n; ++i) {
219 new (d + i) value_type();
220 }
221 }
222
225 TfSmallVector(size_type n, const value_type &v) :
226 _capacity(N) {
227 _InitStorage(n);
228 std::uninitialized_fill_n(data(), n, v);
229 }
230
233 enum DefaultInitTag { DefaultInit };
234 TfSmallVector(size_type n, DefaultInitTag) :
235 _capacity(N) {
236 _InitStorage(n);
237 value_type *d = data();
238 for (size_type i = 0; i < n; ++i) {
239 new (d + i) value_type;
240 }
241 }
242
245 TfSmallVector(const TfSmallVector &rhs) : _capacity(N) {
246 _InitStorage(rhs.size());
247 std::uninitialized_copy(rhs.begin(), rhs.end(), begin());
248 }
249
252 TfSmallVector(TfSmallVector &&rhs) : _size(0), _capacity(N) {
253 // If rhs can not be stored locally, take rhs's remote storage and
254 // reset rhs to empty.
255 if (rhs.size() > N) {
256 _data.SetRemoteStorage(rhs._data.GetRemoteStorage());
257 std::swap(_capacity, rhs._capacity);
258 }
259
260 // If rhs is stored locally, it's faster to simply move the entries
261 // into this vector's storage, destruct the entries at rhs, and swap
262 // sizes. Note that capacities will be the same in this case, so no
263 // need to swap those.
264 else {
265 _UninitializedMove(rhs.begin(), rhs.end(), begin());
266 rhs._Destruct();
267 }
268 std::swap(_size, rhs._size);
269 }
270
272 TfSmallVector(std::initializer_list<T> values)
273 : TfSmallVector(values.begin(), values.end()) {
274 }
275
276 template<typename _ForwardIterator>
277 using _EnableIfForwardIterator =
278 typename std::enable_if<
279 std::is_convertible<
280 typename std::iterator_traits<
281 _ForwardIterator>::iterator_category,
282 std::forward_iterator_tag
283 >::value
284 >::type;
285
288 template<typename ForwardIterator,
289 typename = _EnableIfForwardIterator<ForwardIterator>>
290 TfSmallVector(ForwardIterator first, ForwardIterator last) : _capacity(N)
291 {
292 _InitStorage(std::distance(first, last));
293 std::uninitialized_copy(first, last, begin());
294 }
295
299 _Destruct();
300 _FreeStorage();
301 }
302
306 if (this != &rhs) {
307 assign(rhs.begin(), rhs.end());
308 }
309 return *this;
310 }
311
315 if (this != &rhs) {
316 swap(rhs);
317 }
318 return *this;
319 }
320
323 TfSmallVector &operator=(std::initializer_list<T> ilist) {
324 assign(ilist.begin(), ilist.end());
325 return *this;
326 }
327
330 void swap(TfSmallVector &rhs) {
331 // Both this vector and rhs are stored locally.
332 if (_IsLocal() && rhs._IsLocal()) {
333 TfSmallVector *smaller = size() < rhs.size() ? this : &rhs;
334 TfSmallVector *larger = size() < rhs.size() ? &rhs : this;
335
336 // Swap all the entries up to the size of the smaller vector.
337 std::swap_ranges(smaller->begin(), smaller->end(), larger->begin());
338
339 // Move the tail end of the entries, and destruct them at the
340 // source vector.
341 for (size_type i = smaller->size(); i < larger->size(); ++i) {
342 _MoveConstruct(smaller->data() + i, &(*larger)[i]);
343 (*larger)[i].~value_type();
344 }
345
346 // Swap sizes. Capacities are already equal in this case.
347 std::swap(smaller->_size, larger->_size);
348 }
349
350 // Both this vector and rhs are stored remotely. Simply swap the
351 // pointers, as well as size and capacity.
352 else if (!_IsLocal() && !rhs._IsLocal()) {
353 value_type *tmp = _data.GetRemoteStorage();
354 _data.SetRemoteStorage(rhs._data.GetRemoteStorage());
355 rhs._data.SetRemoteStorage(tmp);
356
357 std::swap(_size, rhs._size);
358 std::swap(_capacity, rhs._capacity);
359 }
360
361 // Either this vector or rhs is stored remotely, whereas the other
362 // one is stored locally.
363 else {
364 TfSmallVector *remote = _IsLocal() ? &rhs : this;
365 TfSmallVector *local = _IsLocal() ? this : &rhs;
366
367 // Get a pointer to the remote storage. We'll be overwriting the
368 // pointer value below, so gotta retain it first.
369 value_type *remoteStorage = remote->_GetStorage();
370
371 // Move all the entries from the vector with the local storage, to
372 // the other vector's local storage. This will overwrite the pointer
373 // to the other vectors remote storage. Note that we will have to
374 // also destruct the elements at the source's local storage. The
375 // source will become the one with the remote storage, so those
376 // entries will be essentially freed.
377 for (size_type i = 0; i < local->size(); ++i) {
378 _MoveConstruct(
379 remote->_data.GetLocalStorage() + i, &(*local)[i]);
380 (*local)[i].~value_type();
381 }
382
383 // Swap the remote storage into the vector which previously had the
384 // local storage. It's been properly cleaned up now.
385 local->_data.SetRemoteStorage(remoteStorage);
386
387 // Swap sizes and capacities. Easy peasy.
388 std::swap(remote->_size, local->_size);
389 std::swap(remote->_capacity, local->_capacity);
390 }
391
392 }
393
396 iterator insert(const_iterator it, value_type &&v) {
397 return _Insert(it, std::move(v));
398 }
399
402 iterator insert(const_iterator it, const value_type &v) {
403 return _Insert(it, v);
404 }
405
408 iterator erase(const_iterator it) {
409 return erase(it, it + 1);
410 }
411
414 iterator erase(const_iterator it, const_iterator last) {
415 value_type *p = const_cast<value_type *>(&*it);
416 value_type *q = const_cast<value_type *>(&*last);
417
418 // If we're not removing anything, bail out.
419 if (p == q) {
420 return iterator(p);
421 }
422
423 const size_type num = std::distance(p, q);
424
425 // Move entries starting at last, down a few slots to starting a it.
426 value_type *e = data() + size();
427 std::move(q, e, p);
428
429 // Destruct all the freed up slots at the end of the vector.
430 for (value_type *i = (e - num); i != e; ++i) {
431 i->~value_type();
432 }
433
434 // Bump down the size.
435 _size -= num;
436
437 // Return an iterator to the next entry.
438 return iterator(p);
439 }
440
443 void reserve(size_type newCapacity) {
444 // Only reserve storage if the new capacity would grow past the local
445 // storage, or the currently allocated storage. We'll grow to
446 // accommodate exactly newCapacity entries.
447 if (newCapacity > capacity()) {
448 _GrowStorage(newCapacity);
449 }
450 }
451
454 void resize(size_type newSize, const value_type &v = value_type()) {
455 // If the new size is smaller than the current size, let go of some
456 // entries at the tail.
457 if (newSize < size()) {
458 erase(const_iterator(data() + newSize),
459 const_iterator(data() + size()));
460 }
461
462 // Otherwise, lets grow and fill: Reserve some storage, fill the tail
463 // end with copies of v, and update the new size.
464 else if (newSize > size()) {
465 reserve(newSize);
466 std::uninitialized_fill(data() + size(), data() + newSize, v);
467 _size = newSize;
468 }
469 }
470
474 void clear() {
475 _Destruct();
476 _size = 0;
477 }
478
482 template<typename ForwardIterator,
483 typename = _EnableIfForwardIterator<ForwardIterator>>
484 void assign(ForwardIterator first, ForwardIterator last) {
485 clear();
486 const size_type newSize = std::distance(first, last);
487 reserve(newSize);
488 std::uninitialized_copy(first, last, begin());
489 _size = newSize;
490 }
491
494 void assign(std::initializer_list<T> ilist) {
495 assign(ilist.begin(), ilist.end());
496 }
497
500 template < typename... Args >
501 void emplace_back(Args&&... args) {
502 if (size() == capacity()) {
503 _GrowStorage(_NextCapacity());
504 }
505 new (data() + size()) value_type(std::forward<Args>(args)...);
506 _size += 1;
507 }
508
511 void push_back(const value_type &v) {
512 emplace_back(v);
513 }
514
517 void push_back(value_type &&v) {
518 emplace_back(std::move(v));
519 }
520
524 template <typename ForwardIterator>
525 void insert(iterator pos, ForwardIterator first, ForwardIterator last)
526 {
527 static_assert(
528 std::is_convertible<
529 typename std::iterator_traits<ForwardIterator>::iterator_category,
530 std::forward_iterator_tag>::value,
531 "Input Iterators not supported.");
532
533 // Check for the insert-at-end special case as the very first thing so
534 // that we give the compiler the best possible opportunity to
535 // eliminate the general case code.
536 const bool insertAtEnd = pos == end();
537
538 const long numNewElems = std::distance(first, last);
539 const size_type neededCapacity = size() + numNewElems;
540 const size_type nextCapacity =
541 std::max(_NextCapacity(), neededCapacity);
542
543 // Insertions at the end would be handled correctly by the code below
544 // without this special case. However, insert(end(), f, l) is an
545 // extremely common operation so we provide this fast path both to
546 // avoid unneeded work and to make it easier for the compiler to
547 // eliminate dead code when pos == end().
548 if (insertAtEnd) {
549 // The reallocation here is not a simple reserve. We want to grow
550 // the storage only when there are too many new elements but the
551 // desired size is based on the growth factor.
552 if (neededCapacity > capacity()) {
553 _GrowStorage(nextCapacity);
554 }
555 std::uninitialized_copy(first, last, end());
556 _size += numNewElems;
557 return;
558 }
559
560 if (neededCapacity > capacity()) {
561 // Because we need to realloc, we can do the insertion by copying
562 // each range, [begin(), pos), [first, last), [pos, end()), into
563 // the new storage.
564
565 const size_type posI = std::distance(begin(), pos);
566 value_type *newStorage = _Allocate(nextCapacity);
567
568 iterator newPrefixBegin = iterator(newStorage);
569 iterator newPos = newPrefixBegin + posI;
570 iterator newSuffixBegin = newPos + numNewElems;
571 _UninitializedMove(begin(), pos, newPrefixBegin);
572 std::uninitialized_copy(first, last, newPos);
573 _UninitializedMove(pos, end(), newSuffixBegin);
574
575 // Destroy old data and set up this new buffer.
576 _Destruct();
577 _FreeStorage();
578 _data.SetRemoteStorage(newStorage);
579 _capacity = nextCapacity;
580 }
581 else {
582 // Insert in-place requires handling four ranges.
583 //
584 // For both the range-to-move [pos, end()) and the range-to-insert
585 // [first, last), there are two subranges: the subrange to copy
586 // and the subrange to uinitialized_copy. Note that only three of
587 // these ranges may be non-empty: either there is a non-empty
588 // prefix of [pos, end()) that needs to be copied over existing
589 // elements or there is a non-empty suffix of [first, last) that
590 // needs to be placed in uninitialized storage.
591
592 const long numMoveElems = std::distance(pos, end());
593 const long numUninitMoves = std::min(numNewElems, numMoveElems);
594 const long numInitMoves = numMoveElems - numUninitMoves;
595 const long numUninitNews = numNewElems - numUninitMoves;
596 const long numInitNews = numNewElems - numUninitNews;
597
598 // Move our existing elements out of the way of new elements.
599 iterator umSrc = pos + numInitMoves;
600 iterator umDst = end() + numUninitNews;
601 _UninitializedMove(umSrc, end(), umDst);
602 std::copy_backward(pos, umSrc, umDst);
603
604 // Copy new elements into place.
605 for (long i=0; i<numInitNews; ++i, ++first, ++pos) {
606 *pos = *first;
607 }
608 std::uninitialized_copy(first, last, end());
609 }
610
611 _size += numNewElems;
612 }
613
616 void insert(iterator pos, std::initializer_list<T> ilist) {
617 insert(pos, ilist.begin(), ilist.end());
618 }
619
622 void pop_back() {
623 back().~value_type();
624 _size -= 1;
625 }
626
629 size_type size() const {
630 return _size;
631 }
632
635 static constexpr size_type max_size() {
636 return std::numeric_limits<size_type>::max();
637 }
638
641 bool empty() const {
642 return size() == 0;
643 }
644
650 size_type capacity() const {
651 return _capacity;
652 }
653
658 static constexpr size_type internal_capacity() {
659 return N;
660 }
661
664
665 iterator begin() {
666 return iterator(_GetStorage());
667 }
668
669 const_iterator begin() const {
670 return const_iterator(_GetStorage());
671 }
672
673 const_iterator cbegin() const {
674 return begin();
675 }
676
678
681
682 iterator end() {
683 return iterator(_GetStorage() + size());
684 }
685
686 const_iterator end() const {
687 return const_iterator(_GetStorage() + size());
688 }
689
690 const_iterator cend() const {
691 return end();
692 }
693
695
698
699 reverse_iterator rbegin() {
700 return reverse_iterator(end());
701 }
702
703 const_reverse_iterator rbegin() const {
704 return const_reverse_iterator(end());
705 }
706
707 const_reverse_iterator crbegin() const {
708 return rbegin();
709 }
710
712
715
716 reverse_iterator rend() {
717 return reverse_iterator(begin());
718 }
719
720 const_reverse_iterator rend() const {
721 return const_reverse_iterator(begin());
722 }
723
724 const_reverse_iterator crend() const {
725 return rend();
726 }
727
729
732 reference front() {
733 return *begin();
734 }
735
738 const_reference front() const {
739 return *begin();
740 }
741
744 reference back() {
745 return *(data() + size() - 1);
746 }
747
750 const_reference back() const {
751 return *(data() + size() - 1);
752 }
753
756 reference operator[](size_type i) {
757 return *(data() + i);
758 }
759
762 const_reference operator[](size_type i) const {
763 return *(data() + i);
764 }
765
768 value_type *data() {
769 return _GetStorage();
770 }
771
774 const value_type *data() const {
775 return _GetStorage();
776 }
777
780 bool operator==(const TfSmallVector &rhs) const {
781 return size() == rhs.size() && std::equal(begin(), end(), rhs.begin());
782 }
783
786 bool operator!=(const TfSmallVector &rhs) const {
787 return !operator==(rhs);
788 }
789
790private:
791
792 // Returns true if the local storage is used.
793 bool _IsLocal() const {
794 return _capacity <= N;
795 }
796
797 // Return a pointer to the storage, which is either local or remote
798 // depending on the current capacity.
799 value_type *_GetStorage() {
800 return _IsLocal() ? _data.GetLocalStorage() : _data.GetRemoteStorage();
801 }
802
803 // Return a const pointer to the storage, which is either local or remote
804 // depending on the current capacity.
805 const value_type *_GetStorage() const {
806 return _IsLocal() ? _data.GetLocalStorage() : _data.GetRemoteStorage();
807 }
808
809 // Free the remotely allocated storage.
810 void _FreeStorage() {
811 if (!_IsLocal()) {
812 free(_data.GetRemoteStorage());
813 }
814 }
815
816 // Destructs all the elements stored in this vector.
817 void _Destruct() {
818 value_type *b = data();
819 value_type *e = b + size();
820 for (value_type *p = b; p != e; ++p) {
821 p->~value_type();
822 }
823 }
824
825 // Allocate a buffer on the heap.
826 static value_type *_Allocate(size_type size) {
827 return static_cast<value_type *>(malloc(sizeof(value_type) * size));
828 }
829
830 // Initialize the vector with new storage, updating the capacity and size.
831 void _InitStorage(size_type size) {
832 if (size > capacity()) {
833 _data.SetRemoteStorage(_Allocate(size));
834 _capacity = size;
835 }
836 _size = size;
837 }
838
839 // Grow the storage to be able to accommodate newCapacity entries. This
840 // always allocates remotes storage.
841 void _GrowStorage(const size_type newCapacity) {
842 value_type *newStorage = _Allocate(newCapacity);
843 _UninitializedMove(begin(), end(), iterator(newStorage));
844 _Destruct();
845 _FreeStorage();
846 _data.SetRemoteStorage(newStorage);
847 _capacity = newCapacity;
848 }
849
850 // Returns the next capacity to use for vector growth. The growth factor
851 // here is 1.5. A constant 1 is added so that we do not have to special
852 // case initial capacities of 0 and 1.
853 size_type _NextCapacity() const {
854 const size_type cap = capacity();
855 return cap + (cap / 2) + 1;
856 }
857
858 // Insert the value v at iterator it. We use this method that takes a
859 // universal reference to de-duplicate the logic required for the insert
860 // overloads, one taking an rvalue reference, and the other one taking a
861 // const reference. This way, we can take the most optimal code path (
862 // move, or copy without making redundant copies) based on whether v is
863 // a rvalue reference or const reference.
864 template < typename U >
865 iterator _Insert(const_iterator it, U &&v) {
866 value_type *newEntry;
867
868 // If the iterator points to the end, simply push back.
869 if (it == end()) {
870 push_back(std::forward<U>(v));
871 return end() - 1;
872 }
873
874 // Grow the remote storage, if we need to. This invalidates iterators,
875 // so special care must be taken in order to return a new, valid
876 // iterator.
877 else if (size() == capacity()) {
878 const size_type newCapacity = _NextCapacity();
879 value_type *newStorage = _Allocate(newCapacity);
880
881 value_type *i = const_cast<value_type *>(&*it);
882 value_type *curData = data();
883 newEntry = _UninitializedMove(curData, i, newStorage);
884
885 new (newEntry) value_type(std::forward<U>(v));
886
887 _UninitializedMove(i, curData + size(), newEntry + 1);
888
889 _Destruct();
890 _FreeStorage();
891
892 _data.SetRemoteStorage(newStorage);
893 _capacity = newCapacity;
894 }
895
896 // Our current capacity is big enough to allow us to simply shift
897 // elements up one slot and insert v at it.
898 else {
899 // Move all the elements after it up by one slot.
900 newEntry = const_cast<value_type *>(&*it);
901 value_type *last = const_cast<value_type *>(&back());
902 new (data() + size()) value_type(std::move(*last));
903 std::move_backward(newEntry, last, last + 1);
904
905 // Move v into the slot at the supplied iterator position.
906 newEntry->~value_type();
907 new (newEntry) value_type(std::forward<U>(v));
908 }
909
910 // Bump size and return an iterator to the newly inserted entry.
911 ++_size;
912 return iterator(newEntry);
913 }
914
915 // The vector storage, which is a union of the local storage and a pointer
916 // to the heap memory, if allocated.
917 _Data<value_type, N> _data;
918
919 // The current size of the vector, i.e. how many entries it contains.
920 size_type _size;
921
922 // The current capacity of the vector, i.e. how big the currently allocated
923 // storage space is.
924 size_type _capacity;
925};
926
928
929template < typename T, uint32_t N >
931{
932 a.swap(b);
933}
934
936
937PXR_NAMESPACE_CLOSE_SCOPE
938
939#endif
This is a small-vector class with local storage optimization, the local storage can be specified via ...
Definition: smallVector.h:179
void push_back(const value_type &v)
Copy an entry to the back of the vector,.
Definition: smallVector.h:511
void pop_back()
Remove the entry at the back of the vector.
Definition: smallVector.h:622
const_reference front() const
Returns the first element in the vector.
Definition: smallVector.h:738
reference operator[](size_type i)
Access the specified element.
Definition: smallVector.h:756
void assign(ForwardIterator first, ForwardIterator last)
Clears any previously held entries, and copies entries between [ first, last ) to this vector.
Definition: smallVector.h:484
void reserve(size_type newCapacity)
Reserve storage for newCapacity entries.
Definition: smallVector.h:443
iterator erase(const_iterator it)
Erase an entry at the given iterator.
Definition: smallVector.h:408
TfSmallVector(ForwardIterator first, ForwardIterator last)
Creates a new vector containing copies of the data between first and last.
Definition: smallVector.h:290
void assign(std::initializer_list< T > ilist)
Replace existing contents with the contents of ilist.
Definition: smallVector.h:494
TfSmallVector(std::initializer_list< T > values)
Construct a new vector from initializer list.
Definition: smallVector.h:272
~TfSmallVector()
Destructor.
Definition: smallVector.h:298
bool operator!=(const TfSmallVector &rhs) const
Lexicographically compares the elements in the vectors for inequality.
Definition: smallVector.h:786
size_type size() const
Returns the current size of the vector.
Definition: smallVector.h:629
const_reference back() const
Returns the last elements in the vector.
Definition: smallVector.h:750
iterator erase(const_iterator it, const_iterator last)
Erase entries between [ first, last ) from the vector.
Definition: smallVector.h:414
TfSmallVector & operator=(std::initializer_list< T > ilist)
Replace existing contents with the contents of ilist.
Definition: smallVector.h:323
TfSmallVector(size_type n)
Construct a vector holding n value-initialized elements.
Definition: smallVector.h:214
bool empty() const
Returns true if this vector is empty.
Definition: smallVector.h:641
reference front()
Returns the first element in the vector.
Definition: smallVector.h:732
static constexpr size_type max_size()
Returns the maximum size of this vector.
Definition: smallVector.h:635
TfSmallVector(size_type n, const value_type &v)
Construct a vector holding n copies of v.
Definition: smallVector.h:225
bool operator==(const TfSmallVector &rhs) const
Lexicographically compares the elements in the vectors for equality.
Definition: smallVector.h:780
void swap(TfSmallVector &rhs)
Swap two vector instances.
Definition: smallVector.h:330
void resize(size_type newSize, const value_type &v=value_type())
Resize the vector to newSize and insert copies of \v.
Definition: smallVector.h:454
const value_type * data() const
Direct access to the underlying array.
Definition: smallVector.h:774
DefaultInitTag
Construct a vector holding n default-initialized elements.
Definition: smallVector.h:233
TfSmallVector(const TfSmallVector &rhs)
Copy constructor.
Definition: smallVector.h:245
const_reference operator[](size_type i) const
Access the specified element.
Definition: smallVector.h:762
TfSmallVector & operator=(const TfSmallVector &rhs)
Assignment operator.
Definition: smallVector.h:305
static constexpr size_type internal_capacity()
Returns the local storage capacity.
Definition: smallVector.h:658
void insert(iterator pos, ForwardIterator first, ForwardIterator last)
Copy the range denoted by [first, last) into this vector before pos.
Definition: smallVector.h:525
void emplace_back(Args &&... args)
Emplace an entry at the back of the vector.
Definition: smallVector.h:501
void clear()
Clear the entries in the vector.
Definition: smallVector.h:474
iterator insert(const_iterator it, value_type &&v)
Insert an rvalue-reference entry at the given iterator position.
Definition: smallVector.h:396
TfSmallVector & operator=(TfSmallVector &&rhs)
Move assignment operator.
Definition: smallVector.h:314
size_type capacity() const
Returns the current capacity of this vector.
Definition: smallVector.h:650
TfSmallVector(TfSmallVector &&rhs)
Move constructor.
Definition: smallVector.h:252
void insert(iterator pos, std::initializer_list< T > ilist)
Insert elements from ilist starting at position pos.
Definition: smallVector.h:616
value_type * data()
Direct access to the underlying array.
Definition: smallVector.h:768
iterator insert(const_iterator it, const value_type &v)
Insert an entry at the given iterator.
Definition: smallVector.h:402
reference back()
Returns the last element in the vector.
Definition: smallVector.h:744
void push_back(value_type &&v)
Move an entry to the back of the vector.
Definition: smallVector.h:517