Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 08:32:10

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       concurrent_flat_map(
0194         unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other)
0195           : table_(std::move(other.table_))
0196       {
0197       }
0198 
0199       ~concurrent_flat_map() = default;
0200 
0201       concurrent_flat_map& operator=(concurrent_flat_map const& rhs)
0202       {
0203         table_ = rhs.table_;
0204         return *this;
0205       }
0206 
0207       concurrent_flat_map& operator=(concurrent_flat_map&& rhs) noexcept(
0208         noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
0209       {
0210         table_ = std::move(rhs.table_);
0211         return *this;
0212       }
0213 
0214       concurrent_flat_map& 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_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_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_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_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_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_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_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       template <class Ty>
0410       BOOST_FORCEINLINE auto insert(Ty&& value)
0411         -> decltype(table_.insert(std::forward<Ty>(value)))
0412       {
0413         return table_.insert(std::forward<Ty>(value));
0414       }
0415 
0416       BOOST_FORCEINLINE bool insert(init_type&& obj)
0417       {
0418         return table_.insert(std::move(obj));
0419       }
0420 
0421       template <class InputIterator>
0422       void insert(InputIterator begin, InputIterator end)
0423       {
0424         for (auto pos = begin; pos != end; ++pos) {
0425           table_.emplace(*pos);
0426         }
0427       }
0428 
0429       void insert(std::initializer_list<value_type> ilist)
0430       {
0431         this->insert(ilist.begin(), ilist.end());
0432       }
0433 
0434       template <class M>
0435       BOOST_FORCEINLINE bool insert_or_assign(key_type const& k, M&& obj)
0436       {
0437         return table_.try_emplace_or_visit(k, std::forward<M>(obj),
0438           [&](value_type& m) { m.second = std::forward<M>(obj); });
0439       }
0440 
0441       template <class M>
0442       BOOST_FORCEINLINE bool insert_or_assign(key_type&& k, M&& obj)
0443       {
0444         return table_.try_emplace_or_visit(std::move(k), std::forward<M>(obj),
0445           [&](value_type& m) { m.second = std::forward<M>(obj); });
0446       }
0447 
0448       template <class K, class M>
0449       BOOST_FORCEINLINE typename std::enable_if<
0450         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0451       insert_or_assign(K&& k, M&& obj)
0452       {
0453         return table_.try_emplace_or_visit(std::forward<K>(k),
0454           std::forward<M>(obj),
0455           [&](value_type& m) { m.second = std::forward<M>(obj); });
0456       }
0457 
0458       template <class Ty, class F>
0459       BOOST_FORCEINLINE auto insert_or_visit(Ty&& value, F f)
0460         -> decltype(table_.insert_or_visit(std::forward<Ty>(value), f))
0461       {
0462         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0463         return table_.insert_or_visit(std::forward<Ty>(value), f);
0464       }
0465 
0466       template <class F>
0467       BOOST_FORCEINLINE bool insert_or_visit(init_type&& obj, F f)
0468       {
0469         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0470         return table_.insert_or_visit(std::move(obj), f);
0471       }
0472 
0473       template <class InputIterator, class F>
0474       void insert_or_visit(InputIterator first, InputIterator last, F f)
0475       {
0476         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0477         for (; first != last; ++first) {
0478           table_.emplace_or_visit(*first, f);
0479         }
0480       }
0481 
0482       template <class F>
0483       void insert_or_visit(std::initializer_list<value_type> ilist, F f)
0484       {
0485         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0486         this->insert_or_visit(ilist.begin(), ilist.end(), f);
0487       }
0488 
0489       template <class Ty, class F>
0490       BOOST_FORCEINLINE auto insert_or_cvisit(Ty&& value, F f)
0491         -> decltype(table_.insert_or_cvisit(std::forward<Ty>(value), f))
0492       {
0493         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0494         return table_.insert_or_cvisit(std::forward<Ty>(value), f);
0495       }
0496 
0497       template <class F>
0498       BOOST_FORCEINLINE bool insert_or_cvisit(init_type&& obj, F f)
0499       {
0500         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0501         return table_.insert_or_cvisit(std::move(obj), f);
0502       }
0503 
0504       template <class InputIterator, class F>
0505       void insert_or_cvisit(InputIterator first, InputIterator last, F f)
0506       {
0507         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0508         for (; first != last; ++first) {
0509           table_.emplace_or_cvisit(*first, f);
0510         }
0511       }
0512 
0513       template <class F>
0514       void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
0515       {
0516         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0517         this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
0518       }
0519 
0520       template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
0521       {
0522         return table_.emplace(std::forward<Args>(args)...);
0523       }
0524 
0525       template <class Arg, class... Args>
0526       BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
0527       {
0528         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0529         return table_.emplace_or_visit(
0530           std::forward<Arg>(arg), std::forward<Args>(args)...);
0531       }
0532 
0533       template <class Arg, class... Args>
0534       BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
0535       {
0536         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0537         return table_.emplace_or_cvisit(
0538           std::forward<Arg>(arg), std::forward<Args>(args)...);
0539       }
0540 
0541       template <class... Args>
0542       BOOST_FORCEINLINE bool try_emplace(key_type const& k, Args&&... args)
0543       {
0544         return table_.try_emplace(k, std::forward<Args>(args)...);
0545       }
0546 
0547       template <class... Args>
0548       BOOST_FORCEINLINE bool try_emplace(key_type&& k, Args&&... args)
0549       {
0550         return table_.try_emplace(std::move(k), std::forward<Args>(args)...);
0551       }
0552 
0553       template <class K, class... Args>
0554       BOOST_FORCEINLINE typename std::enable_if<
0555         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0556       try_emplace(K&& k, Args&&... args)
0557       {
0558         return table_.try_emplace(
0559           std::forward<K>(k), std::forward<Args>(args)...);
0560       }
0561 
0562       template <class Arg, class... Args>
0563       BOOST_FORCEINLINE bool try_emplace_or_visit(
0564         key_type const& k, Arg&& arg, Args&&... args)
0565       {
0566         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0567         return table_.try_emplace_or_visit(
0568           k, std::forward<Arg>(arg), std::forward<Args>(args)...);
0569       }
0570 
0571       template <class Arg, class... Args>
0572       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0573         key_type const& k, Arg&& arg, Args&&... args)
0574       {
0575         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0576         return table_.try_emplace_or_cvisit(
0577           k, std::forward<Arg>(arg), std::forward<Args>(args)...);
0578       }
0579 
0580       template <class Arg, class... Args>
0581       BOOST_FORCEINLINE bool try_emplace_or_visit(
0582         key_type&& k, Arg&& arg, Args&&... args)
0583       {
0584         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0585         return table_.try_emplace_or_visit(
0586           std::move(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
0587       }
0588 
0589       template <class Arg, class... Args>
0590       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0591         key_type&& k, Arg&& arg, Args&&... args)
0592       {
0593         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0594         return table_.try_emplace_or_cvisit(
0595           std::move(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
0596       }
0597 
0598       template <class K, class Arg, class... Args>
0599       BOOST_FORCEINLINE bool try_emplace_or_visit(
0600         K&& k, Arg&& arg, Args&&... args)
0601       {
0602         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0603         return table_.try_emplace_or_visit(std::forward<K>(k),
0604           std::forward<Arg>(arg), std::forward<Args>(args)...);
0605       }
0606 
0607       template <class K, class Arg, class... Args>
0608       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0609         K&& k, Arg&& arg, Args&&... args)
0610       {
0611         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0612         return table_.try_emplace_or_cvisit(std::forward<K>(k),
0613           std::forward<Arg>(arg), std::forward<Args>(args)...);
0614       }
0615 
0616       BOOST_FORCEINLINE size_type erase(key_type const& k)
0617       {
0618         return table_.erase(k);
0619       }
0620 
0621       template <class K>
0622       BOOST_FORCEINLINE typename std::enable_if<
0623         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0624       erase(K&& k)
0625       {
0626         return table_.erase(std::forward<K>(k));
0627       }
0628 
0629       template <class F>
0630       BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
0631       {
0632         return table_.erase_if(k, f);
0633       }
0634 
0635       template <class K, class F>
0636       BOOST_FORCEINLINE typename std::enable_if<
0637         detail::are_transparent<K, hasher, key_equal>::value &&
0638           !detail::is_execution_policy<K>::value,
0639         size_type>::type
0640       erase_if(K&& k, F f)
0641       {
0642         return table_.erase_if(std::forward<K>(k), f);
0643       }
0644 
0645 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0646       template <class ExecPolicy, class F>
0647       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0648         void>::type
0649       erase_if(ExecPolicy&& p, F f)
0650       {
0651         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0652         table_.erase_if(p, f);
0653       }
0654 #endif
0655 
0656       template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
0657 
0658       void swap(concurrent_flat_map& other) noexcept(
0659         boost::allocator_is_always_equal<Allocator>::type::value ||
0660         boost::allocator_propagate_on_container_swap<Allocator>::type::value)
0661       {
0662         return table_.swap(other.table_);
0663       }
0664 
0665       void clear() noexcept { table_.clear(); }
0666 
0667       template <typename H2, typename P2>
0668       size_type merge(concurrent_flat_map<Key, T, H2, P2, Allocator>& x)
0669       {
0670         BOOST_ASSERT(get_allocator() == x.get_allocator());
0671         return table_.merge(x.table_);
0672       }
0673 
0674       template <typename H2, typename P2>
0675       size_type merge(concurrent_flat_map<Key, T, H2, P2, Allocator>&& x)
0676       {
0677         return merge(x);
0678       }
0679 
0680       BOOST_FORCEINLINE size_type count(key_type const& k) const
0681       {
0682         return table_.count(k);
0683       }
0684 
0685       template <class K>
0686       BOOST_FORCEINLINE typename std::enable_if<
0687         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0688       count(K const& k)
0689       {
0690         return table_.count(k);
0691       }
0692 
0693       BOOST_FORCEINLINE bool contains(key_type const& k) const
0694       {
0695         return table_.contains(k);
0696       }
0697 
0698       template <class K>
0699       BOOST_FORCEINLINE typename std::enable_if<
0700         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0701       contains(K const& k) const
0702       {
0703         return table_.contains(k);
0704       }
0705 
0706       /// Hash Policy
0707       ///
0708       size_type bucket_count() const noexcept { return table_.capacity(); }
0709 
0710       float load_factor() const noexcept { return table_.load_factor(); }
0711       float max_load_factor() const noexcept
0712       {
0713         return table_.max_load_factor();
0714       }
0715       void max_load_factor(float) {}
0716       size_type max_load() const noexcept { return table_.max_load(); }
0717 
0718       void rehash(size_type n) { table_.rehash(n); }
0719       void reserve(size_type n) { table_.reserve(n); }
0720 
0721 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0722       /// Stats
0723       ///
0724       stats get_stats() const { return table_.get_stats(); }
0725 
0726       void reset_stats() noexcept { table_.reset_stats(); }
0727 #endif
0728 
0729       /// Observers
0730       ///
0731       allocator_type get_allocator() const noexcept
0732       {
0733         return table_.get_allocator();
0734       }
0735 
0736       hasher hash_function() const { return table_.hash_function(); }
0737       key_equal key_eq() const { return table_.key_eq(); }
0738     };
0739 
0740     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0741     bool operator==(
0742       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
0743       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
0744     {
0745       return lhs.table_ == rhs.table_;
0746     }
0747 
0748     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0749     bool operator!=(
0750       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
0751       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
0752     {
0753       return !(lhs == rhs);
0754     }
0755 
0756     template <class Key, class T, class Hash, class Pred, class Alloc>
0757     void swap(concurrent_flat_map<Key, T, Hash, Pred, Alloc>& x,
0758       concurrent_flat_map<Key, T, Hash, Pred, Alloc>& y)
0759       noexcept(noexcept(x.swap(y)))
0760     {
0761       x.swap(y);
0762     }
0763 
0764     template <class K, class T, class H, class P, class A, class Predicate>
0765     typename concurrent_flat_map<K, T, H, P, A>::size_type erase_if(
0766       concurrent_flat_map<K, T, H, P, A>& c, Predicate pred)
0767     {
0768       return c.table_.erase_if(pred);
0769     }
0770 
0771     template<class Archive, class K, class V, class H, class KE, class A>
0772     void serialize(
0773       Archive& ar, concurrent_flat_map<K, V, H, KE, A>& c, unsigned int)
0774     {
0775       ar & core::make_nvp("table",c.table_);
0776     }
0777 
0778 #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
0779 
0780     template <class InputIterator,
0781       class Hash =
0782         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0783       class Pred =
0784         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0785       class Allocator = std::allocator<
0786         boost::unordered::detail::iter_to_alloc_t<InputIterator> >,
0787       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0788       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0789       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0790       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0791     concurrent_flat_map(InputIterator, InputIterator,
0792       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0793       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0794       -> concurrent_flat_map<
0795         boost::unordered::detail::iter_key_t<InputIterator>,
0796         boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
0797         Allocator>;
0798 
0799     template <class Key, class T,
0800       class Hash = boost::hash<std::remove_const_t<Key> >,
0801       class Pred = std::equal_to<std::remove_const_t<Key> >,
0802       class Allocator = std::allocator<std::pair<const Key, T> >,
0803       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0804       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0805       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0806     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >,
0807       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0808       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0809       -> concurrent_flat_map<std::remove_const_t<Key>, T, Hash, Pred,
0810         Allocator>;
0811 
0812     template <class InputIterator, class Allocator,
0813       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0814       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0815     concurrent_flat_map(InputIterator, InputIterator, std::size_t, Allocator)
0816       -> concurrent_flat_map<
0817         boost::unordered::detail::iter_key_t<InputIterator>,
0818         boost::unordered::detail::iter_val_t<InputIterator>,
0819         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0820         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0821         Allocator>;
0822 
0823     template <class InputIterator, class Allocator,
0824       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0825       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0826     concurrent_flat_map(InputIterator, InputIterator, Allocator)
0827       -> concurrent_flat_map<
0828         boost::unordered::detail::iter_key_t<InputIterator>,
0829         boost::unordered::detail::iter_val_t<InputIterator>,
0830         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0831         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0832         Allocator>;
0833 
0834     template <class InputIterator, class Hash, class Allocator,
0835       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0836       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0837       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0838     concurrent_flat_map(
0839       InputIterator, InputIterator, std::size_t, Hash, Allocator)
0840       -> concurrent_flat_map<
0841         boost::unordered::detail::iter_key_t<InputIterator>,
0842         boost::unordered::detail::iter_val_t<InputIterator>, Hash,
0843         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0844         Allocator>;
0845 
0846     template <class Key, class T, class Allocator,
0847       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0848     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
0849       Allocator) -> concurrent_flat_map<std::remove_const_t<Key>, T,
0850       boost::hash<std::remove_const_t<Key> >,
0851       std::equal_to<std::remove_const_t<Key> >, Allocator>;
0852 
0853     template <class Key, class T, class Allocator,
0854       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0855     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, Allocator)
0856       -> concurrent_flat_map<std::remove_const_t<Key>, T,
0857         boost::hash<std::remove_const_t<Key> >,
0858         std::equal_to<std::remove_const_t<Key> >, Allocator>;
0859 
0860     template <class Key, class T, class Hash, class Allocator,
0861       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0862       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0863     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
0864       Hash, Allocator) -> concurrent_flat_map<std::remove_const_t<Key>, T,
0865       Hash, std::equal_to<std::remove_const_t<Key> >, Allocator>;
0866 
0867 #endif
0868 
0869   } // namespace unordered
0870 } // namespace boost
0871 
0872 #endif // BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP