SmallVector.h revision 80b65823147ba498efd9a5df72afc7ff7d9dc0d9
1//===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the SmallVector class.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_ADT_SMALLVECTOR_H
15#define LLVM_ADT_SMALLVECTOR_H
16
17#include <algorithm>
18#include <iterator>
19#include <memory>
20
21namespace llvm {
22
23/// SmallVectorImpl - This class consists of common code factored out of the
24/// SmallVector class to reduce code duplication based on the SmallVector 'N'
25/// template parameter.
26template <typename T>
27class SmallVectorImpl {
28  T *Begin, *End, *Capacity;
29
30  // Allocate raw space for N elements of type T.  If T has a ctor or dtor, we
31  // don't want it to be automatically run, so we need to represent the space as
32  // something else.  An array of char would work great, but might not be
33  // aligned sufficiently.  Instead, we either use GCC extensions, or some
34  // number of union instances for the space, which guarantee maximal alignment.
35protected:
36  union U {
37    double D;
38    long double LD;
39    long long L;
40    void *P;
41  } FirstEl;
42  // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
43public:
44  // Default ctor - Initialize to empty.
45  SmallVectorImpl(unsigned N)
46    : Begin((T*)&FirstEl), End((T*)&FirstEl), Capacity((T*)&FirstEl+N) {
47  }
48
49  ~SmallVectorImpl() {
50    // Destroy the constructed elements in the vector.
51    for (iterator I = Begin, E = End; I != E; ++I)
52      I->~T();
53
54    // If this wasn't grown from the inline copy, deallocate the old space.
55    if (!isSmall())
56      delete[] (char*)Begin;
57  }
58
59  typedef size_t size_type;
60  typedef T* iterator;
61  typedef const T* const_iterator;
62  typedef T& reference;
63  typedef const T& const_reference;
64
65  bool empty() const { return Begin == End; }
66  size_type size() const { return End-Begin; }
67
68  iterator begin() { return Begin; }
69  const_iterator begin() const { return Begin; }
70
71  iterator end() { return End; }
72  const_iterator end() const { return End; }
73
74  reference operator[](unsigned idx) {
75    return Begin[idx];
76  }
77  const_reference operator[](unsigned idx) const {
78    return Begin[idx];
79  }
80
81  reference back() {
82    return end()[-1];
83  }
84  const_reference back() const {
85    return end()[-1];
86  }
87
88  void push_back(const_reference Elt) {
89    if (End < Capacity) {
90  Retry:
91      new (End) T(Elt);
92      ++End;
93      return;
94    }
95    grow();
96    goto Retry;
97  }
98
99  void pop_back() {
100    --End;
101    End->~T();
102  }
103
104  void clear() {
105    while (End != Begin) {
106      End->~T();
107      --End;
108    }
109  }
110
111  /// append - Add the specified range to the end of the SmallVector.
112  ///
113  template<typename in_iter>
114  void append(in_iter in_start, in_iter in_end) {
115    unsigned NumInputs = std::distance(in_start, in_end);
116    // Grow allocated space if needed.
117    if (End+NumInputs > Capacity)
118      grow(size()+NumInputs);
119
120    // Copy the new elements over.
121    std::uninitialized_copy(in_start, in_end, End);
122    End += NumInputs;
123  }
124
125  void assign(unsigned NumElts, const T &Elt) {
126    clear();
127    if (Begin+NumElts > Capacity)
128      grow(NumElts);
129    End = Begin+NumElts;
130    for (; NumElts; --NumElts)
131      new (Begin+NumElts-1) T(Elt);
132  }
133
134  const SmallVectorImpl &operator=(const SmallVectorImpl &RHS) {
135    // Avoid self-assignment.
136    if (this == &RHS) return *this;
137
138    // If we already have sufficient space, assign the common elements, then
139    // destroy any excess.
140    unsigned RHSSize = RHS.size();
141    unsigned CurSize = size();
142    if (CurSize >= RHSSize) {
143      // Assign common elements.
144      std::copy(RHS.Begin, RHS.Begin+RHSSize, Begin);
145
146      // Destroy excess elements.
147      for (unsigned i = RHSSize; i != CurSize; ++i)
148        Begin[i].~T();
149
150      // Trim.
151      End = Begin + RHSSize;
152      return *this;
153    }
154
155    // If we have to grow to have enough elements, destroy the current elements.
156    // This allows us to avoid copying them during the grow.
157    if (Capacity-Begin < RHSSize) {
158      // Destroy current elements.
159      for (iterator I = Begin, E = End; I != E; ++I)
160        I->~T();
161      End = Begin;
162      CurSize = 0;
163      grow(RHSSize);
164    } else if (CurSize) {
165      // Otherwise, use assignment for the already-constructed elements.
166      std::copy(RHS.Begin, RHS.Begin+CurSize, Begin);
167    }
168
169    // Copy construct the new elements in place.
170    std::uninitialized_copy(RHS.Begin+CurSize, RHS.End, Begin+CurSize);
171
172    // Set end.
173    End = Begin+RHSSize;
174  }
175
176private:
177  /// isSmall - Return true if this is a smallvector which has not had dynamic
178  /// memory allocated for it.
179  bool isSmall() const {
180    return (void*)Begin == (void*)&FirstEl;
181  }
182
183  /// grow - double the size of the allocated memory, guaranteeing space for at
184  /// least one more element or MinSize if specified.
185  void grow(unsigned MinSize = 0) {
186    unsigned CurCapacity = Capacity-Begin;
187    unsigned CurSize = size();
188    unsigned NewCapacity = 2*CurCapacity;
189    if (NewCapacity < MinSize)
190      NewCapacity = MinSize;
191    T *NewElts = reinterpret_cast<T*>(new char[NewCapacity*sizeof(T)]);
192
193    // Copy the elements over.
194    std::uninitialized_copy(Begin, End, NewElts);
195
196    // Destroy the original elements.
197    for (iterator I = Begin, E = End; I != E; ++I)
198      I->~T();
199
200    // If this wasn't grown from the inline copy, deallocate the old space.
201    if (!isSmall())
202      delete[] (char*)Begin;
203
204    Begin = NewElts;
205    End = NewElts+CurSize;
206    Capacity = Begin+NewCapacity;
207  }
208};
209
210
211/// SmallVector - This is a 'vector' (really, a variable-sized array), optimized
212/// for the case when the array is small.  It contains some number of elements
213/// in-place, which allows it to avoid heap allocation when the actual number of
214/// elements is below that threshold.  This allows normal "small" cases to be
215/// fast without losing generality for large inputs.
216///
217/// Note that this does not attempt to be exception safe.
218///
219template <typename T, unsigned N>
220class SmallVector : public SmallVectorImpl<T> {
221  /// InlineElts - These are 'N-1' elements that are stored inline in the body
222  /// of the vector.  The extra '1' element is stored in SmallVectorImpl.
223  typedef typename SmallVectorImpl<T>::U U;
224  U InlineElts[(sizeof(T)*N+sizeof(U)-1)/sizeof(U) - 1];
225public:
226  SmallVector() : SmallVectorImpl<T>(N) {
227  }
228
229  template<typename ItTy>
230  SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
231    append(S, E);
232  }
233
234  SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
235    operator=(RHS);
236  }
237};
238
239} // End llvm namespace
240
241#endif
242