1 //===- llvm/ADT/TinyPtrVector.h - 'Normally tiny' vectors -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_ADT_TINYPTRVECTOR_H
10 #define LLVM_ADT_TINYPTRVECTOR_H
11 
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/PointerUnion.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include <cassert>
16 #include <cstddef>
17 #include <iterator>
18 #include <type_traits>
19 
20 namespace llvm {
21 
22 /// TinyPtrVector - This class is specialized for cases where there are
23 /// normally 0 or 1 element in a vector, but is general enough to go beyond that
24 /// when required.
25 ///
26 /// NOTE: This container doesn't allow you to store a null pointer into it.
27 ///
28 template <typename EltTy>
29 class TinyPtrVector {
30 public:
31   using VecTy = SmallVector<EltTy, 4>;
32   using value_type = typename VecTy::value_type;
33   // EltTy must be the first pointer type so that is<EltTy> is true for the
34   // default-constructed PtrUnion. This allows an empty TinyPtrVector to
35   // naturally vend a begin/end iterator of type EltTy* without an additional
36   // check for the empty state.
37   using PtrUnion = PointerUnion<EltTy, VecTy *>;
38 
39 private:
40   PtrUnion Val;
41 
42 public:
43   TinyPtrVector() = default;
44 
45   ~TinyPtrVector() {
46     if (VecTy *V = Val.template dyn_cast<VecTy*>())
47       delete V;
48   }
49 
50   TinyPtrVector(const TinyPtrVector &RHS) : Val(RHS.Val) {
51     if (VecTy *V = Val.template dyn_cast<VecTy*>())
52       Val = new VecTy(*V);
53   }
54 
55   TinyPtrVector &operator=(const TinyPtrVector &RHS) {
56     if (this == &RHS)
57       return *this;
58     if (RHS.empty()) {
59       this->clear();
60       return *this;
61     }
62 
63     // Try to squeeze into the single slot. If it won't fit, allocate a copied
64     // vector.
65     if (Val.template is<EltTy>()) {
66       if (RHS.size() == 1)
67         Val = RHS.front();
68       else
69         Val = new VecTy(*RHS.Val.template get<VecTy*>());
70       return *this;
71     }
72 
73     // If we have a full vector allocated, try to re-use it.
74     if (RHS.Val.template is<EltTy>()) {
75       Val.template get<VecTy*>()->clear();
76       Val.template get<VecTy*>()->push_back(RHS.front());
77     } else {
78       *Val.template get<VecTy*>() = *RHS.Val.template get<VecTy*>();
79     }
80     return *this;
81   }
82 
83   TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) {
84     RHS.Val = (EltTy)nullptr;
85   }
86 
87   TinyPtrVector &operator=(TinyPtrVector &&RHS) {
88     if (this == &RHS)
89       return *this;
90     if (RHS.empty()) {
91       this->clear();
92       return *this;
93     }
94 
95     // If this vector has been allocated on the heap, re-use it if cheap. If it
96     // would require more copying, just delete it and we'll steal the other
97     // side.
98     if (VecTy *V = Val.template dyn_cast<VecTy*>()) {
99       if (RHS.Val.template is<EltTy>()) {
100         V->clear();
101         V->push_back(RHS.front());
102         RHS.Val = EltTy();
103         return *this;
104       }
105       delete V;
106     }
107 
108     Val = RHS.Val;
109     RHS.Val = EltTy();
110     return *this;
111   }
112 
113   TinyPtrVector(std::initializer_list<EltTy> IL)
114       : Val(IL.size() == 0
115                 ? PtrUnion()
116                 : IL.size() == 1 ? PtrUnion(*IL.begin())
117                                  : PtrUnion(new VecTy(IL.begin(), IL.end()))) {}
118 
119   /// Constructor from an ArrayRef.
120   ///
121   /// This also is a constructor for individual array elements due to the single
122   /// element constructor for ArrayRef.
123   explicit TinyPtrVector(ArrayRef<EltTy> Elts)
124       : Val(Elts.empty()
125                 ? PtrUnion()
126                 : Elts.size() == 1
127                       ? PtrUnion(Elts[0])
128                       : PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {}
129 
130   TinyPtrVector(size_t Count, EltTy Value)
131       : Val(Count == 0 ? PtrUnion()
132                        : Count == 1 ? PtrUnion(Value)
133                                     : PtrUnion(new VecTy(Count, Value))) {}
134 
135   // implicit conversion operator to ArrayRef.
136   operator ArrayRef<EltTy>() const {
137     if (Val.isNull())
138       return std::nullopt;
139     if (Val.template is<EltTy>())
140       return *Val.getAddrOfPtr1();
141     return *Val.template get<VecTy*>();
142   }
143 
144   // implicit conversion operator to MutableArrayRef.
145   operator MutableArrayRef<EltTy>() {
146     if (Val.isNull())
147       return std::nullopt;
148     if (Val.template is<EltTy>())
149       return *Val.getAddrOfPtr1();
150     return *Val.template get<VecTy*>();
151   }
152 
153   // Implicit conversion to ArrayRef<U> if EltTy* implicitly converts to U*.
154   template <
155       typename U,
156       std::enable_if_t<std::is_convertible<ArrayRef<EltTy>, ArrayRef<U>>::value,
157                        bool> = false>
158   operator ArrayRef<U>() const {
159     return operator ArrayRef<EltTy>();
160   }
161 
162   bool empty() const {
163     // This vector can be empty if it contains no element, or if it
164     // contains a pointer to an empty vector.
165     if (Val.isNull()) return true;
166     if (VecTy *Vec = Val.template dyn_cast<VecTy*>())
167       return Vec->empty();
168     return false;
169   }
170 
171   unsigned size() const {
172     if (empty())
173       return 0;
174     if (Val.template is<EltTy>())
175       return 1;
176     return Val.template get<VecTy*>()->size();
177   }
178 
179   using iterator = EltTy *;
180   using const_iterator = const EltTy *;
181   using reverse_iterator = std::reverse_iterator<iterator>;
182   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
183 
184   iterator begin() {
185     if (Val.template is<EltTy>())
186       return Val.getAddrOfPtr1();
187 
188     return Val.template get<VecTy *>()->begin();
189   }
190 
191   iterator end() {
192     if (Val.template is<EltTy>())
193       return begin() + (Val.isNull() ? 0 : 1);
194 
195     return Val.template get<VecTy *>()->end();
196   }
197 
198   const_iterator begin() const {
199     return (const_iterator)const_cast<TinyPtrVector*>(this)->begin();
200   }
201 
202   const_iterator end() const {
203     return (const_iterator)const_cast<TinyPtrVector*>(this)->end();
204   }
205 
206   reverse_iterator rbegin() { return reverse_iterator(end()); }
207   reverse_iterator rend() { return reverse_iterator(begin()); }
208 
209   const_reverse_iterator rbegin() const {
210     return const_reverse_iterator(end());
211   }
212 
213   const_reverse_iterator rend() const {
214     return const_reverse_iterator(begin());
215   }
216 
217   EltTy operator[](unsigned i) const {
218     assert(!Val.isNull() && "can't index into an empty vector");
219     if (Val.template is<EltTy>()) {
220       assert(i == 0 && "tinyvector index out of range");
221       return Val.template get<EltTy>();
222     }
223 
224     assert(i < Val.template get<VecTy*>()->size() &&
225            "tinyvector index out of range");
226     return (*Val.template get<VecTy*>())[i];
227   }
228 
229   EltTy front() const {
230     assert(!empty() && "vector empty");
231     if (Val.template is<EltTy>())
232       return Val.template get<EltTy>();
233     return Val.template get<VecTy*>()->front();
234   }
235 
236   EltTy back() const {
237     assert(!empty() && "vector empty");
238     if (Val.template is<EltTy>())
239       return Val.template get<EltTy>();
240     return Val.template get<VecTy*>()->back();
241   }
242 
243   void push_back(EltTy NewVal) {
244     // If we have nothing, add something.
245     if (Val.isNull()) {
246       Val = NewVal;
247       assert(!Val.isNull() && "Can't add a null value");
248       return;
249     }
250 
251     // If we have a single value, convert to a vector.
252     if (Val.template is<EltTy>()) {
253       EltTy V = Val.template get<EltTy>();
254       Val = new VecTy();
255       Val.template get<VecTy*>()->push_back(V);
256     }
257 
258     // Add the new value, we know we have a vector.
259     Val.template get<VecTy*>()->push_back(NewVal);
260   }
261 
262   void pop_back() {
263     // If we have a single value, convert to empty.
264     if (Val.template is<EltTy>())
265       Val = (EltTy)nullptr;
266     else if (VecTy *Vec = Val.template get<VecTy*>())
267       Vec->pop_back();
268   }
269 
270   void clear() {
271     // If we have a single value, convert to empty.
272     if (Val.template is<EltTy>()) {
273       Val = EltTy();
274     } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
275       // If we have a vector form, just clear it.
276       Vec->clear();
277     }
278     // Otherwise, we're already empty.
279   }
280 
281   iterator erase(iterator I) {
282     assert(I >= begin() && "Iterator to erase is out of bounds.");
283     assert(I < end() && "Erasing at past-the-end iterator.");
284 
285     // If we have a single value, convert to empty.
286     if (Val.template is<EltTy>()) {
287       if (I == begin())
288         Val = EltTy();
289     } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
290       // multiple items in a vector; just do the erase, there is no
291       // benefit to collapsing back to a pointer
292       return Vec->erase(I);
293     }
294     return end();
295   }
296 
297   iterator erase(iterator S, iterator E) {
298     assert(S >= begin() && "Range to erase is out of bounds.");
299     assert(S <= E && "Trying to erase invalid range.");
300     assert(E <= end() && "Trying to erase past the end.");
301 
302     if (Val.template is<EltTy>()) {
303       if (S == begin() && S != E)
304         Val = EltTy();
305     } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
306       return Vec->erase(S, E);
307     }
308     return end();
309   }
310 
311   iterator insert(iterator I, const EltTy &Elt) {
312     assert(I >= this->begin() && "Insertion iterator is out of bounds.");
313     assert(I <= this->end() && "Inserting past the end of the vector.");
314     if (I == end()) {
315       push_back(Elt);
316       return std::prev(end());
317     }
318     assert(!Val.isNull() && "Null value with non-end insert iterator.");
319     if (Val.template is<EltTy>()) {
320       EltTy V = Val.template get<EltTy>();
321       assert(I == begin());
322       Val = Elt;
323       push_back(V);
324       return begin();
325     }
326 
327     return Val.template get<VecTy*>()->insert(I, Elt);
328   }
329 
330   template<typename ItTy>
331   iterator insert(iterator I, ItTy From, ItTy To) {
332     assert(I >= this->begin() && "Insertion iterator is out of bounds.");
333     assert(I <= this->end() && "Inserting past the end of the vector.");
334     if (From == To)
335       return I;
336 
337     // If we have a single value, convert to a vector.
338     ptrdiff_t Offset = I - begin();
339     if (Val.isNull()) {
340       if (std::next(From) == To) {
341         Val = *From;
342         return begin();
343       }
344 
345       Val = new VecTy();
346     } else if (Val.template is<EltTy>()) {
347       EltTy V = Val.template get<EltTy>();
348       Val = new VecTy();
349       Val.template get<VecTy*>()->push_back(V);
350     }
351     return Val.template get<VecTy*>()->insert(begin() + Offset, From, To);
352   }
353 };
354 
355 } // end namespace llvm
356 
357 #endif // LLVM_ADT_TINYPTRVECTOR_H
358