Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
external/tsl/robin_set.h
ShadPKG / external / tsl / robin_set.h
1/**
2 * MIT License
3 *
4 * Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef TSL_ROBIN_SET_H
25#define TSL_ROBIN_SET_H
26 
27#include <cstddef>
28#include <functional>
29#include <initializer_list>
30#include <memory>
31#include <type_traits>
32#include <utility>
33 
34#include "robin_hash.h"
35 
36namespace tsl {
37 
38/**
39 * Implementation of a hash set using open-addressing and the robin hood hashing
40 * algorithm with backward shift deletion.
41 *
42 * For operations modifying the hash set (insert, erase, rehash, ...), the
43 * strong exception guarantee is only guaranteed when the expression
44 * `std::is_nothrow_swappable<Key>::value &&
45 * std::is_nothrow_move_constructible<Key>::value` is true, otherwise if an
46 * exception is thrown during the swap or the move, the hash set may end up in a
47 * undefined state. Per the standard a `Key` with a noexcept copy constructor
48 * and no move constructor also satisfies the
49 * `std::is_nothrow_move_constructible<Key>::value` criterion (and will thus
50 * guarantee the strong exception for the set).
51 *
52 * When `StoreHash` is true, 32 bits of the hash are stored alongside the
53 * values. It can improve the performance during lookups if the `KeyEqual`
54 * function takes time (or engenders a cache-miss for example) as we then
55 * compare the stored hashes before comparing the keys. When
56 * `tsl::rh::power_of_two_growth_policy` is used as `GrowthPolicy`, it may also
57 * speed-up the rehash process as we can avoid to recalculate the hash. When it
58 * is detected that storing the hash will not incur any memory penalty due to
59 * alignment (i.e. `sizeof(tsl::detail_robin_hash::bucket_entry<ValueType,
60 * true>) == sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, false>)`)
61 * and `tsl::rh::power_of_two_growth_policy` is used, the hash will be stored
62 * even if `StoreHash` is false so that we can speed-up the rehash (but it will
63 * not be used on lookups unless `StoreHash` is true).
64 *
65 * `GrowthPolicy` defines how the set grows and consequently how a hash value is
66 * mapped to a bucket. By default the set uses
67 * `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of
68 * buckets to a power of two and uses a mask to set the hash to a bucket instead
69 * of the slow modulo. Other growth policies are available and you may define
70 * your own growth policy, check `tsl::rh::power_of_two_growth_policy` for the
71 * interface.
72 *
73 * `Key` must be swappable.
74 *
75 * `Key` must be copy and/or move constructible.
76 *
77 * If the destructor of `Key` throws an exception, the behaviour of the class is
78 * undefined.
79 *
80 * Iterators invalidation:
81 * - clear, operator=, reserve, rehash: always invalidate the iterators.
82 * - insert, emplace, emplace_hint, operator[]: if there is an effective
83 * insert, invalidate the iterators.
84 * - erase: always invalidate the iterators.
85 */
86template <class Key, class Hash = std::hash<Key>,
87 class KeyEqual = std::equal_to<Key>,
88 class Allocator = std::allocator<Key>, bool StoreHash = false,
89 class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>>
90class robin_set {
91 private:
92 template <typename U>
93 using has_is_transparent = tsl::detail_robin_hash::has_is_transparent<U>;
94 
95 class KeySelect {
96 public:
97 using key_type = Key;
98 
99 const key_type& operator()(const Key& key) const noexcept { return key; }
100 
101 key_type& operator()(Key& key) noexcept { return key; }
102 };
103 
104 using ht = detail_robin_hash::robin_hash<Key, KeySelect, void, Hash, KeyEqual,
105 Allocator, StoreHash, GrowthPolicy>;
106 
107 public:
108 using key_type = typename ht::key_type;
109 using value_type = typename ht::value_type;
110 using size_type = typename ht::size_type;
111 using difference_type = typename ht::difference_type;
112 using hasher = typename ht::hasher;
113 using key_equal = typename ht::key_equal;
114 using allocator_type = typename ht::allocator_type;
115 using reference = typename ht::reference;
116 using const_reference = typename ht::const_reference;
117 using pointer = typename ht::pointer;
118 using const_pointer = typename ht::const_pointer;
119 using iterator = typename ht::iterator;
120 using const_iterator = typename ht::const_iterator;
121 
122 /*
123 * Constructors
124 */
125 robin_set() : robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {}
126 
127 explicit robin_set(size_type bucket_count, const Hash& hash = Hash(),
128 const KeyEqual& equal = KeyEqual(),
129 const Allocator& alloc = Allocator())
130 : m_ht(bucket_count, hash, equal, alloc) {}
131 
132 robin_set(size_type bucket_count, const Allocator& alloc)
133 : robin_set(bucket_count, Hash(), KeyEqual(), alloc) {}
134 
135 robin_set(size_type bucket_count, const Hash& hash, const Allocator& alloc)
136 : robin_set(bucket_count, hash, KeyEqual(), alloc) {}
137 
138 explicit robin_set(const Allocator& alloc)
139 : robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {}
140 
141 template <class InputIt>
142 robin_set(InputIt first, InputIt last,
143 size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
144 const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(),
145 const Allocator& alloc = Allocator())
146 : robin_set(bucket_count, hash, equal, alloc) {
147 insert(first, last);
148 }
149 
150 template <class InputIt>
151 robin_set(InputIt first, InputIt last, size_type bucket_count,
152 const Allocator& alloc)
153 : robin_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) {}
154 
155 template <class InputIt>
156 robin_set(InputIt first, InputIt last, size_type bucket_count,
157 const Hash& hash, const Allocator& alloc)
158 : robin_set(first, last, bucket_count, hash, KeyEqual(), alloc) {}
159 
160 robin_set(std::initializer_list<value_type> init,
161 size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
162 const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(),
163 const Allocator& alloc = Allocator())
164 : robin_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) {}
165 
166 robin_set(std::initializer_list<value_type> init, size_type bucket_count,
167 const Allocator& alloc)
168 : robin_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(),
169 alloc) {}
170 
171 robin_set(std::initializer_list<value_type> init, size_type bucket_count,
172 const Hash& hash, const Allocator& alloc)
173 : robin_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(),
174 alloc) {}
175 
176 robin_set& operator=(std::initializer_list<value_type> ilist) {
177 m_ht.clear();
178 
179 m_ht.reserve(ilist.size());
180 m_ht.insert(ilist.begin(), ilist.end());
181 
182 return *this;
183 }
184 
185 allocator_type get_allocator() const { return m_ht.get_allocator(); }
186 
187 /*
188 * Iterators
189 */
190 iterator begin() noexcept { return m_ht.begin(); }
191 const_iterator begin() const noexcept { return m_ht.begin(); }
192 const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
193 
194 iterator end() noexcept { return m_ht.end(); }
195 const_iterator end() const noexcept { return m_ht.end(); }
196 const_iterator cend() const noexcept { return m_ht.cend(); }
197 
198 /*
199 * Capacity
200 */
201 bool empty() const noexcept { return m_ht.empty(); }
202 size_type size() const noexcept { return m_ht.size(); }
203 size_type max_size() const noexcept { return m_ht.max_size(); }
204 
205 /*
206 * Modifiers
207 */
208 void clear() noexcept { m_ht.clear(); }
209 
210 std::pair<iterator, bool> insert(const value_type& value) {
211 return m_ht.insert(value);
212 }
213 
214 std::pair<iterator, bool> insert(value_type&& value) {
215 return m_ht.insert(std::move(value));
216 }
217 
218 iterator insert(const_iterator hint, const value_type& value) {
219 return m_ht.insert_hint(hint, value);
220 }
221 
222 iterator insert(const_iterator hint, value_type&& value) {
223 return m_ht.insert_hint(hint, std::move(value));
224 }
225 
226 template <class InputIt>
227 void insert(InputIt first, InputIt last) {
228 m_ht.insert(first, last);
229 }
230 
231 void insert(std::initializer_list<value_type> ilist) {
232 m_ht.insert(ilist.begin(), ilist.end());
233 }
234 
235 /**
236 * Due to the way elements are stored, emplace will need to move or copy the
237 * key-value once. The method is equivalent to
238 * insert(value_type(std::forward<Args>(args)...));
239 *
240 * Mainly here for compatibility with the std::unordered_map interface.
241 */
242 template <class... Args>
243 std::pair<iterator, bool> emplace(Args&&... args) {
244 return m_ht.emplace(std::forward<Args>(args)...);
245 }
246 
247 /**
248 * Due to the way elements are stored, emplace_hint will need to move or copy
249 * the key-value once. The method is equivalent to insert(hint,
250 * value_type(std::forward<Args>(args)...));
251 *
252 * Mainly here for compatibility with the std::unordered_map interface.
253 */
254 template <class... Args>
255 iterator emplace_hint(const_iterator hint, Args&&... args) {
256 return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
257 }
258 
259 iterator erase(iterator pos) { return m_ht.erase(pos); }
260 iterator erase(const_iterator pos) { return m_ht.erase(pos); }
261 iterator erase(const_iterator first, const_iterator last) {
262 return m_ht.erase(first, last);
263 }
264 size_type erase(const key_type& key) { return m_ht.erase(key); }
265 
266 /**
267 * Erase the element at position 'pos'. In contrast to the regular erase()
268 * function, erase_fast() does not return an iterator. This allows it to be
269 * faster especially in hash sets with a low load factor, where finding the
270 * next nonempty bucket would be costly.
271 */
272 void erase_fast(iterator pos) { return m_ht.erase_fast(pos); }
273 
274 /**
275 * Use the hash value 'precalculated_hash' instead of hashing the key. The
276 * hash value should be the same as hash_function()(key). Useful to speed-up
277 * the lookup to the value if you already have the hash.
278 */
279 size_type erase(const key_type& key, std::size_t precalculated_hash) {
280 return m_ht.erase(key, precalculated_hash);
281 }
282 
283 /**
284 * This overload only participates in the overload resolution if the typedef
285 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable
286 * to Key.
287 */
288 template <
289 class K, class KE = KeyEqual,
290 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
291 size_type erase(const K& key) {
292 return m_ht.erase(key);
293 }
294 
295 /**
296 * @copydoc erase(const K& key)
297 *
298 * Use the hash value 'precalculated_hash' instead of hashing the key. The
299 * hash value should be the same as hash_function()(key). Useful to speed-up
300 * the lookup to the value if you already have the hash.
301 */
302 template <
303 class K, class KE = KeyEqual,
304 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
305 size_type erase(const K& key, std::size_t precalculated_hash) {
306 return m_ht.erase(key, precalculated_hash);
307 }
308 
309 void swap(robin_set& other) { other.m_ht.swap(m_ht); }
310 
311 /*
312 * Lookup
313 */
314 size_type count(const Key& key) const { return m_ht.count(key); }
315 
316 /**
317 * Use the hash value 'precalculated_hash' instead of hashing the key. The
318 * hash value should be the same as hash_function()(key). Useful to speed-up
319 * the lookup if you already have the hash.
320 */
321 size_type count(const Key& key, std::size_t precalculated_hash) const {
322 return m_ht.count(key, precalculated_hash);
323 }
324 
325 /**
326 * This overload only participates in the overload resolution if the typedef
327 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable
328 * to Key.
329 */
330 template <
331 class K, class KE = KeyEqual,
332 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
333 size_type count(const K& key) const {
334 return m_ht.count(key);
335 }
336 
337 /**
338 * @copydoc count(const K& key) const
339 *
340 * Use the hash value 'precalculated_hash' instead of hashing the key. The
341 * hash value should be the same as hash_function()(key). Useful to speed-up
342 * the lookup if you already have the hash.
343 */
344 template <
345 class K, class KE = KeyEqual,
346 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
347 size_type count(const K& key, std::size_t precalculated_hash) const {
348 return m_ht.count(key, precalculated_hash);
349 }
350 
351 iterator find(const Key& key) { return m_ht.find(key); }
352 
353 /**
354 * Use the hash value 'precalculated_hash' instead of hashing the key. The
355 * hash value should be the same as hash_function()(key). Useful to speed-up
356 * the lookup if you already have the hash.
357 */
358 iterator find(const Key& key, std::size_t precalculated_hash) {
359 return m_ht.find(key, precalculated_hash);
360 }
361 
362 const_iterator find(const Key& key) const { return m_ht.find(key); }
363 
364 /**
365 * @copydoc find(const Key& key, std::size_t precalculated_hash)
366 */
367 const_iterator find(const Key& key, std::size_t precalculated_hash) const {
368 return m_ht.find(key, precalculated_hash);
369 }
370 
371 /**
372 * This overload only participates in the overload resolution if the typedef
373 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable
374 * to Key.
375 */
376 template <
377 class K, class KE = KeyEqual,
378 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
379 iterator find(const K& key) {
380 return m_ht.find(key);
381 }
382 
383 /**
384 * @copydoc find(const K& key)
385 *
386 * Use the hash value 'precalculated_hash' instead of hashing the key. The
387 * hash value should be the same as hash_function()(key). Useful to speed-up
388 * the lookup if you already have the hash.
389 */
390 template <
391 class K, class KE = KeyEqual,
392 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
393 iterator find(const K& key, std::size_t precalculated_hash) {
394 return m_ht.find(key, precalculated_hash);
395 }
396 
397 /**
398 * @copydoc find(const K& key)
399 */
400 template <
401 class K, class KE = KeyEqual,
402 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
403 const_iterator find(const K& key) const {
404 return m_ht.find(key);
405 }
406 
407 /**
408 * @copydoc find(const K& key)
409 *
410 * Use the hash value 'precalculated_hash' instead of hashing the key. The
411 * hash value should be the same as hash_function()(key). Useful to speed-up
412 * the lookup if you already have the hash.
413 */
414 template <
415 class K, class KE = KeyEqual,
416 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
417 const_iterator find(const K& key, std::size_t precalculated_hash) const {
418 return m_ht.find(key, precalculated_hash);
419 }
420 
421 bool contains(const Key& key) const { return m_ht.contains(key); }
422 
423 /**
424 * Use the hash value 'precalculated_hash' instead of hashing the key. The
425 * hash value should be the same as hash_function()(key). Useful to speed-up
426 * the lookup if you already have the hash.
427 */
428 bool contains(const Key& key, std::size_t precalculated_hash) const {
429 return m_ht.contains(key, precalculated_hash);
430 }
431 
432 /**
433 * This overload only participates in the overload resolution if the typedef
434 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable
435 * to Key.
436 */
437 template <
438 class K, class KE = KeyEqual,
439 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
440 bool contains(const K& key) const {
441 return m_ht.contains(key);
442 }
443 
444 /**
445 * @copydoc contains(const K& key) const
446 *
447 * Use the hash value 'precalculated_hash' instead of hashing the key. The
448 * hash value should be the same as hash_function()(key). Useful to speed-up
449 * the lookup if you already have the hash.
450 */
451 template <
452 class K, class KE = KeyEqual,
453 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
454 bool contains(const K& key, std::size_t precalculated_hash) const {
455 return m_ht.contains(key, precalculated_hash);
456 }
457 
458 std::pair<iterator, iterator> equal_range(const Key& key) {
459 return m_ht.equal_range(key);
460 }
461 
462 /**
463 * Use the hash value 'precalculated_hash' instead of hashing the key. The
464 * hash value should be the same as hash_function()(key). Useful to speed-up
465 * the lookup if you already have the hash.
466 */
467 std::pair<iterator, iterator> equal_range(const Key& key,
468 std::size_t precalculated_hash) {
469 return m_ht.equal_range(key, precalculated_hash);
470 }
471 
472 std::pair<const_iterator, const_iterator> equal_range(const Key& key) const {
473 return m_ht.equal_range(key);
474 }
475 
476 /**
477 * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
478 */
479 std::pair<const_iterator, const_iterator> equal_range(
480 const Key& key, std::size_t precalculated_hash) const {
481 return m_ht.equal_range(key, precalculated_hash);
482 }
483 
484 /**
485 * This overload only participates in the overload resolution if the typedef
486 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable
487 * to Key.
488 */
489 template <
490 class K, class KE = KeyEqual,
491 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
492 std::pair<iterator, iterator> equal_range(const K& key) {
493 return m_ht.equal_range(key);
494 }
495 
496 /**
497 * @copydoc equal_range(const K& key)
498 *
499 * Use the hash value 'precalculated_hash' instead of hashing the key. The
500 * hash value should be the same as hash_function()(key). Useful to speed-up
501 * the lookup if you already have the hash.
502 */
503 template <
504 class K, class KE = KeyEqual,
505 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
506 std::pair<iterator, iterator> equal_range(const K& key,
507 std::size_t precalculated_hash) {
508 return m_ht.equal_range(key, precalculated_hash);
509 }
510 
511 /**
512 * @copydoc equal_range(const K& key)
513 */
514 template <
515 class K, class KE = KeyEqual,
516 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
517 std::pair<const_iterator, const_iterator> equal_range(const K& key) const {
518 return m_ht.equal_range(key);
519 }
520 
521 /**
522 * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
523 */
524 template <
525 class K, class KE = KeyEqual,
526 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
527 std::pair<const_iterator, const_iterator> equal_range(
528 const K& key, std::size_t precalculated_hash) const {
529 return m_ht.equal_range(key, precalculated_hash);
530 }
531 
532 /*
533 * Bucket interface
534 */
535 size_type bucket_count() const { return m_ht.bucket_count(); }
536 size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
537 
538 /*
539 * Hash policy
540 */
541 float load_factor() const { return m_ht.load_factor(); }
542 
543 float min_load_factor() const { return m_ht.min_load_factor(); }
544 float max_load_factor() const { return m_ht.max_load_factor(); }
545 
546 /**
547 * Set the `min_load_factor` to `ml`. When the `load_factor` of the set goes
548 * below `min_load_factor` after some erase operations, the set will be
549 * shrunk when an insertion occurs. The erase method itself never shrinks
550 * the set.
551 *
552 * The default value of `min_load_factor` is 0.0f, the set never shrinks by
553 * default.
554 */
555 void min_load_factor(float ml) { m_ht.min_load_factor(ml); }
556 void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
557 
558 void rehash(size_type count_) { m_ht.rehash(count_); }
559 void reserve(size_type count_) { m_ht.reserve(count_); }
560 
561 /*
562 * Observers
563 */
564 hasher hash_function() const { return m_ht.hash_function(); }
565 key_equal key_eq() const { return m_ht.key_eq(); }
566 
567 /*
568 * Other
569 */
570 
571 /**
572 * Convert a const_iterator to an iterator.
573 */
574 iterator mutable_iterator(const_iterator pos) {
575 return m_ht.mutable_iterator(pos);
576 }
577 
578 friend bool operator==(const robin_set& lhs, const robin_set& rhs) {
579 if (lhs.size() != rhs.size()) {
580 return false;
581 }
582 
583 for (const auto& element_lhs : lhs) {
584 const auto it_element_rhs = rhs.find(element_lhs);
585 if (it_element_rhs == rhs.cend()) {
586 return false;
587 }
588 }
589 
590 return true;
591 }
592 
593 /**
594 * Serialize the set through the `serializer` parameter.
595 *
596 * The `serializer` parameter must be a function object that supports the
597 * following call:
598 * - `template<typename U> void operator()(const U& value);` where the types
599 * `std::int16_t`, `std::uint32_t`, `std::uint64_t`, `float` and `Key` must be
600 * supported for U.
601 *
602 * The implementation leaves binary compatibility (endianness, IEEE 754 for
603 * floats, ...) of the types it serializes in the hands of the `Serializer`
604 * function object if compatibility is required.
605 */
606 template <class Serializer>
607 void serialize(Serializer& serializer) const {
608 m_ht.serialize(serializer);
609 }
610 
611 /**
612 * Deserialize a previously serialized set through the `deserializer`
613 * parameter.
614 *
615 * The `deserializer` parameter must be a function object that supports the
616 * following call:
617 * - `template<typename U> U operator()();` where the types `std::int16_t`,
618 * `std::uint32_t`, `std::uint64_t`, `float` and `Key` must be supported for
619 * U.
620 *
621 * If the deserialized hash set type is hash compatible with the serialized
622 * set, the deserialization process can be sped up by setting
623 * `hash_compatible` to true. To be hash compatible, the Hash, KeyEqual and
624 * GrowthPolicy must behave the same way than the ones used on the serialized
625 * set and the StoreHash must have the same value. The `std::size_t` must also
626 * be of the same size as the one on the platform used to serialize the set.
627 * If these criteria are not met, the behaviour is undefined with
628 * `hash_compatible` sets to true.
629 *
630 * The behaviour is undefined if the type `Key` of the `robin_set` is not the
631 * same as the type used during serialization.
632 *
633 * The implementation leaves binary compatibility (endianness, IEEE 754 for
634 * floats, size of int, ...) of the types it deserializes in the hands of the
635 * `Deserializer` function object if compatibility is required.
636 */
637 template <class Deserializer>
638 static robin_set deserialize(Deserializer& deserializer,
639 bool hash_compatible = false) {
640 robin_set set(0);
641 set.m_ht.deserialize(deserializer, hash_compatible);
642 
643 return set;
644 }
645 
646 friend bool operator!=(const robin_set& lhs, const robin_set& rhs) {
647 return !operator==(lhs, rhs);
648 }
649 
650 friend void swap(robin_set& lhs, robin_set& rhs) { lhs.swap(rhs); }
651 
652 private:
653 ht m_ht;
654};
655 
656/**
657 * Same as `tsl::robin_set<Key, Hash, KeyEqual, Allocator, StoreHash,
658 * tsl::rh::prime_growth_policy>`.
659 */
660template <class Key, class Hash = std::hash<Key>,
661 class KeyEqual = std::equal_to<Key>,
662 class Allocator = std::allocator<Key>, bool StoreHash = false>
663using robin_pg_set = robin_set<Key, Hash, KeyEqual, Allocator, StoreHash,
664 tsl::rh::prime_growth_policy>;
665 
666} // end namespace tsl
667 
668#endif
669