File indexing completed on 2026-05-10 08:43:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_ADT_SMALLSET_H
0015 #define LLVM_ADT_SMALLSET_H
0016
0017 #include "llvm/ADT/SmallPtrSet.h"
0018 #include "llvm/ADT/SmallVector.h"
0019 #include "llvm/ADT/iterator.h"
0020 #include <cstddef>
0021 #include <functional>
0022 #include <initializer_list>
0023 #include <set>
0024 #include <utility>
0025
0026 namespace llvm {
0027
0028
0029
0030 template <typename T, unsigned N, typename C>
0031 class SmallSetIterator
0032 : public iterator_facade_base<SmallSetIterator<T, N, C>,
0033 std::forward_iterator_tag, T> {
0034 private:
0035 using SetIterTy = typename std::set<T, C>::const_iterator;
0036 using VecIterTy = typename SmallVector<T, N>::const_iterator;
0037 using SelfTy = SmallSetIterator<T, N, C>;
0038
0039
0040
0041 union {
0042 SetIterTy SetIter;
0043 VecIterTy VecIter;
0044 };
0045
0046 bool IsSmall;
0047
0048 public:
0049 SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), IsSmall(false) {}
0050
0051 SmallSetIterator(VecIterTy VecIter) : VecIter(VecIter), IsSmall(true) {}
0052
0053
0054
0055 ~SmallSetIterator() {
0056 if (IsSmall)
0057 VecIter.~VecIterTy();
0058 else
0059 SetIter.~SetIterTy();
0060 }
0061
0062 SmallSetIterator(const SmallSetIterator &Other) : IsSmall(Other.IsSmall) {
0063 if (IsSmall)
0064 VecIter = Other.VecIter;
0065 else
0066
0067
0068 new (&SetIter) SetIterTy(Other.SetIter);
0069 }
0070
0071 SmallSetIterator(SmallSetIterator &&Other) : IsSmall(Other.IsSmall) {
0072 if (IsSmall)
0073 VecIter = std::move(Other.VecIter);
0074 else
0075
0076
0077 new (&SetIter) SetIterTy(std::move(Other.SetIter));
0078 }
0079
0080 SmallSetIterator& operator=(const SmallSetIterator& Other) {
0081
0082
0083 if (!IsSmall)
0084 SetIter.~SetIterTy();
0085
0086 IsSmall = Other.IsSmall;
0087 if (IsSmall)
0088 VecIter = Other.VecIter;
0089 else
0090 new (&SetIter) SetIterTy(Other.SetIter);
0091 return *this;
0092 }
0093
0094 SmallSetIterator& operator=(SmallSetIterator&& Other) {
0095
0096
0097 if (!IsSmall)
0098 SetIter.~SetIterTy();
0099
0100 IsSmall = Other.IsSmall;
0101 if (IsSmall)
0102 VecIter = std::move(Other.VecIter);
0103 else
0104 new (&SetIter) SetIterTy(std::move(Other.SetIter));
0105 return *this;
0106 }
0107
0108 bool operator==(const SmallSetIterator &RHS) const {
0109 if (IsSmall != RHS.IsSmall)
0110 return false;
0111 if (IsSmall)
0112 return VecIter == RHS.VecIter;
0113 return SetIter == RHS.SetIter;
0114 }
0115
0116 SmallSetIterator &operator++() {
0117 if (IsSmall)
0118 ++VecIter;
0119 else
0120 ++SetIter;
0121 return *this;
0122 }
0123
0124 const T &operator*() const { return IsSmall ? *VecIter : *SetIter; }
0125 };
0126
0127
0128
0129
0130
0131 template <typename T, unsigned N, typename C = std::less<T>>
0132 class SmallSet {
0133
0134
0135
0136 SmallVector<T, N> Vector;
0137 std::set<T, C> Set;
0138
0139
0140
0141
0142 static_assert(N <= 32, "N should be small");
0143
0144 public:
0145 using key_type = T;
0146 using size_type = size_t;
0147 using value_type = T;
0148 using const_iterator = SmallSetIterator<T, N, C>;
0149
0150 SmallSet() = default;
0151 SmallSet(const SmallSet &) = default;
0152 SmallSet(SmallSet &&) = default;
0153
0154 template <typename IterT> SmallSet(IterT Begin, IterT End) {
0155 insert(Begin, End);
0156 }
0157
0158 template <typename RangeT>
0159 explicit SmallSet(const iterator_range<RangeT> &R) {
0160 insert(R.begin(), R.end());
0161 }
0162
0163 SmallSet(std::initializer_list<T> L) { insert(L.begin(), L.end()); }
0164
0165 SmallSet &operator=(const SmallSet &) = default;
0166 SmallSet &operator=(SmallSet &&) = default;
0167
0168 [[nodiscard]] bool empty() const { return Vector.empty() && Set.empty(); }
0169
0170 size_type size() const {
0171 return isSmall() ? Vector.size() : Set.size();
0172 }
0173
0174
0175 size_type count(const T &V) const { return contains(V) ? 1 : 0; }
0176
0177
0178
0179
0180
0181 std::pair<const_iterator, bool> insert(const T &V) { return insertImpl(V); }
0182
0183 std::pair<const_iterator, bool> insert(T &&V) {
0184 return insertImpl(std::move(V));
0185 }
0186
0187 template <typename IterT>
0188 void insert(IterT I, IterT E) {
0189 for (; I != E; ++I)
0190 insert(*I);
0191 }
0192
0193 bool erase(const T &V) {
0194 if (!isSmall())
0195 return Set.erase(V);
0196 auto I = vfind(V);
0197 if (I != Vector.end()) {
0198 Vector.erase(I);
0199 return true;
0200 }
0201 return false;
0202 }
0203
0204 void clear() {
0205 Vector.clear();
0206 Set.clear();
0207 }
0208
0209 const_iterator begin() const {
0210 if (isSmall())
0211 return {Vector.begin()};
0212 return {Set.begin()};
0213 }
0214
0215 const_iterator end() const {
0216 if (isSmall())
0217 return {Vector.end()};
0218 return {Set.end()};
0219 }
0220
0221
0222 bool contains(const T &V) const {
0223 if (isSmall())
0224 return vfind(V) != Vector.end();
0225 return Set.find(V) != Set.end();
0226 }
0227
0228 private:
0229 bool isSmall() const { return Set.empty(); }
0230
0231 template <typename ArgType>
0232 std::pair<const_iterator, bool> insertImpl(ArgType &&V) {
0233 static_assert(std::is_convertible_v<ArgType, T>,
0234 "ArgType must be convertible to T!");
0235 if (!isSmall()) {
0236 auto [I, Inserted] = Set.insert(std::forward<ArgType>(V));
0237 return {const_iterator(I), Inserted};
0238 }
0239
0240 auto I = vfind(V);
0241 if (I != Vector.end())
0242 return {const_iterator(I), false};
0243 if (Vector.size() < N) {
0244 Vector.push_back(std::forward<ArgType>(V));
0245 return {const_iterator(std::prev(Vector.end())), true};
0246 }
0247
0248 Set.insert(std::make_move_iterator(Vector.begin()),
0249 std::make_move_iterator(Vector.end()));
0250 Vector.clear();
0251 return {const_iterator(Set.insert(std::forward<ArgType>(V)).first), true};
0252 }
0253
0254
0255
0256 typename SmallVector<T, N>::const_iterator vfind(const T &V) const {
0257 for (auto I = Vector.begin(), E = Vector.end(); I != E; ++I)
0258 if (*I == V)
0259 return I;
0260 return Vector.end();
0261 }
0262 };
0263
0264
0265
0266 template <typename PointeeType, unsigned N>
0267 class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277 template <typename T, unsigned LN, unsigned RN, typename C>
0278 bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
0279 if (LHS.size() != RHS.size())
0280 return false;
0281
0282
0283 return all_of(LHS, [&RHS](const T &E) { return RHS.count(E); });
0284 }
0285
0286
0287
0288
0289 template <typename T, unsigned LN, unsigned RN, typename C>
0290 bool operator!=(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
0291 return !(LHS == RHS);
0292 }
0293
0294 }
0295
0296 #endif