Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:22

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