LLVM 20.0.0git
SmallSet.h
Go to the documentation of this file.
1//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- 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/// \file
10/// This file defines the SmallSet class.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_ADT_SMALLSET_H
15#define LLVM_ADT_SMALLSET_H
16
19#include "llvm/ADT/iterator.h"
20#include <cstddef>
21#include <functional>
22#include <initializer_list>
23#include <set>
24#include <utility>
25
26namespace llvm {
27
28/// SmallSetIterator - This class implements a const_iterator for SmallSet by
29/// delegating to the underlying SmallVector or Set iterators.
30template <typename T, unsigned N, typename C>
32 : public iterator_facade_base<SmallSetIterator<T, N, C>,
33 std::forward_iterator_tag, T> {
34private:
35 using SetIterTy = typename std::set<T, C>::const_iterator;
36 using VecIterTy = typename SmallVector<T, N>::const_iterator;
38
39 /// Iterators to the parts of the SmallSet containing the data. They are set
40 /// depending on isSmall.
41 union {
42 SetIterTy SetIter;
43 VecIterTy VecIter;
44 };
45
46 bool IsSmall;
47
48public:
49 SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), IsSmall(false) {}
50
51 SmallSetIterator(VecIterTy VecIter) : VecIter(VecIter), IsSmall(true) {}
52
53 // Spell out destructor, copy/move constructor and assignment operators for
54 // MSVC STL, where set<T>::const_iterator is not trivially copy constructible.
56 if (IsSmall)
57 VecIter.~VecIterTy();
58 else
59 SetIter.~SetIterTy();
60 }
61
62 SmallSetIterator(const SmallSetIterator &Other) : IsSmall(Other.IsSmall) {
63 if (IsSmall)
64 VecIter = Other.VecIter;
65 else
66 // Use placement new, to make sure SetIter is properly constructed, even
67 // if it is not trivially copy-able (e.g. in MSVC).
68 new (&SetIter) SetIterTy(Other.SetIter);
69 }
70
72 if (IsSmall)
73 VecIter = std::move(Other.VecIter);
74 else
75 // Use placement new, to make sure SetIter is properly constructed, even
76 // if it is not trivially copy-able (e.g. in MSVC).
77 new (&SetIter) SetIterTy(std::move(Other.SetIter));
78 }
79
81 // Call destructor for SetIter, so it gets properly destroyed if it is
82 // not trivially destructible in case we are setting VecIter.
83 if (!IsSmall)
84 SetIter.~SetIterTy();
85
86 IsSmall = Other.IsSmall;
87 if (IsSmall)
88 VecIter = Other.VecIter;
89 else
90 new (&SetIter) SetIterTy(Other.SetIter);
91 return *this;
92 }
93
95 // Call destructor for SetIter, so it gets properly destroyed if it is
96 // not trivially destructible in case we are setting VecIter.
97 if (!IsSmall)
98 SetIter.~SetIterTy();
99
100 IsSmall = Other.IsSmall;
101 if (IsSmall)
102 VecIter = std::move(Other.VecIter);
103 else
104 new (&SetIter) SetIterTy(std::move(Other.SetIter));
105 return *this;
106 }
107
108 bool operator==(const SmallSetIterator &RHS) const {
109 if (IsSmall != RHS.IsSmall)
110 return false;
111 if (IsSmall)
112 return VecIter == RHS.VecIter;
113 return SetIter == RHS.SetIter;
114 }
115
116 SmallSetIterator &operator++() { // Preincrement
117 if (IsSmall)
118 ++VecIter;
119 else
120 ++SetIter;
121 return *this;
122 }
123
124 const T &operator*() const { return IsSmall ? *VecIter : *SetIter; }
125};
126
127/// SmallSet - This maintains a set of unique values, optimizing for the case
128/// when the set is small (less than N). In this case, the set can be
129/// maintained with no mallocs. If the set gets large, we expand to using an
130/// std::set to maintain reasonable lookup times.
131template <typename T, unsigned N, typename C = std::less<T>>
132class SmallSet {
133 /// Use a SmallVector to hold the elements here (even though it will never
134 /// reach its 'large' stage) to avoid calling the default ctors of elements
135 /// we will never use.
136 SmallVector<T, N> Vector;
137 std::set<T, C> Set;
138
139 // In small mode SmallPtrSet uses linear search for the elements, so it is
140 // not a good idea to choose this value too high. You may consider using a
141 // DenseSet<> instead if you expect many elements in the set.
142 static_assert(N <= 32, "N should be small");
143
144public:
145 using key_type = T;
146 using size_type = size_t;
147 using value_type = T;
149
150 SmallSet() = default;
151 SmallSet(const SmallSet &) = default;
152 SmallSet(SmallSet &&) = default;
153
154 template <typename IterT> SmallSet(IterT Begin, IterT End) {
155 insert(Begin, End);
156 }
157
158 template <typename RangeT>
159 explicit SmallSet(const iterator_range<RangeT> &R) {
160 insert(R.begin(), R.end());
161 }
162
163 SmallSet(std::initializer_list<T> L) { insert(L.begin(), L.end()); }
164
165 SmallSet &operator=(const SmallSet &) = default;
167
168 [[nodiscard]] bool empty() const { return Vector.empty() && Set.empty(); }
169
170 size_type size() const {
171 return isSmall() ? Vector.size() : Set.size();
172 }
173
174 /// count - Return 1 if the element is in the set, 0 otherwise.
175 size_type count(const T &V) const { return contains(V) ? 1 : 0; }
176
177 /// insert - Insert an element into the set if it isn't already there.
178 /// Returns a pair. The first value of it is an iterator to the inserted
179 /// element or the existing element in the set. The second value is true
180 /// if the element is inserted (it was not in the set before).
181 std::pair<const_iterator, bool> insert(const T &V) { return insertImpl(V); }
182
183 std::pair<const_iterator, bool> insert(T &&V) {
184 return insertImpl(std::move(V));
185 }
186
187 template <typename IterT>
188 void insert(IterT I, IterT E) {
189 for (; I != E; ++I)
190 insert(*I);
191 }
192
193 bool erase(const T &V) {
194 if (!isSmall())
195 return Set.erase(V);
196 auto I = vfind(V);
197 if (I != Vector.end()) {
198 Vector.erase(I);
199 return true;
200 }
201 return false;
202 }
203
204 void clear() {
205 Vector.clear();
206 Set.clear();
207 }
208
210 if (isSmall())
211 return {Vector.begin()};
212 return {Set.begin()};
213 }
214
216 if (isSmall())
217 return {Vector.end()};
218 return {Set.end()};
219 }
220
221 /// Check if the SmallSet contains the given element.
222 bool contains(const T &V) const {
223 if (isSmall())
224 return vfind(V) != Vector.end();
225 return Set.find(V) != Set.end();
226 }
227
228private:
229 bool isSmall() const { return Set.empty(); }
230
231 template <typename ArgType>
232 std::pair<const_iterator, bool> insertImpl(ArgType &&V) {
233 static_assert(std::is_convertible_v<ArgType, T>,
234 "ArgType must be convertible to T!");
235 if (!isSmall()) {
236 auto [I, Inserted] = Set.insert(std::forward<ArgType>(V));
237 return {const_iterator(I), Inserted};
238 }
239
240 auto I = vfind(V);
241 if (I != Vector.end()) // Don't reinsert if it already exists.
242 return {const_iterator(I), false};
243 if (Vector.size() < N) {
244 Vector.push_back(std::forward<ArgType>(V));
245 return {const_iterator(std::prev(Vector.end())), true};
246 }
247 // Otherwise, grow from vector to set.
248 Set.insert(std::make_move_iterator(Vector.begin()),
249 std::make_move_iterator(Vector.end()));
250 Vector.clear();
251 return {const_iterator(Set.insert(std::forward<ArgType>(V)).first), true};
252 }
253
254 // Handwritten linear search. The use of std::find might hurt performance as
255 // its implementation may be optimized for larger containers.
256 typename SmallVector<T, N>::const_iterator vfind(const T &V) const {
257 for (auto I = Vector.begin(), E = Vector.end(); I != E; ++I)
258 if (*I == V)
259 return I;
260 return Vector.end();
261 }
262};
263
264/// If this set is of pointer values, transparently switch over to using
265/// SmallPtrSet for performance.
266template <typename PointeeType, unsigned N>
267class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
268
269/// Equality comparison for SmallSet.
270///
271/// Iterates over elements of LHS confirming that each element is also a member
272/// of RHS, and that RHS contains no additional values.
273/// Equivalent to N calls to RHS.count.
274/// For small-set mode amortized complexity is O(N^2)
275/// For large-set mode amortized complexity is linear, worst case is O(N^2) (if
276/// every hash collides).
277template <typename T, unsigned LN, unsigned RN, typename C>
279 if (LHS.size() != RHS.size())
280 return false;
281
282 // All elements in LHS must also be in RHS
283 return all_of(LHS, [&RHS](const T &E) { return RHS.count(E); });
284}
285
286/// Inequality comparison for SmallSet.
287///
288/// Equivalent to !(LHS == RHS). See operator== for performance notes.
289template <typename T, unsigned LN, unsigned RN, typename C>
291 return !(LHS == RHS);
292}
293
294} // end namespace llvm
295
296#endif // LLVM_ADT_SMALLSET_H
basic Basic Alias true
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
bool End
Definition: ELF_riscv.cpp:480
#define I(x, y, z)
Definition: MD5.cpp:58
#define T
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
Value * RHS
Value * LHS
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:519
SmallSetIterator - This class implements a const_iterator for SmallSet by delegating to the underlyin...
Definition: SmallSet.h:33
SmallSetIterator & operator=(SmallSetIterator &&Other)
Definition: SmallSet.h:94
SmallSetIterator & operator++()
Definition: SmallSet.h:116
bool operator==(const SmallSetIterator &RHS) const
Definition: SmallSet.h:108
SmallSetIterator(SetIterTy SetIter)
Definition: SmallSet.h:49
SmallSetIterator & operator=(const SmallSetIterator &Other)
Definition: SmallSet.h:80
SmallSetIterator(const SmallSetIterator &Other)
Definition: SmallSet.h:62
const T & operator*() const
Definition: SmallSet.h:124
SmallSetIterator(VecIterTy VecIter)
Definition: SmallSet.h:51
SmallSetIterator(SmallSetIterator &&Other)
Definition: SmallSet.h:71
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:132
SmallSet(const iterator_range< RangeT > &R)
Definition: SmallSet.h:159
const_iterator begin() const
Definition: SmallSet.h:209
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
Definition: SmallSet.h:175
SmallSetIterator< T, N, C > const_iterator
Definition: SmallSet.h:148
bool empty() const
Definition: SmallSet.h:168
void insert(IterT I, IterT E)
Definition: SmallSet.h:188
std::pair< const_iterator, bool > insert(T &&V)
Definition: SmallSet.h:183
SmallSet(std::initializer_list< T > L)
Definition: SmallSet.h:163
SmallSet()=default
bool erase(const T &V)
Definition: SmallSet.h:193
size_t size_type
Definition: SmallSet.h:146
void clear()
Definition: SmallSet.h:204
SmallSet & operator=(const SmallSet &)=default
SmallSet(SmallSet &&)=default
SmallSet(const SmallSet &)=default
const_iterator end() const
Definition: SmallSet.h:215
SmallSet(IterT Begin, IterT End)
Definition: SmallSet.h:154
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition: SmallSet.h:222
SmallSet & operator=(SmallSet &&)=default
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:181
size_type size() const
Definition: SmallSet.h:170
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
CRTP base class which implements the entire standard iterator facade in terms of a minimal subset of ...
Definition: iterator.h:80
A range adaptor for a pair of iterators.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1739
bool operator!=(uint64_t V1, const APInt &V2)
Definition: APInt.h:2082
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
@ Other
Any other memory.
#define N