Back to home page

EIC code displayed by LXR

 
 

    


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

0001 /* Fast open-addressing concurrent hashmap.
0002  *
0003  * Copyright 2023 Christian Mazakas.
0004  * Copyright 2023 Joaquin M Lopez Munoz.
0005  * Distributed under the Boost Software License, Version 1.0.
0006  * (See accompanying file LICENSE_1_0.txt or copy at
0007  * http://www.boost.org/LICENSE_1_0.txt)
0008  *
0009  * See https://www.boost.org/libs/unordered for library home page.
0010  */
0011 
0012 #ifndef BOOST_UNORDERED_CONCURRENT_FLAT_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       concurrent_flat_map()
0079           : concurrent_flat_map(detail::foa::default_bucket_count)
0080       {
0081       }
0082 
0083       explicit concurrent_flat_map(size_type n, const hasher& hf = hasher(),
0084         const key_equal& eql = key_equal(),
0085         const allocator_type& a = allocator_type())
0086           : table_(n, hf, eql, a)
0087       {
0088       }
0089 
0090       template <class InputIterator>
0091       concurrent_flat_map(InputIterator f, InputIterator l,
0092         size_type n = detail::foa::default_bucket_count,
0093         const hasher& hf = hasher(), const key_equal& eql = key_equal(),
0094         const allocator_type& a = allocator_type())
0095           : table_(n, hf, eql, a)
0096       {
0097         this->insert(f, l);
0098       }
0099 
0100       concurrent_flat_map(concurrent_flat_map const& rhs)
0101           : table_(rhs.table_,
0102               boost::allocator_select_on_container_copy_construction(
0103                 rhs.get_allocator()))
0104       {
0105       }
0106 
0107       concurrent_flat_map(concurrent_flat_map&& rhs)
0108           : table_(std::move(rhs.table_))
0109       {
0110       }
0111 
0112       template <class InputIterator>
0113       concurrent_flat_map(
0114         InputIterator f, InputIterator l, allocator_type const& a)
0115           : concurrent_flat_map(f, l, 0, hasher(), key_equal(), a)
0116       {
0117       }
0118 
0119       explicit concurrent_flat_map(allocator_type const& a)
0120           : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
0121       {
0122       }
0123 
0124       concurrent_flat_map(
0125         concurrent_flat_map const& rhs, allocator_type const& a)
0126           : table_(rhs.table_, a)
0127       {
0128       }
0129 
0130       concurrent_flat_map(concurrent_flat_map&& rhs, allocator_type const& a)
0131           : table_(std::move(rhs.table_), a)
0132       {
0133       }
0134 
0135       concurrent_flat_map(std::initializer_list<value_type> il,
0136         size_type n = detail::foa::default_bucket_count,
0137         const hasher& hf = hasher(), const key_equal& eql = key_equal(),
0138         const allocator_type& a = allocator_type())
0139           : concurrent_flat_map(n, hf, eql, a)
0140       {
0141         this->insert(il.begin(), il.end());
0142       }
0143 
0144       concurrent_flat_map(size_type n, const allocator_type& a)
0145           : concurrent_flat_map(n, hasher(), key_equal(), a)
0146       {
0147       }
0148 
0149       concurrent_flat_map(
0150         size_type n, const hasher& hf, const allocator_type& a)
0151           : concurrent_flat_map(n, hf, key_equal(), a)
0152       {
0153       }
0154 
0155       template <typename InputIterator>
0156       concurrent_flat_map(
0157         InputIterator f, InputIterator l, size_type n, const allocator_type& a)
0158           : concurrent_flat_map(f, l, n, hasher(), key_equal(), a)
0159       {
0160       }
0161 
0162       template <typename InputIterator>
0163       concurrent_flat_map(InputIterator f, InputIterator l, size_type n,
0164         const hasher& hf, const allocator_type& a)
0165           : concurrent_flat_map(f, l, n, hf, key_equal(), a)
0166       {
0167       }
0168 
0169       concurrent_flat_map(
0170         std::initializer_list<value_type> il, const allocator_type& a)
0171           : concurrent_flat_map(
0172               il, detail::foa::default_bucket_count, hasher(), key_equal(), a)
0173       {
0174       }
0175 
0176       concurrent_flat_map(std::initializer_list<value_type> il, size_type n,
0177         const allocator_type& a)
0178           : concurrent_flat_map(il, n, hasher(), key_equal(), a)
0179       {
0180       }
0181 
0182       concurrent_flat_map(std::initializer_list<value_type> il, size_type n,
0183         const hasher& hf, const allocator_type& a)
0184           : concurrent_flat_map(il, n, hf, key_equal(), a)
0185       {
0186       }
0187 
0188 
0189       concurrent_flat_map(
0190         unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other)
0191           : table_(std::move(other.table_))
0192       {
0193       }
0194 
0195       ~concurrent_flat_map() = default;
0196 
0197       concurrent_flat_map& operator=(concurrent_flat_map const& rhs)
0198       {
0199         table_ = rhs.table_;
0200         return *this;
0201       }
0202 
0203       concurrent_flat_map& operator=(concurrent_flat_map&& rhs) noexcept(
0204         noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
0205       {
0206         table_ = std::move(rhs.table_);
0207         return *this;
0208       }
0209 
0210       concurrent_flat_map& operator=(std::initializer_list<value_type> ilist)
0211       {
0212         table_ = ilist;
0213         return *this;
0214       }
0215 
0216       /// Capacity
0217       ///
0218 
0219       size_type size() const noexcept { return table_.size(); }
0220       size_type max_size() const noexcept { return table_.max_size(); }
0221 
0222       BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
0223       {
0224         return size() == 0;
0225       }
0226 
0227       template <class F>
0228       BOOST_FORCEINLINE size_type visit(key_type const& k, F f)
0229       {
0230         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0231         return table_.visit(k, f);
0232       }
0233 
0234       template <class F>
0235       BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const
0236       {
0237         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0238         return table_.visit(k, f);
0239       }
0240 
0241       template <class F>
0242       BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const
0243       {
0244         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0245         return table_.visit(k, f);
0246       }
0247 
0248       template <class K, class F>
0249       BOOST_FORCEINLINE typename std::enable_if<
0250         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0251       visit(K&& k, F f)
0252       {
0253         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0254         return table_.visit(std::forward<K>(k), f);
0255       }
0256 
0257       template <class K, class F>
0258       BOOST_FORCEINLINE typename std::enable_if<
0259         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0260       visit(K&& k, F f) const
0261       {
0262         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0263         return table_.visit(std::forward<K>(k), f);
0264       }
0265 
0266       template <class K, class F>
0267       BOOST_FORCEINLINE typename std::enable_if<
0268         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0269       cvisit(K&& k, F f) const
0270       {
0271         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0272         return table_.visit(std::forward<K>(k), f);
0273       }
0274 
0275       template<class FwdIterator, class F>
0276       BOOST_FORCEINLINE
0277       size_t visit(FwdIterator first, FwdIterator last, F f)
0278       {
0279         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0280         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0281         return table_.visit(first, last, f);
0282       }
0283 
0284       template<class FwdIterator, class F>
0285       BOOST_FORCEINLINE
0286       size_t visit(FwdIterator first, FwdIterator last, F f) const
0287       {
0288         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0289         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0290         return table_.visit(first, last, f);
0291       }
0292 
0293       template<class FwdIterator, class F>
0294       BOOST_FORCEINLINE
0295       size_t cvisit(FwdIterator first, FwdIterator last, F f) const
0296       {
0297         BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
0298         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0299         return table_.visit(first, last, f);
0300       }
0301 
0302       template <class F> size_type visit_all(F f)
0303       {
0304         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0305         return table_.visit_all(f);
0306       }
0307 
0308       template <class F> size_type visit_all(F f) const
0309       {
0310         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0311         return table_.visit_all(f);
0312       }
0313 
0314       template <class F> size_type cvisit_all(F f) const
0315       {
0316         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0317         return table_.cvisit_all(f);
0318       }
0319 
0320 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0321       template <class ExecPolicy, class F>
0322       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0323         void>::type
0324       visit_all(ExecPolicy&& p, F f)
0325       {
0326         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0327         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0328         table_.visit_all(p, f);
0329       }
0330 
0331       template <class ExecPolicy, class F>
0332       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0333         void>::type
0334       visit_all(ExecPolicy&& p, F f) const
0335       {
0336         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0337         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0338         table_.visit_all(p, f);
0339       }
0340 
0341       template <class ExecPolicy, class F>
0342       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0343         void>::type
0344       cvisit_all(ExecPolicy&& p, F f) const
0345       {
0346         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0347         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0348         table_.cvisit_all(p, f);
0349       }
0350 #endif
0351 
0352       template <class F> bool visit_while(F f)
0353       {
0354         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0355         return table_.visit_while(f);
0356       }
0357 
0358       template <class F> bool visit_while(F f) const
0359       {
0360         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0361         return table_.visit_while(f);
0362       }
0363 
0364       template <class F> bool cvisit_while(F f) const
0365       {
0366         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0367         return table_.cvisit_while(f);
0368       }
0369 
0370 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0371       template <class ExecPolicy, class F>
0372       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0373         bool>::type
0374       visit_while(ExecPolicy&& p, F f)
0375       {
0376         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0377         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0378         return table_.visit_while(p, f);
0379       }
0380 
0381       template <class ExecPolicy, class F>
0382       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0383         bool>::type
0384       visit_while(ExecPolicy&& p, F f) const
0385       {
0386         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0387         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0388         return table_.visit_while(p, f);
0389       }
0390 
0391       template <class ExecPolicy, class F>
0392       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0393         bool>::type
0394       cvisit_while(ExecPolicy&& p, F f) const
0395       {
0396         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0397         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0398         return table_.cvisit_while(p, f);
0399       }
0400 #endif
0401 
0402       /// Modifiers
0403       ///
0404 
0405       template <class Ty>
0406       BOOST_FORCEINLINE auto insert(Ty&& value)
0407         -> decltype(table_.insert(std::forward<Ty>(value)))
0408       {
0409         return table_.insert(std::forward<Ty>(value));
0410       }
0411 
0412       BOOST_FORCEINLINE bool insert(init_type&& obj)
0413       {
0414         return table_.insert(std::move(obj));
0415       }
0416 
0417       template <class InputIterator>
0418       void insert(InputIterator begin, InputIterator end)
0419       {
0420         for (auto pos = begin; pos != end; ++pos) {
0421           table_.emplace(*pos);
0422         }
0423       }
0424 
0425       void insert(std::initializer_list<value_type> ilist)
0426       {
0427         this->insert(ilist.begin(), ilist.end());
0428       }
0429 
0430       template <class M>
0431       BOOST_FORCEINLINE bool insert_or_assign(key_type const& k, M&& obj)
0432       {
0433         return table_.try_emplace_or_visit(k, std::forward<M>(obj),
0434           [&](value_type& m) { m.second = std::forward<M>(obj); });
0435       }
0436 
0437       template <class M>
0438       BOOST_FORCEINLINE bool insert_or_assign(key_type&& k, M&& obj)
0439       {
0440         return table_.try_emplace_or_visit(std::move(k), std::forward<M>(obj),
0441           [&](value_type& m) { m.second = std::forward<M>(obj); });
0442       }
0443 
0444       template <class K, class M>
0445       BOOST_FORCEINLINE typename std::enable_if<
0446         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0447       insert_or_assign(K&& k, M&& obj)
0448       {
0449         return table_.try_emplace_or_visit(std::forward<K>(k),
0450           std::forward<M>(obj),
0451           [&](value_type& m) { m.second = std::forward<M>(obj); });
0452       }
0453 
0454       template <class Ty, class F>
0455       BOOST_FORCEINLINE auto insert_or_visit(Ty&& value, F f)
0456         -> decltype(table_.insert_or_visit(std::forward<Ty>(value), f))
0457       {
0458         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0459         return table_.insert_or_visit(std::forward<Ty>(value), f);
0460       }
0461 
0462       template <class F>
0463       BOOST_FORCEINLINE bool insert_or_visit(init_type&& obj, F f)
0464       {
0465         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0466         return table_.insert_or_visit(std::move(obj), f);
0467       }
0468 
0469       template <class InputIterator, class F>
0470       void insert_or_visit(InputIterator first, InputIterator last, F f)
0471       {
0472         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0473         for (; first != last; ++first) {
0474           table_.emplace_or_visit(*first, f);
0475         }
0476       }
0477 
0478       template <class F>
0479       void insert_or_visit(std::initializer_list<value_type> ilist, F f)
0480       {
0481         BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
0482         this->insert_or_visit(ilist.begin(), ilist.end(), f);
0483       }
0484 
0485       template <class Ty, class F>
0486       BOOST_FORCEINLINE auto insert_or_cvisit(Ty&& value, F f)
0487         -> decltype(table_.insert_or_cvisit(std::forward<Ty>(value), f))
0488       {
0489         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0490         return table_.insert_or_cvisit(std::forward<Ty>(value), f);
0491       }
0492 
0493       template <class F>
0494       BOOST_FORCEINLINE bool insert_or_cvisit(init_type&& obj, F f)
0495       {
0496         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0497         return table_.insert_or_cvisit(std::move(obj), f);
0498       }
0499 
0500       template <class InputIterator, class F>
0501       void insert_or_cvisit(InputIterator first, InputIterator last, F f)
0502       {
0503         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0504         for (; first != last; ++first) {
0505           table_.emplace_or_cvisit(*first, f);
0506         }
0507       }
0508 
0509       template <class F>
0510       void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
0511       {
0512         BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
0513         this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
0514       }
0515 
0516       template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
0517       {
0518         return table_.emplace(std::forward<Args>(args)...);
0519       }
0520 
0521       template <class Arg, class... Args>
0522       BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
0523       {
0524         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0525         return table_.emplace_or_visit(
0526           std::forward<Arg>(arg), std::forward<Args>(args)...);
0527       }
0528 
0529       template <class Arg, class... Args>
0530       BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
0531       {
0532         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0533         return table_.emplace_or_cvisit(
0534           std::forward<Arg>(arg), std::forward<Args>(args)...);
0535       }
0536 
0537       template <class... Args>
0538       BOOST_FORCEINLINE bool try_emplace(key_type const& k, Args&&... args)
0539       {
0540         return table_.try_emplace(k, std::forward<Args>(args)...);
0541       }
0542 
0543       template <class... Args>
0544       BOOST_FORCEINLINE bool try_emplace(key_type&& k, Args&&... args)
0545       {
0546         return table_.try_emplace(std::move(k), std::forward<Args>(args)...);
0547       }
0548 
0549       template <class K, class... Args>
0550       BOOST_FORCEINLINE typename std::enable_if<
0551         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0552       try_emplace(K&& k, Args&&... args)
0553       {
0554         return table_.try_emplace(
0555           std::forward<K>(k), std::forward<Args>(args)...);
0556       }
0557 
0558       template <class Arg, class... Args>
0559       BOOST_FORCEINLINE bool try_emplace_or_visit(
0560         key_type const& k, Arg&& arg, Args&&... args)
0561       {
0562         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0563         return table_.try_emplace_or_visit(
0564           k, std::forward<Arg>(arg), std::forward<Args>(args)...);
0565       }
0566 
0567       template <class Arg, class... Args>
0568       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0569         key_type const& k, Arg&& arg, Args&&... args)
0570       {
0571         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0572         return table_.try_emplace_or_cvisit(
0573           k, std::forward<Arg>(arg), std::forward<Args>(args)...);
0574       }
0575 
0576       template <class Arg, class... Args>
0577       BOOST_FORCEINLINE bool try_emplace_or_visit(
0578         key_type&& k, Arg&& arg, Args&&... args)
0579       {
0580         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0581         return table_.try_emplace_or_visit(
0582           std::move(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
0583       }
0584 
0585       template <class Arg, class... Args>
0586       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0587         key_type&& k, Arg&& arg, Args&&... args)
0588       {
0589         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0590         return table_.try_emplace_or_cvisit(
0591           std::move(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
0592       }
0593 
0594       template <class K, class Arg, class... Args>
0595       BOOST_FORCEINLINE bool try_emplace_or_visit(
0596         K&& k, Arg&& arg, Args&&... args)
0597       {
0598         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
0599         return table_.try_emplace_or_visit(std::forward<K>(k),
0600           std::forward<Arg>(arg), std::forward<Args>(args)...);
0601       }
0602 
0603       template <class K, class Arg, class... Args>
0604       BOOST_FORCEINLINE bool try_emplace_or_cvisit(
0605         K&& k, Arg&& arg, Args&&... args)
0606       {
0607         BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
0608         return table_.try_emplace_or_cvisit(std::forward<K>(k),
0609           std::forward<Arg>(arg), std::forward<Args>(args)...);
0610       }
0611 
0612       BOOST_FORCEINLINE size_type erase(key_type const& k)
0613       {
0614         return table_.erase(k);
0615       }
0616 
0617       template <class K>
0618       BOOST_FORCEINLINE typename std::enable_if<
0619         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0620       erase(K&& k)
0621       {
0622         return table_.erase(std::forward<K>(k));
0623       }
0624 
0625       template <class F>
0626       BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
0627       {
0628         return table_.erase_if(k, f);
0629       }
0630 
0631       template <class K, class F>
0632       BOOST_FORCEINLINE typename std::enable_if<
0633         detail::are_transparent<K, hasher, key_equal>::value &&
0634           !detail::is_execution_policy<K>::value,
0635         size_type>::type
0636       erase_if(K&& k, F f)
0637       {
0638         return table_.erase_if(std::forward<K>(k), f);
0639       }
0640 
0641 #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
0642       template <class ExecPolicy, class F>
0643       typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
0644         void>::type
0645       erase_if(ExecPolicy&& p, F f)
0646       {
0647         BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
0648         table_.erase_if(p, f);
0649       }
0650 #endif
0651 
0652       template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
0653 
0654       void swap(concurrent_flat_map& other) noexcept(
0655         boost::allocator_is_always_equal<Allocator>::type::value ||
0656         boost::allocator_propagate_on_container_swap<Allocator>::type::value)
0657       {
0658         return table_.swap(other.table_);
0659       }
0660 
0661       void clear() noexcept { table_.clear(); }
0662 
0663       template <typename H2, typename P2>
0664       size_type merge(concurrent_flat_map<Key, T, H2, P2, Allocator>& x)
0665       {
0666         BOOST_ASSERT(get_allocator() == x.get_allocator());
0667         return table_.merge(x.table_);
0668       }
0669 
0670       template <typename H2, typename P2>
0671       size_type merge(concurrent_flat_map<Key, T, H2, P2, Allocator>&& x)
0672       {
0673         return merge(x);
0674       }
0675 
0676       BOOST_FORCEINLINE size_type count(key_type const& k) const
0677       {
0678         return table_.count(k);
0679       }
0680 
0681       template <class K>
0682       BOOST_FORCEINLINE typename std::enable_if<
0683         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0684       count(K const& k)
0685       {
0686         return table_.count(k);
0687       }
0688 
0689       BOOST_FORCEINLINE bool contains(key_type const& k) const
0690       {
0691         return table_.contains(k);
0692       }
0693 
0694       template <class K>
0695       BOOST_FORCEINLINE typename std::enable_if<
0696         detail::are_transparent<K, hasher, key_equal>::value, bool>::type
0697       contains(K const& k) const
0698       {
0699         return table_.contains(k);
0700       }
0701 
0702       /// Hash Policy
0703       ///
0704       size_type bucket_count() const noexcept { return table_.capacity(); }
0705 
0706       float load_factor() const noexcept { return table_.load_factor(); }
0707       float max_load_factor() const noexcept
0708       {
0709         return table_.max_load_factor();
0710       }
0711       void max_load_factor(float) {}
0712       size_type max_load() const noexcept { return table_.max_load(); }
0713 
0714       void rehash(size_type n) { table_.rehash(n); }
0715       void reserve(size_type n) { table_.reserve(n); }
0716 
0717       /// Observers
0718       ///
0719       allocator_type get_allocator() const noexcept
0720       {
0721         return table_.get_allocator();
0722       }
0723 
0724       hasher hash_function() const { return table_.hash_function(); }
0725       key_equal key_eq() const { return table_.key_eq(); }
0726     };
0727 
0728     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0729     bool operator==(
0730       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
0731       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
0732     {
0733       return lhs.table_ == rhs.table_;
0734     }
0735 
0736     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0737     bool operator!=(
0738       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
0739       concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
0740     {
0741       return !(lhs == rhs);
0742     }
0743 
0744     template <class Key, class T, class Hash, class Pred, class Alloc>
0745     void swap(concurrent_flat_map<Key, T, Hash, Pred, Alloc>& x,
0746       concurrent_flat_map<Key, T, Hash, Pred, Alloc>& y)
0747       noexcept(noexcept(x.swap(y)))
0748     {
0749       x.swap(y);
0750     }
0751 
0752     template <class K, class T, class H, class P, class A, class Predicate>
0753     typename concurrent_flat_map<K, T, H, P, A>::size_type erase_if(
0754       concurrent_flat_map<K, T, H, P, A>& c, Predicate pred)
0755     {
0756       return c.table_.erase_if(pred);
0757     }
0758 
0759     template<class Archive, class K, class V, class H, class KE, class A>
0760     void serialize(
0761       Archive& ar, concurrent_flat_map<K, V, H, KE, A>& c, unsigned int)
0762     {
0763       ar & core::make_nvp("table",c.table_);
0764     }
0765 
0766 #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
0767 
0768     template <class InputIterator,
0769       class Hash =
0770         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0771       class Pred =
0772         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0773       class Allocator = std::allocator<
0774         boost::unordered::detail::iter_to_alloc_t<InputIterator> >,
0775       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0776       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0777       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0778       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0779     concurrent_flat_map(InputIterator, InputIterator,
0780       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0781       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0782       -> concurrent_flat_map<
0783         boost::unordered::detail::iter_key_t<InputIterator>,
0784         boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
0785         Allocator>;
0786 
0787     template <class Key, class T,
0788       class Hash = boost::hash<std::remove_const_t<Key> >,
0789       class Pred = std::equal_to<std::remove_const_t<Key> >,
0790       class Allocator = std::allocator<std::pair<const Key, T> >,
0791       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0792       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0793       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0794     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >,
0795       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0796       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0797       -> concurrent_flat_map<std::remove_const_t<Key>, T, Hash, Pred,
0798         Allocator>;
0799 
0800     template <class InputIterator, class Allocator,
0801       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0802       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0803     concurrent_flat_map(InputIterator, InputIterator, std::size_t, Allocator)
0804       -> concurrent_flat_map<
0805         boost::unordered::detail::iter_key_t<InputIterator>,
0806         boost::unordered::detail::iter_val_t<InputIterator>,
0807         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0808         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0809         Allocator>;
0810 
0811     template <class InputIterator, class Allocator,
0812       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0813       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0814     concurrent_flat_map(InputIterator, InputIterator, Allocator)
0815       -> concurrent_flat_map<
0816         boost::unordered::detail::iter_key_t<InputIterator>,
0817         boost::unordered::detail::iter_val_t<InputIterator>,
0818         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0819         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0820         Allocator>;
0821 
0822     template <class InputIterator, class Hash, class Allocator,
0823       class = std::enable_if_t<detail::is_hash_v<Hash> >,
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(
0827       InputIterator, InputIterator, std::size_t, Hash, Allocator)
0828       -> concurrent_flat_map<
0829         boost::unordered::detail::iter_key_t<InputIterator>,
0830         boost::unordered::detail::iter_val_t<InputIterator>, Hash,
0831         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0832         Allocator>;
0833 
0834     template <class Key, class T, class Allocator,
0835       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0836     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
0837       Allocator) -> concurrent_flat_map<std::remove_const_t<Key>, T,
0838       boost::hash<std::remove_const_t<Key> >,
0839       std::equal_to<std::remove_const_t<Key> >, Allocator>;
0840 
0841     template <class Key, class T, class Allocator,
0842       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0843     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, Allocator)
0844       -> concurrent_flat_map<std::remove_const_t<Key>, T,
0845         boost::hash<std::remove_const_t<Key> >,
0846         std::equal_to<std::remove_const_t<Key> >, Allocator>;
0847 
0848     template <class Key, class T, class Hash, class Allocator,
0849       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0850       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0851     concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
0852       Hash, Allocator) -> concurrent_flat_map<std::remove_const_t<Key>, T,
0853       Hash, std::equal_to<std::remove_const_t<Key> >, Allocator>;
0854 
0855 #endif
0856 
0857   } // namespace unordered
0858 } // namespace boost
0859 
0860 #endif // BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP