clang API Documentation

ASTVector.h
Go to the documentation of this file.
00001 //===- ASTVector.h - Vector that uses ASTContext for allocation  --*- C++ -*-=//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file provides ASTVector, a vector  ADT whose contents are
00011 //  allocated using the allocator associated with an ASTContext..
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 // FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h.
00016 // We can refactor this core logic into something common.
00017 
00018 #ifndef LLVM_CLANG_AST_VECTOR
00019 #define LLVM_CLANG_AST_VECTOR
00020 
00021 #include "llvm/Support/type_traits.h"
00022 #include "llvm/Support/Allocator.h"
00023 #include "llvm/ADT/PointerIntPair.h"
00024 #include <algorithm>
00025 #include <memory>
00026 #include <cstring>
00027 
00028 #ifdef _MSC_VER
00029 namespace std {
00030 #if _MSC_VER <= 1310
00031   // Work around flawed VC++ implementation of std::uninitialized_copy.  Define
00032   // additional overloads so that elements with pointer types are recognized as
00033   // scalars and not objects, causing bizarre type conversion errors.
00034   template<class T1, class T2>
00035   inline _Scalar_ptr_iterator_tag _Ptr_cat(T1 **, T2 **) {
00036     _Scalar_ptr_iterator_tag _Cat;
00037     return _Cat;
00038   }
00039 
00040   template<class T1, class T2>
00041   inline _Scalar_ptr_iterator_tag _Ptr_cat(T1* const *, T2 **) {
00042     _Scalar_ptr_iterator_tag _Cat;
00043     return _Cat;
00044   }
00045 #else
00046   // FIXME: It is not clear if the problem is fixed in VS 2005.  What is clear
00047   // is that the above hack won't work if it wasn't fixed.
00048 #endif
00049 }
00050 #endif
00051 
00052 namespace clang {
00053 
00054 template<typename T>
00055 class ASTVector {
00056   T *Begin, *End, *Capacity;
00057 
00058   void setEnd(T *P) { this->End = P; }
00059 
00060 public:
00061   // Default ctor - Initialize to empty.
00062   explicit ASTVector(ASTContext &C, unsigned N = 0)
00063   : Begin(NULL), End(NULL), Capacity(NULL) {
00064     reserve(C, N);
00065   }
00066 
00067   ~ASTVector() {
00068     if (llvm::is_class<T>::value) {
00069       // Destroy the constructed elements in the vector.
00070       destroy_range(Begin, End);
00071     }
00072   }
00073 
00074   typedef size_t size_type;
00075   typedef ptrdiff_t difference_type;
00076   typedef T value_type;
00077   typedef T* iterator;
00078   typedef const T* const_iterator;
00079 
00080   typedef std::reverse_iterator<const_iterator>  const_reverse_iterator;
00081   typedef std::reverse_iterator<iterator>  reverse_iterator;
00082 
00083   typedef T& reference;
00084   typedef const T& const_reference;
00085   typedef T* pointer;
00086   typedef const T* const_pointer;
00087 
00088   // forward iterator creation methods.
00089   iterator begin() { return Begin; }
00090   const_iterator begin() const { return Begin; }
00091   iterator end() { return End; }
00092   const_iterator end() const { return End; }
00093 
00094   // reverse iterator creation methods.
00095   reverse_iterator rbegin()            { return reverse_iterator(end()); }
00096   const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
00097   reverse_iterator rend()              { return reverse_iterator(begin()); }
00098   const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
00099 
00100   bool empty() const { return Begin == End; }
00101   size_type size() const { return End-Begin; }
00102 
00103   reference operator[](unsigned idx) {
00104     assert(Begin + idx < End);
00105     return Begin[idx];
00106   }
00107   const_reference operator[](unsigned idx) const {
00108     assert(Begin + idx < End);
00109     return Begin[idx];
00110   }
00111 
00112   reference front() {
00113     return begin()[0];
00114   }
00115   const_reference front() const {
00116     return begin()[0];
00117   }
00118 
00119   reference back() {
00120     return end()[-1];
00121   }
00122   const_reference back() const {
00123     return end()[-1];
00124   }
00125 
00126   void pop_back() {
00127     --End;
00128     End->~T();
00129   }
00130 
00131   T pop_back_val() {
00132     T Result = back();
00133     pop_back();
00134     return Result;
00135   }
00136 
00137   void clear() {
00138     if (llvm::is_class<T>::value) {
00139       destroy_range(Begin, End);
00140     }
00141     End = Begin;
00142   }
00143 
00144   /// data - Return a pointer to the vector's buffer, even if empty().
00145   pointer data() {
00146     return pointer(Begin);
00147   }
00148 
00149   /// data - Return a pointer to the vector's buffer, even if empty().
00150   const_pointer data() const {
00151     return const_pointer(Begin);
00152   }
00153 
00154   void push_back(const_reference Elt, ASTContext &C) {
00155     if (End < Capacity) {
00156     Retry:
00157       new (End) T(Elt);
00158       ++End;
00159       return;
00160     }
00161     grow(C);
00162     goto Retry;
00163   }
00164 
00165   void reserve(ASTContext &C, unsigned N) {
00166     if (unsigned(Capacity-Begin) < N)
00167       grow(C, N);
00168   }
00169 
00170   /// capacity - Return the total number of elements in the currently allocated
00171   /// buffer.
00172   size_t capacity() const { return Capacity - Begin; }
00173 
00174   /// append - Add the specified range to the end of the SmallVector.
00175   ///
00176   template<typename in_iter>
00177   void append(ASTContext &C, in_iter in_start, in_iter in_end) {
00178     size_type NumInputs = std::distance(in_start, in_end);
00179 
00180     if (NumInputs == 0)
00181       return;
00182 
00183     // Grow allocated space if needed.
00184     if (NumInputs > size_type(this->capacity_ptr()-this->end()))
00185       this->grow(C, this->size()+NumInputs);
00186 
00187     // Copy the new elements over.
00188     // TODO: NEED To compile time dispatch on whether in_iter is a random access
00189     // iterator to use the fast uninitialized_copy.
00190     std::uninitialized_copy(in_start, in_end, this->end());
00191     this->setEnd(this->end() + NumInputs);
00192   }
00193 
00194   /// append - Add the specified range to the end of the SmallVector.
00195   ///
00196   void append(ASTContext &C, size_type NumInputs, const T &Elt) {
00197     // Grow allocated space if needed.
00198     if (NumInputs > size_type(this->capacity_ptr()-this->end()))
00199       this->grow(C, this->size()+NumInputs);
00200 
00201     // Copy the new elements over.
00202     std::uninitialized_fill_n(this->end(), NumInputs, Elt);
00203     this->setEnd(this->end() + NumInputs);
00204   }
00205 
00206   /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
00207   /// starting with "Dest", constructing elements into it as needed.
00208   template<typename It1, typename It2>
00209   static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
00210     std::uninitialized_copy(I, E, Dest);
00211   }
00212 
00213   iterator insert(ASTContext &C, iterator I, const T &Elt) {
00214     if (I == this->end()) {  // Important special case for empty vector.
00215       push_back(Elt);
00216       return this->end()-1;
00217     }
00218 
00219     if (this->EndX < this->CapacityX) {
00220     Retry:
00221       new (this->end()) T(this->back());
00222       this->setEnd(this->end()+1);
00223       // Push everything else over.
00224       std::copy_backward(I, this->end()-1, this->end());
00225       *I = Elt;
00226       return I;
00227     }
00228     size_t EltNo = I-this->begin();
00229     this->grow(C);
00230     I = this->begin()+EltNo;
00231     goto Retry;
00232   }
00233 
00234   iterator insert(ASTContext &C, iterator I, size_type NumToInsert,
00235                   const T &Elt) {
00236     if (I == this->end()) {  // Important special case for empty vector.
00237       append(C, NumToInsert, Elt);
00238       return this->end()-1;
00239     }
00240 
00241     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
00242     size_t InsertElt = I - this->begin();
00243 
00244     // Ensure there is enough space.
00245     reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
00246 
00247     // Uninvalidate the iterator.
00248     I = this->begin()+InsertElt;
00249 
00250     // If there are more elements between the insertion point and the end of the
00251     // range than there are being inserted, we can use a simple approach to
00252     // insertion.  Since we already reserved space, we know that this won't
00253     // reallocate the vector.
00254     if (size_t(this->end()-I) >= NumToInsert) {
00255       T *OldEnd = this->end();
00256       append(C, this->end()-NumToInsert, this->end());
00257 
00258       // Copy the existing elements that get replaced.
00259       std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
00260 
00261       std::fill_n(I, NumToInsert, Elt);
00262       return I;
00263     }
00264 
00265     // Otherwise, we're inserting more elements than exist already, and we're
00266     // not inserting at the end.
00267 
00268     // Copy over the elements that we're about to overwrite.
00269     T *OldEnd = this->end();
00270     this->setEnd(this->end() + NumToInsert);
00271     size_t NumOverwritten = OldEnd-I;
00272     this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
00273 
00274     // Replace the overwritten part.
00275     std::fill_n(I, NumOverwritten, Elt);
00276 
00277     // Insert the non-overwritten middle part.
00278     std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
00279     return I;
00280   }
00281 
00282   template<typename ItTy>
00283   iterator insert(ASTContext &C, iterator I, ItTy From, ItTy To) {
00284     if (I == this->end()) {  // Important special case for empty vector.
00285       append(C, From, To);
00286       return this->end()-1;
00287     }
00288 
00289     size_t NumToInsert = std::distance(From, To);
00290     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
00291     size_t InsertElt = I - this->begin();
00292 
00293     // Ensure there is enough space.
00294     reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
00295 
00296     // Uninvalidate the iterator.
00297     I = this->begin()+InsertElt;
00298 
00299     // If there are more elements between the insertion point and the end of the
00300     // range than there are being inserted, we can use a simple approach to
00301     // insertion.  Since we already reserved space, we know that this won't
00302     // reallocate the vector.
00303     if (size_t(this->end()-I) >= NumToInsert) {
00304       T *OldEnd = this->end();
00305       append(C, this->end()-NumToInsert, this->end());
00306 
00307       // Copy the existing elements that get replaced.
00308       std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
00309 
00310       std::copy(From, To, I);
00311       return I;
00312     }
00313 
00314     // Otherwise, we're inserting more elements than exist already, and we're
00315     // not inserting at the end.
00316 
00317     // Copy over the elements that we're about to overwrite.
00318     T *OldEnd = this->end();
00319     this->setEnd(this->end() + NumToInsert);
00320     size_t NumOverwritten = OldEnd-I;
00321     this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
00322 
00323     // Replace the overwritten part.
00324     for (; NumOverwritten > 0; --NumOverwritten) {
00325       *I = *From;
00326       ++I; ++From;
00327     }
00328 
00329     // Insert the non-overwritten middle part.
00330     this->uninitialized_copy(From, To, OldEnd);
00331     return I;
00332   }
00333 
00334   void resize(ASTContext &C, unsigned N, const T &NV) {
00335     if (N < this->size()) {
00336       this->destroy_range(this->begin()+N, this->end());
00337       this->setEnd(this->begin()+N);
00338     } else if (N > this->size()) {
00339       if (this->capacity() < N)
00340         this->grow(C, N);
00341       construct_range(this->end(), this->begin()+N, NV);
00342       this->setEnd(this->begin()+N);
00343     }
00344   }
00345 
00346 private:
00347   /// grow - double the size of the allocated memory, guaranteeing space for at
00348   /// least one more element or MinSize if specified.
00349   void grow(ASTContext &C, size_type MinSize = 1);
00350 
00351   void construct_range(T *S, T *E, const T &Elt) {
00352     for (; S != E; ++S)
00353       new (S) T(Elt);
00354   }
00355 
00356   void destroy_range(T *S, T *E) {
00357     while (S != E) {
00358       --E;
00359       E->~T();
00360     }
00361   }
00362 
00363 protected:
00364   iterator capacity_ptr() { return (iterator)this->Capacity; }
00365 };
00366 
00367 // Define this out-of-line to dissuade the C++ compiler from inlining it.
00368 template <typename T>
00369 void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
00370   size_t CurCapacity = Capacity-Begin;
00371   size_t CurSize = size();
00372   size_t NewCapacity = 2*CurCapacity;
00373   if (NewCapacity < MinSize)
00374     NewCapacity = MinSize;
00375 
00376   // Allocate the memory from the ASTContext.
00377   T *NewElts = new (C) T[NewCapacity];
00378 
00379   // Copy the elements over.
00380   if (llvm::is_class<T>::value) {
00381     std::uninitialized_copy(Begin, End, NewElts);
00382     // Destroy the original elements.
00383     destroy_range(Begin, End);
00384   }
00385   else {
00386     // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
00387     memcpy(NewElts, Begin, CurSize * sizeof(T));
00388   }
00389 
00390   C.Deallocate(Begin);
00391   Begin = NewElts;
00392   End = NewElts+CurSize;
00393   Capacity = Begin+NewCapacity;
00394 }
00395 
00396 } // end: clang namespace
00397 #endif