• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- ASTVector.h - Vector that uses ASTContext for allocation  --*- C++ -*-=//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file provides ASTVector, a vector  ADT whose contents are
11 //  allocated using the allocator associated with an ASTContext..
12 //
13 //===----------------------------------------------------------------------===//
14 
15 // FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h.
16 // We can refactor this core logic into something common.
17 
18 #ifndef LLVM_CLANG_AST_ASTVECTOR_H
19 #define LLVM_CLANG_AST_ASTVECTOR_H
20 
21 #include "clang/AST/AttrIterator.h"
22 #include "llvm/ADT/PointerIntPair.h"
23 #include "llvm/Support/Allocator.h"
24 #include "llvm/Support/type_traits.h"
25 #include <algorithm>
26 #include <cstring>
27 #include <memory>
28 
29 namespace clang {
30   class ASTContext;
31 
32 template<typename T>
33 class ASTVector {
34 private:
35   T *Begin, *End;
36   llvm::PointerIntPair<T*, 1, bool> Capacity;
37 
setEnd(T * P)38   void setEnd(T *P) { this->End = P; }
39 
40 protected:
41   // Make a tag bit available to users of this class.
42   // FIXME: This is a horrible hack.
getTag()43   bool getTag() const { return Capacity.getInt(); }
setTag(bool B)44   void setTag(bool B) { Capacity.setInt(B); }
45 
46 public:
47   // Default ctor - Initialize to empty.
ASTVector()48   ASTVector() : Begin(nullptr), End(nullptr), Capacity(nullptr, false) {}
49 
ASTVector(ASTVector && O)50   ASTVector(ASTVector &&O) : Begin(O.Begin), End(O.End), Capacity(O.Capacity) {
51     O.Begin = O.End = nullptr;
52     O.Capacity.setPointer(nullptr);
53     O.Capacity.setInt(false);
54   }
55 
ASTVector(const ASTContext & C,unsigned N)56   ASTVector(const ASTContext &C, unsigned N)
57       : Begin(nullptr), End(nullptr), Capacity(nullptr, false) {
58     reserve(C, N);
59   }
60 
61   ASTVector &operator=(ASTVector &&RHS) {
62     ASTVector O(std::move(RHS));
63     using std::swap;
64     swap(Begin, O.Begin);
65     swap(End, O.End);
66     swap(Capacity, O.Capacity);
67     return *this;
68   }
69 
~ASTVector()70   ~ASTVector() {
71     if (std::is_class<T>::value) {
72       // Destroy the constructed elements in the vector.
73       destroy_range(Begin, End);
74     }
75   }
76 
77   typedef size_t size_type;
78   typedef ptrdiff_t difference_type;
79   typedef T value_type;
80   typedef T* iterator;
81   typedef const T* const_iterator;
82 
83   typedef std::reverse_iterator<const_iterator>  const_reverse_iterator;
84   typedef std::reverse_iterator<iterator>  reverse_iterator;
85 
86   typedef T& reference;
87   typedef const T& const_reference;
88   typedef T* pointer;
89   typedef const T* const_pointer;
90 
91   // forward iterator creation methods.
begin()92   iterator begin() { return Begin; }
begin()93   const_iterator begin() const { return Begin; }
end()94   iterator end() { return End; }
end()95   const_iterator end() const { return End; }
96 
97   // reverse iterator creation methods.
rbegin()98   reverse_iterator rbegin()            { return reverse_iterator(end()); }
rbegin()99   const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
rend()100   reverse_iterator rend()              { return reverse_iterator(begin()); }
rend()101   const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
102 
empty()103   bool empty() const { return Begin == End; }
size()104   size_type size() const { return End-Begin; }
105 
106   reference operator[](unsigned idx) {
107     assert(Begin + idx < End);
108     return Begin[idx];
109   }
110   const_reference operator[](unsigned idx) const {
111     assert(Begin + idx < End);
112     return Begin[idx];
113   }
114 
front()115   reference front() {
116     return begin()[0];
117   }
front()118   const_reference front() const {
119     return begin()[0];
120   }
121 
back()122   reference back() {
123     return end()[-1];
124   }
back()125   const_reference back() const {
126     return end()[-1];
127   }
128 
pop_back()129   void pop_back() {
130     --End;
131     End->~T();
132   }
133 
pop_back_val()134   T pop_back_val() {
135     T Result = back();
136     pop_back();
137     return Result;
138   }
139 
clear()140   void clear() {
141     if (std::is_class<T>::value) {
142       destroy_range(Begin, End);
143     }
144     End = Begin;
145   }
146 
147   /// data - Return a pointer to the vector's buffer, even if empty().
data()148   pointer data() {
149     return pointer(Begin);
150   }
151 
152   /// data - Return a pointer to the vector's buffer, even if empty().
data()153   const_pointer data() const {
154     return const_pointer(Begin);
155   }
156 
push_back(const_reference Elt,const ASTContext & C)157   void push_back(const_reference Elt, const ASTContext &C) {
158     if (End < this->capacity_ptr()) {
159     Retry:
160       new (End) T(Elt);
161       ++End;
162       return;
163     }
164     grow(C);
165     goto Retry;
166   }
167 
reserve(const ASTContext & C,unsigned N)168   void reserve(const ASTContext &C, unsigned N) {
169     if (unsigned(this->capacity_ptr()-Begin) < N)
170       grow(C, N);
171   }
172 
173   /// capacity - Return the total number of elements in the currently allocated
174   /// buffer.
capacity()175   size_t capacity() const { return this->capacity_ptr() - Begin; }
176 
177   /// append - Add the specified range to the end of the SmallVector.
178   ///
179   template<typename in_iter>
append(const ASTContext & C,in_iter in_start,in_iter in_end)180   void append(const ASTContext &C, in_iter in_start, in_iter in_end) {
181     size_type NumInputs = std::distance(in_start, in_end);
182 
183     if (NumInputs == 0)
184       return;
185 
186     // Grow allocated space if needed.
187     if (NumInputs > size_type(this->capacity_ptr()-this->end()))
188       this->grow(C, this->size()+NumInputs);
189 
190     // Copy the new elements over.
191     // TODO: NEED To compile time dispatch on whether in_iter is a random access
192     // iterator to use the fast uninitialized_copy.
193     std::uninitialized_copy(in_start, in_end, this->end());
194     this->setEnd(this->end() + NumInputs);
195   }
196 
197   /// append - Add the specified range to the end of the SmallVector.
198   ///
append(const ASTContext & C,size_type NumInputs,const T & Elt)199   void append(const ASTContext &C, size_type NumInputs, const T &Elt) {
200     // Grow allocated space if needed.
201     if (NumInputs > size_type(this->capacity_ptr()-this->end()))
202       this->grow(C, this->size()+NumInputs);
203 
204     // Copy the new elements over.
205     std::uninitialized_fill_n(this->end(), NumInputs, Elt);
206     this->setEnd(this->end() + NumInputs);
207   }
208 
209   /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
210   /// starting with "Dest", constructing elements into it as needed.
211   template<typename It1, typename It2>
uninitialized_copy(It1 I,It1 E,It2 Dest)212   static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
213     std::uninitialized_copy(I, E, Dest);
214   }
215 
insert(const ASTContext & C,iterator I,const T & Elt)216   iterator insert(const ASTContext &C, iterator I, const T &Elt) {
217     if (I == this->end()) {  // Important special case for empty vector.
218       push_back(Elt, C);
219       return this->end()-1;
220     }
221 
222     if (this->End < this->capacity_ptr()) {
223     Retry:
224       new (this->end()) T(this->back());
225       this->setEnd(this->end()+1);
226       // Push everything else over.
227       std::copy_backward(I, this->end()-1, this->end());
228       *I = Elt;
229       return I;
230     }
231     size_t EltNo = I-this->begin();
232     this->grow(C);
233     I = this->begin()+EltNo;
234     goto Retry;
235   }
236 
insert(const ASTContext & C,iterator I,size_type NumToInsert,const T & Elt)237   iterator insert(const ASTContext &C, iterator I, size_type NumToInsert,
238                   const T &Elt) {
239     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
240     size_t InsertElt = I - this->begin();
241 
242     if (I == this->end()) { // Important special case for empty vector.
243       append(C, NumToInsert, Elt);
244       return this->begin() + InsertElt;
245     }
246 
247     // Ensure there is enough space.
248     reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
249 
250     // Uninvalidate the iterator.
251     I = this->begin()+InsertElt;
252 
253     // If there are more elements between the insertion point and the end of the
254     // range than there are being inserted, we can use a simple approach to
255     // insertion.  Since we already reserved space, we know that this won't
256     // reallocate the vector.
257     if (size_t(this->end()-I) >= NumToInsert) {
258       T *OldEnd = this->end();
259       append(C, this->end()-NumToInsert, this->end());
260 
261       // Copy the existing elements that get replaced.
262       std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
263 
264       std::fill_n(I, NumToInsert, Elt);
265       return I;
266     }
267 
268     // Otherwise, we're inserting more elements than exist already, and we're
269     // not inserting at the end.
270 
271     // Copy over the elements that we're about to overwrite.
272     T *OldEnd = this->end();
273     this->setEnd(this->end() + NumToInsert);
274     size_t NumOverwritten = OldEnd-I;
275     this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
276 
277     // Replace the overwritten part.
278     std::fill_n(I, NumOverwritten, Elt);
279 
280     // Insert the non-overwritten middle part.
281     std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
282     return I;
283   }
284 
285   template<typename ItTy>
insert(const ASTContext & C,iterator I,ItTy From,ItTy To)286   iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) {
287     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
288     size_t InsertElt = I - this->begin();
289 
290     if (I == this->end()) { // Important special case for empty vector.
291       append(C, From, To);
292       return this->begin() + InsertElt;
293     }
294 
295     size_t NumToInsert = std::distance(From, To);
296 
297     // Ensure there is enough space.
298     reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
299 
300     // Uninvalidate the iterator.
301     I = this->begin()+InsertElt;
302 
303     // If there are more elements between the insertion point and the end of the
304     // range than there are being inserted, we can use a simple approach to
305     // insertion.  Since we already reserved space, we know that this won't
306     // reallocate the vector.
307     if (size_t(this->end()-I) >= NumToInsert) {
308       T *OldEnd = this->end();
309       append(C, this->end()-NumToInsert, this->end());
310 
311       // Copy the existing elements that get replaced.
312       std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
313 
314       std::copy(From, To, I);
315       return I;
316     }
317 
318     // Otherwise, we're inserting more elements than exist already, and we're
319     // not inserting at the end.
320 
321     // Copy over the elements that we're about to overwrite.
322     T *OldEnd = this->end();
323     this->setEnd(this->end() + NumToInsert);
324     size_t NumOverwritten = OldEnd-I;
325     this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
326 
327     // Replace the overwritten part.
328     for (; NumOverwritten > 0; --NumOverwritten) {
329       *I = *From;
330       ++I; ++From;
331     }
332 
333     // Insert the non-overwritten middle part.
334     this->uninitialized_copy(From, To, OldEnd);
335     return I;
336   }
337 
resize(const ASTContext & C,unsigned N,const T & NV)338   void resize(const ASTContext &C, unsigned N, const T &NV) {
339     if (N < this->size()) {
340       this->destroy_range(this->begin()+N, this->end());
341       this->setEnd(this->begin()+N);
342     } else if (N > this->size()) {
343       if (this->capacity() < N)
344         this->grow(C, N);
345       construct_range(this->end(), this->begin()+N, NV);
346       this->setEnd(this->begin()+N);
347     }
348   }
349 
350 private:
351   /// grow - double the size of the allocated memory, guaranteeing space for at
352   /// least one more element or MinSize if specified.
353   void grow(const ASTContext &C, size_type MinSize = 1);
354 
construct_range(T * S,T * E,const T & Elt)355   void construct_range(T *S, T *E, const T &Elt) {
356     for (; S != E; ++S)
357       new (S) T(Elt);
358   }
359 
destroy_range(T * S,T * E)360   void destroy_range(T *S, T *E) {
361     while (S != E) {
362       --E;
363       E->~T();
364     }
365   }
366 
367 protected:
capacity_ptr()368   const_iterator capacity_ptr() const {
369     return (iterator) Capacity.getPointer();
370   }
capacity_ptr()371   iterator capacity_ptr() { return (iterator)Capacity.getPointer(); }
372 };
373 
374 // Define this out-of-line to dissuade the C++ compiler from inlining it.
375 template <typename T>
grow(const ASTContext & C,size_t MinSize)376 void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
377   size_t CurCapacity = this->capacity();
378   size_t CurSize = size();
379   size_t NewCapacity = 2*CurCapacity;
380   if (NewCapacity < MinSize)
381     NewCapacity = MinSize;
382 
383   // Allocate the memory from the ASTContext.
384   T *NewElts = new (C, llvm::alignOf<T>()) T[NewCapacity];
385 
386   // Copy the elements over.
387   if (Begin != End) {
388     if (std::is_class<T>::value) {
389       std::uninitialized_copy(Begin, End, NewElts);
390       // Destroy the original elements.
391       destroy_range(Begin, End);
392     } else {
393       // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
394       memcpy(NewElts, Begin, CurSize * sizeof(T));
395     }
396   }
397 
398   // ASTContext never frees any memory.
399   Begin = NewElts;
400   End = NewElts+CurSize;
401   Capacity.setPointer(Begin+NewCapacity);
402 }
403 
404 } // end: clang namespace
405 #endif
406