File indexing completed on 2025-09-18 09:07:43
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 #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 }
0051
0052
0053
0054
0055
0056 #if defined(BOOST_UNORDERED_SUPPRESS_DEPRECATED)
0057 #define BOOST_UNORDERED_DEPRECATED(msg)
0058 #endif
0059
0060
0061
0062
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 }
0119
0120
0121
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 }
0143 }
0144 }
0145
0146 namespace boost {
0147 namespace unordered {
0148 namespace detail {
0149
0150
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
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
0260
0261 compressed& operator=(compressed const&);
0262 };
0263
0264
0265
0266
0267
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)
0284 #pragma warning(disable : 4345)
0285
0286
0287 #endif
0288
0289
0290
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 }
0319 }
0320 }
0321
0322
0323
0324
0325
0326
0327 namespace boost {
0328 namespace unordered {
0329 namespace detail {
0330
0331
0332
0333
0334 #if defined(BOOST_MSVC)
0335 #pragma warning(push)
0336 #pragma warning(disable : 4100)
0337 #endif
0338
0339 namespace func {
0340 template <class T> inline void destroy(T* x) { x->~T(); }
0341 }
0342
0343 #if defined(BOOST_MSVC)
0344 #pragma warning(pop)
0345 #endif
0346
0347
0348
0349
0350
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
0376
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 }
0459 }
0460 }
0461
0462
0463
0464
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 }
0481 }
0482 }
0483
0484 namespace boost {
0485 namespace unordered {
0486 namespace detail {
0487 namespace func {
0488
0489
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
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
0516
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
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 }
0577 }
0578 }
0579 }
0580
0581 namespace boost {
0582 namespace unordered {
0583 namespace detail {
0584
0585
0586
0587
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
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
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 }
0669 }
0670 }
0671
0672 namespace boost {
0673 namespace unordered {
0674 namespace detail {
0675 namespace func {
0676
0677
0678
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 }
0795 }
0796 }
0797 }
0798
0799 #if defined(BOOST_MSVC)
0800 #pragma warning(pop)
0801 #endif
0802
0803 namespace boost {
0804 namespace unordered {
0805 namespace detail {
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816 #if defined(_GLIBCXX_HAVE_BUILTIN_LAUNDER)
0817
0818
0819
0820
0821
0822
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_;
0850
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)
0950 #endif
0951
0952
0953
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
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 }
1179
1180
1181
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
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
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
1336
1337 void recalculate_max_load()
1338 {
1339
1340
1341 std::size_t const bc = buckets_.bucket_count();
1342
1343
1344
1345
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
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
1402
1403 void swap_allocators(table& other, std::false_type)
1404 {
1405 boost::unordered::detail::func::ignore_unused_variable_warning(other);
1406
1407
1408
1409
1410 BOOST_ASSERT(node_alloc() == other.node_alloc());
1411 }
1412
1413
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
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
1448
1449
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
1459
1460
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
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
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
1533
1534 void clear_impl();
1535
1536
1537
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
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
1586
1587 delete_buckets();
1588 buckets_.reset_allocator(x.node_alloc());
1589 buckets_ = std::move(new_buckets);
1590
1591
1592 mlf_ = x.mlf_;
1593 reserve(x.size_);
1594
1595
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
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
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
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
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
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
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) {
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
1800
1801
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
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
2149
2150
2151
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
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
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
2241
2242
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
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
2322
2323
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
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
2538
2539
2540
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
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
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
2588
2589
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
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
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
2690
2691
2692
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
2773
2774
2775
2776
2777
2778
2779
2780
2781
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 }
2910 }
2911 }
2912
2913 #endif