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