1 //===- llvm/ADT/TinyPtrVector.h - 'Normally tiny' vectors -------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_ADT_TINYPTRVECTOR_H
10 #define LLVM_ADT_TINYPTRVECTOR_H
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/None.h"
14 #include "llvm/ADT/PointerUnion.h"
15 #include "llvm/ADT/SmallVector.h"
19 #include <type_traits>
23 /// TinyPtrVector - This class is specialized for cases where there are
24 /// normally 0 or 1 element in a vector, but is general enough to go beyond that
27 /// NOTE: This container doesn't allow you to store a null pointer into it.
29 template <typename EltTy
>
32 using VecTy
= SmallVector
<EltTy
, 4>;
33 using value_type
= typename
VecTy::value_type
;
34 // EltTy must be the first pointer type so that is<EltTy> is true for the
35 // default-constructed PtrUnion. This allows an empty TinyPtrVector to
36 // naturally vend a begin/end iterator of type EltTy* without an additional
37 // check for the empty state.
38 using PtrUnion
= PointerUnion
<EltTy
, VecTy
*>;
44 TinyPtrVector() = default;
47 if (VecTy
*V
= Val
.template dyn_cast
<VecTy
*>())
51 TinyPtrVector(const TinyPtrVector
&RHS
) : Val(RHS
.Val
) {
52 if (VecTy
*V
= Val
.template dyn_cast
<VecTy
*>())
56 TinyPtrVector
&operator=(const TinyPtrVector
&RHS
) {
64 // Try to squeeze into the single slot. If it won't fit, allocate a copied
66 if (Val
.template is
<EltTy
>()) {
70 Val
= new VecTy(*RHS
.Val
.template get
<VecTy
*>());
74 // If we have a full vector allocated, try to re-use it.
75 if (RHS
.Val
.template is
<EltTy
>()) {
76 Val
.template get
<VecTy
*>()->clear();
77 Val
.template get
<VecTy
*>()->push_back(RHS
.front());
79 *Val
.template get
<VecTy
*>() = *RHS
.Val
.template get
<VecTy
*>();
84 TinyPtrVector(TinyPtrVector
&&RHS
) : Val(RHS
.Val
) {
85 RHS
.Val
= (EltTy
)nullptr;
88 TinyPtrVector
&operator=(TinyPtrVector
&&RHS
) {
96 // If this vector has been allocated on the heap, re-use it if cheap. If it
97 // would require more copying, just delete it and we'll steal the other
99 if (VecTy
*V
= Val
.template dyn_cast
<VecTy
*>()) {
100 if (RHS
.Val
.template is
<EltTy
>()) {
102 V
->push_back(RHS
.front());
114 TinyPtrVector(std::initializer_list
<EltTy
> IL
)
117 : IL
.size() == 1 ? PtrUnion(*IL
.begin())
118 : PtrUnion(new VecTy(IL
.begin(), IL
.end()))) {}
120 /// Constructor from an ArrayRef.
122 /// This also is a constructor for individual array elements due to the single
123 /// element constructor for ArrayRef.
124 explicit TinyPtrVector(ArrayRef
<EltTy
> Elts
)
129 : PtrUnion(new VecTy(Elts
.begin(), Elts
.end()))) {}
131 TinyPtrVector(size_t Count
, EltTy Value
)
132 : Val(Count
== 0 ? PtrUnion()
133 : Count
== 1 ? PtrUnion(Value
)
134 : PtrUnion(new VecTy(Count
, Value
))) {}
136 // implicit conversion operator to ArrayRef.
137 operator ArrayRef
<EltTy
>() const {
140 if (Val
.template is
<EltTy
>())
141 return *Val
.getAddrOfPtr1();
142 return *Val
.template get
<VecTy
*>();
145 // implicit conversion operator to MutableArrayRef.
146 operator MutableArrayRef
<EltTy
>() {
149 if (Val
.template is
<EltTy
>())
150 return *Val
.getAddrOfPtr1();
151 return *Val
.template get
<VecTy
*>();
154 // Implicit conversion to ArrayRef<U> if EltTy* implicitly converts to U*.
156 typename
std::enable_if
<
157 std::is_convertible
<ArrayRef
<EltTy
>, ArrayRef
<U
>>::value
,
159 operator ArrayRef
<U
>() const {
160 return operator ArrayRef
<EltTy
>();
164 // This vector can be empty if it contains no element, or if it
165 // contains a pointer to an empty vector.
166 if (Val
.isNull()) return true;
167 if (VecTy
*Vec
= Val
.template dyn_cast
<VecTy
*>())
172 unsigned size() const {
175 if (Val
.template is
<EltTy
>())
177 return Val
.template get
<VecTy
*>()->size();
180 using iterator
= EltTy
*;
181 using const_iterator
= const EltTy
*;
182 using reverse_iterator
= std::reverse_iterator
<iterator
>;
183 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
186 if (Val
.template is
<EltTy
>())
187 return Val
.getAddrOfPtr1();
189 return Val
.template get
<VecTy
*>()->begin();
193 if (Val
.template is
<EltTy
>())
194 return begin() + (Val
.isNull() ? 0 : 1);
196 return Val
.template get
<VecTy
*>()->end();
199 const_iterator
begin() const {
200 return (const_iterator
)const_cast<TinyPtrVector
*>(this)->begin();
203 const_iterator
end() const {
204 return (const_iterator
)const_cast<TinyPtrVector
*>(this)->end();
207 reverse_iterator
rbegin() { return reverse_iterator(end()); }
208 reverse_iterator
rend() { return reverse_iterator(begin()); }
210 const_reverse_iterator
rbegin() const {
211 return const_reverse_iterator(end());
214 const_reverse_iterator
rend() const {
215 return const_reverse_iterator(begin());
218 EltTy
operator[](unsigned i
) const {
219 assert(!Val
.isNull() && "can't index into an empty vector");
220 if (Val
.template is
<EltTy
>()) {
221 assert(i
== 0 && "tinyvector index out of range");
222 return Val
.template get
<EltTy
>();
225 assert(i
< Val
.template get
<VecTy
*>()->size() &&
226 "tinyvector index out of range");
227 return (*Val
.template get
<VecTy
*>())[i
];
230 EltTy
front() const {
231 assert(!empty() && "vector empty");
232 if (Val
.template is
<EltTy
>())
233 return Val
.template get
<EltTy
>();
234 return Val
.template get
<VecTy
*>()->front();
238 assert(!empty() && "vector empty");
239 if (Val
.template is
<EltTy
>())
240 return Val
.template get
<EltTy
>();
241 return Val
.template get
<VecTy
*>()->back();
244 void push_back(EltTy NewVal
) {
245 // If we have nothing, add something.
248 assert(!Val
.isNull() && "Can't add a null value");
252 // If we have a single value, convert to a vector.
253 if (Val
.template is
<EltTy
>()) {
254 EltTy V
= Val
.template get
<EltTy
>();
256 Val
.template get
<VecTy
*>()->push_back(V
);
259 // Add the new value, we know we have a vector.
260 Val
.template get
<VecTy
*>()->push_back(NewVal
);
264 // If we have a single value, convert to empty.
265 if (Val
.template is
<EltTy
>())
266 Val
= (EltTy
)nullptr;
267 else if (VecTy
*Vec
= Val
.template get
<VecTy
*>())
272 // If we have a single value, convert to empty.
273 if (Val
.template is
<EltTy
>()) {
275 } else if (VecTy
*Vec
= Val
.template dyn_cast
<VecTy
*>()) {
276 // If we have a vector form, just clear it.
279 // Otherwise, we're already empty.
282 iterator
erase(iterator I
) {
283 assert(I
>= begin() && "Iterator to erase is out of bounds.");
284 assert(I
< end() && "Erasing at past-the-end iterator.");
286 // If we have a single value, convert to empty.
287 if (Val
.template is
<EltTy
>()) {
290 } else if (VecTy
*Vec
= Val
.template dyn_cast
<VecTy
*>()) {
291 // multiple items in a vector; just do the erase, there is no
292 // benefit to collapsing back to a pointer
293 return Vec
->erase(I
);
298 iterator
erase(iterator S
, iterator E
) {
299 assert(S
>= begin() && "Range to erase is out of bounds.");
300 assert(S
<= E
&& "Trying to erase invalid range.");
301 assert(E
<= end() && "Trying to erase past the end.");
303 if (Val
.template is
<EltTy
>()) {
304 if (S
== begin() && S
!= E
)
306 } else if (VecTy
*Vec
= Val
.template dyn_cast
<VecTy
*>()) {
307 return Vec
->erase(S
, E
);
312 iterator
insert(iterator I
, const EltTy
&Elt
) {
313 assert(I
>= this->begin() && "Insertion iterator is out of bounds.");
314 assert(I
<= this->end() && "Inserting past the end of the vector.");
317 return std::prev(end());
319 assert(!Val
.isNull() && "Null value with non-end insert iterator.");
320 if (Val
.template is
<EltTy
>()) {
321 EltTy V
= Val
.template get
<EltTy
>();
322 assert(I
== begin());
328 return Val
.template get
<VecTy
*>()->insert(I
, Elt
);
331 template<typename ItTy
>
332 iterator
insert(iterator I
, ItTy From
, ItTy To
) {
333 assert(I
>= this->begin() && "Insertion iterator is out of bounds.");
334 assert(I
<= this->end() && "Inserting past the end of the vector.");
338 // If we have a single value, convert to a vector.
339 ptrdiff_t Offset
= I
- begin();
341 if (std::next(From
) == To
) {
347 } else if (Val
.template is
<EltTy
>()) {
348 EltTy V
= Val
.template get
<EltTy
>();
350 Val
.template get
<VecTy
*>()->push_back(V
);
352 return Val
.template get
<VecTy
*>()->insert(begin() + Offset
, From
, To
);
356 } // end namespace llvm
358 #endif // LLVM_ADT_TINYPTRVECTOR_H