Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:52:33

0001 /* Fast open-addressing concurrent hashmap.
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_MAP_HPP
0013 #define BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP
0014 
0015 #include <boost/unordered/concurrent_flat_map_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_map_types.hpp>
0019 #include <boost/unordered/detail/type_traits.hpp>
0020 #include <boost/unordered/unordered_flat_map_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 <type_traits>
0027 
0028 namespace boost {
0029   namespace unordered {
0030     template <class Key, class T, class Hash, class Pred, class Allocator>
0031     class concurrent_flat_map
0032     {
0033     private:
0034       template <class Key2, class T2, class Hash2, class Pred2,
0035         class Allocator2>
0036       friend class concurrent_flat_map;
0037       template <class Key2, class T2, class Hash2, class Pred2,
0038         class Allocator2>
0039       friend class unordered_flat_map;
0040 
0041       using type_policy = detail::foa::flat_map_types<Key, T>;
0042 
0043       using table_type =
0044         detail::foa::concurrent_table<type_policy, Hash, Pred, Allocator>;
0045 
0046       table_type table_;
0047 
0048       template <class K, class V, class H, class KE, class A>
0049       bool friend operator==(concurrent_flat_map<K, V, H, KE, A> const& lhs,
0050         concurrent_flat_map<K, V, H, KE, A> const& rhs);
0051 
0052       template <class K, class V, class H, class KE, class A, class Predicate>
0053       friend typename concurrent_flat_map<K, V, H, KE, A>::size_type erase_if(
0054         concurrent_flat_map<K, V, H, KE, A>& set, Predicate pred);
0055 
0056       template<class Archive, class K, class V, class H, class KE, class A>
0057       friend void serialize(
0058         Archive& ar, concurrent_flat_map<K, V, H, KE, A>& c,
0059         unsigned int version);
0060 
0061     public:
0062       using key_type = Key;
0063       using mapped_type = T;
0064       using value_type = typename type_policy::value_type;
0065       using init_type = typename type_policy::init_type;
0066       using size_type = std::size_t;
0067       using difference_type = std::ptrdiff_t;
0068       using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
0069       using key_equal = typename boost::unordered::detail::type_identity<Pred>::type;
0070       using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
0071       using reference = value_type&;
0072       using const_reference = value_type const&;
0073       using pointer = typename boost::allocator_pointer<allocator_type>::type;
0074       using const_pointer =
0075         typename boost::allocator_const_pointer<allocator_type>::type;
0076       static constexpr size_type bulk_visit_size = table_type::bulk_visit_size;
0077 
0078 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0079       using stats = typename table_type::stats;
0080 #endif
0081 
0082       concurrent_flat_map()
0083           : concurrent_flat_map(detail::foa::default_bucket_count)
0084       {
0085       }
0086 
0087       explicit concurrent_flat_map(size_type n, const hasher& hf = hasher(),
0088         const key_equal& eql = key_equal(),
0089         const allocator_type& a = allocator_type())
0090           : table_(n, hf, eql, a)
0091       {
0092       }
0093 
0094       template <class InputIterator>
0095       concurrent_flat_map(InputIterator f, InputIterator l,
0096         size_type n = detail::foa::default_bucket_count,
0097         const hasher& hf = hasher(), const key_equal& eql = key_equal(),
0098         const allocator_type& a = allocator_type())
0099           : table_(n, hf, eql, a)
0100       {
0101         this->insert(f, l);
0102       }
0103 
0104       concurrent_flat_map(concurrent_flat_map const& rhs)
0105           : table_(rhs.table_,
0106               boost::allocator_select_on_container_copy_construction(
0107                 rhs.get_allocator()))
0108       {
0109       }
0110 
0111       concurrent_flat_map(concurrent_flat_map&& rhs)
0112           : table_(std::move(rhs.table_))
0113       {
0114       }
0115 
0116       template <class InputIterator>
0117       concurrent_flat_map(
0118         InputIterator f, InputIterator l, allocator_type const& a)
0119           : concurrent_flat_map(f, l, 0, hasher(), key_equal(), a)
0120       {
0121       }
0122 
0123       explicit concurrent_flat_map(allocator_type const& a)
0124           : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
0125       {
0126       }
0127 
0128       concurrent_flat_map(
0129         concurrent_flat_map const& rhs, allocator_type const& a)
0130           : table_(rhs.table_, a)
0131       {
0132       }
0133 
0134       concurrent_flat_map(concurrent_flat_map&& rhs, allocator_type const& a)
0135           : table_(std::move(rhs.table_), a)
0136       {
0137       }
0138 
0139       concurrent_flat_map(std::initializer_list<value_type> il,
0140         size_type n = detail::foa::default_bucket_count,
0141         const hasher& hf = hasher(), const key_equal& eql = key_equal(),
0142         const allocator_type& a = allocator_type())
0143           : concurrent_flat_map(n, hf, eql, a)
0144       {
0145         this->insert(il.begin(), il.end());
0146       }
0147 
0148       concurrent_flat_map(size_type n, const allocator_type& a)
0149           : concurrent_flat_map(n, hasher(), key_equal(), a)
0150       {
0151       }
0152 
0153       concurrent_flat_map(
0154         size_type n, const hasher& hf, const allocator_type& a)
0155           : concurrent_flat_map(n, hf, key_equal(), a)
0156       {
0157       }
0158 
0159       template <typename InputIterator>
0160       concurrent_flat_map(
0161         InputIterator f, InputIterator l, size_type n, const allocator_type& a)
0162           : concurrent_flat_map(f, l, n, hasher(), key_equal(), a)
0163       {
0164       }
0165 
0166       template <typename InputIterator>
0167       concurrent_flat_map(InputIterator f, InputIterator l, size_type n,
0168         const hasher& hf, const allocator_type& a)
0169           : concurrent_flat_map(f, l, n, hf, key_equal(), a)
0170       {
0171       }
0172 
0173       concurrent_flat_map(
0174         std::initializer_list<value_type> il, const allocator_type& a)
0175           : concurrent_flat_map(
0176               il, detail::foa::default_bucket_count, hasher(), key_equal(), a)
0177       {
0178       }
0179 
0180       concurrent_flat_map(std::initializer_list<value_type> il, size_type n,
0181         const allocator_type& a)
0182           : concurrent_flat_map(il, n, hasher(), key_equal(), a)
0183       {
0184       }
0185 
0186       concurrent_flat_map(std::initializer_list<value_type> il, size_type n,
0187         const hasher& hf, const allocator_type& a)
0188           : concurrent_flat_map(il, n, hf, key_equal(), a)
0189       {
0190       }
0191 
0192 
0193       template <bool avoid_explicit_instantiation = true>
0194       concurrent_flat_map(
0195         unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other)
0196           : table_(std::move(other.table_))
0197       {
0198       }
0199 
0200       ~concurrent_flat_map() = default;
0201 
0202       concurrent_flat_map& operator=(concurrent_flat_map const& rhs)
0203       {
0204         table_ = rhs.table_;
0205         return *this;
0206       }
0207 
0208       concurrent_flat_map& operator=(concurrent_flat_map&& rhs) noexcept(
0209         noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
0210       {
0211         table_ = std::move(rhs.table_);
0212         return *this;
0213       }
0214 
0215       concurrent_flat_map& operator=(std::initializer_list<value_type> ilist)
0216       {
0217         table_ = ilist;
0218         return *this;
0219       }
0220 
0221       /// Capacity
0222       ///
0223 
0224       size_type size() const noexcept { return table_.size(); }
0225       size_type max_size() const noexcept { return table_.max_size(); }
0226 
0227       BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
0228       {
0229         return size() == 0;
0230       }
0231 
0232       template <class F>
0233       BOOST_FORCEINLINE size_type visit(key_type const& k, F f)
0234       {
0235         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0236         return table_.visit(k, f);
0237       }
0238 
0239       template <class F>
0240       BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const
0241       {
0242         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0243         return table_.visit(k, f);
0244       }
0245 
0246       template <class F>
0247       BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const
0248       {
0249         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0250         return table_.visit(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       visit(K&& k, F f)
0257       {
0258         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0259         return table_.visit(std::forward<K>(k), f);
0260       }
0261 
0262       template <class K, class F>
0263       BOOST_FORCEINLINE typename std::enable_if<
0264         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0265       visit(K&& k, F f) const
0266       {
0267         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0268         return table_.visit(std::forward<K>(k), f);
0269       }
0270 
0271       template <class K, class F>
0272       BOOST_FORCEINLINE typename std::enable_if<
0273         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0274       cvisit(K&& k, F f) const
0275       {
0276         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0277         return table_.visit(std::forward<K>(k), f);
0278       }
0279 
0280       template<class FwdIterator, class F>
0281       BOOST_FORCEINLINE
0282       size_t visit(FwdIterator first, FwdIterator last, F f)
0283       {
0284         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0285         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0286         return table_.visit(first, last, f);
0287       }
0288 
0289       template<class FwdIterator, class F>
0290       BOOST_FORCEINLINE
0291       size_t visit(FwdIterator first, FwdIterator last, F f) const
0292       {
0293         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0294         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0295         return table_.visit(first, last, f);
0296       }
0297 
0298       template<class FwdIterator, class F>
0299       BOOST_FORCEINLINE
0300       size_t cvisit(FwdIterator first, FwdIterator last, F f) const
0301       {
0302         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0303         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0304         return table_.visit(first, last, f);
0305       }
0306 
0307       template <class F> size_type visit_all(F f)
0308       {
0309         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0310         return table_.visit_all(f);
0311       }
0312 
0313       template <class F> size_type visit_all(F f) const
0314       {
0315         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0316         return table_.visit_all(f);
0317       }
0318 
0319       template <class F> size_type cvisit_all(F f) const
0320       {
0321         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0322         return table_.cvisit_all(f);
0323       }
0324 
0325 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0326       template <class ExecPolicy, class F>
0327       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0328         void>::type
0329       visit_all(ExecPolicy&& p, F f)
0330       {
0331         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0332         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0333         table_.visit_all(p, f);
0334       }
0335 
0336       template <class ExecPolicy, class F>
0337       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0338         void>::type
0339       visit_all(ExecPolicy&& p, F f) const
0340       {
0341         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0342         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0343         table_.visit_all(p, f);
0344       }
0345 
0346       template <class ExecPolicy, class F>
0347       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0348         void>::type
0349       cvisit_all(ExecPolicy&& p, F f) const
0350       {
0351         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0352         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0353         table_.cvisit_all(p, f);
0354       }
0355 #endif
0356 
0357       template <class F> bool visit_while(F f)
0358       {
0359         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0360         return table_.visit_while(f);
0361       }
0362 
0363       template <class F> bool visit_while(F f) const
0364       {
0365         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0366         return table_.visit_while(f);
0367       }
0368 
0369       template <class F> bool cvisit_while(F f) const
0370       {
0371         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0372         return table_.cvisit_while(f);
0373       }
0374 
0375 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0376       template <class ExecPolicy, class F>
0377       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0378         bool>::type
0379       visit_while(ExecPolicy&& p, F f)
0380       {
0381         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0382         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0383         return table_.visit_while(p, f);
0384       }
0385 
0386       template <class ExecPolicy, class F>
0387       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0388         bool>::type
0389       visit_while(ExecPolicy&& p, F f) const
0390       {
0391         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0392         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0393         return table_.visit_while(p, f);
0394       }
0395 
0396       template <class ExecPolicy, class F>
0397       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0398         bool>::type
0399       cvisit_while(ExecPolicy&& p, F f) const
0400       {
0401         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0402         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0403         return table_.cvisit_while(p, f);
0404       }
0405 #endif
0406 
0407       /// Modifiers
0408       ///
0409 
0410       template <class Ty>
0411       BOOST_FORCEINLINE auto insert(Ty&& value)
0412         -> decltype(table_.insert(std::forward<Ty>(value)))
0413       {
0414         return table_.insert(std::forward<Ty>(value));
0415       }
0416 
0417       BOOST_FORCEINLINE bool insert(init_type&& obj)
0418       {
0419         return table_.insert(std::move(obj));
0420       }
0421 
0422       template <class InputIterator>
0423       size_type insert(InputIterator begin, InputIterator end)
0424       {
0425         size_type count_elements = 0;
0426         for (auto pos = begin; pos != end; ++pos, ++count_elements) {
0427           table_.emplace(*pos);
0428         }
0429         return count_elements;
0430       }
0431 
0432       size_type insert(std::initializer_list<value_type> ilist)
0433       {
0434         return this->insert(ilist.begin(), ilist.end());
0435       }
0436 
0437       template <class M>
0438       BOOST_FORCEINLINE bool insert_or_assign(key_type const& k, M&& obj)
0439       {
0440         return table_.try_emplace_or_visit(k, std::forward<M>(obj),
0441           [&](value_type& m) { m.second = std::forward<M>(obj); });
0442       }
0443 
0444       template <class M>
0445       BOOST_FORCEINLINE bool insert_or_assign(key_type&& k, M&& obj)
0446       {
0447         return table_.try_emplace_or_visit(std::move(k), std::forward<M>(obj),
0448           [&](value_type& m) { m.second = std::forward<M>(obj); });
0449       }
0450 
0451       template <class K, class M>
0452       BOOST_FORCEINLINE typename std::enable_if<
0453         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0454       insert_or_assign(K&& k, M&& obj)
0455       {
0456         return table_.try_emplace_or_visit(std::forward<K>(k),
0457           std::forward<M>(obj),
0458           [&](value_type& m) { m.second = std::forward<M>(obj); });
0459       }
0460 
0461       template <class Ty, class F>
0462       BOOST_FORCEINLINE auto insert_or_visit(Ty&& value, F f)
0463         -> decltype(table_.insert_or_visit(std::forward<Ty>(value), f))
0464       {
0465         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0466         return table_.insert_or_visit(std::forward<Ty>(value), f);
0467       }
0468 
0469       template <class F>
0470       BOOST_FORCEINLINE bool insert_or_visit(init_type&& obj, F f)
0471       {
0472         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0473         return table_.insert_or_visit(std::move(obj), f);
0474       }
0475 
0476       template <class InputIterator, class F>
0477       size_type insert_or_visit(InputIterator first, InputIterator last, F f)
0478       {
0479         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0480         size_type count_elements = 0;
0481         for (; first != last; ++first, ++count_elements) {
0482           table_.emplace_or_visit(*first, f);
0483         }
0484         return count_elements;
0485       }
0486 
0487       template <class F>
0488       size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
0489       {
0490         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0491         return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f));
0492       }
0493 
0494       template <class Ty, class F>
0495       BOOST_FORCEINLINE auto insert_or_cvisit(Ty&& value, F f)
0496         -> decltype(table_.insert_or_cvisit(std::forward<Ty>(value), f))
0497       {
0498         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0499         return table_.insert_or_cvisit(std::forward<Ty>(value), f);
0500       }
0501 
0502       template <class F>
0503       BOOST_FORCEINLINE bool insert_or_cvisit(init_type&& obj, F f)
0504       {
0505         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0506         return table_.insert_or_cvisit(std::move(obj), 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 Ty, class F1, class F2>
0528       BOOST_FORCEINLINE auto insert_and_visit(Ty&& value, F1 f1, F2 f2)
0529         -> decltype(table_.insert_and_visit(std::forward<Ty>(value), f1, f2))
0530       {
0531         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
0532         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
0533         return table_.insert_and_visit(std::forward<Ty>(value), f1, f2);
0534       }
0535 
0536       template <class F1, class F2>
0537       BOOST_FORCEINLINE bool insert_and_visit(init_type&& obj, F1 f1, F2 f2)
0538       {
0539         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
0540         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
0541         return table_.insert_and_visit(std::move(obj), f1, f2);
0542       }
0543 
0544       template <class InputIterator, class F1, class F2>
0545       size_type insert_and_visit(
0546         InputIterator first, InputIterator last, F1 f1, F2 f2)
0547       {
0548         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
0549         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
0550         size_type count_elements = 0;
0551         for (; first != last; ++first, ++count_elements) {
0552           table_.emplace_and_visit(*first, f1, f2);
0553         }
0554         return count_elements;
0555       }
0556 
0557       template <class F1, class F2>
0558       size_type insert_and_visit(
0559         std::initializer_list<value_type> ilist, F1 f1, F2 f2)
0560       {
0561         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
0562         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
0563         return this->insert_and_visit(
0564           ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
0565       }
0566 
0567       template <class Ty, class F1, class F2>
0568       BOOST_FORCEINLINE auto insert_and_cvisit(Ty&& value, F1 f1, F2 f2)
0569         -> decltype(table_.insert_and_cvisit(std::forward<Ty>(value), f1, f2))
0570       {
0571         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
0572         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0573         return table_.insert_and_cvisit(std::forward<Ty>(value), f1, f2);
0574       }
0575 
0576       template <class F1, class F2>
0577       BOOST_FORCEINLINE bool insert_and_cvisit(init_type&& obj, F1 f1, F2 f2)
0578       {
0579         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
0580         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0581         return table_.insert_and_cvisit(std::move(obj), f1, f2);
0582       }
0583 
0584       template <class InputIterator, class F1, class F2>
0585       size_type insert_and_cvisit(
0586         InputIterator first, InputIterator last, F1 f1, F2 f2)
0587       {
0588         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
0589         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0590         size_type count_elements = 0;
0591         for (; first != last; ++first, ++count_elements) {
0592           table_.emplace_and_cvisit(*first, f1, f2);
0593         }
0594         return count_elements;
0595       }
0596 
0597       template <class F1, class F2>
0598       size_type insert_and_cvisit(
0599         std::initializer_list<value_type> ilist, F1 f1, F2 f2)
0600       {
0601         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
0602         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
0603         return this->insert_and_cvisit(
0604           ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
0605       }
0606 
0607       template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
0608       {
0609         return table_.emplace(std::forward<Args>(args)...);
0610       }
0611 
0612       template <class Arg, class... Args>
0613       BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
0614       {
0615         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0616         return table_.emplace_or_visit(
0617           std::forward<Arg>(arg), std::forward<Args>(args)...);
0618       }
0619 
0620       template <class Arg, class... Args>
0621       BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
0622       {
0623         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0624         return table_.emplace_or_cvisit(
0625           std::forward<Arg>(arg), std::forward<Args>(args)...);
0626       }
0627 
0628       template <class Arg1, class Arg2, class... Args>
0629       BOOST_FORCEINLINE bool emplace_and_visit(
0630          Arg1&& arg1, Arg2&& arg2, Args&&... args)
0631       {
0632         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
0633           Arg1, Arg2, Args...)
0634         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
0635         return table_.emplace_and_visit(
0636           std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0637           std::forward<Args>(args)...);
0638       }
0639 
0640       template <class Arg1, class Arg2, class... Args>
0641       BOOST_FORCEINLINE bool emplace_and_cvisit(
0642         Arg1&& arg1, Arg2&& arg2, Args&&... args)
0643       {
0644         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
0645           Arg1, Arg2, Args...)
0646         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
0647         return table_.emplace_and_cvisit(
0648           std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0649           std::forward<Args>(args)...);
0650       }
0651 
0652       template <class... Args>
0653       BOOST_FORCEINLINE bool try_emplace(key_type const& k, Args&&... args)
0654       {
0655         return table_.try_emplace(k, std::forward<Args>(args)...);
0656       }
0657 
0658       template <class... Args>
0659       BOOST_FORCEINLINE bool try_emplace(key_type&& k, Args&&... args)
0660       {
0661         return table_.try_emplace(std::move(k), std::forward<Args>(args)...);
0662       }
0663 
0664       template <class K, class... Args>
0665       BOOST_FORCEINLINE typename std::enable_if<
0666         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0667       try_emplace(K&& k, Args&&... args)
0668       {
0669         return table_.try_emplace(
0670           std::forward<K>(k), std::forward<Args>(args)...);
0671       }
0672 
0673       template <class Arg, class... Args>
0674       BOOST_FORCEINLINE bool try_emplace_or_visit(
0675         key_type const& k, Arg&& arg, Args&&... args)
0676       {
0677         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0678         return table_.try_emplace_or_visit(
0679           k, std::forward<Arg>(arg), std::forward<Args>(args)...);
0680       }
0681 
0682       template <class Arg, class... Args>
0683       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0684         key_type const& k, Arg&& arg, Args&&... args)
0685       {
0686         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0687         return table_.try_emplace_or_cvisit(
0688           k, std::forward<Arg>(arg), std::forward<Args>(args)...);
0689       }
0690 
0691       template <class Arg, class... Args>
0692       BOOST_FORCEINLINE bool try_emplace_or_visit(
0693         key_type&& k, Arg&& arg, Args&&... args)
0694       {
0695         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0696         return table_.try_emplace_or_visit(
0697           std::move(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
0698       }
0699 
0700       template <class Arg, class... Args>
0701       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0702         key_type&& k, Arg&& arg, Args&&... args)
0703       {
0704         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0705         return table_.try_emplace_or_cvisit(
0706           std::move(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
0707       }
0708 
0709       template <class K, class Arg, class... Args>
0710       BOOST_FORCEINLINE bool try_emplace_or_visit(
0711         K&& k, Arg&& arg, Args&&... args)
0712       {
0713         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0714         return table_.try_emplace_or_visit(std::forward<K>(k),
0715           std::forward<Arg>(arg), std::forward<Args>(args)...);
0716       }
0717 
0718       template <class K, class Arg, class... Args>
0719       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0720         K&& k, Arg&& arg, Args&&... args)
0721       {
0722         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0723         return table_.try_emplace_or_cvisit(std::forward<K>(k),
0724           std::forward<Arg>(arg), std::forward<Args>(args)...);
0725       }
0726 
0727       template <class Arg1, class Arg2, class... Args>
0728       BOOST_FORCEINLINE bool try_emplace_and_visit(
0729         key_type const& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
0730       {
0731         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
0732           Arg1, Arg2, Args...)
0733         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
0734         return table_.try_emplace_and_visit(
0735           k, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0736           std::forward<Args>(args)...);
0737       }
0738 
0739       template <class Arg1, class Arg2, class... Args>
0740       BOOST_FORCEINLINE bool try_emplace_and_cvisit(
0741         key_type const& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
0742       {
0743         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
0744           Arg1, Arg2, Args...)
0745         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
0746         return table_.try_emplace_and_cvisit(
0747           k, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0748           std::forward<Args>(args)...);
0749       }
0750 
0751       template <class Arg1, class Arg2, class... Args>
0752       BOOST_FORCEINLINE bool try_emplace_and_visit(
0753         key_type&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
0754       {
0755         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
0756           Arg1, Arg2, Args...)
0757         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
0758         return table_.try_emplace_and_visit(
0759           std::move(k), std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0760           std::forward<Args>(args)...);
0761       }
0762 
0763       template <class Arg1, class Arg2, class... Args>
0764       BOOST_FORCEINLINE bool try_emplace_and_cvisit(
0765         key_type&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
0766       {
0767         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
0768           Arg1, Arg2, Args...)
0769         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
0770         return table_.try_emplace_and_cvisit(
0771           std::move(k), std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0772           std::forward<Args>(args)...);
0773       }
0774 
0775       template <class K, class Arg1, class Arg2, class... Args>
0776       BOOST_FORCEINLINE bool try_emplace_and_visit(
0777         K&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
0778       {
0779         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
0780           Arg1, Arg2, Args...)
0781         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
0782         return table_.try_emplace_and_visit(std::forward<K>(k),
0783           std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0784           std::forward<Args>(args)...);
0785       }
0786 
0787       template <class K, class Arg1, class Arg2, class... Args>
0788       BOOST_FORCEINLINE bool try_emplace_and_cvisit(
0789         K&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
0790       {
0791         BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
0792           Arg1, Arg2, Args...)
0793         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
0794         return table_.try_emplace_and_cvisit(std::forward<K>(k),
0795           std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
0796           std::forward<Args>(args)...);
0797       }
0798 
0799       BOOST_FORCEINLINE size_type erase(key_type const& k)
0800       {
0801         return table_.erase(k);
0802       }
0803 
0804       template <class K>
0805       BOOST_FORCEINLINE typename std::enable_if<
0806         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0807       erase(K&& k)
0808       {
0809         return table_.erase(std::forward<K>(k));
0810       }
0811 
0812       template <class F>
0813       BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
0814       {
0815         return table_.erase_if(k, f);
0816       }
0817 
0818       template <class K, class F>
0819       BOOST_FORCEINLINE typename std::enable_if<
0820         detail::are_transparent<K, hasher, key_equal>::value &&
0821           !detail::is_execution_policy<K>::value,
0822         size_type>::type
0823       erase_if(K&& k, F f)
0824       {
0825         return table_.erase_if(std::forward<K>(k), f);
0826       }
0827 
0828 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0829       template <class ExecPolicy, class F>
0830       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0831         void>::type
0832       erase_if(ExecPolicy&& p, F f)
0833       {
0834         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0835         table_.erase_if(p, f);
0836       }
0837 #endif
0838 
0839       template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
0840 
0841       void swap(concurrent_flat_map& other) noexcept(
0842         boost::allocator_is_always_equal<Allocator>::type::value ||
0843         boost::allocator_propagate_on_container_swap<Allocator>::type::value)
0844       {
0845         return table_.swap(other.table_);
0846       }
0847 
0848       void clear() noexcept { table_.clear(); }
0849 
0850       template <typename H2, typename P2>
0851       size_type merge(concurrent_flat_map<Key, T, H2, P2, Allocator>& x)
0852       {
0853         BOOST_ASSERT(get_allocator() == x.get_allocator());
0854         return table_.merge(x.table_);
0855       }
0856 
0857       template <typename H2, typename P2>
0858       size_type merge(concurrent_flat_map<Key, T, H2, P2, Allocator>&& x)
0859       {
0860         return merge(x);
0861       }
0862 
0863       BOOST_FORCEINLINE size_type count(key_type const& k) const
0864       {
0865         return table_.count(k);
0866       }
0867 
0868       template <class K>
0869       BOOST_FORCEINLINE typename std::enable_if<
0870         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0871       count(K const& k)
0872       {
0873         return table_.count(k);
0874       }
0875 
0876       BOOST_FORCEINLINE bool contains(key_type const& k) const
0877       {
0878         return table_.contains(k);
0879       }
0880 
0881       template <class K>
0882       BOOST_FORCEINLINE typename std::enable_if<
0883         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0884       contains(K const& k) const
0885       {
0886         return table_.contains(k);
0887       }
0888 
0889       /// Hash Policy
0890       ///
0891       size_type bucket_count() const noexcept { return table_.capacity(); }
0892 
0893       float load_factor() const noexcept { return table_.load_factor(); }
0894       float max_load_factor() const noexcept
0895       {
0896         return table_.max_load_factor();
0897       }
0898       void max_load_factor(float) {}
0899       size_type max_load() const noexcept { return table_.max_load(); }
0900 
0901       void rehash(size_type n) { table_.rehash(n); }
0902       void reserve(size_type n) { table_.reserve(n); }
0903 
0904 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0905       /// Stats
0906       ///
0907       stats get_stats() const { return table_.get_stats(); }
0908 
0909       void reset_stats() noexcept { table_.reset_stats(); }
0910 #endif
0911 
0912       /// Observers
0913       ///
0914       allocator_type get_allocator() const noexcept
0915       {
0916         return table_.get_allocator();
0917       }
0918 
0919       hasher hash_function() const { return table_.hash_function(); }
0920       key_equal key_eq() const { return table_.key_eq(); }
0921     };
0922 
0923     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0924     bool operator==(
0925       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
0926       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
0927     {
0928       return lhs.table_ == rhs.table_;
0929     }
0930 
0931     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0932     bool operator!=(
0933       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
0934       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
0935     {
0936       return !(lhs == rhs);
0937     }
0938 
0939     template <class Key, class T, class Hash, class Pred, class Alloc>
0940     void swap(concurrent_flat_map<Key, T, Hash, Pred, Alloc>& x,
0941       concurrent_flat_map<Key, T, Hash, Pred, Alloc>& y)
0942       noexcept(noexcept(x.swap(y)))
0943     {
0944       x.swap(y);
0945     }
0946 
0947     template <class K, class T, class H, class P, class A, class Predicate>
0948     typename concurrent_flat_map<K, T, H, P, A>::size_type erase_if(
0949       concurrent_flat_map<K, T, H, P, A>& c, Predicate pred)
0950     {
0951       return c.table_.erase_if(pred);
0952     }
0953 
0954     template<class Archive, class K, class V, class H, class KE, class A>
0955     void serialize(
0956       Archive& ar, concurrent_flat_map<K, V, H, KE, A>& c, unsigned int)
0957     {
0958       ar & core::make_nvp("table",c.table_);
0959     }
0960 
0961 #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
0962 
0963     template <class InputIterator,
0964       class Hash =
0965         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0966       class Pred =
0967         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0968       class Allocator = std::allocator<
0969         boost::unordered::detail::iter_to_alloc_t<InputIterator> >,
0970       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0971       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0972       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0973       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0974     concurrent_flat_map(InputIterator, InputIterator,
0975       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0976       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0977       -> concurrent_flat_map<
0978         boost::unordered::detail::iter_key_t<InputIterator>,
0979         boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
0980         Allocator>;
0981 
0982     template <class Key, class T,
0983       class Hash = boost::hash<std::remove_const_t<Key> >,
0984       class Pred = std::equal_to<std::remove_const_t<Key> >,
0985       class Allocator = std::allocator<std::pair<const Key, T> >,
0986       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0987       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0988       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0989     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >,
0990       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0991       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0992       -> concurrent_flat_map<std::remove_const_t<Key>, T, Hash, Pred,
0993         Allocator>;
0994 
0995     template <class InputIterator, class Allocator,
0996       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0997       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0998     concurrent_flat_map(InputIterator, InputIterator, std::size_t, Allocator)
0999       -> concurrent_flat_map<
1000         boost::unordered::detail::iter_key_t<InputIterator>,
1001         boost::unordered::detail::iter_val_t<InputIterator>,
1002         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
1003         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
1004         Allocator>;
1005 
1006     template <class InputIterator, class Allocator,
1007       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
1008       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
1009     concurrent_flat_map(InputIterator, InputIterator, Allocator)
1010       -> concurrent_flat_map<
1011         boost::unordered::detail::iter_key_t<InputIterator>,
1012         boost::unordered::detail::iter_val_t<InputIterator>,
1013         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
1014         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
1015         Allocator>;
1016 
1017     template <class InputIterator, class Hash, class Allocator,
1018       class = std::enable_if_t<detail::is_hash_v<Hash> >,
1019       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
1020       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
1021     concurrent_flat_map(
1022       InputIterator, InputIterator, std::size_t, Hash, Allocator)
1023       -> concurrent_flat_map<
1024         boost::unordered::detail::iter_key_t<InputIterator>,
1025         boost::unordered::detail::iter_val_t<InputIterator>, Hash,
1026         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
1027         Allocator>;
1028 
1029     template <class Key, class T, class Allocator,
1030       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
1031     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
1032       Allocator) -> concurrent_flat_map<std::remove_const_t<Key>, T,
1033       boost::hash<std::remove_const_t<Key> >,
1034       std::equal_to<std::remove_const_t<Key> >, Allocator>;
1035 
1036     template <class Key, class T, class Allocator,
1037       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
1038     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, Allocator)
1039       -> concurrent_flat_map<std::remove_const_t<Key>, T,
1040         boost::hash<std::remove_const_t<Key> >,
1041         std::equal_to<std::remove_const_t<Key> >, Allocator>;
1042 
1043     template <class Key, class T, class Hash, class Allocator,
1044       class = std::enable_if_t<detail::is_hash_v<Hash> >,
1045       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
1046     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
1047       Hash, Allocator) -> concurrent_flat_map<std::remove_const_t<Key>, T,
1048       Hash, std::equal_to<std::remove_const_t<Key> >, Allocator>;
1049 
1050 #endif
1051 
1052   } // namespace unordered
1053 } // namespace boost
1054 
1055 #endif // BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP