File indexing completed on 2024-11-24 05:07:24
0001 /** 0002 * MIT License 0003 * 0004 * Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com> 0005 * 0006 * Permission is hereby granted, free of charge, to any person obtaining a copy 0007 * of this software and associated documentation files (the "Software"), to deal 0008 * in the Software without restriction, including without limitation the rights 0009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0010 * copies of the Software, and to permit persons to whom the Software is 0011 * furnished to do so, subject to the following conditions: 0012 * 0013 * The above copyright notice and this permission notice shall be included in 0014 * all copies or substantial portions of the Software. 0015 * 0016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 0020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 0021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 0022 * SOFTWARE. 0023 */ 0024 #ifndef TSL_ROBIN_SET_H 0025 #define TSL_ROBIN_SET_H 0026 0027 #include <cstddef> 0028 #include <functional> 0029 #include <initializer_list> 0030 #include <memory> 0031 #include <type_traits> 0032 #include <utility> 0033 0034 #include "robin_hash.h" 0035 0036 namespace tsl { 0037 0038 /** 0039 * Implementation of a hash set using open-addressing and the robin hood hashing 0040 * algorithm with backward shift deletion. 0041 * 0042 * For operations modifying the hash set (insert, erase, rehash, ...), the 0043 * strong exception guarantee is only guaranteed when the expression 0044 * `std::is_nothrow_swappable<Key>::value && 0045 * std::is_nothrow_move_constructible<Key>::value` is true, otherwise if an 0046 * exception is thrown during the swap or the move, the hash set may end up in a 0047 * undefined state. Per the standard a `Key` with a noexcept copy constructor 0048 * and no move constructor also satisfies the 0049 * `std::is_nothrow_move_constructible<Key>::value` criterion (and will thus 0050 * guarantee the strong exception for the set). 0051 * 0052 * When `StoreHash` is true, 32 bits of the hash are stored alongside the 0053 * values. It can improve the performance during lookups if the `KeyEqual` 0054 * function takes time (or engenders a cache-miss for example) as we then 0055 * compare the stored hashes before comparing the keys. When 0056 * `tsl::rh::power_of_two_growth_policy` is used as `GrowthPolicy`, it may also 0057 * speed-up the rehash process as we can avoid to recalculate the hash. When it 0058 * is detected that storing the hash will not incur any memory penalty due to 0059 * alignment (i.e. `sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, 0060 * true>) == sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, false>)`) 0061 * and `tsl::rh::power_of_two_growth_policy` is used, the hash will be stored 0062 * even if `StoreHash` is false so that we can speed-up the rehash (but it will 0063 * not be used on lookups unless `StoreHash` is true). 0064 * 0065 * `GrowthPolicy` defines how the set grows and consequently how a hash value is 0066 * mapped to a bucket. By default the set uses 0067 * `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of 0068 * buckets to a power of two and uses a mask to set the hash to a bucket instead 0069 * of the slow modulo. Other growth policies are available and you may define 0070 * your own growth policy, check `tsl::rh::power_of_two_growth_policy` for the 0071 * interface. 0072 * 0073 * `Key` must be swappable. 0074 * 0075 * `Key` must be copy and/or move constructible. 0076 * 0077 * If the destructor of `Key` throws an exception, the behaviour of the class is 0078 * undefined. 0079 * 0080 * Iterators invalidation: 0081 * - clear, operator=, reserve, rehash: always invalidate the iterators. 0082 * - insert, emplace, emplace_hint, operator[]: if there is an effective 0083 * insert, invalidate the iterators. 0084 * - erase: always invalidate the iterators. 0085 */ 0086 template <class Key, class Hash = std::hash<Key>, 0087 class KeyEqual = std::equal_to<Key>, 0088 class Allocator = std::allocator<Key>, bool StoreHash = false, 0089 class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>> 0090 class robin_set { 0091 private: 0092 template <typename U> 0093 using has_is_transparent = tsl::detail_robin_hash::has_is_transparent<U>; 0094 0095 class KeySelect { 0096 public: 0097 using key_type = Key; 0098 0099 const key_type& operator()(const Key& key) const noexcept { return key; } 0100 0101 key_type& operator()(Key& key) noexcept { return key; } 0102 }; 0103 0104 using ht = detail_robin_hash::robin_hash<Key, KeySelect, void, Hash, KeyEqual, 0105 Allocator, StoreHash, GrowthPolicy>; 0106 0107 public: 0108 using key_type = typename ht::key_type; 0109 using value_type = typename ht::value_type; 0110 using size_type = typename ht::size_type; 0111 using difference_type = typename ht::difference_type; 0112 using hasher = typename ht::hasher; 0113 using key_equal = typename ht::key_equal; 0114 using allocator_type = typename ht::allocator_type; 0115 using reference = typename ht::reference; 0116 using const_reference = typename ht::const_reference; 0117 using pointer = typename ht::pointer; 0118 using const_pointer = typename ht::const_pointer; 0119 using iterator = typename ht::iterator; 0120 using const_iterator = typename ht::const_iterator; 0121 0122 /* 0123 * Constructors 0124 */ 0125 robin_set() : robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {} 0126 0127 explicit robin_set(size_type bucket_count, const Hash& hash = Hash(), 0128 const KeyEqual& equal = KeyEqual(), 0129 const Allocator& alloc = Allocator()) 0130 : m_ht(bucket_count, hash, equal, alloc) {} 0131 0132 robin_set(size_type bucket_count, const Allocator& alloc) 0133 : robin_set(bucket_count, Hash(), KeyEqual(), alloc) {} 0134 0135 robin_set(size_type bucket_count, const Hash& hash, const Allocator& alloc) 0136 : robin_set(bucket_count, hash, KeyEqual(), alloc) {} 0137 0138 explicit robin_set(const Allocator& alloc) 0139 : robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {} 0140 0141 template <class InputIt> 0142 robin_set(InputIt first, InputIt last, 0143 size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, 0144 const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(), 0145 const Allocator& alloc = Allocator()) 0146 : robin_set(bucket_count, hash, equal, alloc) { 0147 insert(first, last); 0148 } 0149 0150 template <class InputIt> 0151 robin_set(InputIt first, InputIt last, size_type bucket_count, 0152 const Allocator& alloc) 0153 : robin_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) {} 0154 0155 template <class InputIt> 0156 robin_set(InputIt first, InputIt last, size_type bucket_count, 0157 const Hash& hash, const Allocator& alloc) 0158 : robin_set(first, last, bucket_count, hash, KeyEqual(), alloc) {} 0159 0160 robin_set(std::initializer_list<value_type> init, 0161 size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, 0162 const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(), 0163 const Allocator& alloc = Allocator()) 0164 : robin_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) {} 0165 0166 robin_set(std::initializer_list<value_type> init, size_type bucket_count, 0167 const Allocator& alloc) 0168 : robin_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), 0169 alloc) {} 0170 0171 robin_set(std::initializer_list<value_type> init, size_type bucket_count, 0172 const Hash& hash, const Allocator& alloc) 0173 : robin_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), 0174 alloc) {} 0175 0176 robin_set& operator=(std::initializer_list<value_type> ilist) { 0177 m_ht.clear(); 0178 0179 m_ht.reserve(ilist.size()); 0180 m_ht.insert(ilist.begin(), ilist.end()); 0181 0182 return *this; 0183 } 0184 0185 allocator_type get_allocator() const { return m_ht.get_allocator(); } 0186 0187 /* 0188 * Iterators 0189 */ 0190 iterator begin() noexcept { return m_ht.begin(); } 0191 const_iterator begin() const noexcept { return m_ht.begin(); } 0192 const_iterator cbegin() const noexcept { return m_ht.cbegin(); } 0193 0194 iterator end() noexcept { return m_ht.end(); } 0195 const_iterator end() const noexcept { return m_ht.end(); } 0196 const_iterator cend() const noexcept { return m_ht.cend(); } 0197 0198 /* 0199 * Capacity 0200 */ 0201 bool empty() const noexcept { return m_ht.empty(); } 0202 size_type size() const noexcept { return m_ht.size(); } 0203 size_type max_size() const noexcept { return m_ht.max_size(); } 0204 0205 /* 0206 * Modifiers 0207 */ 0208 void clear() noexcept { m_ht.clear(); } 0209 0210 std::pair<iterator, bool> insert(const value_type& value) { 0211 return m_ht.insert(value); 0212 } 0213 0214 std::pair<iterator, bool> insert(value_type&& value) { 0215 return m_ht.insert(std::move(value)); 0216 } 0217 0218 iterator insert(const_iterator hint, const value_type& value) { 0219 return m_ht.insert_hint(hint, value); 0220 } 0221 0222 iterator insert(const_iterator hint, value_type&& value) { 0223 return m_ht.insert_hint(hint, std::move(value)); 0224 } 0225 0226 template <class InputIt> 0227 void insert(InputIt first, InputIt last) { 0228 m_ht.insert(first, last); 0229 } 0230 0231 void insert(std::initializer_list<value_type> ilist) { 0232 m_ht.insert(ilist.begin(), ilist.end()); 0233 } 0234 0235 /** 0236 * Due to the way elements are stored, emplace will need to move or copy the 0237 * key-value once. The method is equivalent to 0238 * insert(value_type(std::forward<Args>(args)...)); 0239 * 0240 * Mainly here for compatibility with the std::unordered_map interface. 0241 */ 0242 template <class... Args> 0243 std::pair<iterator, bool> emplace(Args&&... args) { 0244 return m_ht.emplace(std::forward<Args>(args)...); 0245 } 0246 0247 /** 0248 * Due to the way elements are stored, emplace_hint will need to move or copy 0249 * the key-value once. The method is equivalent to insert(hint, 0250 * value_type(std::forward<Args>(args)...)); 0251 * 0252 * Mainly here for compatibility with the std::unordered_map interface. 0253 */ 0254 template <class... Args> 0255 iterator emplace_hint(const_iterator hint, Args&&... args) { 0256 return m_ht.emplace_hint(hint, std::forward<Args>(args)...); 0257 } 0258 0259 iterator erase(iterator pos) { return m_ht.erase(pos); } 0260 iterator erase(const_iterator pos) { return m_ht.erase(pos); } 0261 iterator erase(const_iterator first, const_iterator last) { 0262 return m_ht.erase(first, last); 0263 } 0264 size_type erase(const key_type& key) { return m_ht.erase(key); } 0265 0266 /** 0267 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0268 * hash value should be the same as hash_function()(key). Useful to speed-up 0269 * the lookup to the value if you already have the hash. 0270 */ 0271 size_type erase(const key_type& key, std::size_t precalculated_hash) { 0272 return m_ht.erase(key, precalculated_hash); 0273 } 0274 0275 /** 0276 * This overload only participates in the overload resolution if the typedef 0277 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable 0278 * to Key. 0279 */ 0280 template < 0281 class K, class KE = KeyEqual, 0282 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0283 size_type erase(const K& key) { 0284 return m_ht.erase(key); 0285 } 0286 0287 /** 0288 * @copydoc erase(const K& key) 0289 * 0290 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0291 * hash value should be the same as hash_function()(key). Useful to speed-up 0292 * the lookup to the value if you already have the hash. 0293 */ 0294 template < 0295 class K, class KE = KeyEqual, 0296 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0297 size_type erase(const K& key, std::size_t precalculated_hash) { 0298 return m_ht.erase(key, precalculated_hash); 0299 } 0300 0301 void swap(robin_set& other) { other.m_ht.swap(m_ht); } 0302 0303 /* 0304 * Lookup 0305 */ 0306 size_type count(const Key& key) const { return m_ht.count(key); } 0307 0308 /** 0309 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0310 * hash value should be the same as hash_function()(key). Useful to speed-up 0311 * the lookup if you already have the hash. 0312 */ 0313 size_type count(const Key& key, std::size_t precalculated_hash) const { 0314 return m_ht.count(key, precalculated_hash); 0315 } 0316 0317 /** 0318 * This overload only participates in the overload resolution if the typedef 0319 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable 0320 * to Key. 0321 */ 0322 template < 0323 class K, class KE = KeyEqual, 0324 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0325 size_type count(const K& key) const { 0326 return m_ht.count(key); 0327 } 0328 0329 /** 0330 * @copydoc count(const K& key) const 0331 * 0332 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0333 * hash value should be the same as hash_function()(key). Useful to speed-up 0334 * the lookup if you already have the hash. 0335 */ 0336 template < 0337 class K, class KE = KeyEqual, 0338 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0339 size_type count(const K& key, std::size_t precalculated_hash) const { 0340 return m_ht.count(key, precalculated_hash); 0341 } 0342 0343 iterator find(const Key& key) { return m_ht.find(key); } 0344 0345 /** 0346 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0347 * hash value should be the same as hash_function()(key). Useful to speed-up 0348 * the lookup if you already have the hash. 0349 */ 0350 iterator find(const Key& key, std::size_t precalculated_hash) { 0351 return m_ht.find(key, precalculated_hash); 0352 } 0353 0354 const_iterator find(const Key& key) const { return m_ht.find(key); } 0355 0356 /** 0357 * @copydoc find(const Key& key, std::size_t precalculated_hash) 0358 */ 0359 const_iterator find(const Key& key, std::size_t precalculated_hash) const { 0360 return m_ht.find(key, precalculated_hash); 0361 } 0362 0363 /** 0364 * This overload only participates in the overload resolution if the typedef 0365 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable 0366 * to Key. 0367 */ 0368 template < 0369 class K, class KE = KeyEqual, 0370 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0371 iterator find(const K& key) { 0372 return m_ht.find(key); 0373 } 0374 0375 /** 0376 * @copydoc find(const K& key) 0377 * 0378 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0379 * hash value should be the same as hash_function()(key). Useful to speed-up 0380 * the lookup if you already have the hash. 0381 */ 0382 template < 0383 class K, class KE = KeyEqual, 0384 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0385 iterator find(const K& key, std::size_t precalculated_hash) { 0386 return m_ht.find(key, precalculated_hash); 0387 } 0388 0389 /** 0390 * @copydoc find(const K& key) 0391 */ 0392 template < 0393 class K, class KE = KeyEqual, 0394 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0395 const_iterator find(const K& key) const { 0396 return m_ht.find(key); 0397 } 0398 0399 /** 0400 * @copydoc find(const K& key) 0401 * 0402 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0403 * hash value should be the same as hash_function()(key). Useful to speed-up 0404 * the lookup if you already have the hash. 0405 */ 0406 template < 0407 class K, class KE = KeyEqual, 0408 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0409 const_iterator find(const K& key, std::size_t precalculated_hash) const { 0410 return m_ht.find(key, precalculated_hash); 0411 } 0412 0413 bool contains(const Key& key) const { return m_ht.contains(key); } 0414 0415 /** 0416 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0417 * hash value should be the same as hash_function()(key). Useful to speed-up 0418 * the lookup if you already have the hash. 0419 */ 0420 bool contains(const Key& key, std::size_t precalculated_hash) const { 0421 return m_ht.contains(key, precalculated_hash); 0422 } 0423 0424 /** 0425 * This overload only participates in the overload resolution if the typedef 0426 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable 0427 * to Key. 0428 */ 0429 template < 0430 class K, class KE = KeyEqual, 0431 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0432 bool contains(const K& key) const { 0433 return m_ht.contains(key); 0434 } 0435 0436 /** 0437 * @copydoc contains(const K& key) const 0438 * 0439 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0440 * hash value should be the same as hash_function()(key). Useful to speed-up 0441 * the lookup if you already have the hash. 0442 */ 0443 template < 0444 class K, class KE = KeyEqual, 0445 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0446 bool contains(const K& key, std::size_t precalculated_hash) const { 0447 return m_ht.contains(key, precalculated_hash); 0448 } 0449 0450 std::pair<iterator, iterator> equal_range(const Key& key) { 0451 return m_ht.equal_range(key); 0452 } 0453 0454 /** 0455 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0456 * hash value should be the same as hash_function()(key). Useful to speed-up 0457 * the lookup if you already have the hash. 0458 */ 0459 std::pair<iterator, iterator> equal_range(const Key& key, 0460 std::size_t precalculated_hash) { 0461 return m_ht.equal_range(key, precalculated_hash); 0462 } 0463 0464 std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { 0465 return m_ht.equal_range(key); 0466 } 0467 0468 /** 0469 * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) 0470 */ 0471 std::pair<const_iterator, const_iterator> equal_range( 0472 const Key& key, std::size_t precalculated_hash) const { 0473 return m_ht.equal_range(key, precalculated_hash); 0474 } 0475 0476 /** 0477 * This overload only participates in the overload resolution if the typedef 0478 * KeyEqual::is_transparent exists. If so, K must be hashable and comparable 0479 * to Key. 0480 */ 0481 template < 0482 class K, class KE = KeyEqual, 0483 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0484 std::pair<iterator, iterator> equal_range(const K& key) { 0485 return m_ht.equal_range(key); 0486 } 0487 0488 /** 0489 * @copydoc equal_range(const K& key) 0490 * 0491 * Use the hash value 'precalculated_hash' instead of hashing the key. The 0492 * hash value should be the same as hash_function()(key). Useful to speed-up 0493 * the lookup if you already have the hash. 0494 */ 0495 template < 0496 class K, class KE = KeyEqual, 0497 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0498 std::pair<iterator, iterator> equal_range(const K& key, 0499 std::size_t precalculated_hash) { 0500 return m_ht.equal_range(key, precalculated_hash); 0501 } 0502 0503 /** 0504 * @copydoc equal_range(const K& key) 0505 */ 0506 template < 0507 class K, class KE = KeyEqual, 0508 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0509 std::pair<const_iterator, const_iterator> equal_range(const K& key) const { 0510 return m_ht.equal_range(key); 0511 } 0512 0513 /** 0514 * @copydoc equal_range(const K& key, std::size_t precalculated_hash) 0515 */ 0516 template < 0517 class K, class KE = KeyEqual, 0518 typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 0519 std::pair<const_iterator, const_iterator> equal_range( 0520 const K& key, std::size_t precalculated_hash) const { 0521 return m_ht.equal_range(key, precalculated_hash); 0522 } 0523 0524 /* 0525 * Bucket interface 0526 */ 0527 size_type bucket_count() const { return m_ht.bucket_count(); } 0528 size_type max_bucket_count() const { return m_ht.max_bucket_count(); } 0529 0530 /* 0531 * Hash policy 0532 */ 0533 float load_factor() const { return m_ht.load_factor(); } 0534 0535 float min_load_factor() const { return m_ht.min_load_factor(); } 0536 float max_load_factor() const { return m_ht.max_load_factor(); } 0537 0538 /** 0539 * Set the `min_load_factor` to `ml`. When the `load_factor` of the set goes 0540 * below `min_load_factor` after some erase operations, the set will be 0541 * shrunk when an insertion occurs. The erase method itself never shrinks 0542 * the set. 0543 * 0544 * The default value of `min_load_factor` is 0.0f, the set never shrinks by 0545 * default. 0546 */ 0547 void min_load_factor(float ml) { m_ht.min_load_factor(ml); } 0548 void max_load_factor(float ml) { m_ht.max_load_factor(ml); } 0549 0550 void rehash(size_type count_) { m_ht.rehash(count_); } 0551 void reserve(size_type count_) { m_ht.reserve(count_); } 0552 0553 /* 0554 * Observers 0555 */ 0556 hasher hash_function() const { return m_ht.hash_function(); } 0557 key_equal key_eq() const { return m_ht.key_eq(); } 0558 0559 /* 0560 * Other 0561 */ 0562 0563 /** 0564 * Convert a const_iterator to an iterator. 0565 */ 0566 iterator mutable_iterator(const_iterator pos) { 0567 return m_ht.mutable_iterator(pos); 0568 } 0569 0570 friend bool operator==(const robin_set& lhs, const robin_set& rhs) { 0571 if (lhs.size() != rhs.size()) { 0572 return false; 0573 } 0574 0575 for (const auto& element_lhs : lhs) { 0576 const auto it_element_rhs = rhs.find(element_lhs); 0577 if (it_element_rhs == rhs.cend()) { 0578 return false; 0579 } 0580 } 0581 0582 return true; 0583 } 0584 0585 /** 0586 * Serialize the set through the `serializer` parameter. 0587 * 0588 * The `serializer` parameter must be a function object that supports the 0589 * following call: 0590 * - `template<typename U> void operator()(const U& value);` where the types 0591 * `std::int16_t`, `std::uint32_t`, `std::uint64_t`, `float` and `Key` must be 0592 * supported for U. 0593 * 0594 * The implementation leaves binary compatibility (endianness, IEEE 754 for 0595 * floats, ...) of the types it serializes in the hands of the `Serializer` 0596 * function object if compatibility is required. 0597 */ 0598 template <class Serializer> 0599 void serialize(Serializer& serializer) const { 0600 m_ht.serialize(serializer); 0601 } 0602 0603 /** 0604 * Deserialize a previously serialized set through the `deserializer` 0605 * parameter. 0606 * 0607 * The `deserializer` parameter must be a function object that supports the 0608 * following call: 0609 * - `template<typename U> U operator()();` where the types `std::int16_t`, 0610 * `std::uint32_t`, `std::uint64_t`, `float` and `Key` must be supported for 0611 * U. 0612 * 0613 * If the deserialized hash set type is hash compatible with the serialized 0614 * set, the deserialization process can be sped up by setting 0615 * `hash_compatible` to true. To be hash compatible, the Hash, KeyEqual and 0616 * GrowthPolicy must behave the same way than the ones used on the serialized 0617 * set and the StoreHash must have the same value. The `std::size_t` must also 0618 * be of the same size as the one on the platform used to serialize the set. 0619 * If these criteria are not met, the behaviour is undefined with 0620 * `hash_compatible` sets to true. 0621 * 0622 * The behaviour is undefined if the type `Key` of the `robin_set` is not the 0623 * same as the type used during serialization. 0624 * 0625 * The implementation leaves binary compatibility (endianness, IEEE 754 for 0626 * floats, size of int, ...) of the types it deserializes in the hands of the 0627 * `Deserializer` function object if compatibility is required. 0628 */ 0629 template <class Deserializer> 0630 static robin_set deserialize(Deserializer& deserializer, 0631 bool hash_compatible = false) { 0632 robin_set set(0); 0633 set.m_ht.deserialize(deserializer, hash_compatible); 0634 0635 return set; 0636 } 0637 0638 friend bool operator!=(const robin_set& lhs, const robin_set& rhs) { 0639 return !operator==(lhs, rhs); 0640 } 0641 0642 friend void swap(robin_set& lhs, robin_set& rhs) { lhs.swap(rhs); } 0643 0644 private: 0645 ht m_ht; 0646 }; 0647 0648 /** 0649 * Same as `tsl::robin_set<Key, Hash, KeyEqual, Allocator, StoreHash, 0650 * tsl::rh::prime_growth_policy>`. 0651 */ 0652 template <class Key, class Hash = std::hash<Key>, 0653 class KeyEqual = std::equal_to<Key>, 0654 class Allocator = std::allocator<Key>, bool StoreHash = false> 0655 using robin_pg_set = robin_set<Key, Hash, KeyEqual, Allocator, StoreHash, 0656 tsl::rh::prime_growth_policy>; 0657 0658 } // end namespace tsl 0659 0660 #endif