1 //===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- 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 // This file defines the SmallSet class.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_ADT_SMALLSET_H
14 #define LLVM_ADT_SMALLSET_H
16 #include "llvm/ADT/None.h"
17 #include "llvm/ADT/SmallPtrSet.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/iterator.h"
20 #include "llvm/Support/Compiler.h"
21 #include "llvm/Support/type_traits.h"
25 #include <type_traits>
30 /// SmallSetIterator - This class implements a const_iterator for SmallSet by
31 /// delegating to the underlying SmallVector or Set iterators.
32 template <typename T
, unsigned N
, typename C
>
33 class SmallSetIterator
34 : public iterator_facade_base
<SmallSetIterator
<T
, N
, C
>,
35 std::forward_iterator_tag
, T
> {
37 using SetIterTy
= typename
std::set
<T
, C
>::const_iterator
;
38 using VecIterTy
= typename SmallVector
<T
, N
>::const_iterator
;
39 using SelfTy
= SmallSetIterator
<T
, N
, C
>;
41 /// Iterators to the parts of the SmallSet containing the data. They are set
42 /// depending on isSmall.
51 SmallSetIterator(SetIterTy SetIter
) : SetIter(SetIter
), isSmall(false) {}
53 SmallSetIterator(VecIterTy VecIter
) : VecIter(VecIter
), isSmall(true) {}
55 // Spell out destructor, copy/move constructor and assignment operators for
56 // MSVC STL, where set<T>::const_iterator is not trivially copy constructible.
64 SmallSetIterator(const SmallSetIterator
&Other
) : isSmall(Other
.isSmall
) {
66 VecIter
= Other
.VecIter
;
68 // Use placement new, to make sure SetIter is properly constructed, even
69 // if it is not trivially copy-able (e.g. in MSVC).
70 new (&SetIter
) SetIterTy(Other
.SetIter
);
73 SmallSetIterator(SmallSetIterator
&&Other
) : isSmall(Other
.isSmall
) {
75 VecIter
= std::move(Other
.VecIter
);
77 // Use placement new, to make sure SetIter is properly constructed, even
78 // if it is not trivially copy-able (e.g. in MSVC).
79 new (&SetIter
) SetIterTy(std::move(Other
.SetIter
));
82 SmallSetIterator
& operator=(const SmallSetIterator
& Other
) {
83 // Call destructor for SetIter, so it gets properly destroyed if it is
84 // not trivially destructible in case we are setting VecIter.
88 isSmall
= Other
.isSmall
;
90 VecIter
= Other
.VecIter
;
92 new (&SetIter
) SetIterTy(Other
.SetIter
);
96 SmallSetIterator
& operator=(SmallSetIterator
&& Other
) {
97 // Call destructor for SetIter, so it gets properly destroyed if it is
98 // not trivially destructible in case we are setting VecIter.
100 SetIter
.~SetIterTy();
102 isSmall
= Other
.isSmall
;
104 VecIter
= std::move(Other
.VecIter
);
106 new (&SetIter
) SetIterTy(std::move(Other
.SetIter
));
110 bool operator==(const SmallSetIterator
&RHS
) const {
111 if (isSmall
!= RHS
.isSmall
)
114 return VecIter
== RHS
.VecIter
;
115 return SetIter
== RHS
.SetIter
;
118 SmallSetIterator
&operator++() { // Preincrement
126 const T
&operator*() const { return isSmall
? *VecIter
: *SetIter
; }
129 /// SmallSet - This maintains a set of unique values, optimizing for the case
130 /// when the set is small (less than N). In this case, the set can be
131 /// maintained with no mallocs. If the set gets large, we expand to using an
132 /// std::set to maintain reasonable lookup times.
133 template <typename T
, unsigned N
, typename C
= std::less
<T
>>
135 /// Use a SmallVector to hold the elements here (even though it will never
136 /// reach its 'large' stage) to avoid calling the default ctors of elements
137 /// we will never use.
138 SmallVector
<T
, N
> Vector
;
141 using VIterator
= typename SmallVector
<T
, N
>::const_iterator
;
142 using mutable_iterator
= typename SmallVector
<T
, N
>::iterator
;
144 // In small mode SmallPtrSet uses linear search for the elements, so it is
145 // not a good idea to choose this value too high. You may consider using a
146 // DenseSet<> instead if you expect many elements in the set.
147 static_assert(N
<= 32, "N should be small");
150 using size_type
= size_t;
151 using const_iterator
= SmallSetIterator
<T
, N
, C
>;
153 SmallSet() = default;
155 LLVM_NODISCARD
bool empty() const {
156 return Vector
.empty() && Set
.empty();
159 size_type
size() const {
160 return isSmall() ? Vector
.size() : Set
.size();
163 /// count - Return 1 if the element is in the set, 0 otherwise.
164 size_type
count(const T
&V
) const {
166 // Since the collection is small, just do a linear search.
167 return vfind(V
) == Vector
.end() ? 0 : 1;
173 /// insert - Insert an element into the set if it isn't already there.
174 /// Returns true if the element is inserted (it was not in the set before).
175 /// The first value of the returned pair is unused and provided for
176 /// partial compatibility with the standard library self-associative container
178 // FIXME: Add iterators that abstract over the small and large form, and then
179 // return those here.
180 std::pair
<NoneType
, bool> insert(const T
&V
) {
182 return std::make_pair(None
, Set
.insert(V
).second
);
184 VIterator I
= vfind(V
);
185 if (I
!= Vector
.end()) // Don't reinsert if it already exists.
186 return std::make_pair(None
, false);
187 if (Vector
.size() < N
) {
189 return std::make_pair(None
, true);
192 // Otherwise, grow from vector to set.
193 while (!Vector
.empty()) {
194 Set
.insert(Vector
.back());
198 return std::make_pair(None
, true);
201 template <typename IterT
>
202 void insert(IterT I
, IterT E
) {
207 bool erase(const T
&V
) {
210 for (mutable_iterator I
= Vector
.begin(), E
= Vector
.end(); I
!= E
; ++I
)
223 const_iterator
begin() const {
225 return {Vector
.begin()};
226 return {Set
.begin()};
229 const_iterator
end() const {
231 return {Vector
.end()};
236 bool isSmall() const { return Set
.empty(); }
238 VIterator
vfind(const T
&V
) const {
239 for (VIterator I
= Vector
.begin(), E
= Vector
.end(); I
!= E
; ++I
)
246 /// If this set is of pointer values, transparently switch over to using
247 /// SmallPtrSet for performance.
248 template <typename PointeeType
, unsigned N
>
249 class SmallSet
<PointeeType
*, N
> : public SmallPtrSet
<PointeeType
*, N
> {};
251 } // end namespace llvm
253 #endif // LLVM_ADT_SMALLSET_H