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