Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:51:31

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       template <bool avoid_explicit_instantiation = true>
0191       concurrent_flat_set(
0192         unordered_flat_set<Key, Hash, Pred, Allocator>&& other)
0193           : table_(std::move(other.table_))
0194       {
0195       }
0196 
0197       ~concurrent_flat_set() = default;
0198 
0199       concurrent_flat_set& operator=(concurrent_flat_set const& rhs)
0200       {
0201         table_ = rhs.table_;
0202         return *this;
0203       }
0204 
0205       concurrent_flat_set& operator=(concurrent_flat_set&& rhs)
0206         noexcept(boost::allocator_is_always_equal<Allocator>::type::value ||
0207                  boost::allocator_propagate_on_container_move_assignment<
0208                    Allocator>::type::value)
0209       {
0210         table_ = std::move(rhs.table_);
0211         return *this;
0212       }
0213 
0214       concurrent_flat_set& operator=(std::initializer_list<value_type> ilist)
0215       {
0216         table_ = ilist;
0217         return *this;
0218       }
0219 
0220       /// Capacity
0221       ///
0222 
0223       size_type size() const noexcept { return table_.size(); }
0224       size_type max_size() const noexcept { return table_.max_size(); }
0225 
0226       BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
0227       {
0228         return size() == 0;
0229       }
0230 
0231       template <class F>
0232       BOOST_FORCEINLINE size_type visit(key_type const& k, F f)
0233       {
0234         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0235         return table_.visit(k, f);
0236       }
0237 
0238       template <class F>
0239       BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const
0240       {
0241         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0242         return table_.visit(k, f);
0243       }
0244 
0245       template <class F>
0246       BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const
0247       {
0248         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0249         return table_.visit(k, f);
0250       }
0251 
0252       template <class K, class F>
0253       BOOST_FORCEINLINE typename std::enable_if<
0254         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0255       visit(K&& k, F f)
0256       {
0257         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0258         return table_.visit(std::forward<K>(k), f);
0259       }
0260 
0261       template <class K, class F>
0262       BOOST_FORCEINLINE typename std::enable_if<
0263         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0264       visit(K&& k, F f) const
0265       {
0266         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0267         return table_.visit(std::forward<K>(k), f);
0268       }
0269 
0270       template <class K, class F>
0271       BOOST_FORCEINLINE typename std::enable_if<
0272         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0273       cvisit(K&& k, F f) const
0274       {
0275         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0276         return table_.visit(std::forward<K>(k), f);
0277       }
0278 
0279       template<class FwdIterator, class F>
0280       BOOST_FORCEINLINE
0281       size_t visit(FwdIterator first, FwdIterator last, F f)
0282       {
0283         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0284         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0285         return table_.visit(first, last, f);
0286       }
0287 
0288       template<class FwdIterator, class F>
0289       BOOST_FORCEINLINE
0290       size_t visit(FwdIterator first, FwdIterator last, F f) const
0291       {
0292         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0293         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0294         return table_.visit(first, last, f);
0295       }
0296 
0297       template<class FwdIterator, class F>
0298       BOOST_FORCEINLINE
0299       size_t cvisit(FwdIterator first, FwdIterator last, F f) const
0300       {
0301         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0302         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0303         return table_.visit(first, last, f);
0304       }
0305 
0306       template <class F> size_type visit_all(F f)
0307       {
0308         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0309         return table_.visit_all(f);
0310       }
0311 
0312       template <class F> size_type visit_all(F f) const
0313       {
0314         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0315         return table_.visit_all(f);
0316       }
0317 
0318       template <class F> size_type cvisit_all(F f) const
0319       {
0320         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0321         return table_.cvisit_all(f);
0322       }
0323 
0324 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0325       template <class ExecPolicy, class F>
0326       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0327         void>::type
0328       visit_all(ExecPolicy&& p, F f)
0329       {
0330         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0331         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0332         table_.visit_all(p, f);
0333       }
0334 
0335       template <class ExecPolicy, class F>
0336       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0337         void>::type
0338       visit_all(ExecPolicy&& p, F f) const
0339       {
0340         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0341         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0342         table_.visit_all(p, f);
0343       }
0344 
0345       template <class ExecPolicy, class F>
0346       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0347         void>::type
0348       cvisit_all(ExecPolicy&& p, F f) const
0349       {
0350         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0351         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0352         table_.cvisit_all(p, f);
0353       }
0354 #endif
0355 
0356       template <class F> bool visit_while(F f)
0357       {
0358         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0359         return table_.visit_while(f);
0360       }
0361 
0362       template <class F> bool visit_while(F f) const
0363       {
0364         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0365         return table_.visit_while(f);
0366       }
0367 
0368       template <class F> bool cvisit_while(F f) const
0369       {
0370         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0371         return table_.cvisit_while(f);
0372       }
0373 
0374 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0375       template <class ExecPolicy, class F>
0376       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0377         bool>::type
0378       visit_while(ExecPolicy&& p, F f)
0379       {
0380         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0381         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0382         return table_.visit_while(p, f);
0383       }
0384 
0385       template <class ExecPolicy, class F>
0386       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0387         bool>::type
0388       visit_while(ExecPolicy&& p, F f) const
0389       {
0390         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0391         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0392         return table_.visit_while(p, f);
0393       }
0394 
0395       template <class ExecPolicy, class F>
0396       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0397         bool>::type
0398       cvisit_while(ExecPolicy&& p, F f) const
0399       {
0400         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0401         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0402         return table_.cvisit_while(p, f);
0403       }
0404 #endif
0405 
0406       /// Modifiers
0407       ///
0408 
0409       BOOST_FORCEINLINE bool insert(value_type const& obj)
0410       {
0411         return table_.insert(obj);
0412       }
0413 
0414       BOOST_FORCEINLINE bool insert(value_type&& obj)
0415       {
0416         return table_.insert(std::move(obj));
0417       }
0418 
0419       template <class K>
0420       BOOST_FORCEINLINE typename std::enable_if<
0421         detail::are_transparent<K, hasher, key_equal>::value,
0422         bool >::type
0423       insert(K&& k)
0424       {
0425         return table_.try_emplace(std::forward<K>(k));
0426       }
0427 
0428       template <class InputIterator>
0429       size_type insert(InputIterator begin, InputIterator end)
0430       {
0431         size_type count_elements = 0;
0432         for (auto pos = begin; pos != end; ++pos, ++count_elements) {
0433           table_.emplace(*pos);
0434         }
0435         return count_elements;
0436       }
0437 
0438       size_type insert(std::initializer_list<value_type> ilist)
0439       {
0440         return this->insert(ilist.begin(), ilist.end());
0441       }
0442 
0443       template <class F>
0444       BOOST_FORCEINLINE bool insert_or_visit(value_type const& obj, F f)
0445       {
0446         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0447         return table_.insert_or_visit(obj, f);
0448       }
0449 
0450       template <class F>
0451       BOOST_FORCEINLINE bool insert_or_visit(value_type&& obj, F f)
0452       {
0453         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0454         return table_.insert_or_visit(std::move(obj), f);
0455       }
0456 
0457       template <class K, class F>
0458       BOOST_FORCEINLINE typename std::enable_if<
0459         detail::are_transparent<K, hasher, key_equal>::value,
0460         bool >::type
0461       insert_or_visit(K&& k, F f)
0462       {
0463         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0464         return table_.try_emplace_or_visit(std::forward<K>(k), f);
0465       }
0466 
0467       template <class InputIterator, class F>
0468       size_type insert_or_visit(InputIterator first, InputIterator last, F f)
0469       {
0470         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0471         size_type count_elements = 0;
0472         for (; first != last; ++first, ++count_elements) {
0473           table_.emplace_or_visit(*first, f);
0474         }
0475         return count_elements;
0476       }
0477 
0478       template <class F>
0479       size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
0480       {
0481         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0482         return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f));
0483       }
0484 
0485       template <class F>
0486       BOOST_FORCEINLINE bool insert_or_cvisit(value_type const& obj, F f)
0487       {
0488         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0489         return table_.insert_or_cvisit(obj, f);
0490       }
0491 
0492       template <class F>
0493       BOOST_FORCEINLINE bool insert_or_cvisit(value_type&& obj, F f)
0494       {
0495         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0496         return table_.insert_or_cvisit(std::move(obj), 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         bool >::type
0503       insert_or_cvisit(K&& k, F f)
0504       {
0505         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0506         return table_.try_emplace_or_cvisit(std::forward<K>(k), f);
0507       }
0508 
0509       template <class InputIterator, class F>
0510       size_type insert_or_cvisit(InputIterator first, InputIterator last, F f)
0511       {
0512         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0513         size_type count_elements = 0;
0514         for (; first != last; ++first, ++count_elements) {
0515           table_.emplace_or_cvisit(*first, f);
0516         }
0517         return count_elements;
0518       }
0519 
0520       template <class F>
0521       size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
0522       {
0523         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0524         return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f));
0525       }
0526 
0527       template <class F1, class F2>
0528       BOOST_FORCEINLINE bool insert_and_visit(
0529         value_type const& obj, F1 f1, F2 f2)
0530       {
0531         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0532         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0533         return table_.insert_and_visit(obj, f1, f2);
0534       }
0535 
0536       template <class F1, class F2>
0537       BOOST_FORCEINLINE bool insert_and_visit(value_type&& obj, F1 f1, F2 f2)
0538       {
0539         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0540         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0541         return table_.insert_and_visit(std::move(obj), f1, f2);
0542       }
0543 
0544       template <class K, class F1, class F2>
0545       BOOST_FORCEINLINE typename std::enable_if<
0546         detail::are_transparent<K, hasher, key_equal>::value,
0547         bool >::type
0548       insert_and_visit(K&& k, F1 f1, F2 f2)
0549       {
0550         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0551         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0552         return table_.try_emplace_and_visit(std::forward<K>(k), f1, f2);
0553       }
0554 
0555       template <class InputIterator, class F1, class F2>
0556       size_type insert_and_visit(
0557         InputIterator first, InputIterator last, F1 f1, F2 f2)
0558       {
0559         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0560         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0561         size_type count_elements = 0;
0562         for (; first != last; ++first, ++count_elements) {
0563           table_.emplace_and_visit(*first, f1, f2);
0564         }
0565         return count_elements;
0566       }
0567 
0568       template <class F1, class F2>
0569       size_type insert_and_visit(std::initializer_list<value_type> ilist, F1 f1, F2 f2)
0570       {
0571         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0572         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0573         return this->insert_and_visit(
0574           ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
0575       }
0576 
0577       template <class F1, class F2>
0578       BOOST_FORCEINLINE bool insert_and_cvisit(
0579         value_type const& obj, F1 f1, F2 f2)
0580       {
0581         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0582         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0583         return table_.insert_and_cvisit(obj, f1, f2);
0584       }
0585 
0586       template <class F1, class F2>
0587       BOOST_FORCEINLINE bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2)
0588       {
0589         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0590         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0591         return table_.insert_and_cvisit(std::move(obj), f1, f2);
0592       }
0593 
0594       template <class K, class F1, class F2>
0595       BOOST_FORCEINLINE typename std::enable_if<
0596         detail::are_transparent<K, hasher, key_equal>::value,
0597         bool >::type
0598       insert_and_cvisit(K&& k, F1 f1, F2 f2)
0599       {
0600         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0601         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0602         return table_.try_emplace_and_cvisit(std::forward<K>(k), f1, f2);
0603       }
0604 
0605       template <class InputIterator, class F1, class F2>
0606       size_type insert_and_cvisit(
0607         InputIterator first, InputIterator last, F1 f1, F2 f2)
0608       {
0609         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0610         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0611         size_type count_elements = 0;
0612         for (; first != last; ++first, ++count_elements) {
0613           table_.emplace_and_cvisit(*first, f1, f2);
0614         }
0615         return count_elements;
0616       }
0617 
0618       template <class F1, class F2>
0619       size_type insert_and_cvisit(
0620         std::initializer_list<value_type> ilist, F1 f1, F2 f2)
0621       {
0622         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
0623         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0624         return this->insert_and_cvisit(
0625           ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
0626       }
0627 
0628       template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
0629       {
0630         return table_.emplace(std::forward<Args>(args)...);
0631       }
0632 
0633       template <class Arg, class... Args>
0634       BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
0635       {
0636         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0637         return table_.emplace_or_visit(
0638           std::forward<Arg>(arg), std::forward<Args>(args)...);
0639       }
0640 
0641       template <class Arg, class... Args>
0642       BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
0643       {
0644         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0645         return table_.emplace_or_cvisit(
0646           std::forward<Arg>(arg), std::forward<Args>(args)...);
0647       }
0648 
0649       template <class Arg1, class Arg2, class... Args>
0650       BOOST_FORCEINLINE bool emplace_and_visit(
0651         Arg1&& arg1, Arg2&& arg2, Args&&... args)
0652       {
0653         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_CONST_INVOCABLE(
0654           Arg1, Arg2, Args...)
0655         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
0656         return table_.emplace_and_visit(
0657           std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0658           std::forward<Args>(args)...);
0659       }
0660 
0661       template <class Arg1, class Arg2, class... Args>
0662       BOOST_FORCEINLINE bool emplace_and_cvisit(
0663         Arg1&& arg1, Arg2&& arg2, Args&&... args)
0664       {
0665         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_CONST_INVOCABLE(
0666           Arg1, Arg2, Args...)
0667         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
0668         return table_.emplace_and_cvisit(
0669           std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0670           std::forward<Args>(args)...);
0671       }
0672 
0673       BOOST_FORCEINLINE size_type erase(key_type const& k)
0674       {
0675         return table_.erase(k);
0676       }
0677 
0678       template <class K>
0679       BOOST_FORCEINLINE typename std::enable_if<
0680         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0681       erase(K&& k)
0682       {
0683         return table_.erase(std::forward<K>(k));
0684       }
0685 
0686       template <class F>
0687       BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
0688       {
0689         return table_.erase_if(k, f);
0690       }
0691 
0692       template <class K, class F>
0693       BOOST_FORCEINLINE typename std::enable_if<
0694         detail::are_transparent<K, hasher, key_equal>::value &&
0695           !detail::is_execution_policy<K>::value,
0696         size_type>::type
0697       erase_if(K&& k, F f)
0698       {
0699         return table_.erase_if(std::forward<K>(k), f);
0700       }
0701 
0702 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0703       template <class ExecPolicy, class F>
0704       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0705         void>::type
0706       erase_if(ExecPolicy&& p, F f)
0707       {
0708         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0709         table_.erase_if(p, f);
0710       }
0711 #endif
0712 
0713       template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
0714 
0715       void swap(concurrent_flat_set& other) noexcept(
0716         boost::allocator_is_always_equal<Allocator>::type::value ||
0717         boost::allocator_propagate_on_container_swap<Allocator>::type::value)
0718       {
0719         return table_.swap(other.table_);
0720       }
0721 
0722       void clear() noexcept { table_.clear(); }
0723 
0724       template <typename H2, typename P2>
0725       size_type merge(concurrent_flat_set<Key, H2, P2, Allocator>& x)
0726       {
0727         BOOST_ASSERT(get_allocator() == x.get_allocator());
0728         return table_.merge(x.table_);
0729       }
0730 
0731       template <typename H2, typename P2>
0732       size_type merge(concurrent_flat_set<Key, H2, P2, Allocator>&& x)
0733       {
0734         return merge(x);
0735       }
0736 
0737       BOOST_FORCEINLINE size_type count(key_type const& k) const
0738       {
0739         return table_.count(k);
0740       }
0741 
0742       template <class K>
0743       BOOST_FORCEINLINE typename std::enable_if<
0744         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0745       count(K const& k)
0746       {
0747         return table_.count(k);
0748       }
0749 
0750       BOOST_FORCEINLINE bool contains(key_type const& k) const
0751       {
0752         return table_.contains(k);
0753       }
0754 
0755       template <class K>
0756       BOOST_FORCEINLINE typename std::enable_if<
0757         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0758       contains(K const& k) const
0759       {
0760         return table_.contains(k);
0761       }
0762 
0763       /// Hash Policy
0764       ///
0765       size_type bucket_count() const noexcept { return table_.capacity(); }
0766 
0767       float load_factor() const noexcept { return table_.load_factor(); }
0768       float max_load_factor() const noexcept
0769       {
0770         return table_.max_load_factor();
0771       }
0772       void max_load_factor(float) {}
0773       size_type max_load() const noexcept { return table_.max_load(); }
0774 
0775       void rehash(size_type n) { table_.rehash(n); }
0776       void reserve(size_type n) { table_.reserve(n); }
0777 
0778 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0779       /// Stats
0780       ///
0781       stats get_stats() const { return table_.get_stats(); }
0782 
0783       void reset_stats() noexcept { table_.reset_stats(); }
0784 #endif
0785 
0786       /// Observers
0787       ///
0788       allocator_type get_allocator() const noexcept
0789       {
0790         return table_.get_allocator();
0791       }
0792 
0793       hasher hash_function() const { return table_.hash_function(); }
0794       key_equal key_eq() const { return table_.key_eq(); }
0795     };
0796 
0797     template <class Key, class Hash, class KeyEqual, class Allocator>
0798     bool operator==(
0799       concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
0800       concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
0801     {
0802       return lhs.table_ == rhs.table_;
0803     }
0804 
0805     template <class Key, class Hash, class KeyEqual, class Allocator>
0806     bool operator!=(
0807       concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
0808       concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
0809     {
0810       return !(lhs == rhs);
0811     }
0812 
0813     template <class Key, class Hash, class Pred, class Alloc>
0814     void swap(concurrent_flat_set<Key, Hash, Pred, Alloc>& x,
0815       concurrent_flat_set<Key, Hash, Pred, Alloc>& y)
0816       noexcept(noexcept(x.swap(y)))
0817     {
0818       x.swap(y);
0819     }
0820 
0821     template <class K, class H, class P, class A, class Predicate>
0822     typename concurrent_flat_set<K, H, P, A>::size_type erase_if(
0823       concurrent_flat_set<K, H, P, A>& c, Predicate pred)
0824     {
0825       return c.table_.erase_if(pred);
0826     }
0827 
0828     template<class Archive, class K, class H, class KE, class A>
0829     void serialize(
0830       Archive& ar, concurrent_flat_set<K, H, KE, A>& c, unsigned int)
0831     {
0832       ar & core::make_nvp("table",c.table_);
0833     }
0834 
0835 #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
0836 
0837     template <class InputIterator,
0838       class Hash =
0839         boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0840       class Pred =
0841         std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0842       class Allocator = std::allocator<
0843         typename std::iterator_traits<InputIterator>::value_type>,
0844       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0845       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0846       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0847       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0848     concurrent_flat_set(InputIterator, InputIterator,
0849       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0850       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0851       -> concurrent_flat_set<
0852         typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
0853         Allocator>;
0854 
0855     template <class T, class Hash = boost::hash<T>,
0856       class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
0857       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0858       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0859       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0860     concurrent_flat_set(std::initializer_list<T>,
0861       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0862       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0863       -> concurrent_flat_set< T, Hash, Pred, Allocator>;
0864 
0865     template <class InputIterator, class Allocator,
0866       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0867       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0868     concurrent_flat_set(InputIterator, InputIterator, std::size_t, Allocator)
0869       -> concurrent_flat_set<
0870         typename std::iterator_traits<InputIterator>::value_type,
0871         boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0872         std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0873         Allocator>;
0874 
0875     template <class InputIterator, class Allocator,
0876       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0877       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0878     concurrent_flat_set(InputIterator, InputIterator, Allocator)
0879       -> concurrent_flat_set<
0880         typename std::iterator_traits<InputIterator>::value_type,
0881         boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0882         std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0883         Allocator>;
0884 
0885     template <class InputIterator, class Hash, class Allocator,
0886       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0887       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0888       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0889     concurrent_flat_set(
0890       InputIterator, InputIterator, std::size_t, Hash, Allocator)
0891       -> concurrent_flat_set<
0892         typename std::iterator_traits<InputIterator>::value_type, Hash,
0893         std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0894         Allocator>;
0895 
0896     template <class T, class Allocator,
0897       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0898     concurrent_flat_set(std::initializer_list<T>, std::size_t, Allocator)
0899       -> concurrent_flat_set<T, boost::hash<T>,std::equal_to<T>, Allocator>;
0900 
0901     template <class T, class Allocator,
0902       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0903     concurrent_flat_set(std::initializer_list<T >, Allocator)
0904       -> concurrent_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
0905 
0906     template <class T, class Hash, class Allocator,
0907       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0908       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0909     concurrent_flat_set(std::initializer_list<T >, std::size_t,Hash, Allocator)
0910       -> concurrent_flat_set<T, Hash, std::equal_to<T>, Allocator>;
0911 
0912 #endif
0913 
0914   } // namespace unordered
0915 } // namespace boost
0916 
0917 #endif // BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP