DiscordCoreAPI
A Discord bot library written in C++, with custom asynchronous coroutines.
Loading...
Searching...
No Matches
UnorderedSet.hpp
Go to the documentation of this file.
1/*
2 MIT License
3
4 DiscordCoreAPI, A bot library for Discord, written in C++, and featuring explicit multithreading through the usage of custom, asynchronous C++ CoRoutines.
5
6 Copyright 2022, 2023 Chris M. (RealTimeChris)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25*/
26/// UnorderedSet.hpp - Header file for the unordered_set class.
27/// May 12, 2021
28/// https://discordcoreapi.com
29/// \file UnorderedSet.hpp
30#pragma once
31
33
34namespace discord_core_api {
35
36 template<typename value_type> class unordered_set;
37
38 template<typename set_iterator, typename value_type>
39 concept set_container_iterator_t = std::same_as<typename unordered_set<value_type>::iterator, jsonifier_internal::unwrap_t<set_iterator>>;
40
41 template<typename value_type_new>
42 class unordered_set : protected hash_policy<unordered_set<value_type_new>>, protected jsonifier_internal::alloc_wrapper<value_type_new>, protected object_compare {
43 public:
44 template<typename value_type_newer> using key_accessor = key_accessor<value_type_newer>;
45 using key_type = value_type_new;
46 using value_type = value_type_new;
47 using mapped_type = value_type;
48 using allocator_type = jsonifier_internal::alloc_wrapper<value_type>;
49 using allocator_traits = std::allocator_traits<allocator_type>;
50 using size_type = uint64_t;
51 using difference_type = int64_t;
52 using pointer = typename allocator_traits::pointer;
53 using const_pointer = typename allocator_traits::const_pointer;
54 using reference = value_type&;
55 using const_reference = const value_type&;
56 using iterator = hash_iterator<unordered_set<value_type>>;
57 using const_iterator = hash_iterator<const unordered_set<value_type>>;
58 using object_compare = object_compare;
59 using hash_policy_new = hash_policy<unordered_set<value_type>>;
60
61 friend hash_policy_new;
62 friend iterator;
63 friend const_iterator;
64
65 DCA_INLINE unordered_set(){};
66
67 DCA_INLINE unordered_set& operator=(unordered_set&& other) noexcept {
68 if (this != &other) {
69 reset();
70 swap(other);
71 }
72 return *this;
73 }
74
75 DCA_INLINE unordered_set(unordered_set&& other) noexcept {
76 *this = std::move(other);
77 }
78
79 DCA_INLINE unordered_set& operator=(const unordered_set& other) {
80 if (this != &other) {
81 reset();
82
83 reserve(other.capacity());
84 for (const auto& value: other) {
85 emplace(value);
86 }
87 }
88 return *this;
89 }
90
91 DCA_INLINE unordered_set(const unordered_set& other) {
92 *this = other;
93 }
94
95 DCA_INLINE unordered_set(std::initializer_list<value_type> list) {
96 reserve(list.size());
97 for (auto& value: list) {
98 emplace(std::move(value));
99 }
100 };
101
102 template<typename args> iterator emplace(args&& value) {
103 return emplaceInternal(std::forward<args>(value));
104 }
105
106 template<typename key_type_new> DCA_INLINE const_iterator find(key_type_new&& key) const {
107 if (sizeVal > 0) {
108 auto currentIndex = getKey(key) & (capacityVal - 1);
109 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
110 if (sentinelVector[currentIndex] > 0 && object_compare()(getKey(data[currentIndex]), getKey(key))) {
111 return { this, currentIndex };
112 }
113 }
114 }
115 return end();
116 }
117
118 template<typename key_type_new> DCA_INLINE iterator find(key_type_new&& key) {
119 if (sizeVal > 0) {
120 auto currentIndex = getKey(key) & (capacityVal - 1);
121 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
122 if (sentinelVector[currentIndex] > 0 && object_compare()(getKey(data[currentIndex]), getKey(key))) {
123 return { this, currentIndex };
124 }
125 }
126 }
127 return end();
128 }
129
130 template<typename key_type_new> DCA_INLINE const_reference operator[](key_type_new&& key) const {
131 auto iter = find(std::forward<key_type_new>(key));
132 if (iter == end()) {
133 iter = emplace(mapped_type{});
134 }
135 return *iter;
136 }
137
138 template<typename key_type_new> DCA_INLINE reference operator[](key_type_new&& key) {
139 auto iter = find(std::forward<key_type_new>(key));
140 if (iter == end()) {
141 iter = emplace(mapped_type{});
142 }
143 return *iter;
144 }
145
146 template<typename key_type_new> DCA_INLINE const_reference at(key_type_new&& key) const {
147 auto iter = find(std::forward<key_type_new>(key));
148 if (iter == end()) {
149 throw std::runtime_error{ "Sorry, but an object by that key doesn't exist in this map." };
150 }
151 return *iter;
152 }
153
154 template<typename key_type_new> DCA_INLINE reference at(key_type_new&& key) {
155 auto iter = find(std::forward<key_type_new>(key));
156 if (iter == end()) {
157 throw std::runtime_error{ "Sorry, but an object by that key doesn't exist in this map." };
158 }
159 return *iter;
160 }
161
162 template<typename key_type_new> DCA_INLINE bool contains(key_type_new&& key) const {
163 if (sizeVal > 0) {
164 auto currentIndex = getKey(key) & (capacityVal - 1);
165 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
166 if (sentinelVector[currentIndex] > 0 && object_compare()(getKey(data[currentIndex]), getKey(key))) {
167 return true;
168 }
169 }
170 }
171 return false;
172 }
173
174 template<set_container_iterator_t<mapped_type> set_iterator> DCA_INLINE iterator erase(set_iterator&& iter) {
175 if (sizeVal > 0) {
176 auto currentIndex = static_cast<size_type>(iter.getRawPtr() - data);
177 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
178 if (sentinelVector[currentIndex] > 0 && object_compare()(getKey(data[currentIndex]), getKey(iter.operator*()))) {
179 sentinelVector[currentIndex] = 0;
180 --sizeVal;
181 return { this, ++currentIndex };
182 }
183 }
184 }
185 return end();
186 }
187
188 template<typename key_type_new> DCA_INLINE iterator erase(key_type_new&& key) {
189 if (sizeVal > 0) {
190 auto currentIndex = getKey(key) & (capacityVal - 1);
191 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
192 if (sentinelVector[currentIndex] > 0 && object_compare()(getKey(data[currentIndex]), getKey(key))) {
193 sentinelVector[currentIndex] = 0;
194 --sizeVal;
195 return { this, ++currentIndex };
196 }
197 }
198 }
199 return end();
200 }
201
202 DCA_INLINE const_iterator begin() const {
203 for (size_type x{ 0 }; x < capacityVal; ++x) {
204 if (sentinelVector.at(x) > 0) {
205 return { this, x };
206 }
207 }
208 return end();
209 }
210
211 DCA_INLINE const_iterator end() const {
212 return {};
213 }
214
215 DCA_INLINE iterator begin() {
216 for (size_type x{ 0 }; x < capacityVal; ++x) {
217 if (sentinelVector.at(x) > 0) {
218 return { this, x };
219 }
220 }
221 return end();
222 }
223
224 DCA_INLINE iterator end() {
225 return {};
226 }
227
228 DCA_INLINE bool full() const {
229 return static_cast<float>(sizeVal) >= static_cast<float>(capacityVal) * 0.90f;
230 }
231
232 DCA_INLINE size_type size() const {
233 return sizeVal;
234 }
235
236 DCA_INLINE bool empty() const {
237 return sizeVal == 0;
238 }
239
240 DCA_INLINE void reserve(size_type sizeNew) {
241 resize(sizeNew);
242 }
243
244 DCA_INLINE void swap(unordered_set& other) {
245 std::swap(maxLookAheadDistance, other.maxLookAheadDistance);
246 std::swap(sentinelVector, other.sentinelVector);
247 std::swap(capacityVal, other.capacityVal);
248 std::swap(sizeVal, other.sizeVal);
249 std::swap(data, other.data);
250 }
251
252 DCA_INLINE size_type capacity() const {
253 return capacityVal;
254 }
255
256 DCA_INLINE bool operator==(const unordered_set& other) const {
257 if (capacityVal != other.capacityVal || sizeVal != other.sizeVal || data != other.data) {
258 return false;
259 }
260 for (auto iter01{ begin() }, iter02{ other.begin() }; iter01 != end(); ++iter01, ++iter02) {
261 if (!object_compare()(iter01.operator*(), iter02.operator*())) {
262 return false;
263 }
264 }
265 return true;
266 }
267
268 DCA_INLINE void clear() {
269 for (size_type x = 0; x < sentinelVector.size(); ++x) {
270 if (sentinelVector.at(x) > 0) {
271 allocator_traits::destroy(*this, data + x);
272 sentinelVector.at(x) = 0;
273 }
274 }
275 sizeVal = 0;
276 }
277
278 DCA_INLINE ~unordered_set() {
279 reset();
280 };
281
282 protected:
283 jsonifier::vector<int8_t> sentinelVector{};
284 int8_t maxLookAheadDistance{ 0 };
285 size_type capacityVal{};
286 size_type sizeVal{};
287 value_type* data{};
288
289 template<typename mapped_type_new> DCA_INLINE iterator emplaceInternal(mapped_type_new&& value) {
290 if (full() || capacityVal == 0) {
291 resize(capacityVal + 1);
292 }
293 auto currentIndex = getKey(value) & (capacityVal - 1);
294 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
295 if (sentinelVector[currentIndex] == 0) {
296 new (std::addressof(data[currentIndex])) value_type{ std::forward<mapped_type_new>(value) };
297 sentinelVector[currentIndex] = 1;
298 sizeVal++;
299 return { this, currentIndex };
300 } else if (sentinelVector[currentIndex] > 0 && object_compare()(getKey(data[currentIndex]), getKey(value))) {
301 if constexpr (!std::is_void_v<mapped_type_new>) {
302 data[currentIndex] = std::forward<mapped_type_new>(value);
303 }
304 return { this, currentIndex };
305 }
306 }
307 resize(capacityVal + 1);
308 return emplaceInternal(std::forward<mapped_type_new>(value));
309 }
310
311 template<typename value_type_newer> DCA_INLINE uint64_t getKey(value_type_newer&& keyValue) const {
312 return key_accessor<jsonifier_internal::unwrap_t<value_type_newer>>::getHashKey(std::forward<value_type_newer>(keyValue));
313 }
314
315 DCA_INLINE void resize(size_type capacityNew) {
316 auto newSize = hash_policy_new::nextPowerOfTwo(capacityNew);
317 if (newSize > capacityVal) {
318 jsonifier::vector<int8_t> oldSentinelVector = std::move(sentinelVector);
319 auto oldMaxLookAheadDistance = maxLookAheadDistance;
320 auto oldCapacity = capacityVal;
321 auto oldSize = sizeVal;
322 auto oldPtr = data;
323 maxLookAheadDistance = hash_policy_new::computeMaxLookAheadDistance(newSize);
324 sizeVal = 0;
325 data = allocator_traits::allocate(*this, newSize + 1 + maxLookAheadDistance);
326 sentinelVector.resize(newSize + 1 + maxLookAheadDistance);
327 sentinelVector[newSize + maxLookAheadDistance] = -1;
328 capacityVal = newSize;
329 for (size_type x = 0, y = 0; y < oldSize; ++x) {
330 if (oldSentinelVector.at(x) > 0) {
331 ++y;
332 emplaceInternal(std::move(oldPtr[x]));
333 }
334 }
335 if (oldPtr && oldCapacity) {
336 allocator_traits::deallocate(*this, oldPtr, oldCapacity + 1 + oldMaxLookAheadDistance);
337 }
338 }
339 }
340
341 DCA_INLINE void reset() {
342 if (data && sizeVal > 0) {
343 for (uint64_t x = 0; x < sentinelVector.size(); ++x) {
344 if (sentinelVector.at(x) > 0) {
345 allocator_traits::destroy(*this, data + x);
346 sentinelVector.at(x) = 0;
347 }
348 }
349 allocator_traits::deallocate(*this, data, capacityVal + 1 + maxLookAheadDistance);
350 sentinelVector.clear();
351 sizeVal = 0;
352 capacityVal = 0;
353 data = nullptr;
354 }
355 }
356 };
357}
The main namespace for the forward-facing interfaces.