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