Jlm
Loading...
Searching...
No Matches
HashSet.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#ifndef JLM_UTIL_HASHSET_HPP
7#define JLM_UTIL_HASHSET_HPP
8
9#include <jlm/util/Hash.hpp>
11
12#include <unordered_set>
13
14namespace jlm::util
15{
16
22template<typename ItemType, typename HashFunctor = Hash<ItemType>>
24{
25 using InternalSet = std::unordered_set<ItemType, HashFunctor>;
26
27public:
29 {
30 public:
31 using iterator_category = std::forward_iterator_tag;
32 using value_type = ItemType;
33 using difference_type = std::ptrdiff_t;
34 using pointer = ItemType *;
35 using reference = ItemType &;
36
37 private:
38 friend HashSet;
39
40 explicit ItemConstIterator(const typename InternalSet::const_iterator & it)
41 : It_(it)
42 {}
43
44 public:
45 [[nodiscard]] ItemType *
46 Item() const noexcept
47 {
48 return It_.operator->();
49 }
50
51 const ItemType &
52 operator*() const
53 {
54 return It_.operator*();
55 }
56
57 ItemType *
58 operator->() const
59 {
60 return Item();
61 }
62
65 {
66 ++It_;
67 return *this;
68 }
69
72 {
73 ItemConstIterator tmp = *this;
74 ++*this;
75 return tmp;
76 }
77
78 bool
79 operator==(const ItemConstIterator & other) const
80 {
81 return It_ == other.It_;
82 }
83
84 bool
85 operator!=(const ItemConstIterator & other) const
86 {
87 return !operator==(other);
88 }
89
90 private:
91 typename InternalSet::const_iterator It_;
92 };
93
94 ~HashSet() noexcept = default;
95
96 HashSet() = default;
97
98 template<class InputIt>
99 HashSet(InputIt begin, InputIt end)
100 : Set_(begin, end)
101 {}
102
103 HashSet(const HashSet & other)
104 : Set_(other.Set_)
105 {}
106
107 HashSet(HashSet && other) noexcept
108 : Set_(std::move(other.Set_))
109 {}
110
111 HashSet(std::initializer_list<ItemType> initializerList)
112 : Set_(initializerList)
113 {}
114
115 template<typename OtherHashFunctor>
116 explicit HashSet(const std::unordered_set<ItemType, OtherHashFunctor> & other)
117 : Set_(other.begin(), other.end())
118 {}
119
120 HashSet &
121 operator=(const HashSet & other)
122 {
123 Set_ = other.Set_;
124 return *this;
125 }
126
127 HashSet &
128 operator=(HashSet && other) noexcept
129 {
130 Set_ = std::move(other.Set_);
131 return *this;
132 }
133
137 void
138 Clear() noexcept
139 {
140 Set_.clear();
141 }
142
149 bool
150 Contains(const ItemType & item) const noexcept
151 {
152 return Set_.find(item) != Set_.end();
153 }
154
162 bool
163 IsSubsetOf(const HashSet<ItemType> & other) const noexcept
164 {
165 if (Size() > other.Size())
166 {
167 return false;
168 }
169
170 for (auto & item : other.Items())
171 {
172 if (!other.Contains(item))
173 {
174 return false;
175 }
176 }
177
178 return true;
179 }
180
186 [[nodiscard]] std::size_t
187 Size() const noexcept
188 {
189 return Set_.size();
190 }
191
197 [[nodiscard]] bool
198 IsEmpty() const noexcept
199 {
200 return Size() == 0;
201 }
202
209 bool
210 insert(ItemType item)
211 {
212 auto size = Size();
213 Set_.emplace(std::move(item));
214 return (size != Size());
215 }
216
223 Items() const noexcept
224 {
225 return { ItemConstIterator(Set_.begin()), ItemConstIterator(Set_.end()) };
226 }
227
235 bool
237 {
238 const size_t sizeBefore = Size();
239 for (auto & item : other.Items())
240 insert(item);
241 return sizeBefore != Size();
242 }
243
251 bool
253 {
254 // Make *this the largest of the two sets, to make the union cheaper
255 if (Size() < other.Size())
256 std::swap(*this, other);
257
258 bool result = UnionWith(other);
259 other.Clear();
260 return result;
261 }
262
268 void
270 {
271 auto isContained = [&](const ItemType & item)
272 {
273 return !other.Contains(item);
274 };
275
276 RemoveWhere(isContained);
277 }
278
285 void
287 {
288 // Make *this the smallest of the two sets, to make the intersection cheaper
289 if (Size() > other.Size())
290 std::swap(*this, other);
291
292 IntersectWith(other);
293 other.Clear();
294 }
295
301 void
303 {
304 // If this HashSet is smaller, loop over it and remove elements in other.
305 // If other is smaller, loop over it and remove elements from this.
306
307 if (Size() <= other.Size())
308 {
309 // This branch also handles the unlikely case where this and other are the same set.
310
311 auto isInOther = [&](const ItemType & item)
312 {
313 return other.Contains(item);
314 };
315
316 RemoveWhere(isInOther);
317 }
318 else
319 {
320 for (auto & item : other.Set_)
321 Remove(item);
322 }
323 }
324
331 bool
332 Remove(ItemType item)
333 {
334 return Set_.erase(item) != 0;
335 }
336
345 template<typename F>
346 size_t
347 RemoveWhere(const F & match)
348 {
349 size_t numRemoved = 0;
350 auto it = Set_.begin();
351 while (it != Set_.end())
352 {
353 if (match(*it))
354 {
355 it = Set_.erase(it);
356 numRemoved++;
357 }
358 else
359 {
360 it++;
361 }
362 }
363
364 return numRemoved;
365 }
366
372 ItemConstIterator
374 {
375 return ItemConstIterator(Set_.erase(iterator.It_));
376 }
377
384 bool
385 operator==(const HashSet<ItemType> & other) const noexcept
386 {
387 if (Size() != other.Size())
388 return false;
389
390 for (auto & item : Set_)
391 if (!other.Contains(item))
392 return false;
393
394 return true;
395 }
396
403 bool
404 operator!=(const HashSet<ItemType> & other) const noexcept
405 {
406 return !operator==(other);
407 }
408
409private:
411};
412
413}
414
415#endif // JLM_UTIL_HASHSET_HPP
ItemConstIterator(const typename InternalSet::const_iterator &it)
Definition HashSet.hpp:40
InternalSet::const_iterator It_
Definition HashSet.hpp:91
const ItemType & operator*() const
Definition HashSet.hpp:52
ItemType * Item() const noexcept
Definition HashSet.hpp:46
ItemConstIterator & operator++()
Definition HashSet.hpp:64
std::forward_iterator_tag iterator_category
Definition HashSet.hpp:31
bool operator!=(const ItemConstIterator &other) const
Definition HashSet.hpp:85
ItemConstIterator operator++(int)
Definition HashSet.hpp:71
bool operator==(const ItemConstIterator &other) const
Definition HashSet.hpp:79
void DifferenceWith(const HashSet< ItemType > &other)
Definition HashSet.hpp:302
void Clear() noexcept
Definition HashSet.hpp:138
InternalSet Set_
Definition HashSet.hpp:410
bool insert(ItemType item)
Definition HashSet.hpp:210
std::unordered_set< ItemType, HashFunctor > InternalSet
Definition HashSet.hpp:25
ItemConstIterator Erase(ItemConstIterator iterator)
Definition HashSet.hpp:373
size_t RemoveWhere(const F &match)
Definition HashSet.hpp:347
HashSet & operator=(const HashSet &other)
Definition HashSet.hpp:121
~HashSet() noexcept=default
std::size_t Size() const noexcept
Definition HashSet.hpp:187
bool IsSubsetOf(const HashSet< ItemType > &other) const noexcept
Definition HashSet.hpp:163
bool operator==(const HashSet< ItemType > &other) const noexcept
Definition HashSet.hpp:385
IteratorRange< ItemConstIterator > Items() const noexcept
Definition HashSet.hpp:223
bool operator!=(const HashSet< ItemType > &other) const noexcept
Definition HashSet.hpp:404
HashSet(const HashSet &other)
Definition HashSet.hpp:103
bool Contains(const ItemType &item) const noexcept
Definition HashSet.hpp:150
HashSet & operator=(HashSet &&other) noexcept
Definition HashSet.hpp:128
void IntersectWith(const HashSet< ItemType > &other)
Definition HashSet.hpp:269
bool UnionWithAndClear(HashSet< ItemType > &other)
Definition HashSet.hpp:252
bool Remove(ItemType item)
Definition HashSet.hpp:332
HashSet(HashSet &&other) noexcept
Definition HashSet.hpp:107
HashSet(const std::unordered_set< ItemType, OtherHashFunctor > &other)
Definition HashSet.hpp:116
HashSet(std::initializer_list< ItemType > initializerList)
Definition HashSet.hpp:111
bool IsEmpty() const noexcept
Definition HashSet.hpp:198
void IntersectWithAndClear(HashSet< ItemType > &other)
Definition HashSet.hpp:286
bool UnionWith(const HashSet< ItemType > &other)
Definition HashSet.hpp:236