Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 08:28:11

0001 // Copyright (C) 2022-2023 Christian Mazakas
0002 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0003 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0004 
0005 #ifndef BOOST_UNORDERED_UNORDERED_NODE_MAP_HPP_INCLUDED
0006 #define BOOST_UNORDERED_UNORDERED_NODE_MAP_HPP_INCLUDED
0007 
0008 #include <boost/config.hpp>
0009 #if defined(BOOST_HAS_PRAGMA_ONCE)
0010 #pragma once
0011 #endif
0012 
0013 #include <boost/unordered/detail/foa/element_type.hpp>
0014 #include <boost/unordered/detail/foa/node_handle.hpp>
0015 #include <boost/unordered/detail/foa/node_map_types.hpp>
0016 #include <boost/unordered/detail/foa/table.hpp>
0017 #include <boost/unordered/detail/serialize_container.hpp>
0018 #include <boost/unordered/detail/throw_exception.hpp>
0019 #include <boost/unordered/detail/type_traits.hpp>
0020 #include <boost/unordered/unordered_node_map_fwd.hpp>
0021 
0022 #include <boost/core/allocator_access.hpp>
0023 #include <boost/container_hash/hash.hpp>
0024 
0025 #include <initializer_list>
0026 #include <iterator>
0027 #include <stdexcept>
0028 #include <type_traits>
0029 #include <utility>
0030 
0031 namespace boost {
0032   namespace unordered {
0033 
0034 #if defined(BOOST_MSVC)
0035 #pragma warning(push)
0036 #pragma warning(disable : 4714) /* marked as __forceinline not inlined */
0037 #endif
0038 
0039     namespace detail {
0040       template <class TypePolicy, class Allocator>
0041       struct node_map_handle
0042           : public detail::foa::node_handle_base<TypePolicy, Allocator>
0043       {
0044       private:
0045         using base_type = detail::foa::node_handle_base<TypePolicy, Allocator>;
0046 
0047         using typename base_type::type_policy;
0048 
0049         template <class Key, class T, class Hash, class Pred, class Alloc>
0050         friend class boost::unordered::unordered_node_map;
0051 
0052       public:
0053         using key_type = typename TypePolicy::key_type;
0054         using mapped_type = typename TypePolicy::mapped_type;
0055 
0056         constexpr node_map_handle() noexcept = default;
0057         node_map_handle(node_map_handle&& nh) noexcept = default;
0058 
0059         node_map_handle& operator=(node_map_handle&&) noexcept = default;
0060 
0061         key_type& key() const
0062         {
0063           BOOST_ASSERT(!this->empty());
0064           return const_cast<key_type&>(this->data().first);
0065         }
0066 
0067         mapped_type& mapped() const
0068         {
0069           BOOST_ASSERT(!this->empty());
0070           return const_cast<mapped_type&>(this->data().second);
0071         }
0072       };
0073     } // namespace detail
0074 
0075     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0076     class unordered_node_map
0077     {
0078       using map_types = detail::foa::node_map_types<Key, T,
0079         typename boost::allocator_void_pointer<Allocator>::type>;
0080 
0081       using table_type = detail::foa::table<map_types, Hash, KeyEqual,
0082         typename boost::allocator_rebind<Allocator,
0083           std::pair<Key const, T> >::type>;
0084 
0085       table_type table_;
0086 
0087       template <class K, class V, class H, class KE, class A>
0088       bool friend operator==(unordered_node_map<K, V, H, KE, A> const& lhs,
0089         unordered_node_map<K, V, H, KE, A> const& rhs);
0090 
0091       template <class K, class V, class H, class KE, class A, class Pred>
0092       typename unordered_node_map<K, V, H, KE, A>::size_type friend erase_if(
0093         unordered_node_map<K, V, H, KE, A>& set, Pred pred);
0094 
0095     public:
0096       using key_type = Key;
0097       using mapped_type = T;
0098       using value_type = typename map_types::value_type;
0099       using init_type = typename map_types::init_type;
0100       using size_type = std::size_t;
0101       using difference_type = std::ptrdiff_t;
0102       using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
0103       using key_equal = typename boost::unordered::detail::type_identity<KeyEqual>::type;
0104       using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
0105       using reference = value_type&;
0106       using const_reference = value_type const&;
0107       using pointer = typename boost::allocator_pointer<allocator_type>::type;
0108       using const_pointer =
0109         typename boost::allocator_const_pointer<allocator_type>::type;
0110       using iterator = typename table_type::iterator;
0111       using const_iterator = typename table_type::const_iterator;
0112       using node_type = detail::node_map_handle<map_types,
0113         typename boost::allocator_rebind<Allocator,
0114           typename map_types::value_type>::type>;
0115       using insert_return_type =
0116         detail::foa::insert_return_type<iterator, node_type>;
0117 
0118 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0119       using stats = typename table_type::stats;
0120 #endif
0121 
0122       unordered_node_map() : unordered_node_map(0) {}
0123 
0124       explicit unordered_node_map(size_type n, hasher const& h = hasher(),
0125         key_equal const& pred = key_equal(),
0126         allocator_type const& a = allocator_type())
0127           : table_(n, h, pred, a)
0128       {
0129       }
0130 
0131       unordered_node_map(size_type n, allocator_type const& a)
0132           : unordered_node_map(n, hasher(), key_equal(), a)
0133       {
0134       }
0135 
0136       unordered_node_map(size_type n, hasher const& h, allocator_type const& a)
0137           : unordered_node_map(n, h, key_equal(), a)
0138       {
0139       }
0140 
0141       template <class InputIterator>
0142       unordered_node_map(
0143         InputIterator f, InputIterator l, allocator_type const& a)
0144           : unordered_node_map(f, l, size_type(0), hasher(), key_equal(), a)
0145       {
0146       }
0147 
0148       explicit unordered_node_map(allocator_type const& a)
0149           : unordered_node_map(0, a)
0150       {
0151       }
0152 
0153       template <class Iterator>
0154       unordered_node_map(Iterator first, Iterator last, size_type n = 0,
0155         hasher const& h = hasher(), key_equal const& pred = key_equal(),
0156         allocator_type const& a = allocator_type())
0157           : unordered_node_map(n, h, pred, a)
0158       {
0159         this->insert(first, last);
0160       }
0161 
0162       template <class Iterator>
0163       unordered_node_map(
0164         Iterator first, Iterator last, size_type n, allocator_type const& a)
0165           : unordered_node_map(first, last, n, hasher(), key_equal(), a)
0166       {
0167       }
0168 
0169       template <class Iterator>
0170       unordered_node_map(Iterator first, Iterator last, size_type n,
0171         hasher const& h, allocator_type const& a)
0172           : unordered_node_map(first, last, n, h, key_equal(), a)
0173       {
0174       }
0175 
0176       unordered_node_map(unordered_node_map const& other) : table_(other.table_)
0177       {
0178       }
0179 
0180       unordered_node_map(
0181         unordered_node_map const& other, allocator_type const& a)
0182           : table_(other.table_, a)
0183       {
0184       }
0185 
0186       unordered_node_map(unordered_node_map&& other)
0187         noexcept(std::is_nothrow_move_constructible<table_type>::value)
0188           : table_(std::move(other.table_))
0189       {
0190       }
0191 
0192       unordered_node_map(unordered_node_map&& other, allocator_type const& al)
0193           : table_(std::move(other.table_), al)
0194       {
0195       }
0196 
0197       unordered_node_map(std::initializer_list<value_type> ilist,
0198         size_type n = 0, hasher const& h = hasher(),
0199         key_equal const& pred = key_equal(),
0200         allocator_type const& a = allocator_type())
0201           : unordered_node_map(ilist.begin(), ilist.end(), n, h, pred, a)
0202       {
0203       }
0204 
0205       unordered_node_map(
0206         std::initializer_list<value_type> il, allocator_type const& a)
0207           : unordered_node_map(il, size_type(0), hasher(), key_equal(), a)
0208       {
0209       }
0210 
0211       unordered_node_map(std::initializer_list<value_type> init, size_type n,
0212         allocator_type const& a)
0213           : unordered_node_map(init, n, hasher(), key_equal(), a)
0214       {
0215       }
0216 
0217       unordered_node_map(std::initializer_list<value_type> init, size_type n,
0218         hasher const& h, allocator_type const& a)
0219           : unordered_node_map(init, n, h, key_equal(), a)
0220       {
0221       }
0222 
0223       ~unordered_node_map() = default;
0224 
0225       unordered_node_map& operator=(unordered_node_map const& other)
0226       {
0227         table_ = other.table_;
0228         return *this;
0229       }
0230 
0231       unordered_node_map& operator=(unordered_node_map&& other) noexcept(
0232         noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
0233       {
0234         table_ = std::move(other.table_);
0235         return *this;
0236       }
0237 
0238       allocator_type get_allocator() const noexcept
0239       {
0240         return table_.get_allocator();
0241       }
0242 
0243       /// Iterators
0244       ///
0245 
0246       iterator begin() noexcept { return table_.begin(); }
0247       const_iterator begin() const noexcept { return table_.begin(); }
0248       const_iterator cbegin() const noexcept { return table_.cbegin(); }
0249 
0250       iterator end() noexcept { return table_.end(); }
0251       const_iterator end() const noexcept { return table_.end(); }
0252       const_iterator cend() const noexcept { return table_.cend(); }
0253 
0254       /// Capacity
0255       ///
0256 
0257       BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
0258       {
0259         return table_.empty();
0260       }
0261 
0262       size_type size() const noexcept { return table_.size(); }
0263 
0264       size_type max_size() const noexcept { return table_.max_size(); }
0265 
0266       /// Modifiers
0267       ///
0268 
0269       void clear() noexcept { table_.clear(); }
0270 
0271       template <class Ty>
0272       BOOST_FORCEINLINE auto insert(Ty&& value)
0273         -> decltype(table_.insert(std::forward<Ty>(value)))
0274       {
0275         return table_.insert(std::forward<Ty>(value));
0276       }
0277 
0278       BOOST_FORCEINLINE std::pair<iterator, bool> insert(init_type&& value)
0279       {
0280         return table_.insert(std::move(value));
0281       }
0282 
0283       template <class Ty>
0284       BOOST_FORCEINLINE auto insert(const_iterator, Ty&& value)
0285         -> decltype(table_.insert(std::forward<Ty>(value)).first)
0286       {
0287         return table_.insert(std::forward<Ty>(value)).first;
0288       }
0289 
0290       BOOST_FORCEINLINE iterator insert(const_iterator, init_type&& value)
0291       {
0292         return table_.insert(std::move(value)).first;
0293       }
0294 
0295       template <class InputIterator>
0296       BOOST_FORCEINLINE void insert(InputIterator first, InputIterator last)
0297       {
0298         for (auto pos = first; pos != last; ++pos) {
0299           table_.emplace(*pos);
0300         }
0301       }
0302 
0303       void insert(std::initializer_list<value_type> ilist)
0304       {
0305         this->insert(ilist.begin(), ilist.end());
0306       }
0307 
0308       insert_return_type insert(node_type&& nh)
0309       {
0310         if (nh.empty()) {
0311           return {end(), false, node_type{}};
0312         }
0313 
0314         BOOST_ASSERT(get_allocator() == nh.get_allocator());
0315 
0316         auto itp = table_.insert(std::move(nh.element()));
0317         if (itp.second) {
0318           nh.reset();
0319           return {itp.first, true, node_type{}};
0320         } else {
0321           return {itp.first, false, std::move(nh)};
0322         }
0323       }
0324 
0325       iterator insert(const_iterator, node_type&& nh)
0326       {
0327         if (nh.empty()) {
0328           return end();
0329         }
0330 
0331         BOOST_ASSERT(get_allocator() == nh.get_allocator());
0332 
0333         auto itp = table_.insert(std::move(nh.element()));
0334         if (itp.second) {
0335           nh.reset();
0336           return itp.first;
0337         } else {
0338           return itp.first;
0339         }
0340       }
0341 
0342       template <class M>
0343       std::pair<iterator, bool> insert_or_assign(key_type const& key, M&& obj)
0344       {
0345         auto ibp = table_.try_emplace(key, std::forward<M>(obj));
0346         if (ibp.second) {
0347           return ibp;
0348         }
0349         ibp.first->second = std::forward<M>(obj);
0350         return ibp;
0351       }
0352 
0353       template <class M>
0354       std::pair<iterator, bool> insert_or_assign(key_type&& key, M&& obj)
0355       {
0356         auto ibp = table_.try_emplace(std::move(key), std::forward<M>(obj));
0357         if (ibp.second) {
0358           return ibp;
0359         }
0360         ibp.first->second = std::forward<M>(obj);
0361         return ibp;
0362       }
0363 
0364       template <class K, class M>
0365       typename std::enable_if<
0366         boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0367         std::pair<iterator, bool> >::type
0368       insert_or_assign(K&& k, M&& obj)
0369       {
0370         auto ibp = table_.try_emplace(std::forward<K>(k), std::forward<M>(obj));
0371         if (ibp.second) {
0372           return ibp;
0373         }
0374         ibp.first->second = std::forward<M>(obj);
0375         return ibp;
0376       }
0377 
0378       template <class M>
0379       iterator insert_or_assign(const_iterator, key_type const& key, M&& obj)
0380       {
0381         return this->insert_or_assign(key, std::forward<M>(obj)).first;
0382       }
0383 
0384       template <class M>
0385       iterator insert_or_assign(const_iterator, key_type&& key, M&& obj)
0386       {
0387         return this->insert_or_assign(std::move(key), std::forward<M>(obj))
0388           .first;
0389       }
0390 
0391       template <class K, class M>
0392       typename std::enable_if<
0393         boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0394         iterator>::type
0395       insert_or_assign(const_iterator, K&& k, M&& obj)
0396       {
0397         return this->insert_or_assign(std::forward<K>(k), std::forward<M>(obj))
0398           .first;
0399       }
0400 
0401       template <class... Args>
0402       BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
0403       {
0404         return table_.emplace(std::forward<Args>(args)...);
0405       }
0406 
0407       template <class... Args>
0408       BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args)
0409       {
0410         return table_.emplace(std::forward<Args>(args)...).first;
0411       }
0412 
0413       template <class... Args>
0414       BOOST_FORCEINLINE std::pair<iterator, bool> try_emplace(
0415         key_type const& key, Args&&... args)
0416       {
0417         return table_.try_emplace(key, std::forward<Args>(args)...);
0418       }
0419 
0420       template <class... Args>
0421       BOOST_FORCEINLINE std::pair<iterator, bool> try_emplace(
0422         key_type&& key, Args&&... args)
0423       {
0424         return table_.try_emplace(std::move(key), std::forward<Args>(args)...);
0425       }
0426 
0427       template <class K, class... Args>
0428       BOOST_FORCEINLINE typename std::enable_if<
0429         boost::unordered::detail::transparent_non_iterable<K,
0430           unordered_node_map>::value,
0431         std::pair<iterator, bool> >::type
0432       try_emplace(K&& key, Args&&... args)
0433       {
0434         return table_.try_emplace(
0435           std::forward<K>(key), std::forward<Args>(args)...);
0436       }
0437 
0438       template <class... Args>
0439       BOOST_FORCEINLINE iterator try_emplace(
0440         const_iterator, key_type const& key, Args&&... args)
0441       {
0442         return table_.try_emplace(key, std::forward<Args>(args)...).first;
0443       }
0444 
0445       template <class... Args>
0446       BOOST_FORCEINLINE iterator try_emplace(
0447         const_iterator, key_type&& key, Args&&... args)
0448       {
0449         return table_.try_emplace(std::move(key), std::forward<Args>(args)...)
0450           .first;
0451       }
0452 
0453       template <class K, class... Args>
0454       BOOST_FORCEINLINE typename std::enable_if<
0455         boost::unordered::detail::transparent_non_iterable<K,
0456           unordered_node_map>::value,
0457         iterator>::type
0458       try_emplace(const_iterator, K&& key, Args&&... args)
0459       {
0460         return table_
0461           .try_emplace(std::forward<K>(key), std::forward<Args>(args)...)
0462           .first;
0463       }
0464 
0465       BOOST_FORCEINLINE typename table_type::erase_return_type erase(
0466         iterator pos)
0467       {
0468         return table_.erase(pos);
0469       }
0470 
0471       BOOST_FORCEINLINE typename table_type::erase_return_type erase(
0472         const_iterator pos)
0473       {
0474         return table_.erase(pos);
0475       }
0476 
0477       iterator erase(const_iterator first, const_iterator last)
0478       {
0479         while (first != last) {
0480           this->erase(first++);
0481         }
0482         return iterator{detail::foa::const_iterator_cast_tag{}, last};
0483       }
0484 
0485       BOOST_FORCEINLINE size_type erase(key_type const& key)
0486       {
0487         return table_.erase(key);
0488       }
0489 
0490       template <class K>
0491       BOOST_FORCEINLINE typename std::enable_if<
0492         detail::transparent_non_iterable<K, unordered_node_map>::value,
0493         size_type>::type
0494       erase(K const& key)
0495       {
0496         return table_.erase(key);
0497       }
0498 
0499       void swap(unordered_node_map& rhs) noexcept(
0500         noexcept(std::declval<table_type&>().swap(std::declval<table_type&>())))
0501       {
0502         table_.swap(rhs.table_);
0503       }
0504 
0505       node_type extract(const_iterator pos)
0506       {
0507         BOOST_ASSERT(pos != end());
0508         node_type nh;
0509         auto elem = table_.extract(pos);
0510         nh.emplace(std::move(elem), get_allocator());
0511         return nh;
0512       }
0513 
0514       node_type extract(key_type const& key)
0515       {
0516         auto pos = find(key);
0517         return pos != end() ? extract(pos) : node_type();
0518       }
0519 
0520       template <class K>
0521       typename std::enable_if<
0522         boost::unordered::detail::transparent_non_iterable<K,
0523           unordered_node_map>::value,
0524         node_type>::type
0525       extract(K const& key)
0526       {
0527         auto pos = find(key);
0528         return pos != end() ? extract(pos) : node_type();
0529       }
0530 
0531       template <class H2, class P2>
0532       void merge(
0533         unordered_node_map<key_type, mapped_type, H2, P2, allocator_type>&
0534           source)
0535       {
0536         BOOST_ASSERT(get_allocator() == source.get_allocator());
0537         table_.merge(source.table_);
0538       }
0539 
0540       template <class H2, class P2>
0541       void merge(
0542         unordered_node_map<key_type, mapped_type, H2, P2, allocator_type>&&
0543           source)
0544       {
0545         BOOST_ASSERT(get_allocator() == source.get_allocator());
0546         table_.merge(std::move(source.table_));
0547       }
0548 
0549       /// Lookup
0550       ///
0551 
0552       mapped_type& at(key_type const& key)
0553       {
0554         auto pos = table_.find(key);
0555         if (pos != table_.end()) {
0556           return pos->second;
0557         }
0558         // TODO: someday refactor this to conditionally serialize the key and
0559         // include it in the error message
0560         //
0561         boost::unordered::detail::throw_out_of_range(
0562           "key was not found in unordered_node_map");
0563       }
0564 
0565       mapped_type const& at(key_type const& key) const
0566       {
0567         auto pos = table_.find(key);
0568         if (pos != table_.end()) {
0569           return pos->second;
0570         }
0571         boost::unordered::detail::throw_out_of_range(
0572           "key was not found in unordered_node_map");
0573       }
0574 
0575       template <class K>
0576       typename std::enable_if<
0577         boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0578         mapped_type&>::type
0579       at(K&& key)
0580       {
0581         auto pos = table_.find(std::forward<K>(key));
0582         if (pos != table_.end()) {
0583           return pos->second;
0584         }
0585         boost::unordered::detail::throw_out_of_range(
0586           "key was not found in unordered_node_map");
0587       }
0588 
0589       template <class K>
0590       typename std::enable_if<
0591         boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0592         mapped_type const&>::type
0593       at(K&& key) const
0594       {
0595         auto pos = table_.find(std::forward<K>(key));
0596         if (pos != table_.end()) {
0597           return pos->second;
0598         }
0599         boost::unordered::detail::throw_out_of_range(
0600           "key was not found in unordered_node_map");
0601       }
0602 
0603       BOOST_FORCEINLINE mapped_type& operator[](key_type const& key)
0604       {
0605         return table_.try_emplace(key).first->second;
0606       }
0607 
0608       BOOST_FORCEINLINE mapped_type& operator[](key_type&& key)
0609       {
0610         return table_.try_emplace(std::move(key)).first->second;
0611       }
0612 
0613       template <class K>
0614       typename std::enable_if<
0615         boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0616         mapped_type&>::type
0617       operator[](K&& key)
0618       {
0619         return table_.try_emplace(std::forward<K>(key)).first->second;
0620       }
0621 
0622       BOOST_FORCEINLINE size_type count(key_type const& key) const
0623       {
0624         auto pos = table_.find(key);
0625         return pos != table_.end() ? 1 : 0;
0626       }
0627 
0628       template <class K>
0629       BOOST_FORCEINLINE typename std::enable_if<
0630         detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0631       count(K const& key) const
0632       {
0633         auto pos = table_.find(key);
0634         return pos != table_.end() ? 1 : 0;
0635       }
0636 
0637       BOOST_FORCEINLINE iterator find(key_type const& key)
0638       {
0639         return table_.find(key);
0640       }
0641 
0642       BOOST_FORCEINLINE const_iterator find(key_type const& key) const
0643       {
0644         return table_.find(key);
0645       }
0646 
0647       template <class K>
0648       BOOST_FORCEINLINE typename std::enable_if<
0649         boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0650         iterator>::type
0651       find(K const& key)
0652       {
0653         return table_.find(key);
0654       }
0655 
0656       template <class K>
0657       BOOST_FORCEINLINE typename std::enable_if<
0658         boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0659         const_iterator>::type
0660       find(K const& key) const
0661       {
0662         return table_.find(key);
0663       }
0664 
0665       BOOST_FORCEINLINE bool contains(key_type const& key) const
0666       {
0667         return this->find(key) != this->end();
0668       }
0669 
0670       template <class K>
0671       BOOST_FORCEINLINE typename std::enable_if<
0672         boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0673         bool>::type
0674       contains(K const& key) const
0675       {
0676         return this->find(key) != this->end();
0677       }
0678 
0679       std::pair<iterator, iterator> equal_range(key_type const& key)
0680       {
0681         auto pos = table_.find(key);
0682         if (pos == table_.end()) {
0683           return {pos, pos};
0684         }
0685 
0686         auto next = pos;
0687         ++next;
0688         return {pos, next};
0689       }
0690 
0691       std::pair<const_iterator, const_iterator> equal_range(
0692         key_type const& key) const
0693       {
0694         auto pos = table_.find(key);
0695         if (pos == table_.end()) {
0696           return {pos, pos};
0697         }
0698 
0699         auto next = pos;
0700         ++next;
0701         return {pos, next};
0702       }
0703 
0704       template <class K>
0705       typename std::enable_if<
0706         detail::are_transparent<K, hasher, key_equal>::value,
0707         std::pair<iterator, iterator> >::type
0708       equal_range(K const& key)
0709       {
0710         auto pos = table_.find(key);
0711         if (pos == table_.end()) {
0712           return {pos, pos};
0713         }
0714 
0715         auto next = pos;
0716         ++next;
0717         return {pos, next};
0718       }
0719 
0720       template <class K>
0721       typename std::enable_if<
0722         detail::are_transparent<K, hasher, key_equal>::value,
0723         std::pair<const_iterator, const_iterator> >::type
0724       equal_range(K const& key) const
0725       {
0726         auto pos = table_.find(key);
0727         if (pos == table_.end()) {
0728           return {pos, pos};
0729         }
0730 
0731         auto next = pos;
0732         ++next;
0733         return {pos, next};
0734       }
0735 
0736       /// Hash Policy
0737       ///
0738 
0739       size_type bucket_count() const noexcept { return table_.capacity(); }
0740 
0741       float load_factor() const noexcept { return table_.load_factor(); }
0742 
0743       float max_load_factor() const noexcept
0744       {
0745         return table_.max_load_factor();
0746       }
0747 
0748       void max_load_factor(float) {}
0749 
0750       size_type max_load() const noexcept { return table_.max_load(); }
0751 
0752       void rehash(size_type n) { table_.rehash(n); }
0753 
0754       void reserve(size_type n) { table_.reserve(n); }
0755 
0756 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0757       /// Stats
0758       ///
0759       stats get_stats() const { return table_.get_stats(); }
0760 
0761       void reset_stats() noexcept { table_.reset_stats(); }
0762 #endif
0763 
0764       /// Observers
0765       ///
0766 
0767       hasher hash_function() const { return table_.hash_function(); }
0768 
0769       key_equal key_eq() const { return table_.key_eq(); }
0770     };
0771 
0772     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0773     bool operator==(
0774       unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
0775       unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
0776     {
0777       return lhs.table_ == rhs.table_;
0778     }
0779 
0780     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0781     bool operator!=(
0782       unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
0783       unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
0784     {
0785       return !(lhs == rhs);
0786     }
0787 
0788     template <class Key, class T, class Hash, class KeyEqual, class Allocator>
0789     void swap(unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& lhs,
0790       unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& rhs)
0791       noexcept(noexcept(lhs.swap(rhs)))
0792     {
0793       lhs.swap(rhs);
0794     }
0795 
0796     template <class Key, class T, class Hash, class KeyEqual, class Allocator,
0797       class Pred>
0798     typename unordered_node_map<Key, T, Hash, KeyEqual, Allocator>::size_type
0799     erase_if(
0800       unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& map, Pred pred)
0801     {
0802       return erase_if(map.table_, pred);
0803     }
0804 
0805     template <class Archive, class Key, class T, class Hash, class KeyEqual,
0806       class Allocator>
0807     void serialize(Archive& ar,
0808       unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& map,
0809       unsigned int version)
0810     {
0811       detail::serialize_container(ar, map, version);
0812     }
0813 
0814 #if defined(BOOST_MSVC)
0815 #pragma warning(pop) /* C4714 */
0816 #endif
0817 
0818 #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
0819 
0820     template <class InputIterator,
0821       class Hash =
0822         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0823       class Pred =
0824         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0825       class Allocator = std::allocator<
0826         boost::unordered::detail::iter_to_alloc_t<InputIterator> >,
0827       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0828       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0829       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0830       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0831     unordered_node_map(InputIterator, InputIterator,
0832       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0833       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0834       -> unordered_node_map<boost::unordered::detail::iter_key_t<InputIterator>,
0835         boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
0836         Allocator>;
0837 
0838     template <class Key, class T,
0839       class Hash = boost::hash<std::remove_const_t<Key> >,
0840       class Pred = std::equal_to<std::remove_const_t<Key> >,
0841       class Allocator = std::allocator<std::pair<const Key, T> >,
0842       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0843       class = std::enable_if_t<detail::is_pred_v<Pred> >,
0844       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0845     unordered_node_map(std::initializer_list<std::pair<Key, T> >,
0846       std::size_t = boost::unordered::detail::foa::default_bucket_count,
0847       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0848       -> unordered_node_map<std::remove_const_t<Key>, T, Hash, Pred,
0849         Allocator>;
0850 
0851     template <class InputIterator, class Allocator,
0852       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0853       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0854     unordered_node_map(InputIterator, InputIterator, std::size_t, Allocator)
0855       -> unordered_node_map<boost::unordered::detail::iter_key_t<InputIterator>,
0856         boost::unordered::detail::iter_val_t<InputIterator>,
0857         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0858         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0859         Allocator>;
0860 
0861     template <class InputIterator, class Allocator,
0862       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0863       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0864     unordered_node_map(InputIterator, InputIterator, Allocator)
0865       -> unordered_node_map<boost::unordered::detail::iter_key_t<InputIterator>,
0866         boost::unordered::detail::iter_val_t<InputIterator>,
0867         boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
0868         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0869         Allocator>;
0870 
0871     template <class InputIterator, class Hash, class Allocator,
0872       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0873       class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0874       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0875     unordered_node_map(
0876       InputIterator, InputIterator, std::size_t, Hash, Allocator)
0877       -> unordered_node_map<boost::unordered::detail::iter_key_t<InputIterator>,
0878         boost::unordered::detail::iter_val_t<InputIterator>, Hash,
0879         std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
0880         Allocator>;
0881 
0882     template <class Key, class T, class Allocator,
0883       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0884     unordered_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
0885       Allocator) -> unordered_node_map<std::remove_const_t<Key>, T,
0886       boost::hash<std::remove_const_t<Key> >,
0887       std::equal_to<std::remove_const_t<Key> >, Allocator>;
0888 
0889     template <class Key, class T, class Allocator,
0890       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0891     unordered_node_map(std::initializer_list<std::pair<Key, T> >, Allocator)
0892       -> unordered_node_map<std::remove_const_t<Key>, T,
0893         boost::hash<std::remove_const_t<Key> >,
0894         std::equal_to<std::remove_const_t<Key> >, Allocator>;
0895 
0896     template <class Key, class T, class Hash, class Allocator,
0897       class = std::enable_if_t<detail::is_hash_v<Hash> >,
0898       class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0899     unordered_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
0900       Hash, Allocator) -> unordered_node_map<std::remove_const_t<Key>, T,
0901       Hash, std::equal_to<std::remove_const_t<Key> >, Allocator>;
0902 #endif
0903 
0904   } // namespace unordered
0905 } // namespace boost
0906 
0907 #endif