AireEngine
A 3D Open-World Game Engine
Loading...
Searching...
No Matches
hashSet.h
1#pragma once
2#include<vector>
3#include<unordered_map>
4#include<algorithm>
5
6namespace Aire {
17 template<class T>
18 class HashSet {
19 public:
21 struct Iterator {
22 public:
27 Iterator(HashSet<T>* owner, int i): owner(owner), i(i) {}
28
32 ++i;
33 return *this;
34 }
35
39 ++i;
40 return *this;
41 }
42
44 T& operator*() {
45 return owner->elements[i];
46 }
47
50 return owner->elements.data()+i;
51 }
52
53 bool operator==(const Iterator& it) const {
54 return i==it.i;
55 }
56
57 bool operator!=(const Iterator& it) const {
58 return i!=it.i;
59 }
60 private:
61 HashSet<T>* owner;
62 int i;//< index in the array
63 };
64
67 public:
72 ConstIterator(const HashSet<T>* owner, int i): owner(owner), i(i) {}
73
77 ++i;
78 return *this;
79 }
80
84 ++i;
85 return *this;
86 }
87
89 const T& operator*() {
90 return owner->elements[i];
91 }
92
94 const T* operator->() {
95 return owner->elements.data()+i;
96 }
97
98 bool operator==(const ConstIterator& it) const {
99 return i==it.i;
100 }
101
102 bool operator!=(const ConstIterator& it) const {
103 return i!=it.i;
104 }
105 private:
106 const HashSet<T>* owner;
107 int i;//< index in the array
108 };
109
110 HashSet(int sizeHint = 10) {
111 elements.reserve(sizeHint);
112 idxMap.reserve(sizeHint);
113 }
114
118 bool insert(const T& newElement) {
119 // Dynamically grow the array to avoid re-allocation on every insertion.
120 // The capacity of the array is doubled.
121 if (elements.size()==elements.capacity()) {
122 size_t newSize = std::max(elements.size(), size_t(1)) * 2;
123 elements.reserve(newSize);
124 idxMap.reserve(newSize);
125 }
126
127 // If the element does not exist already, insert in the hash map and in the array.
128 // Map the element to the index it is going to take in the array.
129 auto insertSuccess = idxMap.insert({ newElement, int(elements.size()) }).second;
130 if (insertSuccess) {
131 elements.push_back(newElement);
132 }
133 return insertSuccess;
134 }
135
138 void erase(const T& element) {
139 auto it = idxMap.find(element);
140 if (it != idxMap.end()) {
141 // For constant-time deletion, swap with the last element of the array.
142 // Make sure to update the indices in the hash map.
143
144 // Fetch the hash map entry corresponding to the last element in the array
145 auto itLast = idxMap.find(elements.back());
146
147 // Swap the element with the last element in the array and then pop
148 std::swap(elements[itLast->second], elements[it->second]);
149 elements.pop_back();
150
151 // Update the hash map entry of the swapped entry to store its new index
152 (itLast->second) = (it->second);
153
154 // Delete the hash map entry of the deleted element
155 idxMap.erase(it);
156 }
157 }
158
161 void clear() {
162 idxMap.clear();
163 elements.clear();
164 }
165
168 void freeMem() {
169 std::vector<T> elementsEmpty;
170 std::unordered_map<T, int> idxMapEmpty;
171
172 std::swap(elements, elementsEmpty);
173 std::swap(idxMap, idxMapEmpty);
174 }
175
179 void reserve(size_t count) {
180 idxMap.reserve(count);
181 elements.reserve(count);
182 }
183
188 auto it = idxMap.find(element);
189 if (it != idxMap.end()) {
190 return Iterator(this, it->second);
191 } else {
192 return end();
193 }
194 }
195
200 auto it = idxMap.find(newElement);
201 if (it != idxMap.end()) {
202 return ConstIterator(this, it->second);
203 } else {
204 return end();
205 }
206 }
207
209 bool empty() const {
210 return elements.empty();
211 }
212
214 size_t size() const {
215 return elements.size();
216 }
217
219 size_t capacity() const {
220 return elements.capacity();
221 }
222
225 return Iterator(this, 0);
226 }
227
230 return ConstIterator(this, 0);
231 }
232
235 return Iterator(this, int(elements.size()));
236 }
237
240 return ConstIterator(this, int(elements.size()));
241 }
242
243 private:
244 // Use a vector to ensure fast traversal of elements
245 std::vector<T> elements;
246
247 // Use a hash map to ensure uniqueness and to speed up search for an element
248 std::unordered_map<T, int> idxMap;
249 };
250}
Definition hashSet.h:18
void freeMem()
Definition hashSet.h:168
size_t size() const
Definition hashSet.h:214
ConstIterator find(const T &newElement) const
Definition hashSet.h:199
void clear()
Definition hashSet.h:161
size_t capacity() const
Definition hashSet.h:219
Iterator begin()
Definition hashSet.h:224
bool insert(const T &newElement)
Definition hashSet.h:118
ConstIterator begin() const
Definition hashSet.h:229
void erase(const T &element)
Definition hashSet.h:138
ConstIterator end() const
Definition hashSet.h:239
bool empty() const
Definition hashSet.h:209
Iterator end()
Definition hashSet.h:234
void reserve(size_t count)
Definition hashSet.h:179
Iterator find(const T &element)
Definition hashSet.h:187
Iterator to iterate through the elements of a const HashSet.
Definition hashSet.h:66
const T * operator->()
Definition hashSet.h:94
ConstIterator(const HashSet< T > *owner, int i)
Definition hashSet.h:72
ConstIterator & operator++()
Definition hashSet.h:76
const T & operator*()
Definition hashSet.h:89
ConstIterator operator++(int)
Definition hashSet.h:83
Iterator to iterate through the elements of a non-const HashSet.
Definition hashSet.h:21
Iterator(HashSet< T > *owner, int i)
Definition hashSet.h:27
T & operator*()
Definition hashSet.h:44
Iterator operator++(int)
Definition hashSet.h:38
T * operator->()
Definition hashSet.h:49
Iterator & operator++()
Definition hashSet.h:31