GCC extensions are no longer used here - update the comment.
[oota-llvm.git] / include / llvm / ADT / SmallVector.h
index 0e076c8beb8f1fd7aab701b668c8ff0b268ae2e8..10ae049ff91fc2d3c9c95a56c31aff5a8b04984f 100644 (file)
@@ -17,6 +17,8 @@
 #include "llvm/Support/type_traits.h"
 #include <algorithm>
 #include <cassert>
+#include <cstddef>
+#include <cstdlib>
 #include <cstring>
 #include <memory>
 
@@ -55,67 +57,44 @@ protected:
   // Allocate raw space for N elements of type T.  If T has a ctor or dtor, we
   // don't want it to be automatically run, so we need to represent the space as
   // something else.  An array of char would work great, but might not be
-  // aligned sufficiently.  Instead, we either use GCC extensions, or some
-  // number of union instances for the space, which guarantee maximal alignment.
-#ifdef __GNUC__
-  typedef char U;
-  U FirstEl __attribute__((aligned));
-#else
+  // aligned sufficiently.  Instead we use some number of union instances for
+  // the space, which guarantee maximal alignment.
   union U {
     double D;
     long double LD;
     long long L;
     void *P;
   } FirstEl;
-#endif
   // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
-  
+
 protected:
   SmallVectorBase(size_t Size)
     : BeginX(&FirstEl), EndX(&FirstEl), CapacityX((char*)&FirstEl+Size) {}
-  
+
   /// isSmall - Return true if this is a smallvector which has not had dynamic
   /// memory allocated for it.
   bool isSmall() const {
     return BeginX == static_cast<const void*>(&FirstEl);
   }
-  
+
   /// size_in_bytes - This returns size()*sizeof(T).
   size_t size_in_bytes() const {
     return size_t((char*)EndX - (char*)BeginX);
   }
-  
+
   /// capacity_in_bytes - This returns capacity()*sizeof(T).
   size_t capacity_in_bytes() const {
     return size_t((char*)CapacityX - (char*)BeginX);
   }
-  
-  inline void grow_pod(size_t MinSizeInBytes, size_t TSize);
-  
+
+  /// grow_pod - This is an implementation of the grow() method which only works
+  /// on POD-like datatypes and is out of line to reduce code duplication.
+  void grow_pod(size_t MinSizeInBytes, size_t TSize);
+
 public:
   bool empty() const { return BeginX == EndX; }
 };
-  
-inline void SmallVectorBase::grow_pod(size_t MinSizeInBytes, size_t TSize) {
-  size_t CurSizeBytes = size_in_bytes();
-  size_t NewCapacityInBytes = 2 * capacity_in_bytes();
-  if (NewCapacityInBytes < MinSizeInBytes)
-    NewCapacityInBytes = MinSizeInBytes;
-  void *NewElts = operator new(NewCapacityInBytes);
-  
-  // Copy the elements over.
-  memcpy(NewElts, this->BeginX, CurSizeBytes);
-  
-  // If this wasn't grown from the inline copy, deallocate the old space.
-  if (!this->isSmall())
-    operator delete(this->BeginX);
-  
-  this->EndX = (char*)NewElts+CurSizeBytes;
-  this->BeginX = NewElts;
-  this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
-}
 
-  
 
 template <typename T>
 class SmallVectorTemplateCommon : public SmallVectorBase {
@@ -123,21 +102,21 @@ protected:
   void setEnd(T *P) { this->EndX = P; }
 public:
   SmallVectorTemplateCommon(size_t Size) : SmallVectorBase(Size) {}
-  
+
   typedef size_t size_type;
   typedef ptrdiff_t difference_type;
   typedef T value_type;
   typedef T *iterator;
   typedef const T *const_iterator;
-  
+
   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
   typedef std::reverse_iterator<iterator> reverse_iterator;
-  
+
   typedef T &reference;
   typedef const T &const_reference;
   typedef T *pointer;
   typedef const T *const_pointer;
-  
+
   // forward iterator creation methods.
   iterator begin() { return (iterator)this->BeginX; }
   const_iterator begin() const { return (const_iterator)this->BeginX; }
@@ -147,7 +126,7 @@ protected:
   iterator capacity_ptr() { return (iterator)this->CapacityX; }
   const_iterator capacity_ptr() const { return (const_iterator)this->CapacityX;}
 public:
-  
+
   // reverse iterator creation methods.
   reverse_iterator rbegin()            { return reverse_iterator(end()); }
   const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
@@ -156,16 +135,16 @@ public:
 
   size_type size() const { return end()-begin(); }
   size_type max_size() const { return size_type(-1) / sizeof(T); }
-  
+
   /// capacity - Return the total number of elements in the currently allocated
   /// buffer.
   size_t capacity() const { return capacity_ptr() - begin(); }
-  
+
   /// data - Return a pointer to the vector's buffer, even if empty().
   pointer data() { return pointer(begin()); }
   /// data - Return a pointer to the vector's buffer, even if empty().
   const_pointer data() const { return const_pointer(begin()); }
-  
+
   reference operator[](unsigned idx) {
     assert(begin() + idx < end());
     return begin()[idx];
@@ -189,7 +168,7 @@ public:
     return end()[-1];
   }
 };
-  
+
 /// SmallVectorTemplateBase<isPodLike = false> - This is where we put method
 /// implementations that are designed to work with non-POD-like T's.
 template <typename T, bool isPodLike>
@@ -203,14 +182,14 @@ public:
       E->~T();
     }
   }
-  
+
   /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
   /// starting with "Dest", constructing elements into it as needed.
   template<typename It1, typename It2>
   static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
     std::uninitialized_copy(I, E, Dest);
   }
-  
+
   /// grow - double the size of the allocated memory, guaranteeing space for at
   /// least one more element or MinSize if specified.
   void grow(size_t MinSize = 0);
@@ -221,81 +200,92 @@ template <typename T, bool isPodLike>
 void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
   size_t CurCapacity = this->capacity();
   size_t CurSize = this->size();
-  size_t NewCapacity = 2*CurCapacity;
+  size_t NewCapacity = 2*CurCapacity + 1; // Always grow, even from zero.
   if (NewCapacity < MinSize)
     NewCapacity = MinSize;
-  T *NewElts = static_cast<T*>(operator new(NewCapacity*sizeof(T)));
-  
+  T *NewElts = static_cast<T*>(malloc(NewCapacity*sizeof(T)));
+
   // Copy the elements over.
-  uninitialized_copy(this->begin(), this->end(), NewElts);
-  
+  this->uninitialized_copy(this->begin(), this->end(), NewElts);
+
   // Destroy the original elements.
   destroy_range(this->begin(), this->end());
-  
+
   // If this wasn't grown from the inline copy, deallocate the old space.
   if (!this->isSmall())
-    operator delete(this->begin());
-  
-  setEnd(NewElts+CurSize);
+    free(this->begin());
+
+  this->setEnd(NewElts+CurSize);
   this->BeginX = NewElts;
   this->CapacityX = this->begin()+NewCapacity;
 }
-  
-  
+
+
 /// SmallVectorTemplateBase<isPodLike = true> - This is where we put method
 /// implementations that are designed to work with POD-like T's.
 template <typename T>
 class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
 public:
   SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
-  
+
   // No need to do a destroy loop for POD's.
-  static void destroy_range(T *S, T *E) {}
-  
+  static void destroy_range(T *, T *) {}
+
   /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
   /// starting with "Dest", constructing elements into it as needed.
   template<typename It1, typename It2>
   static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
-    // Use memcpy for PODs: std::uninitialized_copy optimizes to memmove, memcpy
-    // is better.
-    memcpy(&*Dest, &*I, (E-I)*sizeof(T));
+    // Arbitrary iterator types; just use the basic implementation.
+    std::uninitialized_copy(I, E, Dest);
   }
-  
+
+  /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
+  /// starting with "Dest", constructing elements into it as needed.
+  template<typename T1, typename T2>
+  static void uninitialized_copy(T1 *I, T1 *E, T2 *Dest) {
+    // Use memcpy for PODs iterated by pointers (which includes SmallVector
+    // iterators): std::uninitialized_copy optimizes to memmove, but we can
+    // use memcpy here.
+    memcpy(Dest, I, (E-I)*sizeof(T));
+  }
+
   /// grow - double the size of the allocated memory, guaranteeing space for at
   /// least one more element or MinSize if specified.
   void grow(size_t MinSize = 0) {
     this->grow_pod(MinSize*sizeof(T), sizeof(T));
   }
 };
-  
-  
+
+
 /// SmallVectorImpl - This class consists of common code factored out of the
 /// SmallVector class to reduce code duplication based on the SmallVector 'N'
 /// template parameter.
 template <typename T>
 class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
   typedef SmallVectorTemplateBase<T, isPodLike<T>::value > SuperClass;
+  
+  SmallVectorImpl(const SmallVectorImpl&); // DISABLED.
 public:
   typedef typename SuperClass::iterator iterator;
   typedef typename SuperClass::size_type size_type;
-  
+
   // Default ctor - Initialize to empty.
   explicit SmallVectorImpl(unsigned N)
     : SmallVectorTemplateBase<T, isPodLike<T>::value>(N*sizeof(T)) {
   }
-  
+
   ~SmallVectorImpl() {
     // Destroy the constructed elements in the vector.
-    destroy_range(this->begin(), this->end());
-    
+    this->destroy_range(this->begin(), this->end());
+
     // If this wasn't grown from the inline copy, deallocate the old space.
     if (!this->isSmall())
-      operator delete(this->begin());
+      free(this->begin());
   }
-  
-  
+
+
   void clear() {
-    destroy_range(this->begin(), this->end());
+    this->destroy_range(this->begin(), this->end());
     this->EndX = this->BeginX;
   }
 
@@ -313,13 +303,13 @@ public:
 
   void resize(unsigned N, const T &NV) {
     if (N < this->size()) {
-      destroy_range(this->begin()+N, this->end());
-      setEnd(this->begin()+N);
+      this->destroy_range(this->begin()+N, this->end());
+      this->setEnd(this->begin()+N);
     } else if (N > this->size()) {
       if (this->capacity() < N)
         this->grow(N);
       construct_range(this->end(), this->begin()+N, NV);
-      setEnd(this->begin()+N);
+      this->setEnd(this->begin()+N);
     }
   }
 
@@ -327,32 +317,32 @@ public:
     if (this->capacity() < N)
       this->grow(N);
   }
-  
+
   void push_back(const T &Elt) {
     if (this->EndX < this->CapacityX) {
     Retry:
       new (this->end()) T(Elt);
-      setEnd(this->end()+1);
+      this->setEnd(this->end()+1);
       return;
     }
     this->grow();
     goto Retry;
   }
-  
+
   void pop_back() {
-    setEnd(this->end()-1);
+    this->setEnd(this->end()-1);
     this->end()->~T();
   }
-  
+
   T pop_back_val() {
     T Result = this->back();
     pop_back();
     return Result;
   }
-  
-  
+
+
   void swap(SmallVectorImpl &RHS);
-  
+
   /// append - Add the specified range to the end of the SmallVector.
   ///
   template<typename in_iter>
@@ -361,34 +351,34 @@ public:
     // Grow allocated space if needed.
     if (NumInputs > size_type(this->capacity_ptr()-this->end()))
       this->grow(this->size()+NumInputs);
-    
+
     // Copy the new elements over.
     // TODO: NEED To compile time dispatch on whether in_iter is a random access
     // iterator to use the fast uninitialized_copy.
     std::uninitialized_copy(in_start, in_end, this->end());
-    setEnd(this->end() + NumInputs);
+    this->setEnd(this->end() + NumInputs);
   }
-  
+
   /// append - Add the specified range to the end of the SmallVector.
   ///
   void append(size_type NumInputs, const T &Elt) {
     // Grow allocated space if needed.
     if (NumInputs > size_type(this->capacity_ptr()-this->end()))
       this->grow(this->size()+NumInputs);
-    
+
     // Copy the new elements over.
     std::uninitialized_fill_n(this->end(), NumInputs, Elt);
-    setEnd(this->end() + NumInputs);
+    this->setEnd(this->end() + NumInputs);
   }
-  
+
   void assign(unsigned NumElts, const T &Elt) {
     clear();
     if (this->capacity() < NumElts)
       this->grow(NumElts);
-    setEnd(this->begin()+NumElts);
+    this->setEnd(this->begin()+NumElts);
     construct_range(this->begin(), this->end(), Elt);
   }
-  
+
   iterator erase(iterator I) {
     iterator N = I;
     // Shift all elts down one.
@@ -397,23 +387,23 @@ public:
     pop_back();
     return(N);
   }
-  
+
   iterator erase(iterator S, iterator E) {
     iterator N = S;
     // Shift all elts down.
     iterator I = std::copy(E, this->end(), S);
     // Drop the last elts.
-    destroy_range(I, this->end());
-    setEnd(I);
+    this->destroy_range(I, this->end());
+    this->setEnd(I);
     return(N);
   }
-  
+
   iterator insert(iterator I, const T &Elt) {
     if (I == this->end()) {  // Important special case for empty vector.
       push_back(Elt);
       return this->end()-1;
     }
-    
+
     if (this->EndX < this->CapacityX) {
     Retry:
       new (this->end()) T(this->back());
@@ -428,22 +418,22 @@ public:
     I = this->begin()+EltNo;
     goto Retry;
   }
-  
+
   iterator insert(iterator I, size_type NumToInsert, const T &Elt) {
     if (I == this->end()) {  // Important special case for empty vector.
       append(NumToInsert, Elt);
       return this->end()-1;
     }
-    
+
     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
     size_t InsertElt = I - this->begin();
-    
+
     // Ensure there is enough space.
     reserve(static_cast<unsigned>(this->size() + NumToInsert));
-    
+
     // Uninvalidate the iterator.
     I = this->begin()+InsertElt;
-    
+
     // If there are more elements between the insertion point and the end of the
     // range than there are being inserted, we can use a simple approach to
     // insertion.  Since we already reserved space, we know that this won't
@@ -451,48 +441,48 @@ public:
     if (size_t(this->end()-I) >= NumToInsert) {
       T *OldEnd = this->end();
       append(this->end()-NumToInsert, this->end());
-      
+
       // Copy the existing elements that get replaced.
       std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
-      
+
       std::fill_n(I, NumToInsert, Elt);
       return I;
     }
-    
+
     // Otherwise, we're inserting more elements than exist already, and we're
     // not inserting at the end.
-    
+
     // Copy over the elements that we're about to overwrite.
     T *OldEnd = this->end();
-    setEnd(this->end() + NumToInsert);
+    this->setEnd(this->end() + NumToInsert);
     size_t NumOverwritten = OldEnd-I;
-    uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
-    
+    this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
+
     // Replace the overwritten part.
     std::fill_n(I, NumOverwritten, Elt);
-    
+
     // Insert the non-overwritten middle part.
     std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
     return I;
   }
-  
+
   template<typename ItTy>
   iterator insert(iterator I, ItTy From, ItTy To) {
     if (I == this->end()) {  // Important special case for empty vector.
       append(From, To);
       return this->end()-1;
     }
-    
+
     size_t NumToInsert = std::distance(From, To);
     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
     size_t InsertElt = I - this->begin();
-    
+
     // Ensure there is enough space.
     reserve(static_cast<unsigned>(this->size() + NumToInsert));
-    
+
     // Uninvalidate the iterator.
     I = this->begin()+InsertElt;
-    
+
     // If there are more elements between the insertion point and the end of the
     // range than there are being inserted, we can use a simple approach to
     // insertion.  Since we already reserved space, we know that this won't
@@ -500,34 +490,37 @@ public:
     if (size_t(this->end()-I) >= NumToInsert) {
       T *OldEnd = this->end();
       append(this->end()-NumToInsert, this->end());
-      
+
       // Copy the existing elements that get replaced.
       std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
-      
+
       std::copy(From, To, I);
       return I;
     }
-    
+
     // Otherwise, we're inserting more elements than exist already, and we're
     // not inserting at the end.
-    
+
     // Copy over the elements that we're about to overwrite.
     T *OldEnd = this->end();
-    setEnd(this->end() + NumToInsert);
+    this->setEnd(this->end() + NumToInsert);
     size_t NumOverwritten = OldEnd-I;
-    uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
-    
+    this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
+
     // Replace the overwritten part.
-    std::copy(From, From+NumOverwritten, I);
-    
+    for (; NumOverwritten > 0; --NumOverwritten) {
+      *I = *From;
+      ++I; ++From;
+    }
+
     // Insert the non-overwritten middle part.
-    uninitialized_copy(From+NumOverwritten, To, OldEnd);
+    this->uninitialized_copy(From, To, OldEnd);
     return I;
   }
-  
+
   const SmallVectorImpl
   &operator=(const SmallVectorImpl &RHS);
-  
+
   bool operator==(const SmallVectorImpl &RHS) const {
     if (this->size() != RHS.size()) return false;
     return std::equal(this->begin(), this->end(), RHS.begin());
@@ -535,12 +528,12 @@ public:
   bool operator!=(const SmallVectorImpl &RHS) const {
     return !(*this == RHS);
   }
-  
+
   bool operator<(const SmallVectorImpl &RHS) const {
     return std::lexicographical_compare(this->begin(), this->end(),
                                         RHS.begin(), RHS.end());
   }
-  
+
   /// set_size - Set the array size to \arg N, which the current array must have
   /// enough capacity for.
   ///
@@ -552,16 +545,16 @@ public:
   /// which will only be overwritten.
   void set_size(unsigned N) {
     assert(N <= this->capacity());
-    setEnd(this->begin() + N);
+    this->setEnd(this->begin() + N);
   }
-  
+
 private:
   static void construct_range(T *S, T *E, const T &Elt) {
     for (; S != E; ++S)
       new (S) T(Elt);
   }
 };
-  
+
 
 template <typename T>
 void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
@@ -588,15 +581,15 @@ void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
   // Copy over the extra elts.
   if (this->size() > RHS.size()) {
     size_t EltDiff = this->size() - RHS.size();
-    uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end());
+    this->uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end());
     RHS.setEnd(RHS.end()+EltDiff);
-    destroy_range(this->begin()+NumShared, this->end());
-    setEnd(this->begin()+NumShared);
+    this->destroy_range(this->begin()+NumShared, this->end());
+    this->setEnd(this->begin()+NumShared);
   } else if (RHS.size() > this->size()) {
     size_t EltDiff = RHS.size() - this->size();
-    uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end());
-    setEnd(this->end() + EltDiff);
-    destroy_range(RHS.begin()+NumShared, RHS.end());
+    this->uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end());
+    this->setEnd(this->end() + EltDiff);
+    this->destroy_range(RHS.begin()+NumShared, RHS.end());
     RHS.setEnd(RHS.begin()+NumShared);
   }
 }
@@ -620,10 +613,10 @@ const SmallVectorImpl<T> &SmallVectorImpl<T>::
       NewEnd = this->begin();
 
     // Destroy excess elements.
-    destroy_range(NewEnd, this->end());
+    this->destroy_range(NewEnd, this->end());
 
     // Trim.
-    setEnd(NewEnd);
+    this->setEnd(NewEnd);
     return *this;
   }
 
@@ -631,8 +624,8 @@ const SmallVectorImpl<T> &SmallVectorImpl<T>::
   // This allows us to avoid copying them during the grow.
   if (this->capacity() < RHSSize) {
     // Destroy current elements.
-    destroy_range(this->begin(), this->end());
-    setEnd(this->begin());
+    this->destroy_range(this->begin(), this->end());
+    this->setEnd(this->begin());
     CurSize = 0;
     this->grow(RHSSize);
   } else if (CurSize) {
@@ -641,10 +634,11 @@ const SmallVectorImpl<T> &SmallVectorImpl<T>::
   }
 
   // Copy construct the new elements in place.
-  uninitialized_copy(RHS.begin()+CurSize, RHS.end(), this->begin()+CurSize);
+  this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(),
+                           this->begin()+CurSize);
 
   // Set end.
-  setEnd(this->begin()+RHSSize);
+  this->setEnd(this->begin()+RHSSize);
   return *this;
 }
 
@@ -707,6 +701,36 @@ public:
 
 };
 
+/// Specialize SmallVector at N=0.  This specialization guarantees
+/// that it can be instantiated at an incomplete T if none of its
+/// members are required.
+template <typename T>
+class SmallVector<T,0> : public SmallVectorImpl<T> {
+public:
+  SmallVector() : SmallVectorImpl<T>(0) {}
+
+  explicit SmallVector(unsigned Size, const T &Value = T())
+    : SmallVectorImpl<T>(0) {
+    this->reserve(Size);
+    while (Size--)
+      this->push_back(Value);
+  }
+
+  template<typename ItTy>
+  SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(0) {
+    this->append(S, E);
+  }
+
+  SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(0) {
+    SmallVectorImpl<T>::operator=(RHS);
+  }
+
+  SmallVector &operator=(const SmallVectorImpl<T> &RHS) {
+    return SmallVectorImpl<T>::operator=(RHS);
+  }
+
+};
+
 } // End llvm namespace
 
 namespace std {