Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:51:09

0001 /* Fast open-addressing concurrent hashset.
0002  *
0003  * Copyright 2023 Christian Mazakas.
0004  * Copyright 2023-2024 Joaquin M Lopez Munoz.
0005  * Distributed under the Boost Software License, Version 1.0.
0006  * (See accompanying file LICENSE_1_0.txt or copy at
0007  * http://www.boost.org/LICENSE_1_0.txt)
0008  *
0009  * See https://www.boost.org/libs/unordered for library home page.
0010  */
0011 
0012 #ifndef BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP
0013 #define BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP
0014 
0015 #include <boost/unordered/concurrent_flat_set_fwd.hpp>
0016 #include <boost/unordered/detail/concurrent_static_asserts.hpp>
0017 #include <boost/unordered/detail/foa/concurrent_table.hpp>
0018 #include <boost/unordered/detail/foa/flat_set_types.hpp>
0019 #include <boost/unordered/detail/type_traits.hpp>
0020 #include <boost/unordered/unordered_flat_set_fwd.hpp>
0021 
0022 #include <boost/container_hash/hash.hpp>
0023 #include <boost/core/allocator_access.hpp>
0024 #include <boost/core/serialization.hpp>
0025 
0026 #include <utility>
0027 
0028 namespace boost {
0029   namespace unordered {
0030     template <class Key, class Hash, class Pred, class Allocator>
0031     class concurrent_flat_set
0032     {
0033     private:
0034       template <class Key2, class Hash2, class Pred2, class Allocator2>
0035       friend class concurrent_flat_set;
0036       template <class Key2, class Hash2, class Pred2, class Allocator2>
0037       friend class unordered_flat_set;
0038 
0039       using type_policy = detail::foa::flat_set_types<Key>;
0040 
0041       using table_type =
0042         detail::foa::concurrent_table<type_policy, Hash, Pred, Allocator>;
0043 
0044       table_type table_;
0045 
0046       template <class K, class H, class KE, class A>
0047       bool friend operator==(concurrent_flat_set<K, H, KE, A> const& lhs,
0048         concurrent_flat_set<K, H, KE, A> const& rhs);
0049 
0050       template <class K, class H, class KE, class A, class Predicate>
0051       friend typename concurrent_flat_set<K, H, KE, A>::size_type erase_if(
0052         concurrent_flat_set<K, H, KE, A>& set, Predicate pred);
0053 
0054       template<class Archive, class K, class H, class KE, class A>
0055       friend void serialize(
0056         Archive& ar, concurrent_flat_set<K, H, KE, A>& c,
0057         unsigned int version);
0058 
0059     public:
0060       using key_type = Key;
0061       using value_type = typename type_policy::value_type;
0062       using init_type = typename type_policy::init_type;
0063       using size_type = std::size_t;
0064       using difference_type = std::ptrdiff_t;
0065       using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
0066       using key_equal = typename boost::unordered::detail::type_identity<Pred>::type;
0067       using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
0068       using reference = value_type&;
0069       using const_reference = value_type const&;
0070       using pointer = typename boost::allocator_pointer<allocator_type>::type;
0071       using const_pointer =
0072         typename boost::allocator_const_pointer<allocator_type>::type;
0073       static constexpr size_type bulk_visit_size = table_type::bulk_visit_size;
0074 
0075 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0076       using stats = typename table_type::stats;
0077 #endif
0078 
0079       concurrent_flat_set()
0080           : concurrent_flat_set(detail::foa::default_bucket_count)
0081       {
0082       }
0083 
0084       explicit concurrent_flat_set(size_type n, const hasher& hf = hasher(),
0085         const key_equal& eql = key_equal(),
0086         const allocator_type& a = allocator_type())
0087           : table_(n, hf, eql, a)
0088       {
0089       }
0090 
0091       template <class InputIterator>
0092       concurrent_flat_set(InputIterator f, InputIterator l,
0093         size_type n = detail::foa::default_bucket_count,
0094         const hasher& hf = hasher(), const key_equal& eql = key_equal(),
0095         const allocator_type& a = allocator_type())
0096           : table_(n, hf, eql, a)
0097       {
0098         this->insert(f, l);
0099       }
0100 
0101       concurrent_flat_set(concurrent_flat_set const& rhs)
0102           : table_(rhs.table_,
0103               boost::allocator_select_on_container_copy_construction(
0104                 rhs.get_allocator()))
0105       {
0106       }
0107 
0108       concurrent_flat_set(concurrent_flat_set&& rhs)
0109           : table_(std::move(rhs.table_))
0110       {
0111       }
0112 
0113       template <class InputIterator>
0114       concurrent_flat_set(
0115         InputIterator f, InputIterator l, allocator_type const& a)
0116           : concurrent_flat_set(f, l, 0, hasher(), key_equal(), a)
0117       {
0118       }
0119 
0120       explicit concurrent_flat_set(allocator_type const& a)
0121           : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
0122       {
0123       }
0124 
0125       concurrent_flat_set(
0126         concurrent_flat_set const& rhs, allocator_type const& a)
0127           : table_(rhs.table_, a)
0128       {
0129       }
0130 
0131       concurrent_flat_set(concurrent_flat_set&& rhs, allocator_type const& a)
0132           : table_(std::move(rhs.table_), a)
0133       {
0134       }
0135 
0136       concurrent_flat_set(std::initializer_list<value_type> il,
0137         size_type n = detail::foa::default_bucket_count,
0138         const hasher& hf = hasher(), const key_equal& eql = key_equal(),
0139         const allocator_type& a = allocator_type())
0140           : concurrent_flat_set(n, hf, eql, a)
0141       {
0142         this->insert(il.begin(), il.end());
0143       }
0144 
0145       concurrent_flat_set(size_type n, const allocator_type& a)
0146           : concurrent_flat_set(n, hasher(), key_equal(), a)
0147       {
0148       }
0149 
0150       concurrent_flat_set(
0151         size_type n, const hasher& hf, const allocator_type& a)
0152           : concurrent_flat_set(n, hf, key_equal(), a)
0153       {
0154       }
0155 
0156       template <typename InputIterator>
0157       concurrent_flat_set(
0158         InputIterator f, InputIterator l, size_type n, const allocator_type& a)
0159           : concurrent_flat_set(f, l, n, hasher(), key_equal(), a)
0160       {
0161       }
0162 
0163       template <typename InputIterator>
0164       concurrent_flat_set(InputIterator f, InputIterator l, size_type n,
0165         const hasher& hf, const allocator_type& a)
0166           : concurrent_flat_set(f, l, n, hf, key_equal(), a)
0167       {
0168       }
0169 
0170       concurrent_flat_set(
0171         std::initializer_list<value_type> il, const allocator_type& a)
0172           : concurrent_flat_set(
0173               il, detail::foa::default_bucket_count, hasher(), key_equal(), a)
0174       {
0175       }
0176 
0177       concurrent_flat_set(std::initializer_list<value_type> il, size_type n,
0178         const allocator_type& a)
0179           : concurrent_flat_set(il, n, hasher(), key_equal(), a)
0180       {
0181       }
0182 
0183       concurrent_flat_set(std::initializer_list<value_type> il, size_type n,
0184         const hasher& hf, const allocator_type& a)
0185           : concurrent_flat_set(il, n, hf, key_equal(), a)
0186       {
0187       }
0188 
0189 
0190       concurrent_flat_set(
0191         unordered_flat_set<Key, Hash, Pred, Allocator>&& other)
0192           : table_(std::move(other.table_))
0193       {
0194       }
0195 
0196       ~concurrent_flat_set() = default;
0197 
0198       concurrent_flat_set& operator=(concurrent_flat_set const& rhs)
0199       {
0200         table_ = rhs.table_;
0201         return *this;
0202       }
0203 
0204       concurrent_flat_set& operator=(concurrent_flat_set&& rhs)
0205         noexcept(boost::allocator_is_always_equal<Allocator>::type::value ||
0206                  boost::allocator_propagate_on_container_move_assignment<
0207                    Allocator>::type::value)
0208       {
0209         table_ = std::move(rhs.table_);
0210         return *this;
0211       }
0212 
0213       concurrent_flat_set& operator=(std::initializer_list<value_type> ilist)
0214       {
0215         table_ = ilist;
0216         return *this;
0217       }
0218 
0219       /// Capacity
0220       ///
0221 
0222       size_type size() const noexcept { return table_.size(); }
0223       size_type max_size() const noexcept { return table_.max_size(); }
0224 
0225       BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
0226       {
0227         return size() == 0;
0228       }
0229 
0230       template <class F>
0231       BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const
0232       {
0233         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0234         return table_.visit(k, f);
0235       }
0236 
0237       template <class F>
0238       BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const
0239       {
0240         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0241         return table_.visit(k, f);
0242       }
0243 
0244       template <class K, class F>
0245       BOOST_FORCEINLINE typename std::enable_if<
0246         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0247       visit(K&& k, F f) const
0248       {
0249         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0250         return table_.visit(std::forward<K>(k), f);
0251       }
0252 
0253       template <class K, class F>
0254       BOOST_FORCEINLINE typename std::enable_if<
0255         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0256       cvisit(K&& k, F f) const
0257       {
0258         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0259         return table_.visit(std::forward<K>(k), f);
0260       }
0261 
0262       template<class FwdIterator, class F>
0263       BOOST_FORCEINLINE
0264       size_t visit(FwdIterator first, FwdIterator last, F f) const
0265       {
0266         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0267         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0268         return table_.visit(first, last, f);
0269       }
0270 
0271       template<class FwdIterator, class F>
0272       BOOST_FORCEINLINE
0273       size_t cvisit(FwdIterator first, FwdIterator last, F f) const
0274       {
0275         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0276         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0277         return table_.visit(first, last, f);
0278       }
0279 
0280       template <class F> size_type visit_all(F f) const
0281       {
0282         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0283         return table_.visit_all(f);
0284       }
0285 
0286       template <class F> size_type cvisit_all(F f) const
0287       {
0288         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0289         return table_.cvisit_all(f);
0290       }
0291 
0292 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0293       template <class ExecPolicy, class F>
0294       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0295         void>::type
0296       visit_all(ExecPolicy&& p, F f) const
0297       {
0298         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0299         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0300         table_.visit_all(p, f);
0301       }
0302 
0303       template <class ExecPolicy, class F>
0304       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0305         void>::type
0306       cvisit_all(ExecPolicy&& p, F f) const
0307       {
0308         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0309         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0310         table_.cvisit_all(p, f);
0311       }
0312 #endif
0313 
0314       template <class F> bool visit_while(F f) const
0315       {
0316         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0317         return table_.visit_while(f);
0318       }
0319 
0320       template <class F> bool cvisit_while(F f) const
0321       {
0322         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0323         return table_.cvisit_while(f);
0324       }
0325 
0326 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0327       template <class ExecPolicy, class F>
0328       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0329         bool>::type
0330       visit_while(ExecPolicy&& p, F f) const
0331       {
0332         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0333         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0334         return table_.visit_while(p, f);
0335       }
0336 
0337       template <class ExecPolicy, class F>
0338       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0339         bool>::type
0340       cvisit_while(ExecPolicy&& p, F f) const
0341       {
0342         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0343         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0344         return table_.cvisit_while(p, f);
0345       }
0346 #endif
0347 
0348       /// Modifiers
0349       ///
0350 
0351       BOOST_FORCEINLINE bool insert(value_type const& obj)
0352       {
0353         return table_.insert(obj);
0354       }
0355 
0356       BOOST_FORCEINLINE bool insert(value_type&& obj)
0357       {
0358         return table_.insert(std::move(obj));
0359       }
0360 
0361       template <class K>
0362       BOOST_FORCEINLINE typename std::enable_if<
0363         detail::are_transparent<K, hasher, key_equal>::value,
0364         bool >::type
0365       insert(K&& k)
0366       {
0367         return table_.try_emplace(std::forward<K>(k));
0368       }
0369 
0370       template <class InputIterator>
0371       void insert(InputIterator begin, InputIterator end)
0372       {
0373         for (auto pos = begin; pos != end; ++pos) {
0374           table_.emplace(*pos);
0375         }
0376       }
0377 
0378       void insert(std::initializer_list<value_type> ilist)
0379       {
0380         this->insert(ilist.begin(), ilist.end());
0381       }
0382 
0383       template <class F>
0384       BOOST_FORCEINLINE bool insert_or_visit(value_type const& obj, F f)
0385       {
0386         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0387         return table_.insert_or_cvisit(obj, f);
0388       }
0389 
0390       template <class F>
0391       BOOST_FORCEINLINE bool insert_or_visit(value_type&& obj, F f)
0392       {
0393         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0394         return table_.insert_or_cvisit(std::move(obj), f);
0395       }
0396 
0397       template <class K, class F>
0398       BOOST_FORCEINLINE typename std::enable_if<
0399         detail::are_transparent<K, hasher, key_equal>::value,
0400         bool >::type
0401       insert_or_visit(K&& k, F f)
0402       {
0403         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0404         return table_.try_emplace_or_cvisit(std::forward<K>(k), f);
0405       }
0406 
0407       template <class InputIterator, class F>
0408       void insert_or_visit(InputIterator first, InputIterator last, F f)
0409       {
0410         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0411         for (; first != last; ++first) {
0412           table_.emplace_or_cvisit(*first, f);
0413         }
0414       }
0415 
0416       template <class F>
0417       void insert_or_visit(std::initializer_list<value_type> ilist, F f)
0418       {
0419         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0420         this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
0421       }
0422 
0423       template <class F>
0424       BOOST_FORCEINLINE bool insert_or_cvisit(value_type const& obj, F f)
0425       {
0426         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0427         return table_.insert_or_cvisit(obj, f);
0428       }
0429 
0430       template <class F>
0431       BOOST_FORCEINLINE bool insert_or_cvisit(value_type&& obj, F f)
0432       {
0433         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0434         return table_.insert_or_cvisit(std::move(obj), f);
0435       }
0436 
0437       template <class K, class F>
0438       BOOST_FORCEINLINE typename std::enable_if<
0439         detail::are_transparent<K, hasher, key_equal>::value,
0440         bool >::type
0441       insert_or_cvisit(K&& k, F f)
0442       {
0443         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0444         return table_.try_emplace_or_cvisit(std::forward<K>(k), f);
0445       }
0446 
0447       template <class InputIterator, class F>
0448       void insert_or_cvisit(InputIterator first, InputIterator last, F f)
0449       {
0450         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0451         for (; first != last; ++first) {
0452           table_.emplace_or_cvisit(*first, f);
0453         }
0454       }
0455 
0456       template <class F>
0457       void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
0458       {
0459         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0460         this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
0461       }
0462 
0463       template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
0464       {
0465         return table_.emplace(std::forward<Args>(args)...);
0466       }
0467 
0468       template <class Arg, class... Args>
0469       BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
0470       {
0471         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0472         return table_.emplace_or_cvisit(
0473           std::forward<Arg>(arg), std::forward<Args>(args)...);
0474       }
0475 
0476       template <class Arg, class... Args>
0477       BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
0478       {
0479         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0480         return table_.emplace_or_cvisit(
0481           std::forward<Arg>(arg), std::forward<Args>(args)...);
0482       }
0483 
0484       BOOST_FORCEINLINE size_type erase(key_type const& k)
0485       {
0486         return table_.erase(k);
0487       }
0488 
0489       template <class K>
0490       BOOST_FORCEINLINE typename std::enable_if<
0491         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0492       erase(K&& k)
0493       {
0494         return table_.erase(std::forward<K>(k));
0495       }
0496 
0497       template <class F>
0498       BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
0499       {
0500         return table_.erase_if(k, f);
0501       }
0502 
0503       template <class K, class F>
0504       BOOST_FORCEINLINE typename std::enable_if<
0505         detail::are_transparent<K, hasher, key_equal>::value &&
0506           !detail::is_execution_policy<K>::value,
0507         size_type>::type
0508       erase_if(K&& k, F f)
0509       {
0510         return table_.erase_if(std::forward<K>(k), f);
0511       }
0512 
0513 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0514       template <class ExecPolicy, class F>
0515       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0516         void>::type
0517       erase_if(ExecPolicy&& p, F f)
0518       {
0519         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0520         table_.erase_if(p, f);
0521       }
0522 #endif
0523 
0524       template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
0525 
0526       void swap(concurrent_flat_set& other) noexcept(
0527         boost::allocator_is_always_equal<Allocator>::type::value ||
0528         boost::allocator_propagate_on_container_swap<Allocator>::type::value)
0529       {
0530         return table_.swap(other.table_);
0531       }
0532 
0533       void clear() noexcept { table_.clear(); }
0534 
0535       template <typename H2, typename P2>
0536       size_type merge(concurrent_flat_set<Key, H2, P2, Allocator>& x)
0537       {
0538         BOOST_ASSERT(get_allocator() == x.get_allocator());
0539         return table_.merge(x.table_);
0540       }
0541 
0542       template <typename H2, typename P2>
0543       size_type merge(concurrent_flat_set<Key, H2, P2, Allocator>&& x)
0544       {
0545         return merge(x);
0546       }
0547 
0548       BOOST_FORCEINLINE size_type count(key_type const& k) const
0549       {
0550         return table_.count(k);
0551       }
0552 
0553       template <class K>
0554       BOOST_FORCEINLINE typename std::enable_if<
0555         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0556       count(K const& k)
0557       {
0558         return table_.count(k);
0559       }
0560 
0561       BOOST_FORCEINLINE bool contains(key_type const& k) const
0562       {
0563         return table_.contains(k);
0564       }
0565 
0566       template <class K>
0567       BOOST_FORCEINLINE typename std::enable_if<
0568         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0569       contains(K const& k) const
0570       {
0571         return table_.contains(k);
0572       }
0573 
0574       /// Hash Policy
0575       ///
0576       size_type bucket_count() const noexcept { return table_.capacity(); }
0577 
0578       float load_factor() const noexcept { return table_.load_factor(); }
0579       float max_load_factor() const noexcept
0580       {
0581         return table_.max_load_factor();
0582       }
0583       void max_load_factor(float) {}
0584       size_type max_load() const noexcept { return table_.max_load(); }
0585 
0586       void rehash(size_type n) { table_.rehash(n); }
0587       void reserve(size_type n) { table_.reserve(n); }
0588 
0589 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0590       /// Stats
0591       ///
0592       stats get_stats() const { return table_.get_stats(); }
0593 
0594       void reset_stats() noexcept { table_.reset_stats(); }
0595 #endif
0596 
0597       /// Observers
0598       ///
0599       allocator_type get_allocator() const noexcept
0600       {
0601         return table_.get_allocator();
0602       }
0603 
0604       hasher hash_function() const { return table_.hash_function(); }
0605       key_equal key_eq() const { return table_.key_eq(); }
0606     };
0607 
0608     template <class Key, class Hash, class KeyEqual, class Allocator>
0609     bool operator==(
0610       concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
0611       concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
0612     {
0613       return lhs.table_ == rhs.table_;
0614     }
0615 
0616     template <class Key, class Hash, class KeyEqual, class Allocator>
0617     bool operator!=(
0618       concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
0619       concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
0620     {
0621       return !(lhs == rhs);
0622     }
0623 
0624     template <class Key, class Hash, class Pred, class Alloc>
0625     void swap(concurrent_flat_set<Key, Hash, Pred, Alloc>& x,
0626       concurrent_flat_set<Key, Hash, Pred, Alloc>& y)
0627       noexcept(noexcept(x.swap(y)))
0628     {
0629       x.swap(y);
0630     }
0631 
0632     template <class K, class H, class P, class A, class Predicate>
0633     typename concurrent_flat_set<K, H, P, A>::size_type erase_if(
0634       concurrent_flat_set<K, H, P, A>& c, Predicate pred)
0635     {
0636       return c.table_.erase_if(pred);
0637     }
0638 
0639     template<class Archive, class K, class H, class KE, class A>
0640     void serialize(
0641       Archive& ar, concurrent_flat_set<K, H, KE, A>& c, unsigned int)
0642     {
0643       ar & core::make_nvp("table",c.table_);
0644     }
0645 
0646 #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
0647 
0648     template <class InputIterator,
0649       class Hash =
0650         boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0651       class Pred =
0652         std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0653       class Allocator = std::allocator<
0654         typename std::iterator_traits<InputIterator>::value_type>,
0655       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0656       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0657       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0658       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0659     concurrent_flat_set(InputIterator, InputIterator,
0660       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0661       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0662       -> concurrent_flat_set<
0663         typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
0664         Allocator>;
0665 
0666     template <class T, class Hash = boost::hash<T>,
0667       class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
0668       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0669       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0670       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0671     concurrent_flat_set(std::initializer_list<T>,
0672       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0673       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0674       -> concurrent_flat_set< T, Hash, Pred, Allocator>;
0675 
0676     template <class InputIterator, class Allocator,
0677       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0678       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0679     concurrent_flat_set(InputIterator, InputIterator, std::size_t, Allocator)
0680       -> concurrent_flat_set<
0681         typename std::iterator_traits<InputIterator>::value_type,
0682         boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0683         std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0684         Allocator>;
0685 
0686     template <class InputIterator, class Allocator,
0687       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0688       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0689     concurrent_flat_set(InputIterator, InputIterator, Allocator)
0690       -> concurrent_flat_set<
0691         typename std::iterator_traits<InputIterator>::value_type,
0692         boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0693         std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0694         Allocator>;
0695 
0696     template <class InputIterator, class Hash, class Allocator,
0697       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0698       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0699       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0700     concurrent_flat_set(
0701       InputIterator, InputIterator, std::size_t, Hash, Allocator)
0702       -> concurrent_flat_set<
0703         typename std::iterator_traits<InputIterator>::value_type, Hash,
0704         std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0705         Allocator>;
0706 
0707     template <class T, class Allocator,
0708       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0709     concurrent_flat_set(std::initializer_list<T>, std::size_t, Allocator)
0710       -> concurrent_flat_set<T, boost::hash<T>,std::equal_to<T>, Allocator>;
0711 
0712     template <class T, class Allocator,
0713       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0714     concurrent_flat_set(std::initializer_list<T >, Allocator)
0715       -> concurrent_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
0716 
0717     template <class T, class Hash, class Allocator,
0718       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0719       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0720     concurrent_flat_set(std::initializer_list<T >, std::size_t,Hash, Allocator)
0721       -> concurrent_flat_set<T, Hash, std::equal_to<T>, Allocator>;
0722 
0723 #endif
0724 
0725   } // namespace unordered
0726 } // namespace boost
0727 
0728 #endif // BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP