Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:07:43

0001 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
0002 // Copyright (C) 2005-2016 Daniel James
0003 // Copyright (C) 2022-2024 Joaquin M Lopez Munoz.
0004 // Copyright (C) 2022-2023 Christian Mazakas
0005 // Copyright (C) 2024 Braden Ganetsky
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 #ifndef BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP
0011 #define BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP
0012 
0013 #include <boost/config.hpp>
0014 #if defined(BOOST_HAS_PRAGMA_ONCE)
0015 #pragma once
0016 #endif
0017 
0018 #include <boost/unordered/detail/allocator_constructed.hpp>
0019 #include <boost/unordered/detail/fca.hpp>
0020 #include <boost/unordered/detail/opt_storage.hpp>
0021 #include <boost/unordered/detail/serialize_tracked_address.hpp>
0022 #include <boost/unordered/detail/static_assert.hpp>
0023 #include <boost/unordered/detail/type_traits.hpp>
0024 #include <boost/unordered/unordered_printers.hpp>
0025 
0026 #include <boost/assert.hpp>
0027 #include <boost/core/allocator_traits.hpp>
0028 #include <boost/core/bit.hpp>
0029 #include <boost/core/invoke_swap.hpp>
0030 #include <boost/core/no_exceptions_support.hpp>
0031 #include <boost/core/pointer_traits.hpp>
0032 #include <boost/core/serialization.hpp>
0033 #include <boost/mp11/algorithm.hpp>
0034 #include <boost/mp11/list.hpp>
0035 #include <boost/throw_exception.hpp>
0036 
0037 #include <algorithm>
0038 #include <cmath>
0039 #include <iterator>
0040 #include <limits>
0041 #include <stdexcept>
0042 #include <type_traits>
0043 #include <utility>
0044 #include <tuple> // std::forward_as_tuple
0045 
0046 namespace boost {
0047   namespace tuples {
0048     struct null_type;
0049   }
0050 } // namespace boost
0051 
0052 // BOOST_UNORDERED_SUPPRESS_DEPRECATED
0053 //
0054 // Define to stop deprecation attributes
0055 
0056 #if defined(BOOST_UNORDERED_SUPPRESS_DEPRECATED)
0057 #define BOOST_UNORDERED_DEPRECATED(msg)
0058 #endif
0059 
0060 // BOOST_UNORDERED_DEPRECATED
0061 //
0062 // Wrapper around various depreaction attributes.
0063 
0064 #if defined(__has_cpp_attribute) &&                                            \
0065   (!defined(__cplusplus) || __cplusplus >= 201402)
0066 #if __has_cpp_attribute(deprecated) && !defined(BOOST_UNORDERED_DEPRECATED)
0067 #define BOOST_UNORDERED_DEPRECATED(msg) [[deprecated(msg)]]
0068 #endif
0069 #endif
0070 
0071 #if !defined(BOOST_UNORDERED_DEPRECATED)
0072 #if defined(__GNUC__) && __GNUC__ >= 4
0073 #define BOOST_UNORDERED_DEPRECATED(msg) __attribute__((deprecated))
0074 #elif defined(_MSC_VER) && _MSC_VER >= 1400
0075 #define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated(msg))
0076 #elif defined(_MSC_VER) && _MSC_VER >= 1310
0077 #define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated)
0078 #else
0079 #define BOOST_UNORDERED_DEPRECATED(msg)
0080 #endif
0081 #endif
0082 
0083 namespace boost {
0084   namespace unordered {
0085 
0086     using std::piecewise_construct;
0087     using std::piecewise_construct_t;
0088 
0089     namespace detail {
0090 
0091       template <typename Types> struct table;
0092 
0093       static const float minimum_max_load_factor = 1e-3f;
0094       static const std::size_t default_bucket_count = 0;
0095 
0096       struct move_tag
0097       {
0098       };
0099 
0100       struct empty_emplace
0101       {
0102       };
0103 
0104       struct no_key
0105       {
0106         no_key() {}
0107         template <class T> no_key(T const&) {}
0108       };
0109 
0110       struct converting_key
0111       {
0112       };
0113 
0114       namespace func {
0115         template <class T> inline void ignore_unused_variable_warning(T const&)
0116         {
0117         }
0118       } // namespace func
0119 
0120       //////////////////////////////////////////////////////////////////////////
0121       // iterator SFINAE
0122 
0123       template <typename I>
0124       struct is_forward : std::is_base_of<std::forward_iterator_tag,
0125                             typename std::iterator_traits<I>::iterator_category>
0126       {
0127       };
0128 
0129       template <typename I, typename ReturnType>
0130       struct enable_if_forward
0131           : std::enable_if<boost::unordered::detail::is_forward<I>::value,
0132               ReturnType>
0133       {
0134       };
0135 
0136       template <typename I, typename ReturnType>
0137       struct disable_if_forward
0138           : std::enable_if<!boost::unordered::detail::is_forward<I>::value,
0139               ReturnType>
0140       {
0141       };
0142     } // namespace detail
0143   } // namespace unordered
0144 } // namespace boost
0145 
0146 namespace boost {
0147   namespace unordered {
0148     namespace detail {
0149       //////////////////////////////////////////////////////////////////////////
0150       // insert_size/initial_size
0151 
0152       template <class I>
0153       inline typename boost::unordered::detail::enable_if_forward<I,
0154         std::size_t>::type
0155       insert_size(I i, I j)
0156       {
0157         return static_cast<std::size_t>(std::distance(i, j));
0158       }
0159 
0160       template <class I>
0161       inline typename boost::unordered::detail::disable_if_forward<I,
0162         std::size_t>::type
0163       insert_size(I, I)
0164       {
0165         return 1;
0166       }
0167 
0168       template <class I>
0169       inline std::size_t initial_size(I i, I j,
0170         std::size_t num_buckets =
0171           boost::unordered::detail::default_bucket_count)
0172       {
0173         return (std::max)(
0174           boost::unordered::detail::insert_size(i, j), num_buckets);
0175       }
0176 
0177       //////////////////////////////////////////////////////////////////////////
0178       // compressed
0179 
0180       template <typename T, int Index>
0181       struct compressed_base : boost::empty_value<T>
0182       {
0183         compressed_base(T const& x) : empty_value<T>(boost::empty_init_t(), x)
0184         {
0185         }
0186         compressed_base(T& x, move_tag)
0187             : empty_value<T>(boost::empty_init_t(), std::move(x))
0188         {
0189         }
0190 
0191         T& get() { return empty_value<T>::get(); }
0192         T const& get() const { return empty_value<T>::get(); }
0193       };
0194 
0195       template <typename T, int Index>
0196       struct generate_base : boost::unordered::detail::compressed_base<T, Index>
0197       {
0198         typedef compressed_base<T, Index> type;
0199 
0200         generate_base() : type() {}
0201       };
0202 
0203       template <typename T1, typename T2>
0204       struct compressed
0205           : private boost::unordered::detail::generate_base<T1, 1>::type,
0206             private boost::unordered::detail::generate_base<T2, 2>::type
0207       {
0208         typedef typename generate_base<T1, 1>::type base1;
0209         typedef typename generate_base<T2, 2>::type base2;
0210 
0211         typedef T1 first_type;
0212         typedef T2 second_type;
0213 
0214         first_type& first() { return static_cast<base1*>(this)->get(); }
0215 
0216         first_type const& first() const
0217         {
0218           return static_cast<base1 const*>(this)->get();
0219         }
0220 
0221         second_type& second() { return static_cast<base2*>(this)->get(); }
0222 
0223         second_type const& second() const
0224         {
0225           return static_cast<base2 const*>(this)->get();
0226         }
0227 
0228         template <typename First, typename Second>
0229         compressed(First const& x1, Second const& x2) : base1(x1), base2(x2)
0230         {
0231         }
0232 
0233         compressed(compressed const& x) : base1(x.first()), base2(x.second()) {}
0234 
0235         compressed(compressed& x, move_tag m)
0236             : base1(x.first(), m), base2(x.second(), m)
0237         {
0238         }
0239 
0240         void assign(compressed const& x)
0241         {
0242           first() = x.first();
0243           second() = x.second();
0244         }
0245 
0246         void move_assign(compressed& x)
0247         {
0248           first() = std::move(x.first());
0249           second() = std::move(x.second());
0250         }
0251 
0252         void swap(compressed& x)
0253         {
0254           boost::core::invoke_swap(first(), x.first());
0255           boost::core::invoke_swap(second(), x.second());
0256         }
0257 
0258       private:
0259         // Prevent assignment just to make use of assign or
0260         // move_assign explicit.
0261         compressed& operator=(compressed const&);
0262       };
0263 
0264       //////////////////////////////////////////////////////////////////////////
0265       // pair_traits
0266       //
0267       // Used to get the types from a pair without instantiating it.
0268 
0269       template <typename Pair> struct pair_traits
0270       {
0271         typedef typename Pair::first_type first_type;
0272         typedef typename Pair::second_type second_type;
0273       };
0274 
0275       template <typename T1, typename T2> struct pair_traits<std::pair<T1, T2> >
0276       {
0277         typedef T1 first_type;
0278         typedef T2 second_type;
0279       };
0280 
0281 #if defined(BOOST_MSVC)
0282 #pragma warning(push)
0283 #pragma warning(disable : 4512) // assignment operator could not be generated.
0284 #pragma warning(disable : 4345) // behavior change: an object of POD type
0285 // constructed with an initializer of the form ()
0286 // will be default-initialized.
0287 #endif
0288 
0289       //////////////////////////////////////////////////////////////////////////
0290       // Bits and pieces for implementing traits
0291 
0292       template <typename T> typename std::add_lvalue_reference<T>::type make();
0293       struct choice2
0294       {
0295         typedef char (&type)[2];
0296       };
0297       struct choice1 : choice2
0298       {
0299         typedef char (&type)[1];
0300       };
0301       choice1 choose();
0302 
0303       typedef choice1::type yes_type;
0304       typedef choice2::type no_type;
0305 
0306       struct private_type
0307       {
0308         private_type const& operator,(int) const;
0309       };
0310 
0311       template <typename T> no_type is_private_type(T const&);
0312       yes_type is_private_type(private_type const&);
0313 
0314       struct convert_from_anything
0315       {
0316         template <typename T> convert_from_anything(T const&);
0317       };
0318     } // namespace detail
0319   } // namespace unordered
0320 } // namespace boost
0321 
0322 ////////////////////////////////////////////////////////////////////////////////
0323 //
0324 // Some utilities for implementing allocator_traits, but useful elsewhere so
0325 // they're always defined.
0326 
0327 namespace boost {
0328   namespace unordered {
0329     namespace detail {
0330 
0331       ////////////////////////////////////////////////////////////////////////////
0332       // Explicitly call a destructor
0333 
0334 #if defined(BOOST_MSVC)
0335 #pragma warning(push)
0336 #pragma warning(disable : 4100) // unreferenced formal parameter
0337 #endif
0338 
0339       namespace func {
0340         template <class T> inline void destroy(T* x) { x->~T(); }
0341       } // namespace func
0342 
0343 #if defined(BOOST_MSVC)
0344 #pragma warning(pop)
0345 #endif
0346 
0347       //////////////////////////////////////////////////////////////////////////
0348       // value_base
0349       //
0350       // Space used to store values.
0351 
0352       template <typename ValueType> struct value_base
0353       {
0354         typedef ValueType value_type;
0355 
0356         opt_storage<value_type> data_;
0357 
0358         value_base() : data_() {}
0359 
0360         void* address() { return this; }
0361 
0362         value_type& value() { return *(ValueType*)this; }
0363 
0364         value_type const& value() const { return *(ValueType const*)this; }
0365 
0366         value_type* value_ptr() { return (ValueType*)this; }
0367 
0368         value_type const* value_ptr() const { return (ValueType const*)this; }
0369 
0370       private:
0371         value_base& operator=(value_base const&);
0372       };
0373 
0374       //////////////////////////////////////////////////////////////////////////
0375       // optional
0376       // TODO: Use std::optional when available.
0377 
0378       template <typename T> class optional
0379       {
0380         boost::unordered::detail::value_base<T> value_;
0381         bool has_value_;
0382 
0383         void destroy()
0384         {
0385           if (has_value_) {
0386             boost::unordered::detail::func::destroy(value_.value_ptr());
0387             has_value_ = false;
0388           }
0389         }
0390 
0391         void move(optional<T>& x)
0392         {
0393           BOOST_ASSERT(!has_value_ && x.has_value_);
0394           new (value_.value_ptr()) T(std::move(x.value_.value()));
0395           boost::unordered::detail::func::destroy(x.value_.value_ptr());
0396           has_value_ = true;
0397           x.has_value_ = false;
0398         }
0399 
0400       public:
0401         optional() noexcept : has_value_(false) {}
0402 
0403         optional(optional const&) = delete;
0404         optional& operator=(optional const&) = delete;
0405 
0406         optional(optional<T>&& x) : has_value_(false)
0407         {
0408           if (x.has_value_) {
0409             move(x);
0410           }
0411         }
0412 
0413         explicit optional(T const& x) : has_value_(true)
0414         {
0415           new (value_.value_ptr()) T(x);
0416         }
0417 
0418         optional& operator=(optional<T>&& x)
0419         {
0420           destroy();
0421           if (x.has_value_) {
0422             move(x);
0423           }
0424           return *this;
0425         }
0426 
0427         ~optional() { destroy(); }
0428 
0429         bool has_value() const { return has_value_; }
0430         T& operator*() { return value_.value(); }
0431         T const& operator*() const { return value_.value(); }
0432         T* operator->() { return value_.value_ptr(); }
0433         T const* operator->() const { return value_.value_ptr(); }
0434 
0435         bool operator==(optional<T> const& x) const
0436         {
0437           return has_value_ ? x.has_value_ && value_.value() == x.value_.value()
0438                             : !x.has_value_;
0439         }
0440 
0441         bool operator!=(optional<T> const& x) const { return !((*this) == x); }
0442 
0443         void swap(optional<T>& x)
0444         {
0445           if (has_value_ != x.has_value_) {
0446             if (has_value_) {
0447               x.move(*this);
0448             } else {
0449               move(x);
0450             }
0451           } else if (has_value_) {
0452             boost::core::invoke_swap(value_.value(), x.value_.value());
0453           }
0454         }
0455 
0456         friend void swap(optional<T>& x, optional<T>& y) { x.swap(y); }
0457       };
0458     } // namespace detail
0459   } // namespace unordered
0460 } // namespace boost
0461 
0462 ////////////////////////////////////////////////////////////////////////////////
0463 //
0464 // Allocator traits
0465 //
0466 
0467 namespace boost {
0468   namespace unordered {
0469     namespace detail {
0470 
0471       template <typename Alloc>
0472       struct allocator_traits : boost::allocator_traits<Alloc>
0473       {
0474       };
0475 
0476       template <typename Alloc, typename T>
0477       struct rebind_wrap : boost::allocator_rebind<Alloc, T>
0478       {
0479       };
0480     } // namespace detail
0481   } // namespace unordered
0482 } // namespace boost
0483 
0484 namespace boost {
0485   namespace unordered {
0486     namespace detail {
0487       namespace func {
0488         ////////////////////////////////////////////////////////////////////////
0489         // Trait to check for piecewise construction.
0490 
0491         template <typename A0> struct use_piecewise
0492         {
0493           static choice1::type test(choice1, std::piecewise_construct_t);
0494 
0495           static choice2::type test(choice2, ...);
0496 
0497           enum
0498           {
0499             value = sizeof(choice1::type) ==
0500                     sizeof(test(choose(), boost::unordered::detail::make<A0>()))
0501           };
0502         };
0503 
0504         ////////////////////////////////////////////////////////////////////////
0505         // Construct from variadic parameters
0506 
0507         template <typename Alloc, typename T, typename... Args>
0508         inline void construct_from_args(
0509           Alloc& alloc, T* address, Args&&... args)
0510         {
0511           boost::allocator_construct(
0512             alloc, address, std::forward<Args>(args)...);
0513         }
0514 
0515         // For backwards compatibility, implement a special case for
0516         // piecewise_construct with boost::tuple
0517 
0518         template <typename A0> struct detect_std_tuple
0519         {
0520           template <class... Args>
0521           static choice1::type test(choice1, std::tuple<Args...> const&);
0522 
0523           static choice2::type test(choice2, ...);
0524 
0525           enum
0526           {
0527             value = sizeof(choice1::type) ==
0528                     sizeof(test(choose(), boost::unordered::detail::make<A0>()))
0529           };
0530         };
0531 
0532         // Special case for piecewise_construct
0533 
0534         template <template <class...> class Tuple, class... Args,
0535           std::size_t... Is, class... TupleArgs>
0536         std::tuple<typename std::add_lvalue_reference<Args>::type...>
0537         to_std_tuple_impl(boost::mp11::mp_list<Args...>,
0538           Tuple<TupleArgs...>& tuple, boost::mp11::index_sequence<Is...>)
0539         {
0540           (void)tuple;
0541           using std::get;
0542           return std::tuple<typename std::add_lvalue_reference<Args>::type...>(
0543             get<Is>(tuple)...);
0544         }
0545 
0546         template <class T>
0547         using add_lvalue_reference_t =
0548           typename std::add_lvalue_reference<T>::type;
0549 
0550         template <template <class...> class Tuple, class... Args>
0551         boost::mp11::mp_transform<add_lvalue_reference_t,
0552           boost::mp11::mp_remove<std::tuple<Args...>,
0553             boost::tuples::null_type> >
0554         to_std_tuple(Tuple<Args...>& tuple)
0555         {
0556           using list = boost::mp11::mp_remove<boost::mp11::mp_list<Args...>,
0557             boost::tuples::null_type>;
0558           using list_size = boost::mp11::mp_size<list>;
0559           using index_seq = boost::mp11::make_index_sequence<list_size::value>;
0560 
0561           return to_std_tuple_impl(list{}, tuple, index_seq{});
0562         }
0563 
0564         template <typename Alloc, typename A, typename B, typename A0,
0565           typename A1, typename A2>
0566         inline typename std::enable_if<use_piecewise<A0>::value &&
0567                                          !detect_std_tuple<A1>::value &&
0568                                          !detect_std_tuple<A2>::value,
0569           void>::type
0570         construct_from_args(
0571           Alloc& alloc, std::pair<A, B>* address, A0&&, A1&& a1, A2&& a2)
0572         {
0573           boost::allocator_construct(alloc, address, std::piecewise_construct,
0574             to_std_tuple(a1), to_std_tuple(a2));
0575         }
0576       } // namespace func
0577     } // namespace detail
0578   } // namespace unordered
0579 } // namespace boost
0580 
0581 namespace boost {
0582   namespace unordered {
0583     namespace detail {
0584 
0585       ///////////////////////////////////////////////////////////////////
0586       //
0587       // Node construction
0588 
0589       template <typename NodeAlloc> struct node_constructor
0590       {
0591         typedef NodeAlloc node_allocator;
0592         typedef boost::unordered::detail::allocator_traits<NodeAlloc>
0593           node_allocator_traits;
0594         typedef typename node_allocator_traits::value_type node;
0595         typedef typename node_allocator_traits::pointer node_pointer;
0596         typedef typename node::value_type value_type;
0597 
0598         node_allocator& alloc_;
0599         node_pointer node_;
0600 
0601         node_constructor(node_allocator& n) : alloc_(n), node_() {}
0602 
0603         ~node_constructor();
0604 
0605         void create_node();
0606 
0607         // no throw
0608         node_pointer release()
0609         {
0610           BOOST_ASSERT(node_);
0611           node_pointer p = node_;
0612           node_ = node_pointer();
0613           return p;
0614         }
0615 
0616       private:
0617         node_constructor(node_constructor const&);
0618         node_constructor& operator=(node_constructor const&);
0619       };
0620 
0621       template <typename Alloc> node_constructor<Alloc>::~node_constructor()
0622       {
0623         if (node_) {
0624           boost::unordered::detail::func::destroy(boost::to_address(node_));
0625           node_allocator_traits::deallocate(alloc_, node_, 1);
0626         }
0627       }
0628 
0629       template <typename Alloc> void node_constructor<Alloc>::create_node()
0630       {
0631         BOOST_ASSERT(!node_);
0632         node_ = node_allocator_traits::allocate(alloc_, 1);
0633         new ((void*)boost::to_address(node_)) node();
0634       }
0635 
0636       template <typename NodeAlloc> struct node_tmp
0637       {
0638         typedef typename boost::allocator_value_type<NodeAlloc>::type node;
0639         typedef typename boost::allocator_pointer<NodeAlloc>::type node_pointer;
0640         typedef typename node::value_type value_type;
0641         typedef typename boost::allocator_rebind<NodeAlloc, value_type>::type
0642           value_allocator;
0643 
0644         NodeAlloc& alloc_;
0645         node_pointer node_;
0646 
0647         explicit node_tmp(node_pointer n, NodeAlloc& a) : alloc_(a), node_(n) {}
0648 
0649         ~node_tmp();
0650 
0651         // no throw
0652         node_pointer release()
0653         {
0654           node_pointer p = node_;
0655           node_ = node_pointer();
0656           return p;
0657         }
0658       };
0659 
0660       template <typename Alloc> node_tmp<Alloc>::~node_tmp()
0661       {
0662         if (node_) {
0663           value_allocator val_alloc(alloc_);
0664           boost::allocator_destroy(val_alloc, node_->value_ptr());
0665           boost::allocator_deallocate(alloc_, node_, 1);
0666         }
0667       }
0668     } // namespace detail
0669   } // namespace unordered
0670 } // namespace boost
0671 
0672 namespace boost {
0673   namespace unordered {
0674     namespace detail {
0675       namespace func {
0676 
0677         // Some nicer construct_node functions, might try to
0678         // improve implementation later.
0679 
0680         template <typename Alloc, typename... Args>
0681         inline typename boost::allocator_pointer<Alloc>::type
0682         construct_node_from_args(Alloc& alloc, Args&&... args)
0683         {
0684           typedef typename boost::allocator_value_type<Alloc>::type node;
0685           typedef typename node::value_type value_type;
0686           typedef typename boost::allocator_rebind<Alloc, value_type>::type
0687             value_allocator;
0688 
0689           value_allocator val_alloc(alloc);
0690 
0691           node_constructor<Alloc> a(alloc);
0692           a.create_node();
0693           construct_from_args(
0694             val_alloc, a.node_->value_ptr(), std::forward<Args>(args)...);
0695           return a.release();
0696         }
0697 
0698         template <typename Alloc, typename U>
0699         inline typename boost::allocator_pointer<Alloc>::type construct_node(
0700           Alloc& alloc, U&& x)
0701         {
0702           node_constructor<Alloc> a(alloc);
0703           a.create_node();
0704 
0705           typedef typename boost::allocator_value_type<Alloc>::type node;
0706           typedef typename node::value_type value_type;
0707           typedef typename boost::allocator_rebind<Alloc, value_type>::type
0708             value_allocator;
0709 
0710           value_allocator val_alloc(alloc);
0711 
0712           boost::allocator_construct(
0713             val_alloc, a.node_->value_ptr(), std::forward<U>(x));
0714           return a.release();
0715         }
0716 
0717         template <typename Alloc, typename Key>
0718         inline typename boost::allocator_pointer<Alloc>::type
0719         construct_node_pair(Alloc& alloc, Key&& k)
0720         {
0721           node_constructor<Alloc> a(alloc);
0722           a.create_node();
0723 
0724           typedef typename boost::allocator_value_type<Alloc>::type node;
0725           typedef typename node::value_type value_type;
0726           typedef typename boost::allocator_rebind<Alloc, value_type>::type
0727             value_allocator;
0728 
0729           value_allocator val_alloc(alloc);
0730 
0731           boost::allocator_construct(val_alloc, a.node_->value_ptr(),
0732             std::piecewise_construct,
0733             std::forward_as_tuple(std::forward<Key>(k)),
0734             std::forward_as_tuple());
0735           return a.release();
0736         }
0737 
0738         template <typename Alloc, typename Key, typename Mapped>
0739         inline typename boost::allocator_pointer<Alloc>::type
0740         construct_node_pair(Alloc& alloc, Key&& k, Mapped&& m)
0741         {
0742           node_constructor<Alloc> a(alloc);
0743           a.create_node();
0744 
0745           typedef typename boost::allocator_value_type<Alloc>::type node;
0746           typedef typename node::value_type value_type;
0747           typedef typename boost::allocator_rebind<Alloc, value_type>::type
0748             value_allocator;
0749 
0750           value_allocator val_alloc(alloc);
0751 
0752           boost::allocator_construct(val_alloc, a.node_->value_ptr(),
0753             std::piecewise_construct,
0754             std::forward_as_tuple(std::forward<Key>(k)),
0755             std::forward_as_tuple(std::forward<Mapped>(m)));
0756           return a.release();
0757         }
0758 
0759         template <typename Alloc, typename Key, typename... Args>
0760         inline typename boost::allocator_pointer<Alloc>::type
0761         construct_node_pair_from_args(Alloc& alloc, Key&& k, Args&&... args)
0762         {
0763           node_constructor<Alloc> a(alloc);
0764           a.create_node();
0765 
0766           typedef typename boost::allocator_value_type<Alloc>::type node;
0767           typedef typename node::value_type value_type;
0768           typedef typename boost::allocator_rebind<Alloc, value_type>::type
0769             value_allocator;
0770 
0771           value_allocator val_alloc(alloc);
0772 
0773           boost::allocator_construct(val_alloc, a.node_->value_ptr(),
0774             std::piecewise_construct,
0775             std::forward_as_tuple(std::forward<Key>(k)),
0776             std::forward_as_tuple(std::forward<Args>(args)...));
0777 
0778           return a.release();
0779         }
0780 
0781         template <typename T, typename Alloc, typename Key>
0782         inline typename boost::allocator_pointer<Alloc>::type
0783         construct_node_from_key(T*, Alloc& alloc, Key&& k)
0784         {
0785           return construct_node(alloc, std::forward<Key>(k));
0786         }
0787 
0788         template <typename T, typename V, typename Alloc, typename Key>
0789         inline typename boost::allocator_pointer<Alloc>::type
0790         construct_node_from_key(std::pair<T const, V>*, Alloc& alloc, Key&& k)
0791         {
0792           return construct_node_pair(alloc, std::forward<Key>(k));
0793         }
0794       } // namespace func
0795     } // namespace detail
0796   } // namespace unordered
0797 } // namespace boost
0798 
0799 #if defined(BOOST_MSVC)
0800 #pragma warning(pop)
0801 #endif
0802 
0803 namespace boost {
0804   namespace unordered {
0805     namespace detail {
0806       //////////////////////////////////////////////////////////////////////////
0807       // Functions
0808       //
0809       // This double buffers the storage for the hash function and key equality
0810       // predicate in order to have exception safe copy/swap. To do so,
0811       // use 'construct_spare' to construct in the spare space, and then when
0812       // ready to use 'switch_functions' to switch to the new functions.
0813       // If an exception is thrown between these two calls, use
0814       // 'cleanup_spare_functions' to destroy the unused constructed functions.
0815 
0816 #if defined(_GLIBCXX_HAVE_BUILTIN_LAUNDER)
0817       // gcc-12 warns when accessing the `current_functions` of our `functions`
0818       // class below with `-Wmaybe-unitialized`. By laundering the pointer, we
0819       // silence the warning and assure the compiler that a valid object exists
0820       // in that region of storage. This warning is also generated in C++03
0821       // which does not have `std::launder`. The compiler builtin is always
0822       // available, regardless of the C++ standard used when compiling.
0823       template <class T> T* launder(T* p) noexcept
0824       {
0825         return __builtin_launder(p);
0826       }
0827 #else
0828       template <class T> T* launder(T* p) noexcept { return p; }
0829 #endif
0830 
0831       template <class H, class P> class functions
0832       {
0833       public:
0834         static const bool nothrow_move_assignable =
0835           std::is_nothrow_move_assignable<H>::value &&
0836           std::is_nothrow_move_assignable<P>::value;
0837         static const bool nothrow_move_constructible =
0838           std::is_nothrow_move_constructible<H>::value &&
0839           std::is_nothrow_move_constructible<P>::value;
0840         static const bool nothrow_swappable =
0841           boost::unordered::detail::is_nothrow_swappable<H>::value &&
0842           boost::unordered::detail::is_nothrow_swappable<P>::value;
0843 
0844       private:
0845         functions& operator=(functions const&);
0846 
0847         typedef compressed<H, P> function_pair;
0848 
0849         unsigned char current_; // 0/1 - Currently active functions
0850                                 // +2 - Both constructed
0851         opt_storage<function_pair> funcs_[2];
0852 
0853       public:
0854         functions(H const& hf, P const& eq) : current_(0)
0855         {
0856           construct_functions(current_, hf, eq);
0857         }
0858 
0859         functions(functions const& bf) : current_(0)
0860         {
0861           construct_functions(current_, bf.current_functions());
0862         }
0863 
0864         functions(functions& bf, boost::unordered::detail::move_tag)
0865             : current_(0)
0866         {
0867           construct_functions(current_, bf.current_functions(),
0868             std::integral_constant<bool, nothrow_move_constructible>());
0869         }
0870 
0871         ~functions()
0872         {
0873           BOOST_ASSERT(!(current_ & 2));
0874           destroy_functions(current_);
0875         }
0876 
0877         H const& hash_function() const { return current_functions().first(); }
0878 
0879         P const& key_eq() const { return current_functions().second(); }
0880 
0881         function_pair const& current_functions() const
0882         {
0883           return *::boost::unordered::detail::launder(
0884             static_cast<function_pair const*>(
0885               static_cast<void const*>(funcs_[current_ & 1].address())));
0886         }
0887 
0888         function_pair& current_functions()
0889         {
0890           return *::boost::unordered::detail::launder(
0891             static_cast<function_pair*>(
0892               static_cast<void*>(funcs_[current_ & 1].address())));
0893         }
0894 
0895         void construct_spare_functions(function_pair const& f)
0896         {
0897           BOOST_ASSERT(!(current_ & 2));
0898           construct_functions(current_ ^ 1, f);
0899           current_ |= 2;
0900         }
0901 
0902         void cleanup_spare_functions()
0903         {
0904           if (current_ & 2) {
0905             current_ = static_cast<unsigned char>(current_ & 1);
0906             destroy_functions(current_ ^ 1);
0907           }
0908         }
0909 
0910         void switch_functions()
0911         {
0912           BOOST_ASSERT(current_ & 2);
0913           destroy_functions(static_cast<unsigned char>(current_ & 1));
0914           current_ ^= 3;
0915         }
0916 
0917       private:
0918         void construct_functions(unsigned char which, H const& hf, P const& eq)
0919         {
0920           BOOST_ASSERT(!(which & 2));
0921           new ((void*)&funcs_[which]) function_pair(hf, eq);
0922         }
0923 
0924         void construct_functions(
0925           unsigned char which, function_pair const& f, std::false_type = {})
0926         {
0927           BOOST_ASSERT(!(which & 2));
0928           new ((void*)&funcs_[which]) function_pair(f);
0929         }
0930 
0931         void construct_functions(
0932           unsigned char which, function_pair& f, std::true_type)
0933         {
0934           BOOST_ASSERT(!(which & 2));
0935           new ((void*)&funcs_[which])
0936             function_pair(f, boost::unordered::detail::move_tag());
0937         }
0938 
0939         void destroy_functions(unsigned char which)
0940         {
0941           BOOST_ASSERT(!(which & 2));
0942           boost::unordered::detail::func::destroy(
0943             (function_pair*)(&funcs_[which]));
0944         }
0945       };
0946 
0947 #if defined(BOOST_MSVC)
0948 #pragma warning(push)
0949 #pragma warning(disable : 4127) // conditional expression is constant
0950 #endif
0951 
0952       //////////////////////////////////////////////////////////////////////////
0953       // convert double to std::size_t
0954 
0955       inline std::size_t double_to_size(double f)
0956       {
0957         return f >= static_cast<double>(
0958                       (std::numeric_limits<std::size_t>::max)())
0959                  ? (std::numeric_limits<std::size_t>::max)()
0960                  : static_cast<std::size_t>(f);
0961       }
0962 
0963       //////////////////////////////////////////////////////////////////////////
0964       // iterator definitions
0965 
0966       namespace iterator_detail {
0967         template <class Node, class Bucket> class c_iterator;
0968 
0969         template <class Node, class Bucket> class iterator
0970         {
0971         public:
0972           typedef typename Node::value_type value_type;
0973           typedef value_type element_type;
0974           typedef value_type* pointer;
0975           typedef value_type& reference;
0976           typedef std::ptrdiff_t difference_type;
0977           typedef std::forward_iterator_tag iterator_category;
0978 
0979           iterator() : p(), itb() {}
0980 
0981           reference operator*() const noexcept { return dereference(); }
0982           pointer operator->() const noexcept
0983           {
0984             pointer x = std::addressof(p->value());
0985             return x;
0986           }
0987 
0988           iterator& operator++() noexcept
0989           {
0990             increment();
0991             return *this;
0992           }
0993 
0994           iterator operator++(int) noexcept
0995           {
0996             iterator old = *this;
0997             increment();
0998             return old;
0999           }
1000 
1001           bool operator==(iterator const& other) const noexcept
1002           {
1003             return equal(other);
1004           }
1005 
1006           bool operator!=(iterator const& other) const noexcept
1007           {
1008             return !equal(other);
1009           }
1010 
1011           bool operator==(
1012             boost::unordered::detail::iterator_detail::c_iterator<Node,
1013               Bucket> const& other) const noexcept
1014           {
1015             return equal(other);
1016           }
1017 
1018           bool operator!=(
1019             boost::unordered::detail::iterator_detail::c_iterator<Node,
1020               Bucket> const& other) const noexcept
1021           {
1022             return !equal(other);
1023           }
1024 
1025         private:
1026           typedef typename Node::node_pointer node_pointer;
1027           typedef grouped_bucket_iterator<Bucket> bucket_iterator;
1028 
1029           node_pointer p;
1030           bucket_iterator itb;
1031 
1032           template <class Types> friend struct boost::unordered::detail::table;
1033           template <class N, class B> friend class c_iterator;
1034 
1035           iterator(node_pointer p_, bucket_iterator itb_) : p(p_), itb(itb_) {}
1036 
1037           value_type& dereference() const noexcept { return p->value(); }
1038 
1039           bool equal(const iterator& x) const noexcept { return (p == x.p); }
1040 
1041           bool equal(
1042             const boost::unordered::detail::iterator_detail::c_iterator<Node,
1043               Bucket>& x) const noexcept
1044           {
1045             return (p == x.p);
1046           }
1047 
1048           void increment() noexcept
1049           {
1050             p = p->next;
1051             if (!p) {
1052               p = (++itb)->next;
1053             }
1054           }
1055 
1056           template <typename Archive>
1057           friend void serialization_track(Archive& ar, const iterator& x)
1058           {
1059             if (x.p) {
1060               track_address(ar, x.p);
1061               serialization_track(ar, x.itb);
1062             }
1063           }
1064 
1065           friend class boost::serialization::access;
1066 
1067           template <typename Archive> void serialize(Archive& ar, unsigned int)
1068           {
1069             if (!p)
1070               itb = bucket_iterator();
1071             serialize_tracked_address(ar, p);
1072             ar& core::make_nvp("bucket_iterator", itb);
1073           }
1074         };
1075 
1076         template <class Node, class Bucket> class c_iterator
1077         {
1078         public:
1079           typedef typename Node::value_type value_type;
1080           typedef value_type const element_type;
1081           typedef value_type const* pointer;
1082           typedef value_type const& reference;
1083           typedef std::ptrdiff_t difference_type;
1084           typedef std::forward_iterator_tag iterator_category;
1085 
1086           c_iterator() : p(), itb() {}
1087           c_iterator(iterator<Node, Bucket> it) : p(it.p), itb(it.itb) {}
1088 
1089           reference operator*() const noexcept { return dereference(); }
1090           pointer operator->() const noexcept
1091           {
1092             pointer x = std::addressof(p->value());
1093             return x;
1094           }
1095 
1096           c_iterator& operator++() noexcept
1097           {
1098             increment();
1099             return *this;
1100           }
1101 
1102           c_iterator operator++(int) noexcept
1103           {
1104             c_iterator old = *this;
1105             increment();
1106             return old;
1107           }
1108 
1109           bool operator==(c_iterator const& other) const noexcept
1110           {
1111             return equal(other);
1112           }
1113 
1114           bool operator!=(c_iterator const& other) const noexcept
1115           {
1116             return !equal(other);
1117           }
1118 
1119           bool operator==(
1120             boost::unordered::detail::iterator_detail::iterator<Node,
1121               Bucket> const& other) const noexcept
1122           {
1123             return equal(other);
1124           }
1125 
1126           bool operator!=(
1127             boost::unordered::detail::iterator_detail::iterator<Node,
1128               Bucket> const& other) const noexcept
1129           {
1130             return !equal(other);
1131           }
1132 
1133         private:
1134           typedef typename Node::node_pointer node_pointer;
1135           typedef grouped_bucket_iterator<Bucket> bucket_iterator;
1136 
1137           node_pointer p;
1138           bucket_iterator itb;
1139 
1140           template <class Types> friend struct boost::unordered::detail::table;
1141           template <class, class> friend class iterator;
1142 
1143           c_iterator(node_pointer p_, bucket_iterator itb_) : p(p_), itb(itb_)
1144           {
1145           }
1146 
1147           value_type const& dereference() const noexcept { return p->value(); }
1148 
1149           bool equal(const c_iterator& x) const noexcept { return (p == x.p); }
1150 
1151           void increment() noexcept
1152           {
1153             p = p->next;
1154             if (!p) {
1155               p = (++itb)->next;
1156             }
1157           }
1158 
1159           template <typename Archive>
1160           friend void serialization_track(Archive& ar, const c_iterator& x)
1161           {
1162             if (x.p) {
1163               track_address(ar, x.p);
1164               serialization_track(ar, x.itb);
1165             }
1166           }
1167 
1168           friend class boost::serialization::access;
1169 
1170           template <typename Archive> void serialize(Archive& ar, unsigned int)
1171           {
1172             if (!p)
1173               itb = bucket_iterator();
1174             serialize_tracked_address(ar, p);
1175             ar& core::make_nvp("bucket_iterator", itb);
1176           }
1177         };
1178       } // namespace iterator_detail
1179 
1180       //////////////////////////////////////////////////////////////////////////
1181       // table structure used by the containers
1182       template <typename Types>
1183       struct table : boost::unordered::detail::functions<typename Types::hasher,
1184                        typename Types::key_equal>
1185       {
1186       private:
1187         table(table const&);
1188         table& operator=(table const&);
1189 
1190       public:
1191         typedef typename Types::hasher hasher;
1192         typedef typename Types::key_equal key_equal;
1193         typedef typename Types::const_key_type const_key_type;
1194         typedef typename Types::extractor extractor;
1195         typedef typename Types::value_type value_type;
1196         typedef typename Types::table table_impl;
1197 
1198         typedef boost::unordered::detail::functions<typename Types::hasher,
1199           typename Types::key_equal>
1200           functions;
1201 
1202         typedef typename Types::value_allocator value_allocator;
1203         typedef typename boost::allocator_void_pointer<value_allocator>::type
1204           void_pointer;
1205         typedef node<value_type, void_pointer> node_type;
1206 
1207         typedef boost::unordered::detail::grouped_bucket_array<
1208           bucket<node_type, void_pointer>, value_allocator, prime_fmod_size<> >
1209           bucket_array_type;
1210 
1211         typedef
1212           typename bucket_array_type::node_allocator_type node_allocator_type;
1213         typedef typename boost::allocator_pointer<node_allocator_type>::type
1214           node_pointer;
1215 
1216         typedef boost::unordered::detail::node_constructor<node_allocator_type>
1217           node_constructor;
1218         typedef boost::unordered::detail::node_tmp<node_allocator_type>
1219           node_tmp;
1220 
1221         typedef typename bucket_array_type::bucket_type bucket_type;
1222 
1223         typedef typename bucket_array_type::iterator bucket_iterator;
1224 
1225         typedef typename bucket_array_type::local_iterator l_iterator;
1226         typedef typename bucket_array_type::const_local_iterator cl_iterator;
1227 
1228         typedef std::size_t size_type;
1229 
1230         typedef iterator_detail::iterator<node_type, bucket_type> iterator;
1231         typedef iterator_detail::c_iterator<node_type, bucket_type> c_iterator;
1232 
1233         typedef std::pair<iterator, bool> emplace_return;
1234 
1235         ////////////////////////////////////////////////////////////////////////
1236         // Members
1237 
1238         std::size_t size_;
1239         float mlf_;
1240         std::size_t max_load_;
1241         bucket_array_type buckets_;
1242 
1243       public:
1244         ////////////////////////////////////////////////////////////////////////
1245         // Data access
1246 
1247         size_type bucket_count() const { return buckets_.bucket_count(); }
1248 
1249         template <class Key>
1250         iterator next_group(Key const& k, c_iterator n) const
1251         {
1252           c_iterator last = this->end();
1253           while (n != last && this->key_eq()(k, extractor::extract(*n))) {
1254             ++n;
1255           }
1256           return iterator(n.p, n.itb);
1257         }
1258 
1259         template <class Key> std::size_t group_count(Key const& k) const
1260         {
1261           if (size_ == 0) {
1262             return 0;
1263           }
1264           std::size_t c = 0;
1265           std::size_t const key_hash = this->hash(k);
1266           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
1267 
1268           bool found = false;
1269 
1270           for (node_pointer pos = itb->next; pos; pos = pos->next) {
1271             if (this->key_eq()(k, this->get_key(pos))) {
1272               ++c;
1273               found = true;
1274             } else if (found) {
1275               break;
1276             }
1277           }
1278           return c;
1279         }
1280 
1281         node_allocator_type const& node_alloc() const
1282         {
1283           return buckets_.get_node_allocator();
1284         }
1285 
1286         node_allocator_type& node_alloc()
1287         {
1288           return buckets_.get_node_allocator();
1289         }
1290 
1291         std::size_t max_bucket_count() const
1292         {
1293           typedef typename bucket_array_type::size_policy size_policy;
1294           return size_policy::size(size_policy::size_index(
1295             boost::allocator_max_size(this->node_alloc())));
1296         }
1297 
1298         iterator begin() const
1299         {
1300           if (size_ == 0) {
1301             return end();
1302           }
1303 
1304           bucket_iterator itb = buckets_.begin();
1305           return iterator(itb->next, itb);
1306         }
1307 
1308         iterator end() const { return iterator(); }
1309 
1310         l_iterator begin(std::size_t bucket_index) const
1311         {
1312           return buckets_.begin(bucket_index);
1313         }
1314 
1315         std::size_t hash_to_bucket(std::size_t hash_value) const
1316         {
1317           return buckets_.position(hash_value);
1318         }
1319 
1320         std::size_t bucket_size(std::size_t index) const
1321         {
1322           std::size_t count = 0;
1323           if (size_ > 0) {
1324             bucket_iterator itb = buckets_.at(index);
1325             node_pointer n = itb->next;
1326             while (n) {
1327               ++count;
1328               n = n->next;
1329             }
1330           }
1331           return count;
1332         }
1333 
1334         ////////////////////////////////////////////////////////////////////////
1335         // Load methods
1336 
1337         void recalculate_max_load()
1338         {
1339           // From 6.3.1/13:
1340           // Only resize when size >= mlf_ * count
1341           std::size_t const bc = buckets_.bucket_count();
1342 
1343           // it's important we do the `bc == 0` check here because the `mlf_`
1344           // can be specified to be infinity. The operation `n * INF` is `INF`
1345           // for all `n > 0` but NaN for `n == 0`.
1346           //
1347           max_load_ =
1348             bc == 0 ? 0
1349                     : boost::unordered::detail::double_to_size(
1350                         static_cast<double>(mlf_) * static_cast<double>(bc));
1351         }
1352 
1353         void max_load_factor(float z)
1354         {
1355           BOOST_ASSERT(z > 0);
1356           mlf_ = (std::max)(z, minimum_max_load_factor);
1357           recalculate_max_load();
1358         }
1359 
1360         ////////////////////////////////////////////////////////////////////////
1361         // Constructors
1362 
1363         table()
1364             : functions(hasher(), key_equal()), size_(0), mlf_(1.0f),
1365               max_load_(0)
1366         {
1367         }
1368 
1369         table(std::size_t num_buckets, hasher const& hf, key_equal const& eq,
1370           value_allocator const& a)
1371             : functions(hf, eq), size_(0), mlf_(1.0f), max_load_(0),
1372               buckets_(num_buckets, a)
1373         {
1374           recalculate_max_load();
1375         }
1376 
1377         table(table const& x, value_allocator const& a)
1378             : functions(x), size_(0), mlf_(x.mlf_), max_load_(0),
1379               buckets_(x.size_, a)
1380         {
1381           recalculate_max_load();
1382         }
1383 
1384         table(table& x, boost::unordered::detail::move_tag m)
1385             : functions(x, m), size_(x.size_), mlf_(x.mlf_),
1386               max_load_(x.max_load_), buckets_(std::move(x.buckets_))
1387         {
1388           x.size_ = 0;
1389           x.max_load_ = 0;
1390         }
1391 
1392         table(table& x, value_allocator const& a,
1393           boost::unordered::detail::move_tag m)
1394             : functions(x, m), size_(0), mlf_(x.mlf_), max_load_(0),
1395               buckets_(x.bucket_count(), a)
1396         {
1397           recalculate_max_load();
1398         }
1399 
1400         ////////////////////////////////////////////////////////////////////////
1401         // Swap and Move
1402 
1403         void swap_allocators(table& other, std::false_type)
1404         {
1405           boost::unordered::detail::func::ignore_unused_variable_warning(other);
1406 
1407           // According to 23.2.1.8, if propagate_on_container_swap is
1408           // false the behaviour is undefined unless the allocators
1409           // are equal.
1410           BOOST_ASSERT(node_alloc() == other.node_alloc());
1411         }
1412 
1413         // Not nothrow swappable
1414         void swap(table& x, std::false_type)
1415         {
1416           if (this == &x) {
1417             return;
1418           }
1419 
1420           this->construct_spare_functions(x.current_functions());
1421           BOOST_TRY { x.construct_spare_functions(this->current_functions()); }
1422           BOOST_CATCH(...)
1423           {
1424             this->cleanup_spare_functions();
1425             BOOST_RETHROW
1426           }
1427           BOOST_CATCH_END
1428           this->switch_functions();
1429           x.switch_functions();
1430 
1431           buckets_.swap(x.buckets_);
1432           boost::core::invoke_swap(size_, x.size_);
1433           std::swap(mlf_, x.mlf_);
1434           std::swap(max_load_, x.max_load_);
1435         }
1436 
1437         // Nothrow swappable
1438         void swap(table& x, std::true_type)
1439         {
1440           buckets_.swap(x.buckets_);
1441           boost::core::invoke_swap(size_, x.size_);
1442           std::swap(mlf_, x.mlf_);
1443           std::swap(max_load_, x.max_load_);
1444           this->current_functions().swap(x.current_functions());
1445         }
1446 
1447         // Only swaps the allocators if propagate_on_container_swap.
1448         // If not propagate_on_container_swap and allocators aren't
1449         // equal, behaviour is undefined.
1450         void swap(table& x)
1451         {
1452           BOOST_ASSERT(boost::allocator_propagate_on_container_swap<
1453                          node_allocator_type>::type::value ||
1454                        node_alloc() == x.node_alloc());
1455           swap(x, std::integral_constant<bool, functions::nothrow_swappable>());
1456         }
1457 
1458         // Only call with nodes allocated with the currect allocator, or
1459         // one that is equal to it. (Can't assert because other's
1460         // allocators might have already been moved).
1461         void move_buckets_from(table& other)
1462         {
1463           buckets_ = std::move(other.buckets_);
1464 
1465           size_ = other.size_;
1466           max_load_ = other.max_load_;
1467 
1468           other.size_ = 0;
1469           other.max_load_ = 0;
1470         }
1471 
1472         // For use in the constructor when allocators might be different.
1473         void move_construct_buckets(table& src)
1474         {
1475           if (this->node_alloc() == src.node_alloc()) {
1476             move_buckets_from(src);
1477             return;
1478           }
1479 
1480           if (src.size_ == 0) {
1481             return;
1482           }
1483 
1484           BOOST_ASSERT(buckets_.bucket_count() == src.buckets_.bucket_count());
1485 
1486           this->reserve(src.size_);
1487           for (iterator pos = src.begin(); pos != src.end(); ++pos) {
1488             node_tmp b(detail::func::construct_node(
1489                          this->node_alloc(), std::move(pos.p->value())),
1490               this->node_alloc());
1491 
1492             const_key_type& k = this->get_key(b.node_);
1493             std::size_t key_hash = this->hash(k);
1494 
1495             bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
1496             buckets_.insert_node(itb, b.release());
1497             ++size_;
1498           }
1499         }
1500 
1501         ////////////////////////////////////////////////////////////////////////
1502         // Delete/destruct
1503 
1504         ~table() { delete_buckets(); }
1505 
1506         void delete_node(node_pointer p)
1507         {
1508           node_allocator_type alloc = this->node_alloc();
1509 
1510           value_allocator val_alloc(alloc);
1511           boost::allocator_destroy(val_alloc, p->value_ptr());
1512           boost::unordered::detail::func::destroy(boost::to_address(p));
1513           boost::allocator_deallocate(alloc, p, 1);
1514         }
1515 
1516         void delete_buckets()
1517         {
1518           iterator pos = begin(), last = this->end();
1519           for (; pos != last;) {
1520             node_pointer p = pos.p;
1521             bucket_iterator itb = pos.itb;
1522             ++pos;
1523             buckets_.extract_node(itb, p);
1524             delete_node(p);
1525             --size_;
1526           }
1527 
1528           buckets_.clear();
1529         }
1530 
1531         ////////////////////////////////////////////////////////////////////////
1532         // Clear
1533 
1534         void clear_impl();
1535 
1536         ////////////////////////////////////////////////////////////////////////
1537         // Assignment
1538 
1539         template <typename UniqueType>
1540         void assign(table const& x, UniqueType is_unique)
1541         {
1542           typedef
1543             typename boost::allocator_propagate_on_container_copy_assignment<
1544               node_allocator_type>::type pocca;
1545 
1546           if (this != &x) {
1547             assign(x, is_unique, std::integral_constant<bool, pocca::value>());
1548           }
1549         }
1550 
1551         template <typename UniqueType>
1552         void assign(table const& x, UniqueType is_unique, std::false_type)
1553         {
1554           // Strong exception safety.
1555           this->construct_spare_functions(x.current_functions());
1556           BOOST_TRY
1557           {
1558             mlf_ = x.mlf_;
1559             recalculate_max_load();
1560 
1561             this->reserve_for_insert(x.size_);
1562             this->clear_impl();
1563           }
1564           BOOST_CATCH(...)
1565           {
1566             this->cleanup_spare_functions();
1567             BOOST_RETHROW
1568           }
1569           BOOST_CATCH_END
1570           this->switch_functions();
1571           copy_buckets(x, is_unique);
1572         }
1573 
1574         template <typename UniqueType>
1575         void assign(table const& x, UniqueType is_unique, std::true_type)
1576         {
1577           if (node_alloc() == x.node_alloc()) {
1578             buckets_.reset_allocator(x.node_alloc());
1579             assign(x, is_unique, std::false_type());
1580           } else {
1581             bucket_array_type new_buckets(x.size_, x.node_alloc());
1582             this->construct_spare_functions(x.current_functions());
1583             this->switch_functions();
1584 
1585             // Delete everything with current allocators before assigning
1586             // the new ones.
1587             delete_buckets();
1588             buckets_.reset_allocator(x.node_alloc());
1589             buckets_ = std::move(new_buckets);
1590 
1591             // Copy over other data, all no throw.
1592             mlf_ = x.mlf_;
1593             reserve(x.size_);
1594 
1595             // Finally copy the elements.
1596             if (x.size_) {
1597               copy_buckets(x, is_unique);
1598             }
1599           }
1600         }
1601 
1602         template <typename UniqueType>
1603         void move_assign(table& x, UniqueType is_unique)
1604         {
1605           if (this != &x) {
1606             move_assign(x, is_unique,
1607               std::integral_constant<bool,
1608                 boost::allocator_propagate_on_container_move_assignment<
1609                   node_allocator_type>::type::value>());
1610           }
1611         }
1612 
1613         // Propagate allocator
1614         template <typename UniqueType>
1615         void move_assign(table& x, UniqueType, std::true_type)
1616         {
1617           if (!functions::nothrow_move_assignable) {
1618             this->construct_spare_functions(x.current_functions());
1619             this->switch_functions();
1620           } else {
1621             this->current_functions().move_assign(x.current_functions());
1622           }
1623           delete_buckets();
1624 
1625           buckets_.reset_allocator(x.buckets_.get_node_allocator());
1626           mlf_ = x.mlf_;
1627           move_buckets_from(x);
1628         }
1629 
1630         // Don't propagate allocator
1631         template <typename UniqueType>
1632         void move_assign(table& x, UniqueType is_unique, std::false_type)
1633         {
1634           if (node_alloc() == x.node_alloc()) {
1635             move_assign_equal_alloc(x);
1636           } else {
1637             move_assign_realloc(x, is_unique);
1638           }
1639         }
1640 
1641         void move_assign_equal_alloc(table& x)
1642         {
1643           if (!functions::nothrow_move_assignable) {
1644             this->construct_spare_functions(x.current_functions());
1645             this->switch_functions();
1646           } else {
1647             this->current_functions().move_assign(x.current_functions());
1648           }
1649           delete_buckets();
1650           mlf_ = x.mlf_;
1651           move_buckets_from(x);
1652         }
1653 
1654         template <typename UniqueType>
1655         void move_assign_realloc(table& x, UniqueType is_unique)
1656         {
1657           this->construct_spare_functions(x.current_functions());
1658           BOOST_TRY
1659           {
1660             mlf_ = x.mlf_;
1661             recalculate_max_load();
1662             if (x.size_ > 0) {
1663               this->reserve_for_insert(x.size_);
1664             }
1665             this->clear_impl();
1666           }
1667           BOOST_CATCH(...)
1668           {
1669             this->cleanup_spare_functions();
1670             BOOST_RETHROW
1671           }
1672           BOOST_CATCH_END
1673           this->switch_functions();
1674           move_assign_buckets(x, is_unique);
1675         }
1676 
1677         // Accessors
1678 
1679         const_key_type& get_key(node_pointer n) const
1680         {
1681           return extractor::extract(n->value());
1682         }
1683 
1684         template <class Key> std::size_t hash(Key const& k) const
1685         {
1686           return this->hash_function()(k);
1687         }
1688 
1689         // Find Node
1690 
1691         template <class Key>
1692         node_pointer find_node_impl(Key const& x, bucket_iterator itb) const
1693         {
1694           node_pointer p = node_pointer();
1695           if (itb != buckets_.end()) {
1696             key_equal const& pred = this->key_eq();
1697             p = itb->next;
1698             for (; p; p = p->next) {
1699               if (pred(x, extractor::extract(p->value()))) {
1700                 break;
1701               }
1702             }
1703           }
1704           return p;
1705         }
1706 
1707         template <class Key> node_pointer find_node(Key const& k) const
1708         {
1709           std::size_t const key_hash = this->hash(k);
1710           return find_node_impl(k, buckets_.at(buckets_.position(key_hash)));
1711         }
1712 
1713         node_pointer find_node(const_key_type& k, bucket_iterator itb) const
1714         {
1715           return find_node_impl(k, itb);
1716         }
1717 
1718         template <class Key> iterator find(Key const& k) const
1719         {
1720           return this->transparent_find(
1721             k, this->hash_function(), this->key_eq());
1722         }
1723 
1724         template <class Key, class Hash, class Pred>
1725         inline iterator transparent_find(
1726           Key const& k, Hash const& h, Pred const& pred) const
1727         {
1728           if (size_ > 0) {
1729             std::size_t const key_hash = h(k);
1730             bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
1731             for (node_pointer p = itb->next; p; p = p->next) {
1732               if (BOOST_LIKELY(pred(k, extractor::extract(p->value())))) {
1733                 return iterator(p, itb);
1734               }
1735             }
1736           }
1737 
1738           return this->end();
1739         }
1740 
1741         template <class Key>
1742         node_pointer* find_prev(Key const& key, bucket_iterator itb)
1743         {
1744           if (size_ > 0) {
1745             key_equal pred = this->key_eq();
1746             for (node_pointer* pp = std::addressof(itb->next); *pp;
1747                  pp = std::addressof((*pp)->next)) {
1748               if (pred(key, extractor::extract((*pp)->value()))) {
1749                 return pp;
1750               }
1751             }
1752           }
1753           typedef node_pointer* node_pointer_pointer;
1754           return node_pointer_pointer();
1755         }
1756 
1757         // Extract and erase
1758 
1759         template <class Key> node_pointer extract_by_key_impl(Key const& k)
1760         {
1761           iterator it = this->find(k);
1762           if (it == this->end()) {
1763             return node_pointer();
1764           }
1765 
1766           buckets_.extract_node(it.itb, it.p);
1767           --size_;
1768 
1769           return it.p;
1770         }
1771 
1772         // Reserve and rehash
1773         void transfer_node(
1774           node_pointer p, bucket_type&, bucket_array_type& new_buckets)
1775         {
1776           const_key_type& key = extractor::extract(p->value());
1777           std::size_t const h = this->hash(key);
1778           bucket_iterator itnewb = new_buckets.at(new_buckets.position(h));
1779           new_buckets.insert_node(itnewb, p);
1780         }
1781 
1782         static std::size_t min_buckets(std::size_t num_elements, float mlf)
1783         {
1784           std::size_t num_buckets = static_cast<std::size_t>(
1785             std::ceil(static_cast<float>(num_elements) / mlf));
1786 
1787           if (num_buckets == 0 && num_elements > 0) { // mlf == inf
1788             num_buckets = 1;
1789           }
1790           return num_buckets;
1791         }
1792 
1793         void rehash(std::size_t);
1794         void reserve(std::size_t);
1795         void reserve_for_insert(std::size_t);
1796         void rehash_impl(std::size_t);
1797 
1798         ////////////////////////////////////////////////////////////////////////
1799         // Unique keys
1800 
1801         // equals
1802 
1803         bool equals_unique(table const& other) const
1804         {
1805           if (this->size_ != other.size_)
1806             return false;
1807 
1808           c_iterator pos = this->begin();
1809           c_iterator last = this->end();
1810 
1811           while (pos != last) {
1812             node_pointer p = pos.p;
1813             node_pointer p2 = other.find_node(this->get_key(p));
1814             if (!p2 || !(p->value() == p2->value())) {
1815               return false;
1816             }
1817             ++pos;
1818           }
1819 
1820           return true;
1821         }
1822 
1823         // Emplace/Insert
1824 
1825         template <typename... Args>
1826         iterator emplace_hint_unique(
1827           c_iterator hint, const_key_type& k, Args&&... args)
1828         {
1829           if (hint.p && this->key_eq()(k, this->get_key(hint.p))) {
1830             return iterator(hint.p, hint.itb);
1831           } else {
1832             return emplace_unique(k, std::forward<Args>(args)...).first;
1833           }
1834         }
1835 
1836         template <typename... Args>
1837         emplace_return emplace_unique(const_key_type& k, Args&&... args)
1838         {
1839           std::size_t key_hash = this->hash(k);
1840           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
1841           node_pointer pos = this->find_node_impl(k, itb);
1842 
1843           if (pos) {
1844             return emplace_return(iterator(pos, itb), false);
1845           } else {
1846             node_tmp b(boost::unordered::detail::func::construct_node_from_args(
1847                          this->node_alloc(), std::forward<Args>(args)...),
1848               this->node_alloc());
1849 
1850             if (size_ + 1 > max_load_) {
1851               reserve(size_ + 1);
1852               itb = buckets_.at(buckets_.position(key_hash));
1853             }
1854 
1855             node_pointer p = b.release();
1856             buckets_.insert_node(itb, p);
1857             ++size_;
1858 
1859             return emplace_return(iterator(p, itb), true);
1860           }
1861         }
1862 
1863         template <typename... Args>
1864         iterator emplace_hint_unique(c_iterator hint, no_key, Args&&... args)
1865         {
1866           node_tmp b(boost::unordered::detail::func::construct_node_from_args(
1867                        this->node_alloc(), std::forward<Args>(args)...),
1868             this->node_alloc());
1869 
1870           const_key_type& k = this->get_key(b.node_);
1871           if (hint.p && this->key_eq()(k, this->get_key(hint.p))) {
1872             return iterator(hint.p, hint.itb);
1873           }
1874 
1875           std::size_t const key_hash = this->hash(k);
1876           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
1877 
1878           node_pointer p = this->find_node_impl(k, itb);
1879           if (p) {
1880             return iterator(p, itb);
1881           }
1882 
1883           if (size_ + 1 > max_load_) {
1884             this->reserve(size_ + 1);
1885             itb = buckets_.at(buckets_.position(key_hash));
1886           }
1887 
1888           p = b.release();
1889           buckets_.insert_node(itb, p);
1890           ++size_;
1891           return iterator(p, itb);
1892         }
1893 
1894         template <typename... Args>
1895         emplace_return emplace_unique(no_key, Args&&... args)
1896         {
1897           node_tmp b(boost::unordered::detail::func::construct_node_from_args(
1898                        this->node_alloc(), std::forward<Args>(args)...),
1899             this->node_alloc());
1900 
1901           const_key_type& k = this->get_key(b.node_);
1902           std::size_t key_hash = this->hash(k);
1903 
1904           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
1905           node_pointer pos = this->find_node_impl(k, itb);
1906 
1907           if (pos) {
1908             return emplace_return(iterator(pos, itb), false);
1909           } else {
1910             if (size_ + 1 > max_load_) {
1911               reserve(size_ + 1);
1912               itb = buckets_.at(buckets_.position(key_hash));
1913             }
1914 
1915             node_pointer p = b.release();
1916             buckets_.insert_node(itb, p);
1917             ++size_;
1918 
1919             return emplace_return(iterator(p, itb), true);
1920           }
1921         }
1922 
1923         template <typename K, typename V>
1924         emplace_return emplace_unique(converting_key, K&& k, V&& v)
1925         {
1926           using alloc_cted = allocator_constructed<node_allocator_type,
1927             typename Types::key_type>;
1928           alloc_cted key(this->node_alloc(), std::forward<K>(k));
1929           return emplace_unique(
1930             key.value(), std::move(key.value()), std::forward<V>(v));
1931         }
1932 
1933         template <typename Key> emplace_return try_emplace_unique(Key&& k)
1934         {
1935           std::size_t key_hash = this->hash(k);
1936           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
1937 
1938           node_pointer pos = this->find_node_impl(k, itb);
1939 
1940           if (pos) {
1941             return emplace_return(iterator(pos, itb), false);
1942           } else {
1943             node_allocator_type alloc = node_alloc();
1944 
1945             value_type* dispatch = BOOST_NULLPTR;
1946 
1947             node_tmp tmp(detail::func::construct_node_from_key(
1948                            dispatch, alloc, std::forward<Key>(k)),
1949               alloc);
1950 
1951             if (size_ + 1 > max_load_) {
1952               reserve(size_ + 1);
1953               itb = buckets_.at(buckets_.position(key_hash));
1954             }
1955 
1956             node_pointer p = tmp.release();
1957             buckets_.insert_node(itb, p);
1958 
1959             ++size_;
1960             return emplace_return(iterator(p, itb), true);
1961           }
1962         }
1963 
1964         template <typename Key>
1965         iterator try_emplace_hint_unique(c_iterator hint, Key&& k)
1966         {
1967           if (hint.p && this->key_eq()(extractor::extract(*hint), k)) {
1968             return iterator(hint.p, hint.itb);
1969           } else {
1970             return try_emplace_unique(k).first;
1971           }
1972         }
1973 
1974         template <typename Key, typename... Args>
1975         emplace_return try_emplace_unique(Key&& k, Args&&... args)
1976         {
1977           std::size_t key_hash = this->hash(k);
1978           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
1979 
1980           node_pointer pos = this->find_node_impl(k, itb);
1981 
1982           if (pos) {
1983             return emplace_return(iterator(pos, itb), false);
1984           }
1985 
1986           node_tmp b(
1987             boost::unordered::detail::func::construct_node_pair_from_args(
1988               this->node_alloc(), k, std::forward<Args>(args)...),
1989             this->node_alloc());
1990 
1991           if (size_ + 1 > max_load_) {
1992             reserve(size_ + 1);
1993             itb = buckets_.at(buckets_.position(key_hash));
1994           }
1995 
1996           pos = b.release();
1997 
1998           buckets_.insert_node(itb, pos);
1999           ++size_;
2000           return emplace_return(iterator(pos, itb), true);
2001         }
2002 
2003         template <typename Key, typename... Args>
2004         iterator try_emplace_hint_unique(
2005           c_iterator hint, Key&& k, Args&&... args)
2006         {
2007           if (hint.p && this->key_eq()(hint->first, k)) {
2008             return iterator(hint.p, hint.itb);
2009           } else {
2010             return try_emplace_unique(k, std::forward<Args>(args)...).first;
2011           }
2012         }
2013 
2014         template <typename Key, typename M>
2015         emplace_return insert_or_assign_unique(Key&& k, M&& obj)
2016         {
2017           std::size_t key_hash = this->hash(k);
2018           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2019 
2020           node_pointer p = this->find_node_impl(k, itb);
2021           if (p) {
2022             p->value().second = std::forward<M>(obj);
2023             return emplace_return(iterator(p, itb), false);
2024           }
2025 
2026           node_tmp b(
2027             boost::unordered::detail::func::construct_node_pair(
2028               this->node_alloc(), std::forward<Key>(k), std::forward<M>(obj)),
2029             node_alloc());
2030 
2031           if (size_ + 1 > max_load_) {
2032             reserve(size_ + 1);
2033             itb = buckets_.at(buckets_.position(key_hash));
2034           }
2035 
2036           p = b.release();
2037 
2038           buckets_.insert_node(itb, p);
2039           ++size_;
2040           return emplace_return(iterator(p, itb), true);
2041         }
2042 
2043         template <typename NodeType, typename InsertReturnType>
2044         void move_insert_node_type_unique(
2045           NodeType& np, InsertReturnType& result)
2046         {
2047           if (!np) {
2048             result.position = this->end();
2049             result.inserted = false;
2050             return;
2051           }
2052 
2053           const_key_type& k = this->get_key(np.ptr_);
2054           std::size_t const key_hash = this->hash(k);
2055           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2056           node_pointer p = this->find_node_impl(k, itb);
2057 
2058           if (p) {
2059             iterator pos(p, itb);
2060             result.node = std::move(np);
2061             result.position = pos;
2062             result.inserted = false;
2063             return;
2064           }
2065 
2066           this->reserve_for_insert(size_ + 1);
2067 
2068           p = np.ptr_;
2069           itb = buckets_.at(buckets_.position(key_hash));
2070 
2071           buckets_.insert_node(itb, p);
2072           np.ptr_ = node_pointer();
2073           ++size_;
2074 
2075           result.position = iterator(p, itb);
2076           result.inserted = true;
2077         }
2078 
2079         template <typename NodeType>
2080         iterator move_insert_node_type_with_hint_unique(
2081           c_iterator hint, NodeType& np)
2082         {
2083           if (!np) {
2084             return this->end();
2085           }
2086 
2087           const_key_type& k = this->get_key(np.ptr_);
2088           if (hint.p && this->key_eq()(k, this->get_key(hint.p))) {
2089             return iterator(hint.p, hint.itb);
2090           }
2091 
2092           std::size_t const key_hash = this->hash(k);
2093           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2094           node_pointer p = this->find_node_impl(k, itb);
2095           if (p) {
2096             return iterator(p, itb);
2097           }
2098 
2099           p = np.ptr_;
2100 
2101           if (size_ + 1 > max_load_) {
2102             this->reserve(size_ + 1);
2103             itb = buckets_.at(buckets_.position(key_hash));
2104           }
2105 
2106           buckets_.insert_node(itb, p);
2107           ++size_;
2108           np.ptr_ = node_pointer();
2109           return iterator(p, itb);
2110         }
2111 
2112         template <typename Types2>
2113         void merge_unique(boost::unordered::detail::table<Types2>& other)
2114         {
2115           typedef boost::unordered::detail::table<Types2> other_table;
2116           BOOST_UNORDERED_STATIC_ASSERT(
2117             (std::is_same<node_type, typename other_table::node_type>::value));
2118           BOOST_ASSERT(this->node_alloc() == other.node_alloc());
2119 
2120           if (other.size_ == 0) {
2121             return;
2122           }
2123 
2124           this->reserve_for_insert(size_ + other.size_);
2125 
2126           iterator last = other.end();
2127           for (iterator pos = other.begin(); pos != last;) {
2128             const_key_type& key = other.get_key(pos.p);
2129             std::size_t const key_hash = this->hash(key);
2130 
2131             bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2132 
2133             if (this->find_node_impl(key, itb)) {
2134               ++pos;
2135               continue;
2136             }
2137 
2138             iterator old = pos;
2139             ++pos;
2140 
2141             node_pointer p = other.extract_by_iterator_unique(old);
2142             buckets_.insert_node(itb, p);
2143             ++size_;
2144           }
2145         }
2146 
2147         ////////////////////////////////////////////////////////////////////////
2148         // Insert range methods
2149         //
2150         // if hash function throws, or inserting > 1 element, basic exception
2151         // safety strong otherwise
2152 
2153         template <class InputIt>
2154         void insert_range_unique(no_key, InputIt i, InputIt j)
2155         {
2156           hasher const& hf = this->hash_function();
2157           node_allocator_type alloc = this->node_alloc();
2158 
2159           for (; i != j; ++i) {
2160             node_tmp tmp(detail::func::construct_node(alloc, *i), alloc);
2161 
2162             value_type const& value = tmp.node_->value();
2163             const_key_type& key = extractor::extract(value);
2164             std::size_t const h = hf(key);
2165 
2166             bucket_iterator itb = buckets_.at(buckets_.position(h));
2167             node_pointer it = find_node_impl(key, itb);
2168             if (it) {
2169               continue;
2170             }
2171 
2172             if (size_ + 1 > max_load_) {
2173               reserve(size_ + 1);
2174               itb = buckets_.at(buckets_.position(h));
2175             }
2176 
2177             node_pointer nptr = tmp.release();
2178             buckets_.insert_node(itb, nptr);
2179             ++size_;
2180           }
2181         }
2182 
2183         ////////////////////////////////////////////////////////////////////////
2184         // Extract
2185 
2186         inline node_pointer extract_by_iterator_unique(c_iterator i)
2187         {
2188           node_pointer p = i.p;
2189           bucket_iterator itb = i.itb;
2190 
2191           buckets_.extract_node(itb, p);
2192           --size_;
2193 
2194           return p;
2195         }
2196 
2197         ////////////////////////////////////////////////////////////////////////
2198         // Erase
2199         //
2200 
2201         template <class Key> std::size_t erase_key_unique_impl(Key const& k)
2202         {
2203           bucket_iterator itb = buckets_.at(buckets_.position(this->hash(k)));
2204           node_pointer* pp = this->find_prev(k, itb);
2205           if (!pp) {
2206             return 0;
2207           }
2208 
2209           node_pointer p = *pp;
2210           buckets_.extract_node_after(itb, pp);
2211           this->delete_node(p);
2212           --size_;
2213           return 1;
2214         }
2215 
2216         iterator erase_node(c_iterator pos)
2217         {
2218           c_iterator next = pos;
2219           ++next;
2220 
2221           bucket_iterator itb = pos.itb;
2222           node_pointer* pp = std::addressof(itb->next);
2223           while (*pp != pos.p) {
2224             pp = std::addressof((*pp)->next);
2225           }
2226 
2227           buckets_.extract_node_after(itb, pp);
2228           this->delete_node(pos.p);
2229           --size_;
2230 
2231           return iterator(next.p, next.itb);
2232         }
2233 
2234         iterator erase_nodes_range(c_iterator first, c_iterator last)
2235         {
2236           if (first == last) {
2237             return iterator(last.p, last.itb);
2238           }
2239 
2240           // though `first` stores of a copy of a pointer to a node, we wish to
2241           // mutate the pointers stored internally by the singly-linked list in
2242           // each bucket group so we have to retrieve it manually by iterating
2243           //
2244           bucket_iterator itb = first.itb;
2245           node_pointer* pp = std::addressof(itb->next);
2246           while (*pp != first.p) {
2247             pp = std::addressof((*pp)->next);
2248           }
2249 
2250           while (*pp != last.p) {
2251             node_pointer p = *pp;
2252             *pp = (*pp)->next;
2253 
2254             this->delete_node(p);
2255             --size_;
2256 
2257             bool const at_end = !(*pp);
2258             bool const is_empty_bucket = !itb->next;
2259 
2260             if (at_end) {
2261               if (is_empty_bucket) {
2262                 buckets_.unlink_bucket(itb++);
2263               } else {
2264                 ++itb;
2265               }
2266               pp = std::addressof(itb->next);
2267             }
2268           }
2269 
2270           return iterator(last.p, last.itb);
2271         }
2272 
2273         ////////////////////////////////////////////////////////////////////////
2274         // fill_buckets_unique
2275 
2276         void copy_buckets(table const& src, std::true_type)
2277         {
2278           BOOST_ASSERT(size_ == 0);
2279 
2280           this->reserve_for_insert(src.size_);
2281 
2282           for (iterator pos = src.begin(); pos != src.end(); ++pos) {
2283             value_type const& value = *pos;
2284             const_key_type& key = extractor::extract(value);
2285             std::size_t const key_hash = this->hash(key);
2286 
2287             bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2288 
2289             node_allocator_type alloc = this->node_alloc();
2290             node_tmp tmp(detail::func::construct_node(alloc, value), alloc);
2291 
2292             buckets_.insert_node(itb, tmp.release());
2293             ++size_;
2294           }
2295         }
2296 
2297         void move_assign_buckets(table& src, std::true_type)
2298         {
2299           BOOST_ASSERT(size_ == 0);
2300           BOOST_ASSERT(max_load_ >= src.size_);
2301 
2302           iterator last = src.end();
2303           node_allocator_type alloc = this->node_alloc();
2304 
2305           for (iterator pos = src.begin(); pos != last; ++pos) {
2306             value_type value = std::move(*pos);
2307             const_key_type& key = extractor::extract(value);
2308             std::size_t const key_hash = this->hash(key);
2309 
2310             bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2311 
2312             node_tmp tmp(
2313               detail::func::construct_node(alloc, std::move(value)), alloc);
2314 
2315             buckets_.insert_node(itb, tmp.release());
2316             ++size_;
2317           }
2318         }
2319 
2320         ////////////////////////////////////////////////////////////////////////
2321         // Equivalent keys
2322 
2323         // Equality
2324 
2325         bool equals_equiv(table const& other) const
2326         {
2327           if (this->size_ != other.size_)
2328             return false;
2329 
2330           iterator last = this->end();
2331           for (iterator n1 = this->begin(); n1 != last;) {
2332             const_key_type& k = extractor::extract(*n1);
2333             iterator n2 = other.find(k);
2334             if (n2 == other.end()) {
2335               return false;
2336             }
2337 
2338             iterator end1 = this->next_group(k, n1);
2339             iterator end2 = other.next_group(k, n2);
2340 
2341             if (!group_equals_equiv(n1, end1, n2, end2)) {
2342               return false;
2343             }
2344 
2345             n1 = end1;
2346           }
2347 
2348           return true;
2349         }
2350 
2351         static bool group_equals_equiv(
2352           iterator n1, iterator end1, iterator n2, iterator end2)
2353         {
2354           for (;;) {
2355             if (*n1 != *n2)
2356               break;
2357 
2358             ++n1;
2359             ++n2;
2360 
2361             if (n1 == end1)
2362               return n2 == end2;
2363 
2364             if (n2 == end2)
2365               return false;
2366           }
2367 
2368           for (iterator n1a = n1, n2a = n2;;) {
2369             ++n1a;
2370             ++n2a;
2371 
2372             if (n1a == end1) {
2373               if (n2a == end2)
2374                 break;
2375               else
2376                 return false;
2377             }
2378 
2379             if (n2a == end2)
2380               return false;
2381           }
2382 
2383           iterator start = n1;
2384           for (; n1 != end1; ++n1) {
2385             value_type const& v = *n1;
2386             if (!find_equiv(start, n1, v)) {
2387               std::size_t matches = count_equal_equiv(n2, end2, v);
2388               if (!matches)
2389                 return false;
2390 
2391               iterator t = n1;
2392               if (matches != 1 + count_equal_equiv(++t, end1, v))
2393                 return false;
2394             }
2395           }
2396 
2397           return true;
2398         }
2399 
2400         static bool find_equiv(iterator n, iterator last, value_type const& v)
2401         {
2402           for (; n != last; ++n)
2403             if (*n == v)
2404               return true;
2405           return false;
2406         }
2407 
2408         static std::size_t count_equal_equiv(
2409           iterator n, iterator last, value_type const& v)
2410         {
2411           std::size_t count = 0;
2412           for (; n != last; ++n)
2413             if (*n == v)
2414               ++count;
2415           return count;
2416         }
2417 
2418         // Emplace/Insert
2419 
2420         iterator emplace_equiv(node_pointer n)
2421         {
2422           node_tmp a(n, this->node_alloc());
2423           const_key_type& k = this->get_key(a.node_);
2424           std::size_t key_hash = this->hash(k);
2425           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2426           node_pointer hint = this->find_node_impl(k, itb);
2427 
2428           if (size_ + 1 > max_load_) {
2429             this->reserve(size_ + 1);
2430             itb = buckets_.at(buckets_.position(key_hash));
2431           }
2432           node_pointer p = a.release();
2433           buckets_.insert_node_hint(itb, p, hint);
2434           ++size_;
2435           return iterator(p, itb);
2436         }
2437 
2438         iterator emplace_hint_equiv(c_iterator hint, node_pointer n)
2439         {
2440           node_tmp a(n, this->node_alloc());
2441           const_key_type& k = this->get_key(a.node_);
2442           bucket_iterator itb = hint.itb;
2443           node_pointer p = hint.p;
2444 
2445           std::size_t key_hash = 0u;
2446 
2447           bool const needs_rehash = (size_ + 1 > max_load_);
2448           bool const usable_hint = (p && this->key_eq()(k, this->get_key(p)));
2449 
2450           if (!usable_hint) {
2451             key_hash = this->hash(k);
2452             itb = buckets_.at(buckets_.position(key_hash));
2453             p = this->find_node_impl(k, itb);
2454           } else if (usable_hint && needs_rehash) {
2455             key_hash = this->hash(k);
2456           }
2457 
2458           if (needs_rehash) {
2459             this->reserve(size_ + 1);
2460             itb = buckets_.at(buckets_.position(key_hash));
2461           }
2462 
2463           a.release();
2464           buckets_.insert_node_hint(itb, n, p);
2465           ++size_;
2466           return iterator(n, itb);
2467         }
2468 
2469         void emplace_no_rehash_equiv(node_pointer n)
2470         {
2471           BOOST_ASSERT(size_ + 1 <= max_load_);
2472           node_tmp a(n, this->node_alloc());
2473           const_key_type& k = this->get_key(a.node_);
2474           std::size_t key_hash = this->hash(k);
2475           bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2476           node_pointer hint = this->find_node_impl(k, itb);
2477           node_pointer p = a.release();
2478           buckets_.insert_node_hint(itb, p, hint);
2479           ++size_;
2480         }
2481 
2482         template <typename NodeType>
2483         iterator move_insert_node_type_equiv(NodeType& np)
2484         {
2485           iterator result;
2486 
2487           if (np) {
2488             this->reserve_for_insert(size_ + 1);
2489 
2490             const_key_type& k = this->get_key(np.ptr_);
2491             std::size_t key_hash = this->hash(k);
2492 
2493             bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2494 
2495             node_pointer hint = this->find_node_impl(k, itb);
2496             buckets_.insert_node_hint(itb, np.ptr_, hint);
2497             ++size_;
2498 
2499             result = iterator(np.ptr_, itb);
2500             np.ptr_ = node_pointer();
2501           }
2502 
2503           return result;
2504         }
2505 
2506         template <typename NodeType>
2507         iterator move_insert_node_type_with_hint_equiv(
2508           c_iterator hint, NodeType& np)
2509         {
2510           iterator result;
2511           if (np) {
2512             bucket_iterator itb = hint.itb;
2513             node_pointer pos = hint.p;
2514             const_key_type& k = this->get_key(np.ptr_);
2515             std::size_t key_hash = this->hash(k);
2516             if (size_ + 1 > max_load_) {
2517               this->reserve(size_ + 1);
2518               itb = buckets_.at(buckets_.position(key_hash));
2519             }
2520 
2521             if (hint.p && this->key_eq()(k, this->get_key(hint.p))) {
2522             } else {
2523               itb = buckets_.at(buckets_.position(key_hash));
2524               pos = this->find_node_impl(k, itb);
2525             }
2526             buckets_.insert_node_hint(itb, np.ptr_, pos);
2527             ++size_;
2528             result = iterator(np.ptr_, itb);
2529 
2530             np.ptr_ = node_pointer();
2531           }
2532 
2533           return result;
2534         }
2535 
2536         ////////////////////////////////////////////////////////////////////////
2537         // Insert range methods
2538 
2539         // if hash function throws, or inserting > 1 element, basic exception
2540         // safety. Strong otherwise
2541         template <class I>
2542         typename boost::unordered::detail::enable_if_forward<I, void>::type
2543         insert_range_equiv(I i, I j)
2544         {
2545           if (i == j)
2546             return;
2547 
2548           std::size_t distance = static_cast<std::size_t>(std::distance(i, j));
2549           if (distance == 1) {
2550             emplace_equiv(boost::unordered::detail::func::construct_node(
2551               this->node_alloc(), *i));
2552           } else {
2553             // Only require basic exception safety here
2554             this->reserve_for_insert(size_ + distance);
2555 
2556             for (; i != j; ++i) {
2557               emplace_no_rehash_equiv(
2558                 boost::unordered::detail::func::construct_node(
2559                   this->node_alloc(), *i));
2560             }
2561           }
2562         }
2563 
2564         template <class I>
2565         typename boost::unordered::detail::disable_if_forward<I, void>::type
2566         insert_range_equiv(I i, I j)
2567         {
2568           for (; i != j; ++i) {
2569             emplace_equiv(boost::unordered::detail::func::construct_node(
2570               this->node_alloc(), *i));
2571           }
2572         }
2573 
2574         ////////////////////////////////////////////////////////////////////////
2575         // Extract
2576 
2577         inline node_pointer extract_by_iterator_equiv(c_iterator n)
2578         {
2579           node_pointer p = n.p;
2580           bucket_iterator itb = n.itb;
2581           buckets_.extract_node(itb, p);
2582           --size_;
2583           return p;
2584         }
2585 
2586         ////////////////////////////////////////////////////////////////////////
2587         // Erase
2588         //
2589         // no throw
2590 
2591         template <class Key> std::size_t erase_key_equiv_impl(Key const& k)
2592         {
2593           std::size_t deleted_count = 0;
2594 
2595           bucket_iterator itb = buckets_.at(buckets_.position(this->hash(k)));
2596           node_pointer* pp = this->find_prev(k, itb);
2597           if (pp) {
2598             while (*pp && this->key_eq()(this->get_key(*pp), k)) {
2599               node_pointer p = *pp;
2600               *pp = (*pp)->next;
2601 
2602               this->delete_node(p);
2603               --size_;
2604               ++deleted_count;
2605             }
2606 
2607             if (!itb->next) {
2608               buckets_.unlink_bucket(itb);
2609             }
2610           }
2611           return deleted_count;
2612         }
2613 
2614         std::size_t erase_key_equiv(const_key_type& k)
2615         {
2616           return this->erase_key_equiv_impl(k);
2617         }
2618 
2619         ////////////////////////////////////////////////////////////////////////
2620         // fill_buckets
2621 
2622         void copy_buckets(table const& src, std::false_type)
2623         {
2624           BOOST_ASSERT(size_ == 0);
2625 
2626           this->reserve_for_insert(src.size_);
2627 
2628           iterator last = src.end();
2629           for (iterator pos = src.begin(); pos != last; ++pos) {
2630             value_type const& value = *pos;
2631             const_key_type& key = extractor::extract(value);
2632             std::size_t const key_hash = this->hash(key);
2633 
2634             bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2635             node_allocator_type alloc = this->node_alloc();
2636             node_tmp tmp(detail::func::construct_node(alloc, value), alloc);
2637             node_pointer hint = this->find_node_impl(key, itb);
2638             buckets_.insert_node_hint(itb, tmp.release(), hint);
2639             ++size_;
2640           }
2641         }
2642 
2643         void move_assign_buckets(table& src, std::false_type)
2644         {
2645           BOOST_ASSERT(size_ == 0);
2646           BOOST_ASSERT(max_load_ >= src.size_);
2647 
2648           iterator last = src.end();
2649           node_allocator_type alloc = this->node_alloc();
2650 
2651           for (iterator pos = src.begin(); pos != last; ++pos) {
2652             value_type value = std::move(*pos);
2653             const_key_type& key = extractor::extract(value);
2654             std::size_t const key_hash = this->hash(key);
2655 
2656             bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
2657 
2658             node_pointer hint = this->find_node_impl(key, itb);
2659             node_tmp tmp(
2660               detail::func::construct_node(alloc, std::move(value)), alloc);
2661 
2662             buckets_.insert_node_hint(itb, tmp.release(), hint);
2663             ++size_;
2664           }
2665         }
2666       };
2667 
2668       //////////////////////////////////////////////////////////////////////////
2669       // Clear
2670 
2671       template <typename Types> inline void table<Types>::clear_impl()
2672       {
2673         bucket_iterator itb = buckets_.begin(), last = buckets_.end();
2674         for (; itb != last;) {
2675           bucket_iterator next_itb = itb;
2676           ++next_itb;
2677           node_pointer* pp = std::addressof(itb->next);
2678           while (*pp) {
2679             node_pointer p = *pp;
2680             buckets_.extract_node_after(itb, pp);
2681             this->delete_node(p);
2682             --size_;
2683           }
2684           itb = next_itb;
2685         }
2686       }
2687 
2688       //////////////////////////////////////////////////////////////////////////
2689       // Reserve & Rehash
2690 
2691       // if hash function throws, basic exception safety
2692       // strong otherwise.
2693       template <typename Types>
2694       inline void table<Types>::rehash(std::size_t num_buckets)
2695       {
2696         num_buckets = buckets_.bucket_count_for(
2697           (std::max)(min_buckets(size_, mlf_), num_buckets));
2698 
2699         if (num_buckets != this->bucket_count()) {
2700           this->rehash_impl(num_buckets);
2701         }
2702       }
2703 
2704       template <class Types>
2705       inline void table<Types>::reserve(std::size_t num_elements)
2706       {
2707         std::size_t num_buckets = min_buckets(num_elements, mlf_);
2708         this->rehash(num_buckets);
2709       }
2710 
2711       template <class Types>
2712       inline void table<Types>::reserve_for_insert(std::size_t num_elements)
2713       {
2714         if (num_elements > max_load_) {
2715           std::size_t const num_buckets = static_cast<std::size_t>(
2716             1.0f + std::ceil(static_cast<float>(num_elements) / mlf_));
2717 
2718           this->rehash_impl(num_buckets);
2719         }
2720       }
2721 
2722       template <class Types>
2723       inline void table<Types>::rehash_impl(std::size_t num_buckets)
2724       {
2725         bucket_array_type new_buckets(
2726           num_buckets, buckets_.get_allocator());
2727 
2728         BOOST_TRY
2729         {
2730           boost::unordered::detail::span<bucket_type> bspan = buckets_.raw();
2731 
2732           bucket_type* pos = bspan.data;
2733           std::size_t size = bspan.size;
2734           bucket_type* last = pos + size;
2735 
2736           for (; pos != last; ++pos) {
2737             bucket_type& b = *pos;
2738             for (node_pointer p = b.next; p;) {
2739               node_pointer next_p = p->next;
2740               transfer_node(p, b, new_buckets);
2741               p = next_p;
2742               b.next = p;
2743             }
2744           }
2745         }
2746         BOOST_CATCH(...)
2747         {
2748           for (bucket_iterator pos = new_buckets.begin();
2749                pos != new_buckets.end(); ++pos) {
2750             bucket_type& b = *pos;
2751             for (node_pointer p = b.next; p;) {
2752               node_pointer next_p = p->next;
2753               delete_node(p);
2754               --size_;
2755               p = next_p;
2756             }
2757           }
2758           buckets_.unlink_empty_buckets();
2759           BOOST_RETHROW
2760         }
2761         BOOST_CATCH_END
2762 
2763         buckets_ = std::move(new_buckets);
2764         recalculate_max_load();
2765       }
2766 
2767 #if defined(BOOST_MSVC)
2768 #pragma warning(pop)
2769 #endif
2770 
2771       ////////////////////////////////////////////////////////////////////////
2772       // key extractors
2773       //
2774       // no throw
2775       //
2776       // 'extract_key' is called with the emplace parameters to return a
2777       // key if available or 'no_key' is one isn't and will need to be
2778       // constructed. This could be done by overloading the emplace
2779       // implementation
2780       // for the different cases, but that's a bit tricky on compilers without
2781       // variadic templates.
2782 
2783       template <typename Key, typename T> struct is_key
2784       {
2785         template <typename T2> static choice1::type test(T2 const&);
2786         static choice2::type test(Key const&);
2787 
2788         enum
2789         {
2790           value = sizeof(test(boost::unordered::detail::make<T>())) ==
2791                   sizeof(choice2::type)
2792         };
2793 
2794         typedef typename std::conditional<value, Key const&, no_key>::type type;
2795       };
2796 
2797       template <class ValueType> struct set_extractor
2798       {
2799         typedef ValueType value_type;
2800         typedef ValueType key_type;
2801 
2802         static key_type const& extract(value_type const& v) { return v; }
2803 
2804         static key_type const& extract(value_type&& v) { return v; }
2805 
2806         static no_key extract() { return no_key(); }
2807 
2808         template <class Arg> static no_key extract(Arg const&)
2809         {
2810           return no_key();
2811         }
2812 
2813         template <class Arg1, class Arg2, class... Args>
2814         static no_key extract(Arg1 const&, Arg2 const&, Args const&...)
2815         {
2816           return no_key();
2817         }
2818       };
2819 
2820       template <class ValueType> struct map_extractor
2821       {
2822         typedef ValueType value_type;
2823         typedef typename std::remove_const<typename boost::unordered::detail::
2824             pair_traits<ValueType>::first_type>::type key_type;
2825 
2826         static key_type const& extract(value_type const& v) { return v.first; }
2827 
2828         template <class Second>
2829         static key_type const& extract(std::pair<key_type, Second> const& v)
2830         {
2831           return v.first;
2832         }
2833 
2834         template <class Second>
2835         static key_type const& extract(
2836           std::pair<key_type const, Second> const& v)
2837         {
2838           return v.first;
2839         }
2840 
2841         template <class Arg1>
2842         static key_type const& extract(key_type const& k, Arg1 const&)
2843         {
2844           return k;
2845         }
2846 
2847         static no_key extract() { return no_key(); }
2848 
2849         template <class Arg> static no_key extract(Arg const&)
2850         {
2851           return no_key();
2852         }
2853 
2854         template <class Arg1, class Arg2>
2855         static typename std::conditional<
2856           (is_similar<Arg1, key_type>::value ||
2857             is_complete_and_move_constructible<key_type>::value),
2858           converting_key, no_key>::type
2859         extract(Arg1 const&, Arg2 const&)
2860         {
2861           return {};
2862         }
2863 
2864         template <class Arg1, class Arg2, class Arg3, class... Args>
2865         static no_key extract(
2866           Arg1 const&, Arg2 const&, Arg3 const&, Args const&...)
2867         {
2868           return no_key();
2869         }
2870 
2871         template <template <class...> class Tuple, typename T2>
2872         static no_key extract(
2873           std::piecewise_construct_t, Tuple<> const&, T2 const&)
2874         {
2875           return no_key();
2876         }
2877 
2878         template <template <typename...> class Tuple, typename T, typename T2,
2879           typename... Args>
2880         static auto extract(
2881           std::piecewise_construct_t, Tuple<T, Args...> const& k, T2 const&) ->
2882           typename std::enable_if<
2883             !std::is_same<T, boost::tuples::null_type>::value,
2884             typename is_key<key_type, T>::type>::type
2885         {
2886           using std::get;
2887           return typename is_key<key_type, T>::type(get<0>(k));
2888         }
2889       };
2890 
2891       template <class Container, class Predicate>
2892       typename Container::size_type erase_if(Container& c, Predicate& pred)
2893       {
2894         typedef typename Container::size_type size_type;
2895         typedef typename Container::iterator iterator;
2896 
2897         size_type const size = c.size();
2898 
2899         for (iterator pos = c.begin(), last = c.end(); pos != last;) {
2900           if (pred(*pos)) {
2901             pos = c.erase(pos);
2902           } else {
2903             ++pos;
2904           }
2905         }
2906 
2907         return (size - c.size());
2908       }
2909     } // namespace detail
2910   } // namespace unordered
2911 } // namespace boost
2912 
2913 #endif