LLVM 22.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
17#include "llvm/ADT/ADL.h"
21#include "llvm/ADT/iterator.h"
22#include <cstddef>
23#include <functional>
24#include <initializer_list>
25#include <set>
26#include <utility>
27
28namespace llvm {
29
30/// SmallSetIterator - This class implements a const_iterator for SmallSet by
31/// delegating to the underlying SmallVector or Set iterators.
32template <typename T, unsigned N, typename C>
34 : public iterator_facade_base<SmallSetIterator<T, N, C>,
35 std::forward_iterator_tag, T> {
36private:
37 using SetIterTy = typename std::set<T, C>::const_iterator;
38 using VecIterTy = typename SmallVector<T, N>::const_iterator;
40
41 /// Iterators to the parts of the SmallSet containing the data. They are set
42 /// depending on isSmall.
43 union {
44 SetIterTy SetIter;
45 VecIterTy VecIter;
46 };
47
48 bool IsSmall;
49
50public:
51 SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), IsSmall(false) {}
52
53 SmallSetIterator(VecIterTy VecIter) : VecIter(VecIter), IsSmall(true) {}
54
55 // Spell out destructor, copy/move constructor and assignment operators for
56 // MSVC STL, where set<T>::const_iterator is not trivially copy constructible.
58 if (IsSmall)
59 VecIter.~VecIterTy();
60 else
61 SetIter.~SetIterTy();
62 }
63
64 SmallSetIterator(const SmallSetIterator &Other) : IsSmall(Other.IsSmall) {
65 if (IsSmall)
66 VecIter = Other.VecIter;
67 else
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);
71 }
72
74 if (IsSmall)
75 VecIter = std::move(Other.VecIter);
76 else
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));
80 }
81
83 // Call destructor for SetIter, so it gets properly destroyed if it is
84 // not trivially destructible in case we are setting VecIter.
85 if (!IsSmall)
86 SetIter.~SetIterTy();
87
88 IsSmall = Other.IsSmall;
89 if (IsSmall)
90 VecIter = Other.VecIter;
91 else
92 new (&SetIter) SetIterTy(Other.SetIter);
93 return *this;
94 }
95
97 // Call destructor for SetIter, so it gets properly destroyed if it is
98 // not trivially destructible in case we are setting VecIter.
99 if (!IsSmall)
100 SetIter.~SetIterTy();
101
102 IsSmall = Other.IsSmall;
103 if (IsSmall)
104 VecIter = std::move(Other.VecIter);
105 else
106 new (&SetIter) SetIterTy(std::move(Other.SetIter));
107 return *this;
108 }
109
110 bool operator==(const SmallSetIterator &RHS) const {
111 if (IsSmall != RHS.IsSmall)
112 return false;
113 if (IsSmall)
114 return VecIter == RHS.VecIter;
115 return SetIter == RHS.SetIter;
116 }
117
118 SmallSetIterator &operator++() { // Preincrement
119 if (IsSmall)
120 ++VecIter;
121 else
122 ++SetIter;
123 return *this;
124 }
125
126 const T &operator*() const { return IsSmall ? *VecIter : *SetIter; }
127};
128
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.
133template <typename T, unsigned N, typename C = std::less<T>>
134class SmallSet {
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;
139 std::set<T, C> Set;
140
141 // In small mode SmallPtrSet uses linear search for the elements, so it is
142 // not a good idea to choose this value too high. You may consider using a
143 // DenseSet<> instead if you expect many elements in the set.
144 static_assert(N <= 32, "N should be small");
145
146public:
147 using key_type = T;
148 using size_type = size_t;
149 using value_type = T;
151
152 SmallSet() = default;
153 SmallSet(const SmallSet &) = default;
154 SmallSet(SmallSet &&) = default;
155
156 template <typename IterT> SmallSet(IterT Begin, IterT End) {
157 insert(Begin, End);
158 }
159
160 template <typename Range>
162 : SmallSet(adl_begin(R), adl_end(R)) {}
163
164 SmallSet(std::initializer_list<T> L) { insert(L.begin(), L.end()); }
165
166 SmallSet &operator=(const SmallSet &) = default;
168
169 [[nodiscard]] bool empty() const { return Vector.empty() && Set.empty(); }
170
171 size_type size() const {
172 return isSmall() ? Vector.size() : Set.size();
173 }
174
175 /// count - Return 1 if the element is in the set, 0 otherwise.
176 size_type count(const T &V) const { return contains(V) ? 1 : 0; }
177
178 /// insert - Insert an element into the set if it isn't already there.
179 /// Returns a pair. The first value of it is an iterator to the inserted
180 /// element or the existing element in the set. The second value is true
181 /// if the element is inserted (it was not in the set before).
182 std::pair<const_iterator, bool> insert(const T &V) { return insertImpl(V); }
183
184 std::pair<const_iterator, bool> insert(T &&V) {
185 return insertImpl(std::move(V));
186 }
187
188 template <typename IterT>
189 void insert(IterT I, IterT E) {
190 for (; I != E; ++I)
191 insert(*I);
192 }
193
194 template <typename Range> void insert_range(Range &&R) {
195 insert(adl_begin(R), adl_end(R));
196 }
197
198 bool erase(const T &V) {
199 if (!isSmall())
200 return Set.erase(V);
201 auto I = vfind(V);
202 if (I != Vector.end()) {
203 Vector.erase(I);
204 return true;
205 }
206 return false;
207 }
208
209 void clear() {
210 Vector.clear();
211 Set.clear();
212 }
213
215 if (isSmall())
216 return {Vector.begin()};
217 return {Set.begin()};
218 }
219
221 if (isSmall())
222 return {Vector.end()};
223 return {Set.end()};
224 }
225
226 /// Check if the SmallSet contains the given element.
227 bool contains(const T &V) const {
228 if (isSmall())
229 return vfind(V) != Vector.end();
230 return Set.find(V) != Set.end();
231 }
232
233private:
234 bool isSmall() const { return Set.empty(); }
235
236 template <typename ArgType>
237 std::pair<const_iterator, bool> insertImpl(ArgType &&V) {
238 static_assert(std::is_convertible_v<ArgType, T>,
239 "ArgType must be convertible to T!");
240 if (!isSmall()) {
241 auto [I, Inserted] = Set.insert(std::forward<ArgType>(V));
242 return {const_iterator(I), Inserted};
243 }
244
245 auto I = vfind(V);
246 if (I != Vector.end()) // Don't reinsert if it already exists.
247 return {const_iterator(I), false};
248 if (Vector.size() < N) {
249 Vector.push_back(std::forward<ArgType>(V));
250 return {const_iterator(std::prev(Vector.end())), true};
251 }
252 // Otherwise, grow from vector to set.
253 Set.insert(std::make_move_iterator(Vector.begin()),
254 std::make_move_iterator(Vector.end()));
255 Vector.clear();
256 return {const_iterator(Set.insert(std::forward<ArgType>(V)).first), true};
257 }
258
259 // Handwritten linear search. The use of std::find might hurt performance as
260 // its implementation may be optimized for larger containers.
261 typename SmallVector<T, N>::const_iterator vfind(const T &V) const {
262 for (auto I = Vector.begin(), E = Vector.end(); I != E; ++I)
263 if (*I == V)
264 return I;
265 return Vector.end();
266 }
267};
268
269/// If this set is of pointer values, transparently switch over to using
270/// SmallPtrSet for performance.
271template <typename PointeeType, unsigned N>
272class SmallSet<PointeeType *, N> : public SmallPtrSet<PointeeType *, N> {};
273
274/// Equality comparison for SmallSet.
275///
276/// Iterates over elements of LHS confirming that each element is also a member
277/// of RHS, and that RHS contains no additional values.
278/// Equivalent to N calls to RHS.count.
279/// For small-set mode amortized complexity is O(N^2)
280/// For large-set mode amortized complexity is linear, worst case is O(N^2) (if
281/// every hash collides).
282template <typename T, unsigned LN, unsigned RN, typename C>
284 if (LHS.size() != RHS.size())
285 return false;
286
287 // All elements in LHS must also be in RHS
288 return all_of(LHS, [&RHS](const T &E) { return RHS.count(E); });
289}
290
291/// Inequality comparison for SmallSet.
292///
293/// Equivalent to !(LHS == RHS). See operator== for performance notes.
294template <typename T, unsigned LN, unsigned RN, typename C>
296 return !(LHS == RHS);
297}
298
299} // end namespace llvm
300
301#endif // LLVM_ADT_SMALLSET_H
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
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
This file contains library features backported from future STL versions.
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:541
SmallSetIterator - This class implements a const_iterator for SmallSet by delegating to the underlyin...
Definition: SmallSet.h:35
SmallSetIterator & operator=(SmallSetIterator &&Other)
Definition: SmallSet.h:96
SmallSetIterator & operator++()
Definition: SmallSet.h:118
bool operator==(const SmallSetIterator &RHS) const
Definition: SmallSet.h:110
SmallSetIterator(SetIterTy SetIter)
Definition: SmallSet.h:51
SmallSetIterator & operator=(const SmallSetIterator &Other)
Definition: SmallSet.h:82
SmallSetIterator(const SmallSetIterator &Other)
Definition: SmallSet.h:64
const T & operator*() const
Definition: SmallSet.h:126
SmallSetIterator(VecIterTy VecIter)
Definition: SmallSet.h:53
SmallSetIterator(SmallSetIterator &&Other)
Definition: SmallSet.h:73
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:134
const_iterator begin() const
Definition: SmallSet.h:214
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
Definition: SmallSet.h:176
SmallSetIterator< T, N, C > const_iterator
Definition: SmallSet.h:150
bool empty() const
Definition: SmallSet.h:169
void insert(IterT I, IterT E)
Definition: SmallSet.h:189
void insert_range(Range &&R)
Definition: SmallSet.h:194
std::pair< const_iterator, bool > insert(T &&V)
Definition: SmallSet.h:184
SmallSet(std::initializer_list< T > L)
Definition: SmallSet.h:164
SmallSet()=default
bool erase(const T &V)
Definition: SmallSet.h:198
size_t size_type
Definition: SmallSet.h:148
void clear()
Definition: SmallSet.h:209
SmallSet(llvm::from_range_t, Range &&R)
Definition: SmallSet.h:161
SmallSet & operator=(const SmallSet &)=default
SmallSet(SmallSet &&)=default
SmallSet(const SmallSet &)=default
const_iterator end() const
Definition: SmallSet.h:220
SmallSet(IterT Begin, IterT End)
Definition: SmallSet.h:156
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition: SmallSet.h:227
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:182
size_type size() const
Definition: SmallSet.h:171
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
CRTP base class which implements the entire standard iterator facade in terms of a minimal subset of ...
Definition: iterator.h:80
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:1744
constexpr auto adl_begin(RangeT &&range) -> decltype(adl_detail::begin_impl(std::forward< RangeT >(range)))
Returns the begin iterator to range using std::begin and function found through Argument-Dependent Lo...
Definition: ADL.h:78
bool operator!=(uint64_t V1, const APInt &V2)
Definition: APInt.h:2113
constexpr auto adl_end(RangeT &&range) -> decltype(adl_detail::end_impl(std::forward< RangeT >(range)))
Returns the end iterator to range using std::end and functions found through Argument-Dependent Looku...
Definition: ADL.h:86
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
@ Other
Any other memory.
#define N