Files
BayesNet/html/libtorch/include/c10/util/SmallVector.h.gcov.html

164 KiB

<html lang="en"> <head> </head>
LCOV - code coverage report
Current view: top level - libtorch/include/c10/util - SmallVector.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 55 0
Test Date: 2024-04-30 13:17:26 Functions: 0.0 % 21 0

            Line data    Source code
       1              : //===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
       2              : //
       3              : // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
       4              : // See https://llvm.org/LICENSE.txt for license information.
       5              : // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
       6              : //
       7              : //===----------------------------------------------------------------------===//
       8              : //
       9              : // This file defines the SmallVector class.
      10              : //
      11              : //===----------------------------------------------------------------------===//
      12              : 
      13              : // ATen: modified from llvm::SmallVector.
      14              : // used std::is_trivially_{copy,move}_constructible
      15              : // replaced iterator_range constructor with inline Container&& constructor
      16              : // replaced LLVM_NODISCARD, LLVM_LIKELY, and LLVM_UNLIKELY with c10 equivalents
      17              : // removed LLVM_GSL_OWNER
      18              : // added SmallVector::at
      19              : // added operator<< for std::ostream
      20              : // added C10_API to export SmallVectorBase
      21              : 
      22              : #pragma once
      23              : 
      24              : #include <c10/macros/Macros.h>
      25              : #include <c10/util/AlignOf.h>
      26              : 
      27              : #include <algorithm>
      28              : #include <cassert>
      29              : #include <cstddef>
      30              : #include <cstdlib>
      31              : #include <cstring>
      32              : #include <functional>
      33              : #include <initializer_list>
      34              : #include <iterator>
      35              : #include <limits>
      36              : #include <memory>
      37              : #include <new>
      38              : #include <ostream>
      39              : #include <type_traits>
      40              : #include <utility>
      41              : 
      42              : C10_CLANG_DIAGNOSTIC_PUSH()
      43              : #if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32")
      44              : C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32")
      45              : #endif
      46              : 
      47              : namespace c10 {
      48              : 
      49              : /// This is all the stuff common to all SmallVectors.
      50              : ///
      51              : /// The template parameter specifies the type which should be used to hold the
      52              : /// Size and Capacity of the SmallVector, so it can be adjusted.
      53              : /// Using 32 bit size is desirable to shrink the size of the SmallVector.
      54              : /// Using 64 bit size is desirable for cases like SmallVector<char>, where a
      55              : /// 32 bit size would limit the vector to ~4GB. SmallVectors are used for
      56              : /// buffering bitcode output - which can exceed 4GB.
      57              : template <class Size_T>
      58              : class C10_API SmallVectorBase {
      59              :  protected:
      60              :   void* BeginX;
      61              :   Size_T Size = 0, Capacity;
      62              : 
      63              :   /// The maximum value of the Size_T used.
      64              :   static constexpr size_t SizeTypeMax() {
      65              :     return std::numeric_limits<Size_T>::max();
      66              :   }
      67              : 
      68            0 :   SmallVectorBase(void* FirstEl, size_t TotalCapacity)
      69            0 :       : BeginX(FirstEl), Capacity(TotalCapacity) {}
      70              : 
      71              :   /// This is a helper for \a grow() that's out of line to reduce code
      72              :   /// duplication.  This function will report a fatal error if it can't grow at
      73              :   /// least to \p MinSize.
      74              :   void* mallocForGrow(size_t MinSize, size_t TSize, size_t& NewCapacity);
      75              : 
      76              :   /// This is an implementation of the grow() method which only works
      77              :   /// on POD-like data types and is out of line to reduce code duplication.
      78              :   /// This function will report a fatal error if it cannot increase capacity.
      79              :   void grow_pod(void* FirstEl, size_t MinSize, size_t TSize);
      80              : 
      81              :  public:
      82              :   SmallVectorBase() = delete;
      83            0 :   size_t size() const {
      84            0 :     return Size;
      85              :   }
      86            0 :   size_t capacity() const {
      87            0 :     return Capacity;
      88              :   }
      89              : 
      90              :   C10_NODISCARD bool empty() const {
      91              :     return !Size;
      92              :   }
      93              : 
      94              :   /// Set the array size to \p N, which the current array must have enough
      95              :   /// capacity for.
      96              :   ///
      97              :   /// This does not construct or destroy any elements in the vector.
      98              :   ///
      99              :   /// Clients can use this in conjunction with capacity() to write past the end
     100              :   /// of the buffer when they know that more elements are available, and only
     101              :   /// update the size later. This avoids the cost of value initializing elements
     102              :   /// which will only be overwritten.
     103            0 :   void set_size(size_t N) {
     104            0 :     assert(N <= capacity());
     105            0 :     Size = N;
     106            0 :   }
     107              : };
     108              : 
     109              : template <class T>
     110              : using SmallVectorSizeType = typename std::
     111              :     conditional<sizeof(T) < 4 && sizeof(void*) >= 8, uint64_t, uint32_t>::type;
     112              : 
     113              : /// Figure out the offset of the first element.
     114              : template <class T, typename = void>
     115              : struct SmallVectorAlignmentAndSize {
     116              :   alignas(SmallVectorBase<SmallVectorSizeType<T>>) char Base[sizeof(
     117              :       SmallVectorBase<SmallVectorSizeType<T>>)];
     118              :   alignas(T) char FirstEl[sizeof(T)];
     119              : };
     120              : 
     121              : /// This is the part of SmallVectorTemplateBase which does not depend on whether
     122              : /// the type T is a POD. The extra dummy template argument is used by ArrayRef
     123              : /// to avoid unnecessarily requiring T to be complete.
     124              : template <typename T, typename = void>
     125              : class SmallVectorTemplateCommon
     126              :     : public SmallVectorBase<SmallVectorSizeType<T>> {
     127              :   using Base = SmallVectorBase<SmallVectorSizeType<T>>;
     128              : 
     129              :   /// Find the address of the first element.  For this pointer math to be valid
     130              :   /// with small-size of 0 for T with lots of alignment, it's important that
     131              :   /// SmallVectorStorage is properly-aligned even for small-size of 0.
     132            0 :   void* getFirstEl() const {
     133              :     return const_cast<void*>(reinterpret_cast<const void*>(
     134              :         reinterpret_cast<const char*>(this) +
     135            0 :         offsetof(SmallVectorAlignmentAndSize<T>, FirstEl)));
     136              :   }
     137              :   // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
     138              : 
     139              :  protected:
     140            0 :   SmallVectorTemplateCommon(size_t Size) : Base(getFirstEl(), Size) {}
     141              : 
     142            0 :   void grow_pod(size_t MinSize, size_t TSize) {
     143            0 :     Base::grow_pod(getFirstEl(), MinSize, TSize);
     144            0 :   }
     145              : 
     146              :   /// Return true if this is a smallvector which has not had dynamic
     147              :   /// memory allocated for it.
     148            0 :   bool isSmall() const {
     149            0 :     return this->BeginX == getFirstEl();
     150              :   }
     151              : 
     152              :   /// Put this vector in a state of being small.
     153              :   void resetToSmall() {
     154              :     this->BeginX = getFirstEl();
     155              :     this->Size = this->Capacity = 0; // FIXME: Setting Capacity to 0 is suspect.
     156              :   }
     157              : 
     158              :   /// Return true if V is an internal reference to the given range.
     159              :   bool isReferenceToRange(const void* V, const void* First, const void* Last)
     160              :       const {
     161              :     // Use std::less to avoid UB.
     162              :     std::less<> LessThan;
     163              :     return !LessThan(V, First) && LessThan(V, Last);
     164              :   }
     165              : 
     166              :   /// Return true if V is an internal reference to this vector.
     167              :   bool isReferenceToStorage(const void* V) const {
     168              :     return isReferenceToRange(V, this->begin(), this->end());
     169              :   }
     170              : 
     171              :   /// Return true if First and Last form a valid (possibly empty) range in this
     172              :   /// vector's storage.
     173              :   bool isRangeInStorage(const void* First, const void* Last) const {
     174              :     // Use std::less to avoid UB.
     175              :     std::less<> LessThan;
     176              :     return !LessThan(First, this->begin()) && !LessThan(Last, First) &&
     177              :         !LessThan(this->end(), Last);
     178              :   }
     179              : 
     180              :   /// Return true unless Elt will be invalidated by resizing the vector to
     181              :   /// NewSize.
     182              :   bool isSafeToReferenceAfterResize(const void* Elt, size_t NewSize) {
     183              :     // Past the end.
     184              :     if (C10_LIKELY(!isReferenceToStorage(Elt)))
     185              :       return true;
     186              : 
     187              :     // Return false if Elt will be destroyed by shrinking.
     188              :     if (NewSize <= this->size())
     189              :       return Elt < this->begin() + NewSize;
     190              : 
     191              :     // Return false if we need to grow.
     192              :     return NewSize <= this->capacity();
     193              :   }
     194              : 
     195              :   /// Check whether Elt will be invalidated by resizing the vector to NewSize.
     196              :   void assertSafeToReferenceAfterResize(const void* Elt, size_t NewSize) {
     197              :     (void)Elt; // Suppress unused variable warning
     198              :     (void)NewSize; // Suppress unused variable warning
     199              :     assert(
     200              :         isSafeToReferenceAfterResize(Elt, NewSize) &&
     201              :         "Attempting to reference an element of the vector in an operation "
     202              :         "that invalidates it");
     203              :   }
     204              : 
     205              :   /// Check whether Elt will be invalidated by increasing the size of the
     206              :   /// vector by N.
     207              :   void assertSafeToAdd(const void* Elt, size_t N = 1) {
     208              :     this->assertSafeToReferenceAfterResize(Elt, this->size() + N);
     209              :   }
     210              : 
     211              :   /// Check whether any part of the range will be invalidated by clearing.
     212              :   void assertSafeToReferenceAfterClear(const T* From, const T* To) {
     213              :     if (From == To)
     214              :       return;
     215              :     this->assertSafeToReferenceAfterResize(From, 0);
     216              :     this->assertSafeToReferenceAfterResize(To - 1, 0);
     217              :   }
     218              :   template <
     219              :       class ItTy,
     220              :       std::enable_if_t<
     221              :           !std::is_same<std::remove_const_t<ItTy>, T*>::value,
     222              :           bool> = false>
     223              :   void assertSafeToReferenceAfterClear(ItTy, ItTy) {}
     224              : 
     225              :   /// Check whether any part of the range will be invalidated by growing.
     226              :   void assertSafeToAddRange(const T* From, const T* To) {
     227              :     if (From == To)
     228              :       return;
     229              :     this->assertSafeToAdd(From, To - From);
     230              :     this->assertSafeToAdd(To - 1, To - From);
     231              :   }
     232              :   template <
     233              :       class ItTy,
     234              :       std::enable_if_t<
     235              :           !std::is_same<std::remove_const_t<ItTy>, T*>::value,
     236              :           bool> = false>
     237              :   void assertSafeToAddRange(ItTy, ItTy) {}
     238              : 
     239              :   /// Reserve enough space to add one element, and return the updated element
     240              :   /// pointer in case it was a reference to the storage.
     241              :   template <class U>
     242            0 :   static const T* reserveForParamAndGetAddressImpl(
     243              :       U* This,
     244              :       const T& Elt,
     245              :       size_t N) {
     246            0 :     size_t NewSize = This->size() + N;
     247            0 :     if (C10_LIKELY(NewSize <= This->capacity()))
     248            0 :       return &Elt;
     249              : 
     250            0 :     bool ReferencesStorage = false;
     251            0 :     int64_t Index = -1;
     252              :     if (!U::TakesParamByValue) {
     253              :       if (C10_UNLIKELY(This->isReferenceToStorage(&Elt))) {
     254              :         ReferencesStorage = true;
     255              :         Index = &Elt - This->begin();
     256              :       }
     257              :     }
     258            0 :     This->grow(NewSize);
     259            0 :     return ReferencesStorage ? This->begin() + Index : &Elt;
     260              :   }
     261              : 
     262              :  public:
     263              :   using size_type = size_t;
     264              :   using difference_type = ptrdiff_t;
     265              :   using value_type = T;
     266              :   using iterator = T*;
     267              :   using const_iterator = const T*;
     268              : 
     269              :   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
     270              :   using reverse_iterator = std::reverse_iterator<iterator>;
     271              : 
     272              :   using reference = T&;
     273              :   using const_reference = const T&;
     274              :   using pointer = T*;
     275              :   using const_pointer = const T*;
     276              : 
     277              :   using Base::capacity;
     278              :   using Base::empty;
     279              :   using Base::size;
     280              : 
     281              :   // forward iterator creation methods.
     282            0 :   iterator begin() {
     283            0 :     return (iterator)this->BeginX;
     284              :   }
     285              :   const_iterator begin() const {
     286              :     return (const_iterator)this->BeginX;
     287              :   }
     288            0 :   iterator end() {
     289            0 :     return begin() + size();
     290              :   }
     291              :   const_iterator end() const {
     292              :     return begin() + size();
     293              :   }
     294              : 
     295              :   // reverse iterator creation methods.
     296              :   reverse_iterator rbegin() {
     297              :     return reverse_iterator(end());
     298              :   }
     299              :   const_reverse_iterator rbegin() const {
     300              :     return const_reverse_iterator(end());
     301              :   }
     302              :   reverse_iterator rend() {
     303              :     return reverse_iterator(begin());
     304              :   }
     305              :   const_reverse_iterator rend() const {
     306              :     return const_reverse_iterator(begin());
     307              :   }
     308              : 
     309              :   size_type size_in_bytes() const {
     310              :     return size() * sizeof(T);
     311              :   }
     312              :   size_type max_size() const {
     313              :     return std::min(this->SizeTypeMax(), size_type(-1) / sizeof(T));
     314              :   }
     315              : 
     316              :   size_t capacity_in_bytes() const {
     317              :     return capacity() * sizeof(T);
     318              :   }
     319              : 
     320              :   /// Return a pointer to the vector's buffer, even if empty().
     321              :   pointer data() {
     322              :     return pointer(begin());
     323              :   }
     324              :   /// Return a pointer to the vector's buffer, even if empty().
     325              :   const_pointer data() const {
     326              :     return const_pointer(begin());
     327              :   }
     328              : 
     329              :   // SmallVector::at is NOT from LLVM.
     330              :   reference at(size_type idx) {
     331              :     assert(idx < size());
     332              :     return begin()[idx];
     333              :   }
     334              :   const_reference at(size_type idx) const {
     335              :     assert(idx < size());
     336              :     return begin()[idx];
     337              :   }
     338              :   reference operator[](size_type idx) {
     339              :     assert(idx < size());
     340              :     return begin()[idx];
     341              :   }
     342              :   const_reference operator[](size_type idx) const {
     343              :     assert(idx < size());
     344              :     return begin()[idx];
     345              :   }
     346              : 
     347              :   reference front() {
     348              :     assert(!empty());
     349              :     return begin()[0];
     350              :   }
     351              :   const_reference front() const {
     352              :     assert(!empty());
     353              :     return begin()[0];
     354              :   }
     355              : 
     356              :   reference back() {
     357              :     assert(!empty());
     358              :     return end()[-1];
     359              :   }
     360              :   const_reference back() const {
     361              :     assert(!empty());
     362              :     return end()[-1];
     363              :   }
     364              : };
     365              : 
     366              : /// SmallVectorTemplateBase<TriviallyCopyable = false> - This is where we put
     367              : /// method implementations that are designed to work with non-trivial T's.
     368              : ///
     369              : /// We approximate is_trivially_copyable with trivial move/copy construction and
     370              : /// trivial destruction. While the standard doesn't specify that you're allowed
     371              : /// copy these types with memcpy, there is no way for the type to observe this.
     372              : /// This catches the important case of std::pair<POD, POD>, which is not
     373              : /// trivially assignable.
     374              : ///
     375              : /// XXX: if build fails here fall back to C10_IS_TRIVIALLY_COPYABLE and make a
     376              : /// note
     377              : template <
     378              :     typename T,
     379              :     bool = (std::is_trivially_copy_constructible<T>::value) &&
     380              :         (std::is_trivially_move_constructible<T>::value) &&
     381              :         std::is_trivially_destructible<T>::value>
     382              : class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
     383              :   friend class SmallVectorTemplateCommon<T>;
     384              : 
     385              :  protected:
     386              :   static constexpr bool TakesParamByValue = false;
     387              :   using ValueParamT = const T&;
     388              : 
     389              :   SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
     390              : 
     391              :   static void destroy_range(T* S, T* E) {
     392              :     while (S != E) {
     393              :       --E;
     394              :       E->~T();
     395              :     }
     396              :   }
     397              : 
     398              :   /// Move the range [I, E) into the uninitialized memory starting with "Dest",
     399              :   /// constructing elements as needed.
     400              :   template <typename It1, typename It2>
     401              :   static void uninitialized_move(It1 I, It1 E, It2 Dest) {
     402              :     std::uninitialized_copy(
     403              :         std::make_move_iterator(I), std::make_move_iterator(E), Dest);
     404              :   }
     405              : 
     406              :   /// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
     407              :   /// constructing elements as needed.
     408              :   template <typename It1, typename It2>
     409              :   static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
     410              :     std::uninitialized_copy(I, E, Dest);
     411              :   }
     412              : 
     413              :   /// Grow the allocated memory (without initializing new elements), doubling
     414              :   /// the size of the allocated memory. Guarantees space for at least one more
     415              :   /// element, or MinSize more elements if specified.
     416              :   void grow(size_t MinSize = 0);
     417              : 
     418              :   /// Create a new allocation big enough for \p MinSize and pass back its size
     419              :   /// in \p NewCapacity. This is the first section of \a grow().
     420              :   T* mallocForGrow(size_t MinSize, size_t& NewCapacity) {
     421              :     return static_cast<T*>(
     422              :         SmallVectorBase<SmallVectorSizeType<T>>::mallocForGrow(
     423              :             MinSize, sizeof(T), NewCapacity));
     424              :   }
     425              : 
     426              :   /// Move existing elements over to the new allocation \p NewElts, the middle
     427              :   /// section of \a grow().
     428              :   void moveElementsForGrow(T* NewElts);
     429              : 
     430              :   /// Transfer ownership of the allocation, finishing up \a grow().
     431              :   void takeAllocationForGrow(T* NewElts, size_t NewCapacity);
     432              : 
     433              :   /// Reserve enough space to add one element, and return the updated element
     434              :   /// pointer in case it was a reference to the storage.
     435              :   const T* reserveForParamAndGetAddress(const T& Elt, size_t N = 1) {
     436              :     return this->reserveForParamAndGetAddressImpl(this, Elt, N);
     437              :   }
     438              : 
     439              :   /// Reserve enough space to add one element, and return the updated element
     440              :   /// pointer in case it was a reference to the storage.
     441              :   T* reserveForParamAndGetAddress(T& Elt, size_t N = 1) {
     442              :     return const_cast<T*>(this->reserveForParamAndGetAddressImpl(this, Elt, N));
     443              :   }
     444              : 
     445              :   static T&& forward_value_param(T&& V) {
     446              :     return std::move(V);
     447              :   }
     448              :   static const T& forward_value_param(const T& V) {
     449              :     return V;
     450              :   }
     451              : 
     452              :   void growAndAssign(size_t NumElts, const T& Elt) {
     453              :     // Grow manually in case Elt is an internal reference.
     454              :     size_t NewCapacity = 0;
     455              :     T* NewElts = mallocForGrow(NumElts, NewCapacity);
     456              :     std::uninitialized_fill_n(NewElts, NumElts, Elt);
     457              :     this->destroy_range(this->begin(), this->end());
     458              :     takeAllocationForGrow(NewElts, NewCapacity);
     459              :     this->set_size(NumElts);
     460              :   }
     461              : 
     462              :   template <typename... ArgTypes>
     463              :   T& growAndEmplaceBack(ArgTypes&&... Args) {
     464              :     // Grow manually in case one of Args is an internal reference.
     465              :     size_t NewCapacity = 0;
     466              :     T* NewElts = mallocForGrow(0, NewCapacity);
     467              :     ::new ((void*)(NewElts + this->size())) T(std::forward<ArgTypes>(Args)...);
     468              :     moveElementsForGrow(NewElts);
     469              :     takeAllocationForGrow(NewElts, NewCapacity);
     470              :     this->set_size(this->size() + 1);
     471              :     return this->back();
     472              :   }
     473              : 
     474              :  public:
     475              :   void push_back(const T& Elt) {
     476              :     const T* EltPtr = reserveForParamAndGetAddress(Elt);
     477              :     ::new ((void*)this->end()) T(*EltPtr);
     478              :     this->set_size(this->size() + 1);
     479              :   }
     480              : 
     481              :   void push_back(T&& Elt) {
     482              :     T* EltPtr = reserveForParamAndGetAddress(Elt);
     483              :     ::new ((void*)this->end()) T(::std::move(*EltPtr));
     484              :     this->set_size(this->size() + 1);
     485              :   }
     486              : 
     487              :   void pop_back() {
     488              :     this->set_size(this->size() - 1);
     489              :     this->end()->~T();
     490              :   }
     491              : };
     492              : 
     493              : // Define this out-of-line to dissuade the C++ compiler from inlining it.
     494              : template <typename T, bool TriviallyCopyable>
     495              : void SmallVectorTemplateBase<T, TriviallyCopyable>::grow(size_t MinSize) {
     496              :   size_t NewCapacity = 0;
     497              :   T* NewElts = mallocForGrow(MinSize, NewCapacity);
     498              :   moveElementsForGrow(NewElts);
     499              :   takeAllocationForGrow(NewElts, NewCapacity);
     500              : }
     501              : 
     502              : // Define this out-of-line to dissuade the C++ compiler from inlining it.
     503              : template <typename T, bool TriviallyCopyable>
     504              : void SmallVectorTemplateBase<T, TriviallyCopyable>::moveElementsForGrow(
     505              :     T* NewElts) {
     506              :   // Move the elements over.
     507              :   this->uninitialized_move(this->begin(), this->end(), NewElts);
     508              : 
     509              :   // Destroy the original elements.
     510              :   destroy_range(this->begin(), this->end());
     511              : }
     512              : 
     513              : // Define this out-of-line to dissuade the C++ compiler from inlining it.
     514              : template <typename T, bool TriviallyCopyable>
     515              : void SmallVectorTemplateBase<T, TriviallyCopyable>::takeAllocationForGrow(
     516              :     T* NewElts,
     517              :     size_t NewCapacity) {
     518              :   // If this wasn't grown from the inline copy, deallocate the old space.
     519              :   if (!this->isSmall())
     520              :     free(this->begin());
     521              : 
     522              :   this->BeginX = NewElts;
     523              :   this->Capacity = NewCapacity;
     524              : }
     525              : 
     526              : /// SmallVectorTemplateBase<TriviallyCopyable = true> - This is where we put
     527              : /// method implementations that are designed to work with trivially copyable
     528              : /// T's. This allows using memcpy in place of copy/move construction and
     529              : /// skipping destruction.
     530              : template <typename T>
     531              : class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
     532              :   friend class SmallVectorTemplateCommon<T>;
     533              : 
     534              :  protected:
     535              :   /// True if it's cheap enough to take parameters by value. Doing so avoids
     536              :   /// overhead related to mitigations for reference invalidation.
     537              :   static constexpr bool TakesParamByValue = sizeof(T) <= 2 * sizeof(void*);
     538              : 
     539              :   /// Either const T& or T, depending on whether it's cheap enough to take
     540              :   /// parameters by value.
     541              :   using ValueParamT =
     542              :       typename std::conditional<TakesParamByValue, T, const T&>::type;
     543              : 
     544            0 :   SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
     545              : 
     546              :   // No need to do a destroy loop for POD's.
     547            0 :   static void destroy_range(T*, T*) {}
     548              : 
     549              :   /// Move the range [I, E) onto the uninitialized memory
     550              :   /// starting with "Dest", constructing elements into it as needed.
     551              :   template <typename It1, typename It2>
     552              :   static void uninitialized_move(It1 I, It1 E, It2 Dest) {
     553              :     // Just do a copy.
     554              :     uninitialized_copy(I, E, Dest);
     555              :   }
     556              : 
     557              :   /// Copy the range [I, E) onto the uninitialized memory
     558              :   /// starting with "Dest", constructing elements into it as needed.
     559              :   template <typename It1, typename It2>
     560              :   static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
     561              :     // Arbitrary iterator types; just use the basic implementation.
     562              :     std::uninitialized_copy(I, E, Dest);
     563              :   }
     564              : 
     565              :   /// Copy the range [I, E) onto the uninitialized memory
     566              :   /// starting with "Dest", constructing elements into it as needed.
     567              :   template <typename T1, typename T2>
     568              :   static void uninitialized_copy(
     569              :       T1* I,
     570              :       T1* E,
     571              :       T2* Dest,
     572              :       std::enable_if_t<
     573              :           std::is_same<typename std::remove_const<T1>::type, T2>::value>* =
     574              :           nullptr) {
     575              :     // Use memcpy for PODs iterated by pointers (which includes SmallVector
     576              :     // iterators): std::uninitialized_copy optimizes to memmove, but we can
     577              :     // use memcpy here. Note that I and E are iterators and thus might be
     578              :     // invalid for memcpy if they are equal.
     579              :     if (I != E)
     580              :       memcpy(reinterpret_cast<void*>(Dest), I, (E - I) * sizeof(T));
     581              :   }
     582              : 
     583              :   /// Double the size of the allocated memory, guaranteeing space for at
     584              :   /// least one more element or MinSize if specified.
     585            0 :   void grow(size_t MinSize = 0) {
     586            0 :     this->grow_pod(MinSize, sizeof(T));
     587            0 :   }
     588              : 
     589              :   /// Reserve enough space to add one element, and return the updated element
     590              :   /// pointer in case it was a reference to the storage.
     591              :   const T* reserveForParamAndGetAddress(const T& Elt, size_t N = 1) {
     592              :     return this->reserveForParamAndGetAddressImpl(this, Elt, N);
     593              :   }
     594              : 
     595              :   /// Reserve enough space to add one element, and return the updated element
     596              :   /// pointer in case it was a reference to the storage.
     597            0 :   T* reserveForParamAndGetAddress(T& Elt, size_t N = 1) {
     598            0 :     return const_cast<T*>(this->reserveForParamAndGetAddressImpl(this, Elt, N));
     599              :   }
     600              : 
     601              :   /// Copy \p V or return a reference, depending on \a ValueParamT.
     602              :   static ValueParamT forward_value_param(ValueParamT V) {
     603              :     return V;
     604              :   }
     605              : 
     606              :   void growAndAssign(size_t NumElts, T Elt) {
     607              :     // Elt has been copied in case it's an internal reference, side-stepping
     608              :     // reference invalidation problems without losing the realloc optimization.
     609              :     this->set_size(0);
     610              :     this->grow(NumElts);
     611              :     std::uninitialized_fill_n(this->begin(), NumElts, Elt);
     612              :     this->set_size(NumElts);
     613              :   }
     614              : 
     615              :   template <typename... ArgTypes>
     616              :   T& growAndEmplaceBack(ArgTypes&&... Args) {
     617              :     // Use push_back with a copy in case Args has an internal reference,
     618              :     // side-stepping reference invalidation problems without losing the realloc
     619              :     // optimization.
     620              :     push_back(T(std::forward<ArgTypes>(Args)...));
     621              :     return this->back();
     622              :   }
     623              : 
     624              :  public:
     625            0 :   void push_back(ValueParamT Elt) {
     626            0 :     const T* EltPtr = reserveForParamAndGetAddress(Elt);
     627            0 :     memcpy(reinterpret_cast<void*>(this->end()), EltPtr, sizeof(T));
     628            0 :     this->set_size(this->size() + 1);
     629            0 :   }
     630              : 
     631              :   void pop_back() {
     632              :     this->set_size(this->size() - 1);
     633              :   }
     634              : };
     635              : 
     636              : /// This class consists of common code factored out of the SmallVector class to
     637              : /// reduce code duplication based on the SmallVector 'N' template parameter.
     638              : template <typename T>
     639              : class SmallVectorImpl : public SmallVectorTemplateBase<T> {
     640              :   using SuperClass = SmallVectorTemplateBase<T>;
     641              : 
     642              :  public:
     643              :   using iterator = typename SuperClass::iterator;
     644              :   using const_iterator = typename SuperClass::const_iterator;
     645              :   using reference = typename SuperClass::reference;
     646              :   using size_type = typename SuperClass::size_type;
     647              : 
     648              :  protected:
     649              :   using SmallVectorTemplateBase<T>::TakesParamByValue;
     650              :   using ValueParamT = typename SuperClass::ValueParamT;
     651              : 
     652              :   // Default ctor - Initialize to empty.
     653            0 :   explicit SmallVectorImpl(unsigned N) : SmallVectorTemplateBase<T>(N) {}
     654              : 
     655              :  public:
     656              :   SmallVectorImpl(const SmallVectorImpl&) = delete;
     657              : 
     658            0 :   ~SmallVectorImpl() {
     659              :     // Subclass has already destructed this vector's elements.
     660              :     // If this wasn't grown from the inline copy, deallocate the old space.
     661            0 :     if (!this->isSmall())
     662            0 :       free(this->begin());
     663            0 :   }
     664              : 
     665              :   void clear() {
     666              :     this->destroy_range(this->begin(), this->end());
     667              :     this->Size = 0;
     668              :   }
     669              : 
     670              :  private:
     671              :   template <bool ForOverwrite>
     672              :   void resizeImpl(size_type N) {
     673              :     if (N < this->size()) {
     674              :       this->pop_back_n(this->size() - N);
     675              :     } else if (N > this->size()) {
     676              :       this->reserve(N);
     677              :       for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
     678              :         if (ForOverwrite)
     679              :           new (&*I) T;
     680              :         else
     681              :           new (&*I) T();
     682              :       this->set_size(N);
     683              :     }
     684              :   }
     685              : 
     686              :  public:
     687              :   void resize(size_type N) {
     688              :     resizeImpl<false>(N);
     689              :   }
     690              : 
     691              :   /// Like resize, but \ref T is POD, the new values won't be initialized.
     692              :   void resize_for_overwrite(size_type N) {
     693              :     resizeImpl<true>(N);
     694              :   }
     695              : 
     696              :   void resize(size_type N, ValueParamT NV) {
     697              :     if (N == this->size())
     698              :       return;
     699              : 
     700              :     if (N < this->size()) {
     701              :       this->pop_back_n(this->size() - N);
     702              :       return;
     703              :     }
     704              : 
     705              :     // N > this->size(). Defer to append.
     706              :     this->append(N - this->size(), NV);
     707              :   }
     708              : 
     709            0 :   void reserve(size_type N) {
     710            0 :     if (this->capacity() < N)
     711            0 :       this->grow(N);
     712            0 :   }
     713              : 
     714              :   void pop_back_n(size_type NumItems) {
     715              :     assert(this->size() >= NumItems);
     716              :     this->destroy_range(this->end() - NumItems, this->end());
     717              :     this->set_size(this->size() - NumItems);
     718              :   }
     719              : 
     720              :   C10_NODISCARD T pop_back_val() {
     721              :     T Result = ::std::move(this->back());
     722              :     this->pop_back();
     723              :     return Result;
     724              :   }
     725              : 
     726              :   void swap(SmallVectorImpl& RHS);
     727              : 
     728              :   /// Add the specified range to the end of the SmallVector.
     729              :   template <
     730              :       typename in_iter,
     731              :       typename = std::enable_if_t<std::is_convertible<
     732              :           typename std::iterator_traits<in_iter>::iterator_category,
     733              :           std::input_iterator_tag>::value>>
     734              :   void append(in_iter in_start, in_iter in_end) {
     735              :     this->assertSafeToAddRange(in_start, in_end);
     736              :     size_type NumInputs = std::distance(in_start, in_end);
     737              :     this->reserve(this->size() + NumInputs);
     738              :     this->uninitialized_copy(in_start, in_end, this->end());
     739              :     this->set_size(this->size() + NumInputs);
     740              :   }
     741              : 
     742              :   /// Append \p NumInputs copies of \p Elt to the end.
     743              :   void append(size_type NumInputs, ValueParamT Elt) {
     744              :     const T* EltPtr = this->reserveForParamAndGetAddress(Elt, NumInputs);
     745              :     std::uninitialized_fill_n(this->end(), NumInputs, *EltPtr);
     746              :     this->set_size(this->size() + NumInputs);
     747              :   }
     748              : 
     749              :   void append(std::initializer_list<T> IL) {
     750              :     append(IL.begin(), IL.end());
     751              :   }
     752              : 
     753              :   void append(const SmallVectorImpl& RHS) {
     754              :     append(RHS.begin(), RHS.end());
     755              :   }
     756              : 
     757              :   void assign(size_type NumElts, ValueParamT Elt) {
     758              :     // Note that Elt could be an internal reference.
     759              :     if (NumElts > this->capacity()) {
     760              :       this->growAndAssign(NumElts, Elt);
     761              :       return;
     762              :     }
     763              : 
     764              :     // Assign over existing elements.
     765              :     std::fill_n(this->begin(), std::min(NumElts, this->size()), Elt);
     766              :     if (NumElts > this->size())
     767              :       std::uninitialized_fill_n(this->end(), NumElts - this->size(), Elt);
     768              :     else if (NumElts < this->size())
     769              :       this->destroy_range(this->begin() + NumElts, this->end());
     770              :     this->set_size(NumElts);
     771              :   }
     772              : 
     773              :   // FIXME: Consider assigning over existing elements, rather than clearing &
     774              :   // re-initializing them - for all assign(...) variants.
     775              : 
     776              :   template <
     777              :       typename in_iter,
     778              :       typename = std::enable_if_t<std::is_convertible<
     779              :           typename std::iterator_traits<in_iter>::iterator_category,
     780              :           std::input_iterator_tag>::value>>
     781              :   void assign(in_iter in_start, in_iter in_end) {
     782              :     this->assertSafeToReferenceAfterClear(in_start, in_end);
     783              :     clear();
     784              :     append(in_start, in_end);
     785              :   }
     786              : 
     787              :   void assign(std::initializer_list<T> IL) {
     788              :     clear();
     789              :     append(IL);
     790              :   }
     791              : 
     792              :   void assign(const SmallVectorImpl& RHS) {
     793              :     assign(RHS.begin(), RHS.end());
     794              :   }
     795              : 
     796              :   iterator erase(const_iterator CI) {
     797              :     // Just cast away constness because this is a non-const member function.
     798              :     iterator I = const_cast<iterator>(CI);
     799              : 
     800              :     assert(
     801              :         this->isReferenceToStorage(CI) &&
     802              :         "Iterator to erase is out of bounds.");
     803              : 
     804              :     iterator N = I;
     805              :     // Shift all elts down one.
     806              :     std::move(I + 1, this->end(), I);
     807              :     // Drop the last elt.
     808              :     this->pop_back();
     809              :     return (N);
     810              :   }
     811              : 
     812              :   iterator erase(const_iterator CS, const_iterator CE) {
     813              :     // Just cast away constness because this is a non-const member function.
     814              :     iterator S = const_cast<iterator>(CS);
     815              :     iterator E = const_cast<iterator>(CE);
     816              : 
     817              :     assert(this->isRangeInStorage(S, E) && "Range to erase is out of bounds.");
     818              : 
     819              :     iterator N = S;
     820              :     // Shift all elts down.
     821              :     iterator I = std::move(E, this->end(), S);
     822              :     // Drop the last elts.
     823              :     this->destroy_range(I, this->end());
     824              :     this->set_size(I - this->begin());
     825              :     return (N);
     826              :   }
     827              : 
     828              :  private:
     829              :   template <class ArgType>
     830              :   iterator insert_one_impl(iterator I, ArgType&& Elt) {
     831              :     // Callers ensure that ArgType is derived from T.
     832              :     static_assert(
     833              :         std::is_same<std::remove_const_t<std::remove_reference_t<ArgType>>, T>::
     834              :             value,
     835              :         "ArgType must be derived from T!");
     836              : 
     837              :     if (I == this->end()) { // Important special case for empty vector.
     838              :       this->push_back(::std::forward<ArgType>(Elt));
     839              :       return this->end() - 1;
     840              :     }
     841              : 
     842              :     assert(
     843              :         this->isReferenceToStorage(I) &&
     844              :         "Insertion iterator is out of bounds.");
     845              : 
     846              :     // Grow if necessary.
     847              :     size_t Index = I - this->begin();
     848              :     std::remove_reference_t<ArgType>* EltPtr =
     849              :         this->reserveForParamAndGetAddress(Elt);
     850              :     I = this->begin() + Index;
     851              : 
     852              :     ::new ((void*)this->end()) T(::std::move(this->back()));
     853              :     // Push everything else over.
     854              :     std::move_backward(I, this->end() - 1, this->end());
     855              :     this->set_size(this->size() + 1);
     856              : 
     857              :     // If we just moved the element we're inserting, be sure to update
     858              :     // the reference (never happens if TakesParamByValue).
     859              :     static_assert(
     860              :         !TakesParamByValue || std::is_same<ArgType, T>::value,
     861              :         "ArgType must be 'T' when taking by value!");
     862              :     if (!TakesParamByValue && this->isReferenceToRange(EltPtr, I, this->end()))
     863              :       ++EltPtr;
     864              : 
     865              :     *I = ::std::forward<ArgType>(*EltPtr);
     866              :     return I;
     867              :   }
     868              : 
     869              :  public:
     870              :   iterator insert(iterator I, T&& Elt) {
     871              :     return insert_one_impl(I, this->forward_value_param(std::move(Elt)));
     872              :   }
     873              : 
     874              :   iterator insert(iterator I, const T& Elt) {
     875              :     return insert_one_impl(I, this->forward_value_param(Elt));
     876              :   }
     877              : 
     878              :   iterator insert(iterator I, size_type NumToInsert, ValueParamT Elt) {
     879              :     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
     880              :     size_t InsertElt = I - this->begin();
     881              : 
     882              :     if (I == this->end()) { // Important special case for empty vector.
     883              :       append(NumToInsert, Elt);
     884              :       return this->begin() + InsertElt;
     885              :     }
     886              : 
     887              :     assert(
     888              :         this->isReferenceToStorage(I) &&
     889              :         "Insertion iterator is out of bounds.");
     890              : 
     891              :     // Ensure there is enough space, and get the (maybe updated) address of
     892              :     // Elt.
     893              :     const T* EltPtr = this->reserveForParamAndGetAddress(Elt, NumToInsert);
     894              : 
     895              :     // Uninvalidate the iterator.
     896              :     I = this->begin() + InsertElt;
     897              : 
     898              :     // If there are more elements between the insertion point and the end of the
     899              :     // range than there are being inserted, we can use a simple approach to
     900              :     // insertion.  Since we already reserved space, we know that this won't
     901              :     // reallocate the vector.
     902              :     if (size_t(this->end() - I) >= NumToInsert) {
     903              :       T* OldEnd = this->end();
     904              :       append(
     905              :           std::move_iterator<iterator>(this->end() - NumToInsert),
     906              :           std::move_iterator<iterator>(this->end()));
     907              : 
     908              :       // Copy the existing elements that get replaced.
     909              :       std::move_backward(I, OldEnd - NumToInsert, OldEnd);
     910              : 
     911              :       // If we just moved the element we're inserting, be sure to update
     912              :       // the reference (never happens if TakesParamByValue).
     913              :       if (!TakesParamByValue && I <= EltPtr && EltPtr < this->end())
     914              :         EltPtr += NumToInsert;
     915              : 
     916              :       std::fill_n(I, NumToInsert, *EltPtr);
     917              :       return I;
     918              :     }
     919              : 
     920              :     // Otherwise, we're inserting more elements than exist already, and we're
     921              :     // not inserting at the end.
     922              : 
     923              :     // Move over the elements that we're about to overwrite.
     924              :     T* OldEnd = this->end();
     925              :     this->set_size(this->size() + NumToInsert);
     926              :     size_t NumOverwritten = OldEnd - I;
     927              :     this->uninitialized_move(I, OldEnd, this->end() - NumOverwritten);
     928              : 
     929              :     // If we just moved the element we're inserting, be sure to update
     930              :     // the reference (never happens if TakesParamByValue).
     931              :     if (!TakesParamByValue && I <= EltPtr && EltPtr < this->end())
     932              :       EltPtr += NumToInsert;
     933              : 
     934              :     // Replace the overwritten part.
     935              :     std::fill_n(I, NumOverwritten, *EltPtr);
     936              : 
     937              :     // Insert the non-overwritten middle part.
     938              :     std::uninitialized_fill_n(OldEnd, NumToInsert - NumOverwritten, *EltPtr);
     939              :     return I;
     940              :   }
     941              : 
     942              :   template <
     943              :       typename ItTy,
     944              :       typename = std::enable_if_t<std::is_convertible<
     945              :           typename std::iterator_traits<ItTy>::iterator_category,
     946              :           std::input_iterator_tag>::value>>
     947              :   iterator insert(iterator I, ItTy From, ItTy To) {
     948              :     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
     949              :     size_t InsertElt = I - this->begin();
     950              : 
     951              :     if (I == this->end()) { // Important special case for empty vector.
     952              :       append(From, To);
     953              :       return this->begin() + InsertElt;
     954              :     }
     955              : 
     956              :     assert(
     957              :         this->isReferenceToStorage(I) &&
     958              :         "Insertion iterator is out of bounds.");
     959              : 
     960              :     // Check that the reserve that follows doesn't invalidate the iterators.
     961              :     this->assertSafeToAddRange(From, To);
     962              : 
     963              :     size_t NumToInsert = std::distance(From, To);
     964              : 
     965              :     // Ensure there is enough space.
     966              :     reserve(this->size() + NumToInsert);
     967              : 
     968              :     // Uninvalidate the iterator.
     969              :     I = this->begin() + InsertElt;
     970              : 
     971              :     // If there are more elements between the insertion point and the end of the
     972              :     // range than there are being inserted, we can use a simple approach to
     973              :     // insertion.  Since we already reserved space, we know that this won't
     974              :     // reallocate the vector.
     975              :     if (size_t(this->end() - I) >= NumToInsert) {
     976              :       T* OldEnd = this->end();
     977              :       append(
     978              :           std::move_iterator<iterator>(this->end() - NumToInsert),
     979              :           std::move_iterator<iterator>(this->end()));
     980              : 
     981              :       // Copy the existing elements that get replaced.
     982              :       std::move_backward(I, OldEnd - NumToInsert, OldEnd);
     983              : 
     984              :       std::copy(From, To, I);
     985              :       return I;
     986              :     }
     987              : 
     988              :     // Otherwise, we're inserting more elements than exist already, and we're
     989              :     // not inserting at the end.
     990              : 
     991              :     // Move over the elements that we're about to overwrite.
     992              :     T* OldEnd = this->end();
     993              :     this->set_size(this->size() + NumToInsert);
     994              :     size_t NumOverwritten = OldEnd - I;
     995              :     this->uninitialized_move(I, OldEnd, this->end() - NumOverwritten);
     996              : 
     997              :     // Replace the overwritten part.
     998              :     for (T* J = I; NumOverwritten > 0; --NumOverwritten) {
     999              :       *J = *From;
    1000              :       ++J;
    1001              :       ++From;
    1002              :     }
    1003              : 
    1004              :     // Insert the non-overwritten middle part.
    1005              :     this->uninitialized_copy(From, To, OldEnd);
    1006              :     return I;
    1007              :   }
    1008              : 
    1009              :   void insert(iterator I, std::initializer_list<T> IL) {
    1010              :     insert(I, IL.begin(), IL.end());
    1011              :   }
    1012              : 
    1013              :   template <typename... ArgTypes>
    1014              :   reference emplace_back(ArgTypes&&... Args) {
    1015              :     if (C10_UNLIKELY(this->size() >= this->capacity()))
    1016              :       return this->growAndEmplaceBack(std::forward<ArgTypes>(Args)...);
    1017              : 
    1018              :     ::new ((void*)this->end()) T(std::forward<ArgTypes>(Args)...);
    1019              :     this->set_size(this->size() + 1);
    1020              :     return this->back();
    1021              :   }
    1022              : 
    1023              :   SmallVectorImpl& operator=(const SmallVectorImpl& RHS);
    1024              : 
    1025              :   SmallVectorImpl& operator=(SmallVectorImpl&& RHS);
    1026              : 
    1027              :   bool operator==(const SmallVectorImpl& RHS) const {
    1028              :     if (this->size() != RHS.size())
    1029              :       return false;
    1030              :     return std::equal(this->begin(), this->end(), RHS.begin());
    1031              :   }
    1032              :   bool operator!=(const SmallVectorImpl& RHS) const {
    1033              :     return !(*this == RHS);
    1034              :   }
    1035              : 
    1036              :   bool operator<(const SmallVectorImpl& RHS) const {
    1037              :     return std::lexicographical_compare(
    1038              :         this->begin(), this->end(), RHS.begin(), RHS.end());
    1039              :   }
    1040              : };
    1041              : 
    1042              : template <typename T>
    1043              : void SmallVectorImpl<T>::swap(SmallVectorImpl<T>& RHS) {
    1044              :   if (this == &RHS)
    1045              :     return;
    1046              : 
    1047              :   // We can only avoid copying elements if neither vector is small.
    1048              :   if (!this->isSmall() && !RHS.isSmall()) {
    1049              :     std::swap(this->BeginX, RHS.BeginX);
    1050              :     std::swap(this->Size, RHS.Size);
    1051              :     std::swap(this->Capacity, RHS.Capacity);
    1052              :     return;
    1053              :   }
    1054              :   this->reserve(RHS.size());
    1055              :   RHS.reserve(this->size());
    1056              : 
    1057              :   // Swap the shared elements.
    1058              :   size_t NumShared = this->size();
    1059              :   if (NumShared > RHS.size())
    1060              :     NumShared = RHS.size();
    1061              :   for (size_type i = 0; i != NumShared; ++i)
    1062              :     std::swap((*this)[i], RHS[i]);
    1063              : 
    1064              :   // Copy over the extra elts.
    1065              :   if (this->size() > RHS.size()) {
    1066              :     size_t EltDiff = this->size() - RHS.size();
    1067              :     this->uninitialized_copy(this->begin() + NumShared, this->end(), RHS.end());
    1068              :     RHS.set_size(RHS.size() + EltDiff);
    1069              :     this->destroy_range(this->begin() + NumShared, this->end());
    1070              :     this->set_size(NumShared);
    1071              :   } else if (RHS.size() > this->size()) {
    1072              :     size_t EltDiff = RHS.size() - this->size();
    1073              :     this->uninitialized_copy(RHS.begin() + NumShared, RHS.end(), this->end());
    1074              :     this->set_size(this->size() + EltDiff);
    1075              :     this->destroy_range(RHS.begin() + NumShared, RHS.end());
    1076              :     RHS.set_size(NumShared);
    1077              :   }
    1078              : }
    1079              : 
    1080              : template <typename T>
    1081              : SmallVectorImpl<T>& SmallVectorImpl<T>::operator=(
    1082              :     const SmallVectorImpl<T>& RHS) {
    1083              :   // Avoid self-assignment.
    1084              :   if (this == &RHS)
    1085              :     return *this;
    1086              : 
    1087              :   // If we already have sufficient space, assign the common elements, then
    1088              :   // destroy any excess.
    1089              :   size_t RHSSize = RHS.size();
    1090              :   size_t CurSize = this->size();
    1091              :   if (CurSize >= RHSSize) {
    1092              :     // Assign common elements.
    1093              :     iterator NewEnd;
    1094              :     if (RHSSize)
    1095              :       NewEnd = std::copy(RHS.begin(), RHS.begin() + RHSSize, this->begin());
    1096              :     else
    1097              :       NewEnd = this->begin();
    1098              : 
    1099              :     // Destroy excess elements.
    1100              :     this->destroy_range(NewEnd, this->end());
    1101              : 
    1102              :     // Trim.
    1103              :     this->set_size(RHSSize);
    1104              :     return *this;
    1105              :   }
    1106              : 
    1107              :   // If we have to grow to have enough elements, destroy the current elements.
    1108              :   // This allows us to avoid copying them during the grow.
    1109              :   // FIXME: don't do this if they're efficiently moveable.
    1110              :   if (this->capacity() < RHSSize) {
    1111              :     // Destroy current elements.
    1112              :     this->clear();
    1113              :     CurSize = 0;
    1114              :     this->grow(RHSSize);
    1115              :   } else if (CurSize) {
    1116              :     // Otherwise, use assignment for the already-constructed elements.
    1117              :     std::copy(RHS.begin(), RHS.begin() + CurSize, this->begin());
    1118              :   }
    1119              : 
    1120              :   // Copy construct the new elements in place.
    1121              :   this->uninitialized_copy(
    1122              :       RHS.begin() + CurSize, RHS.end(), this->begin() + CurSize);
    1123              : 
    1124              :   // Set end.
    1125              :   this->set_size(RHSSize);
    1126              :   return *this;
    1127              : }
    1128              : 
    1129              : template <typename T>
    1130              : SmallVectorImpl<T>& SmallVectorImpl<T>::operator=(SmallVectorImpl<T>&& RHS) {
    1131              :   // Avoid self-assignment.
    1132              :   if (this == &RHS)
    1133              :     return *this;
    1134              : 
    1135              :   // If the RHS isn't small, clear this vector and then steal its buffer.
    1136              :   if (!RHS.isSmall()) {
    1137              :     this->destroy_range(this->begin(), this->end());
    1138              :     if (!this->isSmall())
    1139              :       free(this->begin());
    1140              :     this->BeginX = RHS.BeginX;
    1141              :     this->Size = RHS.Size;
    1142              :     this->Capacity = RHS.Capacity;
    1143              :     RHS.resetToSmall();
    1144              :     return *this;
    1145              :   }
    1146              : 
    1147              :   // If we already have sufficient space, assign the common elements, then
    1148              :   // destroy any excess.
    1149              :   size_t RHSSize = RHS.size();
    1150              :   size_t CurSize = this->size();
    1151              :   if (CurSize >= RHSSize) {
    1152              :     // Assign common elements.
    1153              :     iterator NewEnd = this->begin();
    1154              :     if (RHSSize)
    1155              :       NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
    1156              : 
    1157              :     // Destroy excess elements and trim the bounds.
    1158              :     this->destroy_range(NewEnd, this->end());
    1159              :     this->set_size(RHSSize);
    1160              : 
    1161              :     // Clear the RHS.
    1162              :     RHS.clear();
    1163              : 
    1164              :     return *this;
    1165              :   }
    1166              : 
    1167              :   // If we have to grow to have enough elements, destroy the current elements.
    1168              :   // This allows us to avoid copying them during the grow.
    1169              :   // FIXME: this may not actually make any sense if we can efficiently move
    1170              :   // elements.
    1171              :   if (this->capacity() < RHSSize) {
    1172              :     // Destroy current elements.
    1173              :     this->clear();
    1174              :     CurSize = 0;
    1175              :     this->grow(RHSSize);
    1176              :   } else if (CurSize) {
    1177              :     // Otherwise, use assignment for the already-constructed elements.
    1178              :     std::move(RHS.begin(), RHS.begin() + CurSize, this->begin());
    1179              :   }
    1180              : 
    1181              :   // Move-construct the new elements in place.
    1182              :   this->uninitialized_move(
    1183              :       RHS.begin() + CurSize, RHS.end(), this->begin() + CurSize);
    1184              : 
    1185              :   // Set end.
    1186              :   this->set_size(RHSSize);
    1187              : 
    1188              :   RHS.clear();
    1189              :   return *this;
    1190              : }
    1191              : 
    1192              : /// Storage for the SmallVector elements.  This is specialized for the N=0 case
    1193              : /// to avoid allocating unnecessary storage.
    1194              : template <typename T, unsigned N>
    1195              : struct SmallVectorStorage {
    1196              :   alignas(T) char InlineElts[N * sizeof(T)];
    1197              : };
    1198              : 
    1199              : /// We need the storage to be properly aligned even for small-size of 0 so that
    1200              : /// the pointer math in \a SmallVectorTemplateCommon::getFirstEl() is
    1201              : /// well-defined.
    1202              : template <typename T>
    1203              : struct alignas(T) SmallVectorStorage<T, 0> {};
    1204              : 
    1205              : /// Forward declaration of SmallVector so that
    1206              : /// calculateSmallVectorDefaultInlinedElements can reference
    1207              : /// `sizeof(SmallVector<T, 0>)`.
    1208              : template <typename T, unsigned N>
    1209              : class /* LLVM_GSL_OWNER */ SmallVector;
    1210              : 
    1211              : /// Helper class for calculating the default number of inline elements for
    1212              : /// `SmallVector<T>`.
    1213              : ///
    1214              : /// This should be migrated to a constexpr function when our minimum
    1215              : /// compiler support is enough for multi-statement constexpr functions.
    1216              : template <typename T>
    1217              : struct CalculateSmallVectorDefaultInlinedElements {
    1218              :   // Parameter controlling the default number of inlined elements
    1219              :   // for `SmallVector<T>`.
    1220              :   //
    1221              :   // The default number of inlined elements ensures that
    1222              :   // 1. There is at least one inlined element.
    1223              :   // 2. `sizeof(SmallVector<T>) <= kPreferredSmallVectorSizeof` unless
    1224              :   // it contradicts 1.
    1225              :   static constexpr size_t kPreferredSmallVectorSizeof = 64;
    1226              : 
    1227              :   // static_assert that sizeof(T) is not "too big".
    1228              :   //
    1229              :   // Because our policy guarantees at least one inlined element, it is possible
    1230              :   // for an arbitrarily large inlined element to allocate an arbitrarily large
    1231              :   // amount of inline storage. We generally consider it an antipattern for a
    1232              :   // SmallVector to allocate an excessive amount of inline storage, so we want
    1233              :   // to call attention to these cases and make sure that users are making an
    1234              :   // intentional decision if they request a lot of inline storage.
    1235              :   //
    1236              :   // We want this assertion to trigger in pathological cases, but otherwise
    1237              :   // not be too easy to hit. To accomplish that, the cutoff is actually somewhat
    1238              :   // larger than kPreferredSmallVectorSizeof (otherwise,
    1239              :   // `SmallVector<SmallVector<T>>` would be one easy way to trip it, and that
    1240              :   // pattern seems useful in practice).
    1241              :   //
    1242              :   // One wrinkle is that this assertion is in theory non-portable, since
    1243              :   // sizeof(T) is in general platform-dependent. However, we don't expect this
    1244              :   // to be much of an issue, because most LLVM development happens on 64-bit
    1245              :   // hosts, and therefore sizeof(T) is expected to *decrease* when compiled for
    1246              :   // 32-bit hosts, dodging the issue. The reverse situation, where development
    1247              :   // happens on a 32-bit host and then fails due to sizeof(T) *increasing* on a
    1248              :   // 64-bit host, is expected to be very rare.
    1249              :   static_assert(
    1250              :       sizeof(T) <= 256,
    1251              :       "You are trying to use a default number of inlined elements for "
    1252              :       "`SmallVector<T>` but `sizeof(T)` is really big! Please use an "
    1253              :       "explicit number of inlined elements with `SmallVector<T, N>` to make "
    1254              :       "sure you really want that much inline storage.");
    1255              : 
    1256              :   // Discount the size of the header itself when calculating the maximum inline
    1257              :   // bytes.
    1258              :   static constexpr size_t PreferredInlineBytes =
    1259              :       kPreferredSmallVectorSizeof - sizeof(SmallVector<T, 0>);
    1260              :   static constexpr size_t NumElementsThatFit = PreferredInlineBytes / sizeof(T);
    1261              :   static constexpr size_t value =
    1262              :       NumElementsThatFit == 0 ? 1 : NumElementsThatFit;
    1263              : };
    1264              : 
    1265              : /// This is a 'vector' (really, a variable-sized array), optimized
    1266              : /// for the case when the array is small.  It contains some number of elements
    1267              : /// in-place, which allows it to avoid heap allocation when the actual number of
    1268              : /// elements is below that threshold.  This allows normal "small" cases to be
    1269              : /// fast without losing generality for large inputs.
    1270              : ///
    1271              : /// \note
    1272              : /// In the absence of a well-motivated choice for the number of inlined
    1273              : /// elements \p N, it is recommended to use \c SmallVector<T> (that is,
    1274              : /// omitting the \p N). This will choose a default number of inlined elements
    1275              : /// reasonable for allocation on the stack (for example, trying to keep \c
    1276              : /// sizeof(SmallVector<T>) around 64 bytes).
    1277              : ///
    1278              : /// \warning This does not attempt to be exception safe.
    1279              : ///
    1280              : /// \see https://llvm.org/docs/ProgrammersManual.html#llvm-adt-smallvector-h
    1281              : template <
    1282              :     typename T,
    1283              :     unsigned N = CalculateSmallVectorDefaultInlinedElements<T>::value>
    1284              : class /* LLVM_GSL_OWNER */ SmallVector : public SmallVectorImpl<T>,
    1285              :                                          SmallVectorStorage<T, N> {
    1286              :  public:
    1287            0 :   SmallVector() : SmallVectorImpl<T>(N) {}
    1288              : 
    1289            0 :   ~SmallVector() {
    1290              :     // Destroy the constructed elements in the vector.
    1291            0 :     this->destroy_range(this->begin(), this->end());
    1292            0 :   }
    1293              : 
    1294              :   explicit SmallVector(size_t Size, const T& Value = T())
    1295              :       : SmallVectorImpl<T>(N) {
    1296              :     this->assign(Size, Value);
    1297              :   }
    1298              : 
    1299              :   template <
    1300              :       typename ItTy,
    1301              :       typename = std::enable_if_t<std::is_convertible<
    1302              :           typename std::iterator_traits<ItTy>::iterator_category,
    1303              :           std::input_iterator_tag>::value>>
    1304              :   SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
    1305              :     this->append(S, E);
    1306              :   }
    1307              : 
    1308              :   // note: The enable_if restricts Container to types that have a .begin() and
    1309              :   // .end() that return valid input iterators.
    1310              :   template <
    1311              :       typename Container,
    1312              :       std::enable_if_t<
    1313              :           std::is_convertible<
    1314              :               typename std::iterator_traits<
    1315              :                   decltype(std::declval<Container>()
    1316              :                                .begin())>::iterator_category,
    1317              :               std::input_iterator_tag>::value &&
    1318              :               std::is_convertible<
    1319              :                   typename std::iterator_traits<
    1320              :                       decltype(std::declval<Container>()
    1321              :                                    .end())>::iterator_category,
    1322              :                   std::input_iterator_tag>::value,
    1323              :           int> = 0>
    1324              :   explicit SmallVector(Container&& c) : SmallVectorImpl<T>(N) {
    1325              :     this->append(c.begin(), c.end());
    1326              :   }
    1327              : 
    1328              :   SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
    1329              :     this->assign(IL);
    1330              :   }
    1331              : 
    1332              :   SmallVector(const SmallVector& RHS) : SmallVectorImpl<T>(N) {
    1333              :     if (!RHS.empty())
    1334              :       SmallVectorImpl<T>::operator=(RHS);
    1335              :   }
    1336              : 
    1337              :   SmallVector& operator=(const SmallVector& RHS) {
    1338              :     SmallVectorImpl<T>::operator=(RHS);
    1339              :     return *this;
    1340              :   }
    1341              : 
    1342              :   SmallVector(SmallVector&& RHS) : SmallVectorImpl<T>(N) {
    1343              :     if (!RHS.empty())
    1344              :       SmallVectorImpl<T>::operator=(::std::move(RHS));
    1345              :   }
    1346              : 
    1347              :   // note: The enable_if restricts Container to types that have a .begin() and
    1348              :   // .end() that return valid input iterators.
    1349              :   template <
    1350              :       typename Container,
    1351              :       std::enable_if_t<
    1352              :           std::is_convertible<
    1353              :               typename std::iterator_traits<
    1354              :                   decltype(std::declval<Container>()
    1355              :                                .begin())>::iterator_category,
    1356              :               std::input_iterator_tag>::value &&
    1357              :               std::is_convertible<
    1358              :                   typename std::iterator_traits<
    1359              :                       decltype(std::declval<Container>()
    1360              :                                    .end())>::iterator_category,
    1361              :                   std::input_iterator_tag>::value,
    1362              :           int> = 0>
    1363              :   const SmallVector& operator=(const Container& RHS) {
    1364              :     this->assign(RHS.begin(), RHS.end());
    1365              :     return *this;
    1366              :   }
    1367              : 
    1368              :   SmallVector(SmallVectorImpl<T>&& RHS) : SmallVectorImpl<T>(N) {
    1369              :     if (!RHS.empty())
    1370              :       SmallVectorImpl<T>::operator=(::std::move(RHS));
    1371              :   }
    1372              : 
    1373              :   SmallVector& operator=(SmallVector&& RHS) {
    1374              :     SmallVectorImpl<T>::operator=(::std::move(RHS));
    1375              :     return *this;
    1376              :   }
    1377              : 
    1378              :   SmallVector& operator=(SmallVectorImpl<T>&& RHS) {
    1379              :     SmallVectorImpl<T>::operator=(::std::move(RHS));
    1380              :     return *this;
    1381              :   }
    1382              : 
    1383              :   // note: The enable_if restricts Container to types that have a .begin() and
    1384              :   // .end() that return valid input iterators.
    1385              :   template <
    1386              :       typename Container,
    1387              :       std::enable_if_t<
    1388              :           std::is_convertible<
    1389              :               typename std::iterator_traits<
    1390              :                   decltype(std::declval<Container>()
    1391              :                                .begin())>::iterator_category,
    1392              :               std::input_iterator_tag>::value &&
    1393              :               std::is_convertible<
    1394              :                   typename std::iterator_traits<
    1395              :                       decltype(std::declval<Container>()
    1396              :                                    .end())>::iterator_category,
    1397              :                   std::input_iterator_tag>::value,
    1398              :           int> = 0>
    1399              :   const SmallVector& operator=(Container&& C) {
    1400              :     this->assign(C.begin(), C.end());
    1401              :     return *this;
    1402              :   }
    1403              : 
    1404              :   SmallVector& operator=(std::initializer_list<T> IL) {
    1405              :     this->assign(IL);
    1406              :     return *this;
    1407              :   }
    1408              : };
    1409              : 
    1410              : template <typename T, unsigned N>
    1411              : inline size_t capacity_in_bytes(const SmallVector<T, N>& X) {
    1412              :   return X.capacity_in_bytes();
    1413              : }
    1414              : 
    1415              : template <typename T, unsigned N>
    1416              : std::ostream& operator<<(std::ostream& out, const SmallVector<T, N>& list) {
    1417              :   int i = 0;
    1418              :   out << "[";
    1419              :   for (auto e : list) {
    1420              :     if (i++ > 0)
    1421              :       out << ", ";
    1422              :     out << e;
    1423              :   }
    1424              :   out << "]";
    1425              :   return out;
    1426              : }
    1427              : 
    1428              : template <typename RangeType>
    1429              : using ValueTypeFromRangeType =
    1430              :     typename std::remove_const<typename std::remove_reference<
    1431              :         decltype(*std::begin(std::declval<RangeType&>()))>::type>::type;
    1432              : 
    1433              : /// Given a range of type R, iterate the entire range and return a
    1434              : /// SmallVector with elements of the vector.  This is useful, for example,
    1435              : /// when you want to iterate a range and then sort the results.
    1436              : template <unsigned Size, typename R>
    1437              : SmallVector<ValueTypeFromRangeType<R>, Size> to_vector(R&& Range) {
    1438              :   return {std::begin(Range), std::end(Range)};
    1439              : }
    1440              : template <typename R>
    1441              : SmallVector<
    1442              :     ValueTypeFromRangeType<R>,
    1443              :     CalculateSmallVectorDefaultInlinedElements<
    1444              :         ValueTypeFromRangeType<R>>::value>
    1445              : to_vector(R&& Range) {
    1446              :   return {std::begin(Range), std::end(Range)};
    1447              : }
    1448              : 
    1449              : } // end namespace c10
    1450              : 
    1451              : namespace std {
    1452              : 
    1453              : /// Implement std::swap in terms of SmallVector swap.
    1454              : template <typename T>
    1455              : inline void swap(c10::SmallVectorImpl<T>& LHS, c10::SmallVectorImpl<T>& RHS) {
    1456              :   LHS.swap(RHS);
    1457              : }
    1458              : 
    1459              : /// Implement std::swap in terms of SmallVector swap.
    1460              : template <typename T, unsigned N>
    1461              : inline void swap(c10::SmallVector<T, N>& LHS, c10::SmallVector<T, N>& RHS) {
    1462              :   LHS.swap(RHS);
    1463              : }
    1464              : 
    1465              : } // end namespace std
    1466              : 
    1467              : C10_CLANG_DIAGNOSTIC_POP()
        

Generated by: LCOV version 2.0-1

</html>