1 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
2 // Copyright (C) 2005-2016 Daniel James
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP
8 #define BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP
10 #include <boost/config.hpp>
11 #if defined(BOOST_HAS_PRAGMA_ONCE)
15 #include <boost/assert.hpp>
16 #include <boost/detail/no_exceptions_support.hpp>
17 #include <boost/detail/select_type.hpp>
18 #include <boost/iterator/iterator_categories.hpp>
19 #include <boost/limits.hpp>
20 #include <boost/move/move.hpp>
21 #include <boost/predef.h>
22 #include <boost/preprocessor/arithmetic/inc.hpp>
23 #include <boost/preprocessor/cat.hpp>
24 #include <boost/preprocessor/repetition/enum.hpp>
25 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
26 #include <boost/preprocessor/repetition/enum_params.hpp>
27 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
28 #include <boost/preprocessor/seq/enum.hpp>
29 #include <boost/preprocessor/seq/size.hpp>
30 #include <boost/swap.hpp>
31 #include <boost/throw_exception.hpp>
32 #include <boost/tuple/tuple.hpp>
33 #include <boost/type_traits/add_lvalue_reference.hpp>
34 #include <boost/type_traits/aligned_storage.hpp>
35 #include <boost/type_traits/alignment_of.hpp>
36 #include <boost/type_traits/is_class.hpp>
37 #include <boost/type_traits/is_convertible.hpp>
38 #include <boost/type_traits/is_empty.hpp>
39 #include <boost/type_traits/is_nothrow_move_assignable.hpp>
40 #include <boost/type_traits/is_nothrow_move_constructible.hpp>
41 #include <boost/type_traits/is_same.hpp>
42 #include <boost/type_traits/remove_const.hpp>
43 #include <boost/unordered/detail/fwd.hpp>
44 #include <boost/utility/addressof.hpp>
45 #include <boost/utility/enable_if.hpp>
51 #if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
52 #include <type_traits>
55 ////////////////////////////////////////////////////////////////////////////////
58 // Unless documented elsewhere these configuration macros should be considered
59 // an implementation detail, I'll try not to break them, but you never know.
61 // Use Sun C++ workarounds
62 // I'm not sure which versions of the compiler require these workarounds, so
63 // I'm just using them of everything older than the current test compilers
66 #if !defined(BOOST_UNORDERED_SUN_WORKAROUNDS1)
67 #if BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 20, 0)
68 #define BOOST_UNORDERED_SUN_WORKAROUNDS1 1
70 #define BOOST_UNORDERED_SUN_WORKAROUNDS1 0
74 // BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters in
75 // emplace (not including things like hints). Don't set it to a lower value, as
76 // that might break something.
78 #if !defined BOOST_UNORDERED_EMPLACE_LIMIT
79 #define BOOST_UNORDERED_EMPLACE_LIMIT 10
82 // BOOST_UNORDERED_USE_ALLOCATOR_TRAITS - Pick which version of
83 // allocator_traits to use.
85 // 0 = Own partial implementation
86 // 1 = std::allocator_traits
87 // 2 = boost::container::allocator_traits
89 #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
90 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
91 #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1
92 #elif defined(BOOST_MSVC)
94 // Use container's allocator_traits for older versions of Visual
95 // C++ as I don't test with them.
96 #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2
101 #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
102 #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0
105 // BOOST_UNORDERED_TUPLE_ARGS
107 // Maximum number of std::tuple members to support, or 0 if std::tuple
108 // isn't avaiable. More are supported when full C++11 is used.
110 // Already defined, so do nothing
111 #if defined(BOOST_UNORDERED_TUPLE_ARGS)
113 // Assume if we have C++11 tuple it's properly variadic,
114 // and just use a max number of 10 arguments.
115 #elif !defined(BOOST_NO_CXX11_HDR_TUPLE)
116 #define BOOST_UNORDERED_TUPLE_ARGS 10
118 // Visual C++ has a decent enough tuple for piecewise construction,
119 // so use that if available, using _VARIADIC_MAX for the maximum
120 // number of parameters. Note that this comes after the check
121 // for a full C++11 tuple.
122 #elif defined(BOOST_MSVC)
123 #if !BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
124 #define BOOST_UNORDERED_TUPLE_ARGS 0
125 #elif defined(_VARIADIC_MAX)
126 #define BOOST_UNORDERED_TUPLE_ARGS _VARIADIC_MAX
128 #define BOOST_UNORDERED_TUPLE_ARGS 5
131 // Assume that we don't have std::tuple
133 #define BOOST_UNORDERED_TUPLE_ARGS 0
136 #if BOOST_UNORDERED_TUPLE_ARGS
140 // BOOST_UNORDERED_CXX11_CONSTRUCTION
142 // Use C++11 construction, requires variadic arguments, good construct support
143 // in allocator_traits and piecewise construction of std::pair
144 // Otherwise allocators aren't used for construction/destruction
146 #if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT && \
147 !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && BOOST_UNORDERED_TUPLE_ARGS
148 #if BOOST_COMP_SUNPRO && BOOST_LIB_STD_GNU
149 // Sun C++ std::pair piecewise construction doesn't seem to be exception safe.
150 // (At least for Sun C++ 12.5 using libstdc++).
151 #define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
152 #elif BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4, 7, 0)
153 // Piecewise construction in GCC 4.6 doesn't work for uncopyable types.
154 #define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
155 #elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && \
156 !defined(BOOST_NO_SFINAE_EXPR)
157 #define BOOST_UNORDERED_CXX11_CONSTRUCTION 1
158 #elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
159 #define BOOST_UNORDERED_CXX11_CONSTRUCTION 1
163 #if !defined(BOOST_UNORDERED_CXX11_CONSTRUCTION)
164 #define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
167 // BOOST_UNORDERED_SUPPRESS_DEPRECATED
169 // Define to stop deprecation attributes
171 #if defined(BOOST_UNORDERED_SUPPRESS_DEPRECATED)
172 #define BOOST_UNORDERED_DEPRECATED(msg)
175 // BOOST_UNORDERED_DEPRECATED
177 // Wrapper around various depreaction attributes.
179 #if defined(__has_cpp_attribute) && \
180 (!defined(__cplusplus) || __cplusplus >= 201402)
181 #if __has_cpp_attribute(deprecated) && !defined(BOOST_UNORDERED_DEPRECATED)
182 #define BOOST_UNORDERED_DEPRECATED(msg) [[deprecated(msg)]]
186 #if !defined(BOOST_UNORDERED_DEPRECATED)
187 #if defined(__GNUC__) && __GNUC__ >= 4
188 #define BOOST_UNORDERED_DEPRECATED(msg) __attribute__((deprecated))
189 #elif defined(_MSC_VER) && _MSC_VER >= 1400
190 #define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated(msg))
191 #elif defined(_MSC_VER) && _MSC_VER >= 1310
192 #define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated)
194 #define BOOST_UNORDERED_DEPRECATED(msg)
199 namespace unordered {
200 namespace iterator_detail {
201 template <typename Node> struct iterator;
202 template <typename Node> struct c_iterator;
203 template <typename Node> struct l_iterator;
204 template <typename Node> struct cl_iterator;
210 namespace unordered {
213 template <typename Types> struct table;
214 template <typename NodePointer> struct bucket;
217 template <typename A, typename T> struct node;
218 template <typename T> struct ptr_node;
220 static const float minimum_max_load_factor = 1e-3f;
221 static const std::size_t default_bucket_count = 11;
234 template <class T> no_key(T const&) {}
238 template <class T> inline void ignore_unused_variable_warning(T const&)
243 //////////////////////////////////////////////////////////////////////////
246 template <typename I>
248 : boost::is_convertible<typename boost::iterator_traversal<I>::type,
249 boost::forward_traversal_tag>
253 template <typename I, typename ReturnType>
254 struct enable_if_forward
255 : boost::enable_if_c<boost::unordered::detail::is_forward<I>::value,
260 template <typename I, typename ReturnType>
261 struct disable_if_forward
262 : boost::disable_if_c<boost::unordered::detail::is_forward<I>::value,
270 ////////////////////////////////////////////////////////////////////////////////
274 #define BOOST_UNORDERED_PRIMES \
275 (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \
276 (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \
277 (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \
278 (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \
279 (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \
280 (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \
281 (1610612741ul)(3221225473ul)(4294967291ul)
285 namespace unordered {
287 template <class T> struct prime_list_template
289 static std::size_t const value[];
291 #if !BOOST_UNORDERED_SUN_WORKAROUNDS1
292 static std::ptrdiff_t const length;
294 static std::ptrdiff_t const length =
295 BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES);
300 std::size_t const prime_list_template<T>::value[] = {
301 BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)};
303 #if !BOOST_UNORDERED_SUN_WORKAROUNDS1
305 std::ptrdiff_t const prime_list_template<T>::length = BOOST_PP_SEQ_SIZE(
306 BOOST_UNORDERED_PRIMES);
309 #undef BOOST_UNORDERED_PRIMES
311 typedef prime_list_template<std::size_t> prime_list;
314 inline std::size_t next_prime(std::size_t num)
316 std::size_t const* const prime_list_begin = prime_list::value;
317 std::size_t const* const prime_list_end =
318 prime_list_begin + prime_list::length;
319 std::size_t const* bound =
320 std::lower_bound(prime_list_begin, prime_list_end, num);
321 if (bound == prime_list_end)
327 inline std::size_t prev_prime(std::size_t num)
329 std::size_t const* const prime_list_begin = prime_list::value;
330 std::size_t const* const prime_list_end =
331 prime_list_begin + prime_list::length;
332 std::size_t const* bound =
333 std::upper_bound(prime_list_begin, prime_list_end, num);
334 if (bound != prime_list_begin)
339 //////////////////////////////////////////////////////////////////////////
340 // insert_size/initial_size
343 inline std::size_t insert_size(I i, I j,
344 typename boost::unordered::detail::enable_if_forward<I, void*>::type =
347 return static_cast<std::size_t>(std::distance(i, j));
351 inline std::size_t insert_size(I, I,
352 typename boost::unordered::detail::disable_if_forward<I, void*>::type =
359 inline std::size_t initial_size(I i, I j,
360 std::size_t num_buckets =
361 boost::unordered::detail::default_bucket_count)
364 boost::unordered::detail::insert_size(i, j), num_buckets);
367 //////////////////////////////////////////////////////////////////////////
370 template <typename T, int Index> struct compressed_base : private T
372 compressed_base(T const& x) : T(x) {}
373 compressed_base(T& x, move_tag) : T(boost::move(x)) {}
375 T& get() { return *this; }
376 T const& get() const { return *this; }
379 template <typename T, int Index> struct uncompressed_base
381 uncompressed_base(T const& x) : value_(x) {}
382 uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {}
384 T& get() { return value_; }
385 T const& get() const { return value_; }
391 template <typename T, int Index>
393 : boost::detail::if_true<
394 boost::is_empty<T>::value>::BOOST_NESTED_TEMPLATE
395 then<boost::unordered::detail::compressed_base<T, Index>,
396 boost::unordered::detail::uncompressed_base<T, Index> >
400 template <typename T1, typename T2>
402 : private boost::unordered::detail::generate_base<T1, 1>::type,
403 private boost::unordered::detail::generate_base<T2, 2>::type
405 typedef typename generate_base<T1, 1>::type base1;
406 typedef typename generate_base<T2, 2>::type base2;
408 typedef T1 first_type;
409 typedef T2 second_type;
411 first_type& first() { return static_cast<base1*>(this)->get(); }
413 first_type const& first() const
415 return static_cast<base1 const*>(this)->get();
418 second_type& second() { return static_cast<base2*>(this)->get(); }
420 second_type const& second() const
422 return static_cast<base2 const*>(this)->get();
425 template <typename First, typename Second>
426 compressed(First const& x1, Second const& x2) : base1(x1), base2(x2)
430 compressed(compressed const& x) : base1(x.first()), base2(x.second()) {}
432 compressed(compressed& x, move_tag m)
433 : base1(x.first(), m), base2(x.second(), m)
437 void assign(compressed const& x)
440 second() = x.second();
443 void move_assign(compressed& x)
445 first() = boost::move(x.first());
446 second() = boost::move(x.second());
449 void swap(compressed& x)
451 boost::swap(first(), x.first());
452 boost::swap(second(), x.second());
456 // Prevent assignment just to make use of assign or
457 // move_assign explicit.
458 compressed& operator=(compressed const&);
461 //////////////////////////////////////////////////////////////////////////
464 // Used to get the types from a pair without instantiating it.
466 template <typename Pair> struct pair_traits
468 typedef typename Pair::first_type first_type;
469 typedef typename Pair::second_type second_type;
472 template <typename T1, typename T2> struct pair_traits<std::pair<T1, T2> >
474 typedef T1 first_type;
475 typedef T2 second_type;
478 #if defined(BOOST_MSVC)
479 #pragma warning(push)
480 #pragma warning(disable : 4512) // assignment operator could not be generated.
481 #pragma warning(disable : 4345) // behavior change: an object of POD type
482 // constructed with an initializer of the form ()
483 // will be default-initialized.
486 //////////////////////////////////////////////////////////////////////////
487 // Bits and pieces for implementing traits
489 template <typename T>
490 typename boost::add_lvalue_reference<T>::type make();
493 typedef char (&type)[9];
495 struct choice8 : choice9
497 typedef char (&type)[8];
499 struct choice7 : choice8
501 typedef char (&type)[7];
503 struct choice6 : choice7
505 typedef char (&type)[6];
507 struct choice5 : choice6
509 typedef char (&type)[5];
511 struct choice4 : choice5
513 typedef char (&type)[4];
515 struct choice3 : choice4
517 typedef char (&type)[3];
519 struct choice2 : choice3
521 typedef char (&type)[2];
523 struct choice1 : choice2
525 typedef char (&type)[1];
529 typedef choice1::type yes_type;
530 typedef choice2::type no_type;
534 private_type const& operator,(int) const;
537 template <typename T> no_type is_private_type(T const&);
538 yes_type is_private_type(private_type const&);
540 struct convert_from_anything
542 template <typename T> convert_from_anything(T const&);
545 // Get a pointer from a smart pointer, a bit simpler than pointer_traits
546 // as we already know the pointer type that we want.
547 template <typename T> struct pointer
549 template <typename Ptr> static T* get(Ptr const& x)
551 return static_cast<T*>(x.operator->());
554 template <typename T2> static T* get(T2* x)
556 return static_cast<T*>(x);
563 ////////////////////////////////////////////////////////////////////////////
566 // Either forwarding variadic arguments, or storing the arguments in
569 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
571 #define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
572 #define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args
573 #define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)...
577 #define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args
578 #define BOOST_UNORDERED_EMPLACE_ARGS Args const& args
579 #define BOOST_UNORDERED_EMPLACE_FORWARD args
581 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
583 #define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
584 typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
585 BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
589 #define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
590 typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \
591 BOOST_PP_CAT(Arg, n); \
592 BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
596 #define BOOST_UNORDERED_FWD_PARAM(z, n, a) \
597 BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n)
599 #define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \
600 boost::forward<BOOST_PP_CAT(A, i)>(BOOST_PP_CAT(a, i))
602 #define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
603 BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
605 #define BOOST_UNORDERED_EARGS(z, n, _) \
606 template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
607 struct BOOST_PP_CAT(emplace_args, n) \
609 BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) BOOST_PP_CAT( \
610 emplace_args, n)(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, b)) \
611 : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \
616 template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
617 inline BOOST_PP_CAT(emplace_args, n)<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> \
618 create_emplace_args(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, b)) \
620 BOOST_PP_CAT(emplace_args, n)<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> e( \
621 BOOST_PP_ENUM_PARAMS_Z(z, n, b)); \
626 namespace unordered {
628 template <typename A0> struct emplace_args1
630 BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
632 explicit emplace_args1(Arg0 b0) : a0(b0) {}
635 template <typename A0>
636 inline emplace_args1<A0> create_emplace_args(BOOST_FWD_REF(A0) b0)
638 emplace_args1<A0> e(b0);
642 template <typename A0, typename A1> struct emplace_args2
644 BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
645 BOOST_UNORDERED_EARGS_MEMBER(1, 1, _)
647 emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {}
650 template <typename A0, typename A1>
651 inline emplace_args2<A0, A1> create_emplace_args(
652 BOOST_FWD_REF(A0) b0, BOOST_FWD_REF(A1) b1)
654 emplace_args2<A0, A1> e(b0, b1);
658 template <typename A0, typename A1, typename A2> struct emplace_args3
660 BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
661 BOOST_UNORDERED_EARGS_MEMBER(1, 1, _)
662 BOOST_UNORDERED_EARGS_MEMBER(1, 2, _)
664 emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {}
667 template <typename A0, typename A1, typename A2>
668 inline emplace_args3<A0, A1, A2> create_emplace_args(
669 BOOST_FWD_REF(A0) b0, BOOST_FWD_REF(A1) b1, BOOST_FWD_REF(A2) b2)
671 emplace_args3<A0, A1, A2> e(b0, b1, b2);
675 BOOST_UNORDERED_EARGS(1, 4, _)
676 BOOST_UNORDERED_EARGS(1, 5, _)
677 BOOST_UNORDERED_EARGS(1, 6, _)
678 BOOST_UNORDERED_EARGS(1, 7, _)
679 BOOST_UNORDERED_EARGS(1, 8, _)
680 BOOST_UNORDERED_EARGS(1, 9, _)
681 BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT),
682 BOOST_UNORDERED_EARGS, _)
687 #undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS
688 #undef BOOST_UNORDERED_EARGS_MEMBER
689 #undef BOOST_UNORDERED_EARGS_INIT
693 ////////////////////////////////////////////////////////////////////////////////
695 // Some utilities for implementing allocator_traits, but useful elsewhere so
696 // they're always defined.
699 namespace unordered {
702 ////////////////////////////////////////////////////////////////////////////
703 // Integral_constrant, true_type, false_type
705 // Uses the standard versions if available.
707 #if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
709 using std::integral_constant;
710 using std::true_type;
711 using std::false_type;
715 template <typename T, T Value> struct integral_constant
723 typedef boost::unordered::detail::integral_constant<bool, true> true_type;
724 typedef boost::unordered::detail::integral_constant<bool, false>
729 ////////////////////////////////////////////////////////////////////////////
730 // Explicitly call a destructor
732 #if defined(BOOST_MSVC)
733 #pragma warning(push)
734 #pragma warning(disable : 4100) // unreferenced formal parameter
738 template <class T> inline void destroy(T* x) { x->~T(); }
741 #if defined(BOOST_MSVC)
748 ////////////////////////////////////////////////////////////////////////////
749 // Expression test mechanism
751 // When SFINAE expressions are available, define
752 // BOOST_UNORDERED_HAS_FUNCTION which can check if a function call is
753 // supported by a class, otherwise define BOOST_UNORDERED_HAS_MEMBER which
754 // can detect if a class has the specified member, but not that it has the
755 // correct type, this is good enough for a passable impression of
758 #if !defined(BOOST_NO_SFINAE_EXPR)
761 namespace unordered {
763 template <typename T, long unsigned int> struct expr_test;
764 template <typename T> struct expr_test<T, sizeof(char)> : T
771 #define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \
772 template <typename U> \
774 typename boost::unordered::detail::expr_test<BOOST_PP_CAT(choice, result), \
775 sizeof(for_expr_test(((expression), 0)))>::type \
776 test(BOOST_PP_CAT(choice, count))
778 #define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \
779 template <typename U> \
780 static BOOST_PP_CAT(choice, result)::type test(BOOST_PP_CAT(choice, count))
782 #define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \
783 struct BOOST_PP_CAT(has_, name) \
785 template <typename U> static char for_expr_test(U const&); \
786 BOOST_UNORDERED_CHECK_EXPRESSION( \
787 1, 1, boost::unordered::detail::make<thing>().name args); \
788 BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \
792 value = sizeof(test<T>(choose())) == sizeof(choice1::type) \
799 namespace unordered {
801 template <typename T> struct identity
809 #define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \
812 typename boost::unordered::detail::identity<member>::type BOOST_PP_CAT( \
815 template <BOOST_PP_CAT(check, count) e> struct BOOST_PP_CAT(test, count) \
817 typedef BOOST_PP_CAT(choice, result) type; \
821 static typename BOOST_PP_CAT(test, count)<&U::name>::type test( \
822 BOOST_PP_CAT(choice, count))
824 #define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \
826 static BOOST_PP_CAT(choice, result)::type test(BOOST_PP_CAT(choice, count))
828 #define BOOST_UNORDERED_HAS_MEMBER(name) \
829 struct BOOST_PP_CAT(has_, name) \
837 struct base : public T, public base_mixin \
841 BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, int base_mixin::*); \
842 BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \
846 value = sizeof(choice2::type) == sizeof(test<base>(choose())) \
852 value = impl::value \
858 ////////////////////////////////////////////////////////////////////////////////
862 // First our implementation, then later light wrappers around the alternatives
864 #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0
866 #include <boost/limits.hpp>
867 #include <boost/pointer_to_other.hpp>
868 #include <boost/utility/enable_if.hpp>
871 namespace unordered {
874 template <typename Alloc, typename T> struct rebind_alloc;
876 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
878 template <template <typename, typename...> class Alloc, typename U,
879 typename T, typename... Args>
880 struct rebind_alloc<Alloc<U, Args...>, T>
882 typedef Alloc<T, Args...> type;
887 template <template <typename> class Alloc, typename U, typename T>
888 struct rebind_alloc<Alloc<U>, T>
890 typedef Alloc<T> type;
893 template <template <typename, typename> class Alloc, typename U,
894 typename T, typename A0>
895 struct rebind_alloc<Alloc<U, A0>, T>
897 typedef Alloc<T, A0> type;
900 template <template <typename, typename, typename> class Alloc, typename U,
901 typename T, typename A0, typename A1>
902 struct rebind_alloc<Alloc<U, A0, A1>, T>
904 typedef Alloc<T, A0, A1> type;
909 template <typename Alloc, typename T> struct rebind_wrap
911 template <typename X>
912 static choice1::type test(
913 choice1, typename X::BOOST_NESTED_TEMPLATE rebind<T>::other* = 0);
914 template <typename X> static choice2::type test(choice2, void* = 0);
918 value = (1 == sizeof(test<Alloc>(choose())))
923 template <typename U> struct rebind
925 typedef typename rebind_alloc<Alloc, T>::type other;
930 typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE then<
931 Alloc, fallback>::type::BOOST_NESTED_TEMPLATE rebind<T>::other type;
937 #if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
939 #define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
940 template <typename Tp, typename Default> struct default_type_##tname \
943 template <typename X> \
944 static choice1::type test(choice1, typename X::tname* = 0); \
946 template <typename X> static choice2::type test(choice2, void* = 0); \
950 typedef Default tname; \
955 value = (1 == sizeof(test<Tp>(choose()))) \
958 typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE \
959 then<Tp, DefaultWrap>::type::tname type; \
965 namespace unordered {
967 template <typename T, typename T2> struct sfinae : T2
974 #define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
975 template <typename Tp, typename Default> struct default_type_##tname \
978 template <typename X> \
979 static typename boost::unordered::detail::sfinae<typename X::tname, \
980 choice1>::type test(choice1); \
982 template <typename X> static choice2::type test(choice2); \
986 typedef Default tname; \
991 value = (1 == sizeof(test<Tp>(choose()))) \
994 typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE \
995 then<Tp, DefaultWrap>::type::tname type; \
1000 #define BOOST_UNORDERED_DEFAULT_TYPE(T, tname, arg) \
1001 typename default_type_##tname<T, arg>::type
1004 namespace unordered {
1006 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer);
1007 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer);
1008 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(void_pointer);
1009 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_void_pointer);
1010 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(difference_type);
1011 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(size_type);
1012 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(
1013 propagate_on_container_copy_assignment);
1014 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(
1015 propagate_on_container_move_assignment);
1016 BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
1018 #if !defined(BOOST_NO_SFINAE_EXPR)
1020 template <typename T>
1021 BOOST_UNORDERED_HAS_FUNCTION(
1022 select_on_container_copy_construction, U const, (), 0);
1024 template <typename T>
1025 BOOST_UNORDERED_HAS_FUNCTION(max_size, U const, (), 0);
1027 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1029 template <typename T, typename ValueType, typename... Args>
1030 BOOST_UNORDERED_HAS_FUNCTION(construct, U,
1031 (boost::unordered::detail::make<ValueType*>(),
1032 boost::unordered::detail::make<Args const>()...),
1037 template <typename T, typename ValueType>
1038 BOOST_UNORDERED_HAS_FUNCTION(construct, U,
1039 (boost::unordered::detail::make<ValueType*>(),
1040 boost::unordered::detail::make<ValueType const>()),
1045 template <typename T, typename ValueType>
1046 BOOST_UNORDERED_HAS_FUNCTION(
1047 destroy, U, (boost::unordered::detail::make<ValueType*>()), 1);
1051 template <typename T>
1052 BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction);
1054 template <typename T> BOOST_UNORDERED_HAS_MEMBER(max_size);
1056 template <typename T, typename ValueType>
1057 BOOST_UNORDERED_HAS_MEMBER(construct);
1059 template <typename T, typename ValueType>
1060 BOOST_UNORDERED_HAS_MEMBER(destroy);
1068 namespace unordered {
1072 template <typename Alloc>
1073 inline Alloc call_select_on_container_copy_construction(
1075 typename boost::enable_if_c<
1076 boost::unordered::detail::has_select_on_container_copy_construction<
1080 return rhs.select_on_container_copy_construction();
1083 template <typename Alloc>
1084 inline Alloc call_select_on_container_copy_construction(
1086 typename boost::disable_if_c<
1087 boost::unordered::detail::has_select_on_container_copy_construction<
1094 template <typename SizeType, typename Alloc>
1095 inline SizeType call_max_size(const Alloc& a,
1096 typename boost::enable_if_c<
1097 boost::unordered::detail::has_max_size<Alloc>::value, void*>::type =
1100 return a.max_size();
1103 template <typename SizeType, typename Alloc>
1104 inline SizeType call_max_size(const Alloc&,
1105 typename boost::disable_if_c<
1106 boost::unordered::detail::has_max_size<Alloc>::value, void*>::type =
1109 return (std::numeric_limits<SizeType>::max)();
1111 } // namespace func.
1117 namespace unordered {
1119 template <typename Alloc> struct allocator_traits
1121 typedef Alloc allocator_type;
1122 typedef typename Alloc::value_type value_type;
1124 typedef BOOST_UNORDERED_DEFAULT_TYPE(
1125 Alloc, pointer, value_type*) pointer;
1127 template <typename T>
1128 struct pointer_to_other : boost::pointer_to_other<pointer, T>
1132 typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
1133 typename pointer_to_other<const value_type>::type) const_pointer;
1135 // typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer,
1136 // typename pointer_to_other<void>::type)
1139 // typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer,
1140 // typename pointer_to_other<const void>::type)
1141 // const_void_pointer;
1143 typedef BOOST_UNORDERED_DEFAULT_TYPE(
1144 Alloc, difference_type, std::ptrdiff_t) difference_type;
1146 typedef BOOST_UNORDERED_DEFAULT_TYPE(
1147 Alloc, size_type, std::size_t) size_type;
1149 #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
1150 template <typename T>
1151 using rebind_alloc = typename rebind_wrap<Alloc, T>::type;
1153 template <typename T>
1154 using rebind_traits =
1155 boost::unordered::detail::allocator_traits<rebind_alloc<T> >;
1158 static pointer allocate(Alloc& a, size_type n) { return a.allocate(n); }
1160 // I never use this, so I'll just comment it out for now.
1162 // static pointer allocate(Alloc& a, size_type n,
1163 // const_void_pointer hint)
1164 // { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); }
1166 static void deallocate(Alloc& a, pointer p, size_type n)
1172 #if BOOST_UNORDERED_CXX11_CONSTRUCTION
1174 template <typename T, typename... Args>
1176 typename boost::enable_if_c<boost::unordered::detail::has_construct<
1177 Alloc, T, Args...>::value>::type
1178 construct(Alloc& a, T* p, BOOST_FWD_REF(Args)... x)
1180 a.construct(p, boost::forward<Args>(x)...);
1183 template <typename T, typename... Args>
1185 typename boost::disable_if_c<boost::unordered::detail::has_construct<
1186 Alloc, T, Args...>::value>::type
1187 construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x)
1189 new (static_cast<void*>(p)) T(boost::forward<Args>(x)...);
1192 template <typename T>
1193 static typename boost::enable_if_c<
1194 boost::unordered::detail::has_destroy<Alloc, T>::value>::type
1195 destroy(Alloc& a, T* p)
1200 template <typename T>
1201 static typename boost::disable_if_c<
1202 boost::unordered::detail::has_destroy<Alloc, T>::value>::type
1203 destroy(Alloc&, T* p)
1205 boost::unordered::detail::func::destroy(p);
1208 #elif !defined(BOOST_NO_SFINAE_EXPR)
1210 template <typename T>
1211 static typename boost::enable_if_c<
1212 boost::unordered::detail::has_construct<Alloc, T>::value>::type
1213 construct(Alloc& a, T* p, T const& x)
1218 template <typename T>
1219 static typename boost::disable_if_c<
1220 boost::unordered::detail::has_construct<Alloc, T>::value>::type
1221 construct(Alloc&, T* p, T const& x)
1223 new (static_cast<void*>(p)) T(x);
1226 template <typename T>
1227 static typename boost::enable_if_c<
1228 boost::unordered::detail::has_destroy<Alloc, T>::value>::type
1229 destroy(Alloc& a, T* p)
1234 template <typename T>
1235 static typename boost::disable_if_c<
1236 boost::unordered::detail::has_destroy<Alloc, T>::value>::type
1237 destroy(Alloc&, T* p)
1239 boost::unordered::detail::func::destroy(p);
1244 // If we don't have SFINAE expressions, only call construct for the
1245 // copy constructor for the allocator's value_type - as that's
1246 // the only construct method that old fashioned allocators support.
1248 template <typename T>
1249 static void construct(Alloc& a, T* p, T const& x,
1250 typename boost::enable_if_c<
1251 boost::unordered::detail::has_construct<Alloc, T>::value &&
1252 boost::is_same<T, value_type>::value,
1258 template <typename T>
1259 static void construct(Alloc&, T* p, T const& x,
1260 typename boost::disable_if_c<
1261 boost::unordered::detail::has_construct<Alloc, T>::value &&
1262 boost::is_same<T, value_type>::value,
1265 new (static_cast<void*>(p)) T(x);
1268 template <typename T>
1269 static void destroy(Alloc& a, T* p,
1270 typename boost::enable_if_c<
1271 boost::unordered::detail::has_destroy<Alloc, T>::value &&
1272 boost::is_same<T, value_type>::value,
1278 template <typename T>
1279 static void destroy(Alloc&, T* p,
1280 typename boost::disable_if_c<
1281 boost::unordered::detail::has_destroy<Alloc, T>::value &&
1282 boost::is_same<T, value_type>::value,
1285 boost::unordered::detail::func::destroy(p);
1290 static size_type max_size(const Alloc& a)
1292 return boost::unordered::detail::func::call_max_size<size_type>(a);
1295 // Allocator propagation on construction
1297 static Alloc select_on_container_copy_construction(Alloc const& rhs)
1299 return boost::unordered::detail::func::
1300 call_select_on_container_copy_construction(rhs);
1303 // Allocator propagation on assignment and swap.
1304 // Return true if lhs is modified.
1305 typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc,
1306 propagate_on_container_copy_assignment,
1307 false_type) propagate_on_container_copy_assignment;
1308 typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc,
1309 propagate_on_container_move_assignment,
1310 false_type) propagate_on_container_move_assignment;
1311 typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, propagate_on_container_swap,
1312 false_type) propagate_on_container_swap;
1318 #undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT
1319 #undef BOOST_UNORDERED_DEFAULT_TYPE
1321 ////////////////////////////////////////////////////////////////////////////////
1323 // std::allocator_traits
1325 #elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
1330 namespace unordered {
1333 template <typename Alloc>
1334 struct allocator_traits : std::allocator_traits<Alloc>
1338 template <typename Alloc, typename T> struct rebind_wrap
1340 typedef typename std::allocator_traits<Alloc>::template rebind_alloc<T>
1347 ////////////////////////////////////////////////////////////////////////////////
1349 // boost::container::allocator_traits
1351 #elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2
1353 #include <boost/container/allocator_traits.hpp>
1356 namespace unordered {
1359 template <typename Alloc>
1360 struct allocator_traits : boost::container::allocator_traits<Alloc>
1364 template <typename Alloc, typename T>
1365 struct rebind_wrap : boost::container::allocator_traits<
1366 Alloc>::template portable_rebind_alloc<T>
1375 #error "Invalid BOOST_UNORDERED_USE_ALLOCATOR_TRAITS value."
1379 ////////////////////////////////////////////////////////////////////////////
1380 // Functions used to construct nodes. Emulates variadic construction,
1381 // piecewise construction etc.
1383 ////////////////////////////////////////////////////////////////////////////
1386 // Only use allocator_traits::construct, allocator_traits::destroy when full
1387 // C++11 support is available.
1389 #if BOOST_UNORDERED_CXX11_CONSTRUCTION
1391 #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
1392 Traits::construct(alloc, address, a0)
1393 #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) Traits::destroy(alloc, x)
1395 #elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1398 namespace unordered {
1401 template <typename T, typename... Args>
1402 inline void construct_value(T* address, BOOST_FWD_REF(Args)... args)
1404 new ((void*)address) T(boost::forward<Args>(args)...);
1411 #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
1412 boost::unordered::detail::func::construct_value(address, a0)
1413 #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \
1414 boost::unordered::detail::func::destroy(x)
1419 namespace unordered {
1422 template <typename T> inline void construct_value(T* address)
1424 new ((void*)address) T();
1427 template <typename T, typename A0>
1428 inline void construct_value(T* address, BOOST_FWD_REF(A0) a0)
1430 new ((void*)address) T(boost::forward<A0>(a0));
1437 #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
1438 boost::unordered::detail::func::construct_value(address, a0)
1439 #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \
1440 boost::unordered::detail::func::destroy(x)
1444 ////////////////////////////////////////////////////////////////////////////
1445 // Construct from tuple
1447 // Used to emulate piecewise construction.
1449 #define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \
1450 template <typename Alloc, typename T, \
1451 BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
1452 void construct_from_tuple(Alloc&, T* ptr, \
1453 namespace_::tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
1456 T(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \
1459 #define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_::get<n>(x)
1461 // construct_from_tuple for boost::tuple
1462 // The workaround for old Sun compilers comes later in the file.
1464 #if !BOOST_UNORDERED_SUN_WORKAROUNDS1
1467 namespace unordered {
1470 template <typename Alloc, typename T>
1471 void construct_from_tuple(Alloc&, T* ptr, boost::tuple<>)
1473 new ((void*)ptr) T();
1476 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, boost)
1477 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, boost)
1478 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, boost)
1479 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, boost)
1480 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, boost)
1481 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 6, boost)
1482 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 7, boost)
1483 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 8, boost)
1484 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 9, boost)
1485 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 10, boost)
1493 // construct_from_tuple for std::tuple
1495 #if !BOOST_UNORDERED_CXX11_CONSTRUCTION && BOOST_UNORDERED_TUPLE_ARGS
1498 namespace unordered {
1501 template <typename Alloc, typename T>
1502 void construct_from_tuple(Alloc&, T* ptr, std::tuple<>)
1504 new ((void*)ptr) T();
1507 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, std)
1508 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, std)
1509 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, std)
1510 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, std)
1511 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, std)
1513 #if BOOST_UNORDERED_TUPLE_ARGS >= 6
1514 BOOST_PP_REPEAT_FROM_TO(6, BOOST_PP_INC(BOOST_UNORDERED_TUPLE_ARGS),
1515 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE, std)
1524 #undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
1525 #undef BOOST_UNORDERED_GET_TUPLE_ARG
1527 // construct_from_tuple for boost::tuple on old versions of sunpro.
1529 // Old versions of Sun C++ had problems with template overloads of
1530 // boost::tuple, so to fix it I added a distinct type for each length to
1531 // the overloads. That means there's no possible ambiguity between the
1532 // different overloads, so that the compiler doesn't get confused
1534 #if BOOST_UNORDERED_SUN_WORKAROUNDS1
1536 #define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \
1537 template <typename Alloc, typename T, \
1538 BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
1539 void construct_from_tuple_impl(boost::unordered::detail::func::length<n>, \
1541 namespace_::tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
1544 T(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \
1547 #define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_::get<n>(x)
1550 namespace unordered {
1553 template <int N> struct length
1557 template <typename Alloc, typename T>
1558 void construct_from_tuple_impl(
1559 boost::unordered::detail::func::length<0>, Alloc&, T* ptr,
1562 new ((void*)ptr) T();
1565 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, boost)
1566 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, boost)
1567 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, boost)
1568 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, boost)
1569 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, boost)
1570 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 6, boost)
1571 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 7, boost)
1572 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 8, boost)
1573 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 9, boost)
1574 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 10, boost)
1576 template <typename Alloc, typename T, typename Tuple>
1577 void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x)
1579 construct_from_tuple_impl(boost::unordered::detail::func::length<
1580 boost::tuples::length<Tuple>::value>(),
1588 #undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
1589 #undef BOOST_UNORDERED_GET_TUPLE_ARG
1594 namespace unordered {
1597 ////////////////////////////////////////////////////////////////////////
1598 // Trait to check for piecewise construction.
1600 template <typename A0> struct use_piecewise
1602 static choice1::type test(
1603 choice1, boost::unordered::piecewise_construct_t);
1605 static choice2::type test(choice2, ...);
1609 value = sizeof(choice1::type) ==
1610 sizeof(test(choose(), boost::unordered::detail::make<A0>()))
1614 #if BOOST_UNORDERED_CXX11_CONSTRUCTION
1616 ////////////////////////////////////////////////////////////////////////
1617 // Construct from variadic parameters
1619 template <typename Alloc, typename T, typename... Args>
1620 inline void construct_from_args(
1621 Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args)
1623 boost::unordered::detail::allocator_traits<Alloc>::construct(
1624 alloc, address, boost::forward<Args>(args)...);
1627 // For backwards compatibility, implement a special case for
1628 // piecewise_construct with boost::tuple
1630 template <typename A0> struct detect_boost_tuple
1632 template <typename T0, typename T1, typename T2, typename T3,
1633 typename T4, typename T5, typename T6, typename T7, typename T8,
1635 static choice1::type test(choice1,
1636 boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> const&);
1638 static choice2::type test(choice2, ...);
1642 value = sizeof(choice1::type) ==
1643 sizeof(test(choose(), boost::unordered::detail::make<A0>()))
1647 // Special case for piecewise_construct
1649 template <typename Alloc, typename A, typename B, typename A0,
1650 typename A1, typename A2>
1651 inline typename boost::enable_if_c<use_piecewise<A0>::value &&
1652 detect_boost_tuple<A1>::value &&
1653 detect_boost_tuple<A2>::value,
1655 construct_from_args(Alloc& alloc, std::pair<A, B>* address,
1656 BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
1658 boost::unordered::detail::func::construct_from_tuple(
1659 alloc, boost::addressof(address->first), boost::forward<A1>(a1));
1662 boost::unordered::detail::func::construct_from_tuple(
1663 alloc, boost::addressof(address->second), boost::forward<A2>(a2));
1667 boost::unordered::detail::func::destroy(
1668 boost::addressof(address->first));
1674 #elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1676 ////////////////////////////////////////////////////////////////////////
1677 // Construct from variadic parameters
1679 template <typename Alloc, typename T, typename... Args>
1680 inline void construct_from_args(
1681 Alloc&, T* address, BOOST_FWD_REF(Args)... args)
1683 new ((void*)address) T(boost::forward<Args>(args)...);
1686 // Special case for piecewise_construct
1688 template <typename Alloc, typename A, typename B, typename A0,
1689 typename A1, typename A2>
1690 inline typename enable_if<use_piecewise<A0>, void>::type
1691 construct_from_args(Alloc& alloc, std::pair<A, B>* address,
1692 BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
1694 boost::unordered::detail::func::construct_from_tuple(
1695 alloc, boost::addressof(address->first), boost::forward<A1>(a1));
1698 boost::unordered::detail::func::construct_from_tuple(
1699 alloc, boost::addressof(address->second), boost::forward<A2>(a2));
1703 boost::unordered::detail::func::destroy(
1704 boost::addressof(address->first));
1710 #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
1712 ////////////////////////////////////////////////////////////////////////
1713 // Construct from emplace_args
1715 // Explicitly write out first three overloads for the sake of sane
1718 template <typename Alloc, typename T, typename A0>
1719 inline void construct_from_args(
1720 Alloc&, T* address, emplace_args1<A0> const& args)
1722 new ((void*)address) T(boost::forward<A0>(args.a0));
1725 template <typename Alloc, typename T, typename A0, typename A1>
1726 inline void construct_from_args(
1727 Alloc&, T* address, emplace_args2<A0, A1> const& args)
1729 new ((void*)address)
1730 T(boost::forward<A0>(args.a0), boost::forward<A1>(args.a1));
1733 template <typename Alloc, typename T, typename A0, typename A1,
1735 inline void construct_from_args(
1736 Alloc&, T* address, emplace_args3<A0, A1, A2> const& args)
1738 new ((void*)address) T(boost::forward<A0>(args.a0),
1739 boost::forward<A1>(args.a1), boost::forward<A2>(args.a2));
1742 // Use a macro for the rest.
1744 #define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
1745 template <typename Alloc, typename T, \
1746 BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A)> \
1747 inline void construct_from_args(Alloc&, T* address, \
1748 boost::unordered::detail::BOOST_PP_CAT(emplace_args, num_params) < \
1749 BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) > const& args) \
1751 new ((void*)address) \
1752 T(BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_FORWARD, args.a)); \
1755 BOOST_UNORDERED_CONSTRUCT_IMPL(1, 4, _)
1756 BOOST_UNORDERED_CONSTRUCT_IMPL(1, 5, _)
1757 BOOST_UNORDERED_CONSTRUCT_IMPL(1, 6, _)
1758 BOOST_UNORDERED_CONSTRUCT_IMPL(1, 7, _)
1759 BOOST_UNORDERED_CONSTRUCT_IMPL(1, 8, _)
1760 BOOST_UNORDERED_CONSTRUCT_IMPL(1, 9, _)
1761 BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT),
1762 BOOST_UNORDERED_CONSTRUCT_IMPL, _)
1764 #undef BOOST_UNORDERED_CONSTRUCT_IMPL
1766 // Construct with piecewise_construct
1768 template <typename Alloc, typename A, typename B, typename A0,
1769 typename A1, typename A2>
1770 inline void construct_from_args(Alloc& alloc, std::pair<A, B>* address,
1771 boost::unordered::detail::emplace_args3<A0, A1, A2> const& args,
1772 typename enable_if<use_piecewise<A0>, void*>::type = 0)
1774 boost::unordered::detail::func::construct_from_tuple(
1775 alloc, boost::addressof(address->first), args.a1);
1778 boost::unordered::detail::func::construct_from_tuple(
1779 alloc, boost::addressof(address->second), args.a2);
1783 boost::unordered::detail::func::destroy(
1784 boost::addressof(address->first));
1790 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
1797 namespace unordered {
1800 ///////////////////////////////////////////////////////////////////
1802 // Node construction
1804 template <typename NodeAlloc> struct node_constructor
1806 typedef NodeAlloc node_allocator;
1807 typedef boost::unordered::detail::allocator_traits<NodeAlloc>
1808 node_allocator_traits;
1809 typedef typename node_allocator_traits::value_type node;
1810 typedef typename node_allocator_traits::pointer node_pointer;
1811 typedef typename node::value_type value_type;
1813 node_allocator& alloc_;
1816 node_constructor(node_allocator& n) : alloc_(n), node_() {}
1818 ~node_constructor();
1823 node_pointer release()
1825 BOOST_ASSERT(node_);
1826 node_pointer p = node_;
1827 node_ = node_pointer();
1831 void reclaim(node_pointer p)
1833 BOOST_ASSERT(!node_);
1835 BOOST_UNORDERED_CALL_DESTROY(
1836 node_allocator_traits, alloc_, node_->value_ptr());
1840 node_constructor(node_constructor const&);
1841 node_constructor& operator=(node_constructor const&);
1844 template <typename Alloc> node_constructor<Alloc>::~node_constructor()
1847 boost::unordered::detail::func::destroy(pointer<node>::get(node_));
1848 node_allocator_traits::deallocate(alloc_, node_, 1);
1852 template <typename Alloc> void node_constructor<Alloc>::create_node()
1854 BOOST_ASSERT(!node_);
1855 node_ = node_allocator_traits::allocate(alloc_, 1);
1856 new (pointer<void>::get(node_)) node();
1859 template <typename NodeAlloc> struct node_tmp
1861 typedef boost::unordered::detail::allocator_traits<NodeAlloc>
1862 node_allocator_traits;
1863 typedef typename node_allocator_traits::pointer node_pointer;
1864 typedef typename node_allocator_traits::value_type node;
1869 explicit node_tmp(node_pointer n, NodeAlloc& a) : alloc_(a), node_(n) {}
1874 node_pointer release()
1876 node_pointer p = node_;
1877 node_ = node_pointer();
1882 template <typename Alloc> node_tmp<Alloc>::~node_tmp()
1885 BOOST_UNORDERED_CALL_DESTROY(
1886 node_allocator_traits, alloc_, node_->value_ptr());
1887 boost::unordered::detail::func::destroy(pointer<node>::get(node_));
1888 node_allocator_traits::deallocate(alloc_, node_, 1);
1896 namespace unordered {
1900 // Some nicer construct_node functions, might try to
1901 // improve implementation later.
1903 template <typename Alloc, BOOST_UNORDERED_EMPLACE_TEMPLATE>
1905 typename boost::unordered::detail::allocator_traits<Alloc>::pointer
1906 construct_node_from_args(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS)
1908 node_constructor<Alloc> a(alloc);
1910 construct_from_args(
1911 alloc, a.node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
1915 template <typename Alloc, typename U>
1917 typename boost::unordered::detail::allocator_traits<Alloc>::pointer
1918 construct_node(Alloc& alloc, BOOST_FWD_REF(U) x)
1920 node_constructor<Alloc> a(alloc);
1922 BOOST_UNORDERED_CALL_CONSTRUCT1(
1923 boost::unordered::detail::allocator_traits<Alloc>, alloc,
1924 a.node_->value_ptr(), boost::forward<U>(x));
1928 #if BOOST_UNORDERED_CXX11_CONSTRUCTION
1930 template <typename Alloc, typename Key>
1932 typename boost::unordered::detail::allocator_traits<Alloc>::pointer
1933 construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
1935 node_constructor<Alloc> a(alloc);
1937 boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
1938 a.node_->value_ptr(), std::piecewise_construct,
1939 std::forward_as_tuple(boost::forward<Key>(k)),
1940 std::forward_as_tuple());
1944 template <typename Alloc, typename Key, typename Mapped>
1946 typename boost::unordered::detail::allocator_traits<Alloc>::pointer
1947 construct_node_pair(
1948 Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
1950 node_constructor<Alloc> a(alloc);
1952 boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
1953 a.node_->value_ptr(), std::piecewise_construct,
1954 std::forward_as_tuple(boost::forward<Key>(k)),
1955 std::forward_as_tuple(boost::forward<Mapped>(m)));
1959 template <typename Alloc, typename Key, typename... Args>
1961 typename boost::unordered::detail::allocator_traits<Alloc>::pointer
1962 construct_node_pair_from_args(
1963 Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Args)... args)
1965 node_constructor<Alloc> a(alloc);
1967 #if !(BOOST_COMP_CLANG && BOOST_COMP_CLANG < BOOST_VERSION_NUMBER(3, 8, 0) && \
1968 defined(BOOST_LIBSTDCXX11))
1969 boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
1970 a.node_->value_ptr(), std::piecewise_construct,
1971 std::forward_as_tuple(boost::forward<Key>(k)),
1972 std::forward_as_tuple(boost::forward<Args>(args)...));
1974 // It doesn't seem to be possible to construct a tuple with 3 variadic
1975 // rvalue reference members when using older versions of clang with
1976 // libstdc++, so just use std::make_tuple instead of
1977 // std::forward_as_tuple.
1978 boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
1979 a.node_->value_ptr(), std::piecewise_construct,
1980 std::forward_as_tuple(boost::forward<Key>(k)),
1981 std::make_tuple(boost::forward<Args>(args)...));
1988 template <typename Alloc, typename Key>
1990 typename boost::unordered::detail::allocator_traits<Alloc>::pointer
1991 construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
1993 node_constructor<Alloc> a(alloc);
1995 boost::unordered::detail::func::construct_value(
1996 boost::addressof(a.node_->value_ptr()->first),
1997 boost::forward<Key>(k));
2000 boost::unordered::detail::func::construct_value(
2001 boost::addressof(a.node_->value_ptr()->second));
2005 boost::unordered::detail::func::destroy(
2006 boost::addressof(a.node_->value_ptr()->first));
2013 template <typename Alloc, typename Key, typename Mapped>
2015 typename boost::unordered::detail::allocator_traits<Alloc>::pointer
2016 construct_node_pair(
2017 Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
2019 node_constructor<Alloc> a(alloc);
2021 boost::unordered::detail::func::construct_value(
2022 boost::addressof(a.node_->value_ptr()->first),
2023 boost::forward<Key>(k));
2026 boost::unordered::detail::func::construct_value(
2027 boost::addressof(a.node_->value_ptr()->second),
2028 boost::forward<Mapped>(m));
2032 boost::unordered::detail::func::destroy(
2033 boost::addressof(a.node_->value_ptr()->first));
2040 template <typename Alloc, typename Key,
2041 BOOST_UNORDERED_EMPLACE_TEMPLATE>
2043 typename boost::unordered::detail::allocator_traits<Alloc>::pointer
2044 construct_node_pair_from_args(
2045 Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS)
2047 node_constructor<Alloc> a(alloc);
2049 boost::unordered::detail::func::construct_value(
2050 boost::addressof(a.node_->value_ptr()->first),
2051 boost::forward<Key>(k));
2054 boost::unordered::detail::func::construct_from_args(alloc,
2055 boost::addressof(a.node_->value_ptr()->second),
2056 BOOST_UNORDERED_EMPLACE_FORWARD);
2060 boost::unordered::detail::func::destroy(
2061 boost::addressof(a.node_->value_ptr()->first));
2074 #if defined(BOOST_MSVC)
2075 #pragma warning(pop)
2078 // The 'iterator_detail' namespace was a misguided attempt at avoiding ADL
2079 // in the detail namespace. It didn't work because the template parameters
2080 // were in detail. I'm not changing it at the moment to be safe. I might
2081 // do in the future if I change the iterator types.
2083 namespace unordered {
2084 namespace iterator_detail {
2086 //////////////////////////////////////////////////////////////////////////
2091 template <typename Node>
2093 : public std::iterator<std::forward_iterator_tag,
2094 typename Node::value_type, std::ptrdiff_t,
2095 typename Node::value_type*, typename Node::value_type&>
2097 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
2098 template <typename Node2>
2099 friend struct boost::unordered::iterator_detail::cl_iterator;
2103 typedef typename Node::node_pointer node_pointer;
2105 std::size_t bucket_;
2106 std::size_t bucket_count_;
2109 typedef typename Node::value_type value_type;
2111 l_iterator() BOOST_NOEXCEPT : ptr_() {}
2113 l_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT
2120 value_type& operator*() const { return ptr_->value(); }
2122 value_type* operator->() const { return ptr_->value_ptr(); }
2124 l_iterator& operator++()
2126 ptr_ = static_cast<node_pointer>(ptr_->next_);
2127 if (ptr_ && ptr_->get_bucket() != bucket_)
2128 ptr_ = node_pointer();
2132 l_iterator operator++(int)
2134 l_iterator tmp(*this);
2139 bool operator==(l_iterator x) const BOOST_NOEXCEPT
2141 return ptr_ == x.ptr_;
2144 bool operator!=(l_iterator x) const BOOST_NOEXCEPT
2146 return ptr_ != x.ptr_;
2150 template <typename Node>
2152 : public std::iterator<std::forward_iterator_tag,
2153 typename Node::value_type, std::ptrdiff_t,
2154 typename Node::value_type const*, typename Node::value_type const&>
2156 friend struct boost::unordered::iterator_detail::l_iterator<Node>;
2159 typedef typename Node::node_pointer node_pointer;
2161 std::size_t bucket_;
2162 std::size_t bucket_count_;
2165 typedef typename Node::value_type value_type;
2167 cl_iterator() BOOST_NOEXCEPT : ptr_() {}
2169 cl_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT
2177 boost::unordered::iterator_detail::l_iterator<Node> const& x)
2178 BOOST_NOEXCEPT : ptr_(x.ptr_),
2180 bucket_count_(x.bucket_count_)
2184 value_type const& operator*() const { return ptr_->value(); }
2186 value_type const* operator->() const { return ptr_->value_ptr(); }
2188 cl_iterator& operator++()
2190 ptr_ = static_cast<node_pointer>(ptr_->next_);
2191 if (ptr_ && ptr_->get_bucket() != bucket_)
2192 ptr_ = node_pointer();
2196 cl_iterator operator++(int)
2198 cl_iterator tmp(*this);
2203 friend bool operator==(
2204 cl_iterator const& x, cl_iterator const& y) BOOST_NOEXCEPT
2206 return x.ptr_ == y.ptr_;
2209 friend bool operator!=(
2210 cl_iterator const& x, cl_iterator const& y) BOOST_NOEXCEPT
2212 return x.ptr_ != y.ptr_;
2216 template <typename Node>
2218 : public std::iterator<std::forward_iterator_tag,
2219 typename Node::value_type, std::ptrdiff_t,
2220 typename Node::value_type*, typename Node::value_type&>
2222 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
2224 friend struct boost::unordered::iterator_detail::c_iterator;
2225 template <typename> friend struct boost::unordered::detail::table;
2229 typedef typename Node::node_pointer node_pointer;
2233 typedef typename Node::value_type value_type;
2235 iterator() BOOST_NOEXCEPT : node_() {}
2237 explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT
2238 : node_(static_cast<node_pointer>(x))
2242 value_type& operator*() const { return node_->value(); }
2244 value_type* operator->() const { return node_->value_ptr(); }
2246 iterator& operator++()
2248 node_ = static_cast<node_pointer>(node_->next_);
2252 iterator operator++(int)
2254 iterator tmp(node_);
2255 node_ = static_cast<node_pointer>(node_->next_);
2259 bool operator==(iterator const& x) const BOOST_NOEXCEPT
2261 return node_ == x.node_;
2264 bool operator!=(iterator const& x) const BOOST_NOEXCEPT
2266 return node_ != x.node_;
2270 template <typename Node>
2272 : public std::iterator<std::forward_iterator_tag,
2273 typename Node::value_type, std::ptrdiff_t,
2274 typename Node::value_type const*, typename Node::value_type const&>
2276 friend struct boost::unordered::iterator_detail::iterator<Node>;
2278 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
2279 template <typename> friend struct boost::unordered::detail::table;
2283 typedef typename Node::node_pointer node_pointer;
2284 typedef boost::unordered::iterator_detail::iterator<Node> n_iterator;
2288 typedef typename Node::value_type value_type;
2290 c_iterator() BOOST_NOEXCEPT : node_() {}
2292 explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT
2293 : node_(static_cast<node_pointer>(x))
2297 c_iterator(n_iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {}
2299 value_type const& operator*() const { return node_->value(); }
2301 value_type const* operator->() const { return node_->value_ptr(); }
2303 c_iterator& operator++()
2305 node_ = static_cast<node_pointer>(node_->next_);
2309 c_iterator operator++(int)
2311 c_iterator tmp(node_);
2312 node_ = static_cast<node_pointer>(node_->next_);
2316 friend bool operator==(
2317 c_iterator const& x, c_iterator const& y) BOOST_NOEXCEPT
2319 return x.node_ == y.node_;
2322 friend bool operator!=(
2323 c_iterator const& x, c_iterator const& y) BOOST_NOEXCEPT
2325 return x.node_ != y.node_;
2333 namespace unordered {
2336 ///////////////////////////////////////////////////////////////////
2340 // Temporary store for nodes. Deletes any that aren't used.
2342 template <typename NodeAlloc> struct node_holder
2345 typedef NodeAlloc node_allocator;
2346 typedef boost::unordered::detail::allocator_traits<NodeAlloc>
2347 node_allocator_traits;
2348 typedef typename node_allocator_traits::value_type node;
2349 typedef typename node_allocator_traits::pointer node_pointer;
2350 typedef typename node::value_type value_type;
2351 typedef typename node::link_pointer link_pointer;
2352 typedef boost::unordered::iterator_detail::iterator<node> iterator;
2354 node_constructor<NodeAlloc> constructor_;
2355 node_pointer nodes_;
2358 template <typename Table>
2359 explicit node_holder(Table& b) : constructor_(b.node_alloc()), nodes_()
2362 typename Table::link_pointer prev = b.get_previous_start();
2363 nodes_ = static_cast<node_pointer>(prev->next_);
2364 prev->next_ = link_pointer();
2371 node_pointer pop_node()
2373 node_pointer n = nodes_;
2374 nodes_ = static_cast<node_pointer>(nodes_->next_);
2375 n->next_ = link_pointer();
2379 template <typename T> inline node_pointer copy_of(T const& v)
2382 constructor_.reclaim(pop_node());
2384 constructor_.create_node();
2386 BOOST_UNORDERED_CALL_CONSTRUCT1(node_allocator_traits,
2387 constructor_.alloc_, constructor_.node_->value_ptr(), v);
2388 return constructor_.release();
2391 template <typename T> inline node_pointer move_copy_of(T& v)
2394 constructor_.reclaim(pop_node());
2396 constructor_.create_node();
2398 BOOST_UNORDERED_CALL_CONSTRUCT1(node_allocator_traits,
2399 constructor_.alloc_, constructor_.node_->value_ptr(),
2401 return constructor_.release();
2404 iterator begin() const { return iterator(nodes_); }
2407 template <typename Alloc> node_holder<Alloc>::~node_holder()
2410 node_pointer p = nodes_;
2411 nodes_ = static_cast<node_pointer>(p->next_);
2413 BOOST_UNORDERED_CALL_DESTROY(
2414 node_allocator_traits, constructor_.alloc_, p->value_ptr());
2415 boost::unordered::detail::func::destroy(pointer<node>::get(p));
2416 node_allocator_traits::deallocate(constructor_.alloc_, p, 1);
2420 ///////////////////////////////////////////////////////////////////
2424 template <typename NodePointer> struct bucket
2426 typedef NodePointer link_pointer;
2429 bucket() : next_() {}
2430 bucket(link_pointer n) : next_(n) {}
2432 link_pointer first_from_start() { return next_; }
2442 typedef ptr_bucket* link_pointer;
2445 ptr_bucket() : next_(0) {}
2446 ptr_bucket(link_pointer n) : next_(n) {}
2448 link_pointer first_from_start() { return this; }
2456 ///////////////////////////////////////////////////////////////////
2460 template <typename SizeT> struct prime_policy
2462 template <typename Hash, typename T>
2463 static inline SizeT apply_hash(Hash const& hf, T const& x)
2468 static inline SizeT to_bucket(SizeT bucket_count, SizeT hash)
2470 return hash % bucket_count;
2473 static inline SizeT new_bucket_count(SizeT min)
2475 return boost::unordered::detail::next_prime(min);
2478 static inline SizeT prev_bucket_count(SizeT max)
2480 return boost::unordered::detail::prev_prime(max);
2484 template <typename SizeT> struct mix64_policy
2486 template <typename Hash, typename T>
2487 static inline SizeT apply_hash(Hash const& hf, T const& x)
2490 key = (~key) + (key << 21); // key = (key << 21) - key - 1;
2491 key = key ^ (key >> 24);
2492 key = (key + (key << 3)) + (key << 8); // key * 265
2493 key = key ^ (key >> 14);
2494 key = (key + (key << 2)) + (key << 4); // key * 21
2495 key = key ^ (key >> 28);
2496 key = key + (key << 31);
2500 static inline SizeT to_bucket(SizeT bucket_count, SizeT hash)
2502 return hash & (bucket_count - 1);
2505 static inline SizeT new_bucket_count(SizeT min)
2519 static inline SizeT prev_bucket_count(SizeT max)
2527 return (max >> 1) + 1;
2531 template <int digits, int radix> struct pick_policy_impl
2533 typedef prime_policy<std::size_t> type;
2536 template <> struct pick_policy_impl<64, 2>
2538 typedef mix64_policy<std::size_t> type;
2541 template <typename T>
2543 : pick_policy_impl<std::numeric_limits<std::size_t>::digits,
2544 std::numeric_limits<std::size_t>::radix>
2548 // While the mix policy is generally faster, the prime policy is a lot
2549 // faster when a large number consecutive integers are used, because
2550 // there are no collisions. Since that is probably quite common, use
2551 // prime policy for integeral types. But not the smaller ones, as they
2552 // don't have enough unique values for this to be an issue.
2554 template <> struct pick_policy2<int>
2556 typedef prime_policy<std::size_t> type;
2559 template <> struct pick_policy2<unsigned int>
2561 typedef prime_policy<std::size_t> type;
2564 template <> struct pick_policy2<long>
2566 typedef prime_policy<std::size_t> type;
2569 template <> struct pick_policy2<unsigned long>
2571 typedef prime_policy<std::size_t> type;
2574 #if !defined(BOOST_NO_LONG_LONG)
2575 template <> struct pick_policy2<boost::long_long_type>
2577 typedef prime_policy<std::size_t> type;
2580 template <> struct pick_policy2<boost::ulong_long_type>
2582 typedef prime_policy<std::size_t> type;
2586 template <typename T>
2587 struct pick_policy : pick_policy2<typename boost::remove_cv<T>::type>
2591 //////////////////////////////////////////////////////////////////////////
2594 // Assigning and swapping the equality and hash function objects
2595 // needs strong exception safety. To implement that normally we'd
2596 // require one of them to be known to not throw and the other to
2597 // guarantee strong exception safety. Unfortunately they both only
2598 // have basic exception safety. So to acheive strong exception
2599 // safety we have storage space for two copies, and assign the new
2600 // copies to the unused space. Then switch to using that to use
2601 // them. This is implemented in 'set_hash_functions' which
2602 // atomically assigns the new function objects in a strongly
2603 // exception safe manner.
2605 template <class H, class P, bool NoThrowMoveAssign>
2606 class set_hash_functions;
2608 template <class H, class P> class functions
2611 static const bool nothrow_move_assignable =
2612 boost::is_nothrow_move_assignable<H>::value &&
2613 boost::is_nothrow_move_assignable<P>::value;
2614 static const bool nothrow_move_constructible =
2615 boost::is_nothrow_move_constructible<H>::value &&
2616 boost::is_nothrow_move_constructible<P>::value;
2619 friend class boost::unordered::detail::set_hash_functions<H, P,
2620 nothrow_move_assignable>;
2621 functions& operator=(functions const&);
2623 typedef compressed<H, P> function_pair;
2625 typedef typename boost::aligned_storage<sizeof(function_pair),
2626 boost::alignment_of<function_pair>::value>::type aligned_function;
2628 bool current_; // The currently active functions.
2629 aligned_function funcs_[2];
2631 function_pair const& current() const
2633 return *static_cast<function_pair const*>(
2634 static_cast<void const*>(funcs_[current_].address()));
2637 function_pair& current()
2639 return *static_cast<function_pair*>(
2640 static_cast<void*>(funcs_[current_].address()));
2643 void construct(bool which, H const& hf, P const& eq)
2645 new ((void*)&funcs_[which]) function_pair(hf, eq);
2648 void construct(bool which, function_pair const& f,
2649 boost::unordered::detail::false_type =
2650 boost::unordered::detail::false_type())
2652 new ((void*)&funcs_[which]) function_pair(f);
2656 bool which, function_pair& f, boost::unordered::detail::true_type)
2658 new ((void*)&funcs_[which])
2659 function_pair(f, boost::unordered::detail::move_tag());
2662 void destroy(bool which)
2664 boost::unordered::detail::func::destroy(
2665 (function_pair*)(&funcs_[which]));
2669 typedef boost::unordered::detail::set_hash_functions<H, P,
2670 nothrow_move_assignable>
2673 functions(H const& hf, P const& eq) : current_(false)
2675 construct(current_, hf, eq);
2678 functions(functions const& bf) : current_(false)
2680 construct(current_, bf.current());
2683 functions(functions& bf, boost::unordered::detail::move_tag)
2686 construct(current_, bf.current(),
2687 boost::unordered::detail::integral_constant<bool,
2688 nothrow_move_constructible>());
2691 ~functions() { this->destroy(current_); }
2693 H const& hash_function() const { return current().first(); }
2695 P const& key_eq() const { return current().second(); }
2698 template <class H, class P> class set_hash_functions<H, P, false>
2700 set_hash_functions(set_hash_functions const&);
2701 set_hash_functions& operator=(set_hash_functions const&);
2703 typedef functions<H, P> functions_type;
2705 functions_type& functions_;
2706 bool tmp_functions_;
2709 set_hash_functions(functions_type& f, H const& h, P const& p)
2710 : functions_(f), tmp_functions_(!f.current_)
2712 f.construct(tmp_functions_, h, p);
2715 set_hash_functions(functions_type& f, functions_type const& other)
2716 : functions_(f), tmp_functions_(!f.current_)
2718 f.construct(tmp_functions_, other.current());
2721 ~set_hash_functions() { functions_.destroy(tmp_functions_); }
2725 functions_.current_ = tmp_functions_;
2726 tmp_functions_ = !tmp_functions_;
2730 template <class H, class P> class set_hash_functions<H, P, true>
2732 set_hash_functions(set_hash_functions const&);
2733 set_hash_functions& operator=(set_hash_functions const&);
2735 typedef functions<H, P> functions_type;
2737 functions_type& functions_;
2742 set_hash_functions(functions_type& f, H const& h, P const& p)
2743 : functions_(f), hash_(h), pred_(p)
2747 set_hash_functions(functions_type& f, functions_type const& other)
2748 : functions_(f), hash_(other.hash_function()), pred_(other.key_eq())
2754 functions_.current().first() = boost::move(hash_);
2755 functions_.current().second() = boost::move(pred_);
2759 ////////////////////////////////////////////////////////////////////////////
2760 // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
2763 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
2764 #define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
2766 struct please_ignore_this_overload
2768 typedef please_ignore_this_overload type;
2771 template <typename T> struct rv_ref_impl
2773 typedef BOOST_RV_REF(T) type;
2776 template <typename T>
2778 : boost::detail::if_true<boost::is_class<T>::value>::
2779 BOOST_NESTED_TEMPLATE then<boost::unordered::detail::rv_ref_impl<T>,
2780 please_ignore_this_overload>::type
2784 #define BOOST_UNORDERED_RV_REF(T) \
2785 typename boost::unordered::detail::rv_ref<T>::type
2788 #if defined(BOOST_MSVC)
2789 #pragma warning(push)
2790 #pragma warning(disable : 4127) // conditional expression is constant
2793 //////////////////////////////////////////////////////////////////////////
2794 // convert double to std::size_t
2796 inline std::size_t double_to_size(double f)
2798 return f >= static_cast<double>(
2799 (std::numeric_limits<std::size_t>::max)())
2800 ? (std::numeric_limits<std::size_t>::max)()
2801 : static_cast<std::size_t>(f);
2804 // The space used to store values in a node.
2806 template <typename ValueType> struct value_base
2808 typedef ValueType value_type;
2810 typename boost::aligned_storage<sizeof(value_type),
2811 boost::alignment_of<value_type>::value>::type data_;
2813 value_base() : data_() {}
2815 void* address() { return this; }
2817 value_type& value() { return *(ValueType*)this; }
2819 value_type const& value() const { return *(ValueType const*)this; }
2821 value_type* value_ptr() { return (ValueType*)this; }
2823 value_type const* value_ptr() const { return (ValueType const*)this; }
2826 value_base& operator=(value_base const&);
2829 template <typename Types>
2830 struct table : boost::unordered::detail::functions<typename Types::hasher,
2831 typename Types::key_equal>
2834 table(table const&);
2835 table& operator=(table const&);
2838 typedef typename Types::node node;
2839 typedef typename Types::bucket bucket;
2840 typedef typename Types::hasher hasher;
2841 typedef typename Types::key_equal key_equal;
2842 typedef typename Types::const_key_type const_key_type;
2843 typedef typename Types::extractor extractor;
2844 typedef typename Types::value_type value_type;
2845 typedef typename Types::table table_impl;
2846 typedef typename Types::link_pointer link_pointer;
2847 typedef typename Types::policy policy;
2848 typedef typename Types::iterator iterator;
2849 typedef typename Types::c_iterator c_iterator;
2850 typedef typename Types::l_iterator l_iterator;
2851 typedef typename Types::cl_iterator cl_iterator;
2853 typedef boost::unordered::detail::functions<typename Types::hasher,
2854 typename Types::key_equal>
2856 typedef typename functions::set_hash_functions set_hash_functions;
2858 typedef typename Types::value_allocator value_allocator;
2859 typedef typename boost::unordered::detail::rebind_wrap<value_allocator,
2860 node>::type node_allocator;
2861 typedef typename boost::unordered::detail::rebind_wrap<value_allocator,
2862 bucket>::type bucket_allocator;
2863 typedef boost::unordered::detail::allocator_traits<node_allocator>
2864 node_allocator_traits;
2865 typedef boost::unordered::detail::allocator_traits<bucket_allocator>
2866 bucket_allocator_traits;
2867 typedef typename node_allocator_traits::pointer node_pointer;
2869 typename node_allocator_traits::const_pointer const_node_pointer;
2870 typedef typename bucket_allocator_traits::pointer bucket_pointer;
2871 typedef boost::unordered::detail::node_constructor<node_allocator>
2873 typedef boost::unordered::detail::node_tmp<node_allocator> node_tmp;
2875 typedef std::pair<iterator, bool> emplace_return;
2877 ////////////////////////////////////////////////////////////////////////
2880 boost::unordered::detail::compressed<bucket_allocator, node_allocator>
2882 std::size_t bucket_count_;
2885 std::size_t max_load_;
2886 bucket_pointer buckets_;
2888 ////////////////////////////////////////////////////////////////////////
2891 static node_pointer get_node(c_iterator it) { return it.node_; }
2893 static node_pointer next_node(link_pointer n)
2895 return static_cast<node_pointer>(n->next_);
2898 static node_pointer next_for_find(link_pointer n)
2900 node_pointer n2 = static_cast<node_pointer>(n);
2903 } while (n2 && !n2->is_first_in_group());
2907 node_pointer next_group(node_pointer n) const
2909 node_pointer n1 = n;
2912 } while (n1 && !n1->is_first_in_group());
2916 std::size_t group_count(node_pointer n) const
2919 node_pointer it = n;
2923 } while (it && !it->is_first_in_group());
2928 std::size_t node_bucket(node_pointer n) const
2930 return n->get_bucket();
2933 bucket_allocator const& bucket_alloc() const
2935 return allocators_.first();
2938 node_allocator const& node_alloc() const
2940 return allocators_.second();
2943 bucket_allocator& bucket_alloc() { return allocators_.first(); }
2945 node_allocator& node_alloc() { return allocators_.second(); }
2947 std::size_t max_bucket_count() const
2949 // -1 to account for the start bucket.
2950 return policy::prev_bucket_count(
2951 bucket_allocator_traits::max_size(bucket_alloc()) - 1);
2954 bucket_pointer get_bucket(std::size_t bucket_index) const
2956 BOOST_ASSERT(buckets_);
2957 return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
2960 link_pointer get_previous_start() const
2962 return get_bucket(bucket_count_)->first_from_start();
2965 link_pointer get_previous_start(std::size_t bucket_index) const
2967 return get_bucket(bucket_index)->next_;
2970 node_pointer begin() const
2972 return size_ ? next_node(get_previous_start()) : node_pointer();
2975 node_pointer begin(std::size_t bucket_index) const
2978 return node_pointer();
2979 link_pointer prev = get_previous_start(bucket_index);
2980 return prev ? next_node(prev) : node_pointer();
2983 std::size_t hash_to_bucket(std::size_t hash_value) const
2985 return policy::to_bucket(bucket_count_, hash_value);
2988 std::size_t bucket_size(std::size_t index) const
2990 node_pointer n = begin(index);
2994 std::size_t count = 0;
2995 while (n && node_bucket(n) == index) {
3003 ////////////////////////////////////////////////////////////////////////
3006 void recalculate_max_load()
3008 using namespace std;
3011 // Only resize when size >= mlf_ * count
3012 max_load_ = buckets_ ? boost::unordered::detail::double_to_size(
3013 ceil(static_cast<double>(mlf_) *
3014 static_cast<double>(bucket_count_)))
3018 void max_load_factor(float z)
3020 BOOST_ASSERT(z > 0);
3021 mlf_ = (std::max)(z, minimum_max_load_factor);
3022 recalculate_max_load();
3025 std::size_t min_buckets_for_size(std::size_t size) const
3027 BOOST_ASSERT(mlf_ >= minimum_max_load_factor);
3029 using namespace std;
3031 // From insert/emplace requirements:
3033 // size <= mlf_ * count
3034 // => count >= size / mlf_
3036 // Or from rehash post-condition:
3038 // count >= size / mlf_
3040 return policy::new_bucket_count(
3041 boost::unordered::detail::double_to_size(
3042 floor(static_cast<double>(size) / static_cast<double>(mlf_)) +
3046 ////////////////////////////////////////////////////////////////////////
3049 table(std::size_t num_buckets, hasher const& hf, key_equal const& eq,
3050 node_allocator const& a)
3051 : functions(hf, eq), allocators_(a, a),
3052 bucket_count_(policy::new_bucket_count(num_buckets)), size_(0),
3053 mlf_(1.0f), max_load_(0), buckets_()
3057 table(table const& x, node_allocator const& a)
3058 : functions(x), allocators_(a, a),
3059 bucket_count_(x.min_buckets_for_size(x.size_)), size_(0),
3060 mlf_(x.mlf_), max_load_(0), buckets_()
3064 table(table& x, boost::unordered::detail::move_tag m)
3065 : functions(x, m), allocators_(x.allocators_, m),
3066 bucket_count_(x.bucket_count_), size_(x.size_), mlf_(x.mlf_),
3067 max_load_(x.max_load_), buckets_(x.buckets_)
3069 x.buckets_ = bucket_pointer();
3074 table(table& x, node_allocator const& a,
3075 boost::unordered::detail::move_tag m)
3076 : functions(x, m), allocators_(a, a),
3077 bucket_count_(x.bucket_count_), size_(0), mlf_(x.mlf_),
3078 max_load_(0), buckets_()
3082 ////////////////////////////////////////////////////////////////////////
3083 // Clear buckets and Create buckets
3085 // IMPORTANT: If the container already contains any elements, the
3086 // buckets will not contain any links to them. This will
3087 // need to be dealt with, for example by:
3089 // - putting them in a 'node_holder' for future use
3090 // (as in assignment)
3091 // - placing them in buckets (see rehash_impl)
3093 // Clear the bucket pointers.
3094 void clear_buckets()
3096 bucket_pointer end = get_bucket(bucket_count_);
3097 for (bucket_pointer it = buckets_; it != end; ++it) {
3098 it->next_ = node_pointer();
3102 // Create container buckets. If the container already contains any
3104 // the linked list will be transferred to the new buckets, but none
3105 // of the bucket pointers will be set. See above note.
3107 // Strong exception safety.
3108 void create_buckets(std::size_t new_count)
3110 link_pointer dummy_node;
3112 // Construct the new buckets and dummy node, and destroy the old
3116 (buckets_ + static_cast<std::ptrdiff_t>(bucket_count_))->next_;
3117 bucket_pointer new_buckets =
3118 bucket_allocator_traits::allocate(bucket_alloc(), new_count + 1);
3120 buckets_ = new_buckets;
3121 } else if (bucket::extra_node) {
3122 node_constructor a(node_alloc());
3125 bucket_allocator_traits::allocate(bucket_alloc(), new_count + 1);
3126 dummy_node = a.release();
3128 dummy_node = link_pointer();
3130 bucket_allocator_traits::allocate(bucket_alloc(), new_count + 1);
3133 // nothrow from here...
3134 bucket_count_ = new_count;
3135 recalculate_max_load();
3137 bucket_pointer end =
3138 buckets_ + static_cast<std::ptrdiff_t>(new_count);
3139 for (bucket_pointer i = buckets_; i != end; ++i) {
3140 new (pointer<void>::get(i)) bucket();
3142 new (pointer<void>::get(end)) bucket(dummy_node);
3145 ////////////////////////////////////////////////////////////////////////
3148 void swap_allocators(table& other, false_type)
3150 boost::unordered::detail::func::ignore_unused_variable_warning(other);
3152 // According to 23.2.1.8, if propagate_on_container_swap is
3153 // false the behaviour is undefined unless the allocators
3155 BOOST_ASSERT(node_alloc() == other.node_alloc());
3158 void swap_allocators(table& other, true_type)
3160 allocators_.swap(other.allocators_);
3163 // Only swaps the allocators if propagate_on_container_swap
3166 set_hash_functions op1(*this, x);
3167 set_hash_functions op2(x, *this);
3169 // I think swap can throw if Propagate::value,
3170 // since the allocators' swap can throw. Not sure though.
3172 x, boost::unordered::detail::integral_constant<bool,
3174 node_allocator>::propagate_on_container_swap::value>());
3176 boost::swap(buckets_, x.buckets_);
3177 boost::swap(bucket_count_, x.bucket_count_);
3178 boost::swap(size_, x.size_);
3179 std::swap(mlf_, x.mlf_);
3180 std::swap(max_load_, x.max_load_);
3185 // Only call with nodes allocated with the currect allocator, or
3186 // one that is equal to it. (Can't assert because other's
3187 // allocators might have already been moved).
3188 void move_buckets_from(table& other)
3190 BOOST_ASSERT(!buckets_);
3191 buckets_ = other.buckets_;
3192 bucket_count_ = other.bucket_count_;
3193 size_ = other.size_;
3194 max_load_ = other.max_load_;
3195 other.buckets_ = bucket_pointer();
3197 other.max_load_ = 0;
3200 // For use in the constructor when allocators might be different.
3201 void move_construct_buckets(table& src)
3203 if (this->node_alloc() == src.node_alloc()) {
3204 move_buckets_from(src);
3206 this->create_buckets(this->bucket_count_);
3207 link_pointer prev = this->get_previous_start();
3208 std::size_t last_bucket = this->bucket_count_;
3209 for (node_pointer n = src.begin(); n; n = next_node(n)) {
3210 std::size_t bucket = n->get_bucket();
3211 if (bucket != last_bucket) {
3212 this->get_bucket(bucket)->next_ = prev;
3214 node_pointer n2 = boost::unordered::detail::func::construct_node(
3215 this->node_alloc(), boost::move(n->value()));
3216 n2->bucket_info_ = n->bucket_info_;
3220 last_bucket = bucket;
3225 ////////////////////////////////////////////////////////////////////////
3228 ~table() { delete_buckets(); }
3230 void destroy_node(node_pointer n)
3232 BOOST_UNORDERED_CALL_DESTROY(
3233 node_allocator_traits, node_alloc(), n->value_ptr());
3234 boost::unordered::detail::func::destroy(pointer<node>::get(n));
3235 node_allocator_traits::deallocate(node_alloc(), n, 1);
3238 void delete_buckets()
3242 static_cast<node_pointer>(get_bucket(bucket_count_)->next_);
3244 if (bucket::extra_node) {
3245 node_pointer next = next_node(n);
3246 boost::unordered::detail::func::destroy(pointer<node>::get(n));
3247 node_allocator_traits::deallocate(node_alloc(), n, 1);
3252 node_pointer next = next_node(n);
3258 buckets_ = bucket_pointer();
3264 void destroy_buckets()
3266 bucket_pointer end = get_bucket(bucket_count_ + 1);
3267 for (bucket_pointer it = buckets_; it != end; ++it) {
3268 boost::unordered::detail::func::destroy(pointer<bucket>::get(it));
3271 bucket_allocator_traits::deallocate(
3272 bucket_alloc(), buckets_, bucket_count_ + 1);
3275 ////////////////////////////////////////////////////////////////////////
3276 // Fix buckets after delete/extract
3278 // (prev,next) should mark an open range of nodes in a single bucket
3280 // have either been unlinked, or are about to be.
3282 std::size_t fix_bucket(
3283 std::size_t bucket_index, link_pointer prev, node_pointer next)
3285 std::size_t bucket_index2 = bucket_index;
3288 bucket_index2 = node_bucket(next);
3290 // If next is in the same bucket, then there's nothing to do.
3291 if (bucket_index == bucket_index2) {
3292 return bucket_index2;
3295 // Update the bucket containing next.
3296 get_bucket(bucket_index2)->next_ = prev;
3299 // Check if this bucket is now empty.
3300 bucket_pointer this_bucket = get_bucket(bucket_index);
3301 if (this_bucket->next_ == prev) {
3302 this_bucket->next_ = link_pointer();
3305 return bucket_index2;
3308 ////////////////////////////////////////////////////////////////////////
3313 ////////////////////////////////////////////////////////////////////////
3316 template <typename UniqueType>
3317 void assign(table const& x, UniqueType is_unique)
3320 assign(x, is_unique,
3321 boost::unordered::detail::integral_constant<bool,
3322 allocator_traits<node_allocator>::
3323 propagate_on_container_copy_assignment::value>());
3327 template <typename UniqueType>
3328 void assign(table const& x, UniqueType is_unique, false_type)
3330 // Strong exception safety.
3331 set_hash_functions new_func_this(*this, x);
3333 recalculate_max_load();
3335 if (x.size_ > max_load_) {
3336 create_buckets(min_buckets_for_size(x.size_));
3341 new_func_this.commit();
3343 assign_buckets(x, is_unique);
3346 template <typename UniqueType>
3347 void assign(table const& x, UniqueType is_unique, true_type)
3349 if (node_alloc() == x.node_alloc()) {
3350 allocators_.assign(x.allocators_);
3351 assign(x, is_unique, false_type());
3353 set_hash_functions new_func_this(*this, x);
3355 // Delete everything with current allocators before assigning
3358 allocators_.assign(x.allocators_);
3360 // Copy over other data, all no throw.
3361 new_func_this.commit();
3363 bucket_count_ = min_buckets_for_size(x.size_);
3365 // Finally copy the elements.
3367 copy_buckets(x, is_unique);
3372 template <typename UniqueType>
3373 void move_assign(table& x, UniqueType is_unique)
3376 move_assign(x, is_unique,
3377 boost::unordered::detail::integral_constant<bool,
3378 allocator_traits<node_allocator>::
3379 propagate_on_container_move_assignment::value>());
3383 template <typename UniqueType>
3384 void move_assign(table& x, UniqueType, true_type)
3387 set_hash_functions new_func_this(*this, x);
3388 allocators_.move_assign(x.allocators_);
3389 // No throw from here.
3391 move_buckets_from(x);
3392 new_func_this.commit();
3395 template <typename UniqueType>
3396 void move_assign(table& x, UniqueType is_unique, false_type)
3398 if (node_alloc() == x.node_alloc()) {
3400 set_hash_functions new_func_this(*this, x);
3401 // No throw from here.
3403 move_buckets_from(x);
3404 new_func_this.commit();
3406 set_hash_functions new_func_this(*this, x);
3408 recalculate_max_load();
3410 if (x.size_ > max_load_) {
3411 create_buckets(min_buckets_for_size(x.size_));
3416 new_func_this.commit();
3418 move_assign_buckets(x, is_unique);
3424 const_key_type& get_key(node_pointer n) const
3426 return extractor::extract(n->value());
3429 std::size_t hash(const_key_type& k) const
3431 return policy::apply_hash(this->hash_function(), k);
3436 node_pointer find_node(std::size_t key_hash, const_key_type& k) const
3438 return this->find_node_impl(key_hash, k, this->key_eq());
3441 node_pointer find_node(const_key_type& k) const
3443 return this->find_node_impl(hash(k), k, this->key_eq());
3446 template <class Key, class Pred>
3447 node_pointer find_node_impl(
3448 std::size_t key_hash, Key const& k, Pred const& eq) const
3450 std::size_t bucket_index = this->hash_to_bucket(key_hash);
3451 node_pointer n = this->begin(bucket_index);
3457 if (eq(k, this->get_key(n))) {
3459 } else if (this->node_bucket(n) != bucket_index) {
3460 return node_pointer();
3463 n = next_for_find(n);
3467 // Find the node before the key, so that it can be erased.
3468 link_pointer find_previous_node(
3469 const_key_type& k, std::size_t bucket_index)
3471 link_pointer prev = this->get_previous_start(bucket_index);
3477 node_pointer n = next_node(prev);
3479 return link_pointer();
3480 } else if (n->is_first_in_group()) {
3481 if (node_bucket(n) != bucket_index) {
3482 return link_pointer();
3483 } else if (this->key_eq()(k, this->get_key(n))) {
3491 // Extract and erase
3493 inline node_pointer extract_by_key(const_key_type& k)
3496 return node_pointer();
3498 std::size_t key_hash = this->hash(k);
3499 std::size_t bucket_index = this->hash_to_bucket(key_hash);
3500 link_pointer prev = this->find_previous_node(k, bucket_index);
3502 return node_pointer();
3504 node_pointer n = next_node(prev);
3505 node_pointer n2 = next_node(n);
3507 n2->set_first_in_group();
3511 this->fix_bucket(bucket_index, prev, n2);
3512 n->next_ = link_pointer();
3517 // Reserve and rehash
3519 void reserve_for_insert(std::size_t);
3520 void rehash(std::size_t);
3521 void reserve(std::size_t);
3522 void rehash_impl(std::size_t);
3524 ////////////////////////////////////////////////////////////////////////
3529 bool equals_unique(table const& other) const
3531 if (this->size_ != other.size_)
3534 for (node_pointer n1 = this->begin(); n1; n1 = next_node(n1)) {
3535 node_pointer n2 = other.find_node(other.get_key(n1));
3537 if (!n2 || n1->value() != n2->value())
3546 inline node_pointer add_node_unique(
3547 node_pointer n, std::size_t key_hash)
3549 std::size_t bucket_index = this->hash_to_bucket(key_hash);
3550 bucket_pointer b = this->get_bucket(bucket_index);
3552 n->bucket_info_ = bucket_index;
3553 n->set_first_in_group();
3556 link_pointer start_node = this->get_previous_start();
3558 if (start_node->next_) {
3559 this->get_bucket(node_bucket(next_node(start_node)))->next_ = n;
3562 b->next_ = start_node;
3563 n->next_ = start_node->next_;
3564 start_node->next_ = n;
3566 n->next_ = b->next_->next_;
3567 b->next_->next_ = n;
3574 inline node_pointer resize_and_add_node_unique(
3575 node_pointer n, std::size_t key_hash)
3577 node_tmp b(n, this->node_alloc());
3578 this->reserve_for_insert(this->size_ + 1);
3579 return this->add_node_unique(b.release(), key_hash);
3582 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
3583 iterator emplace_hint_unique(
3584 c_iterator hint, const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS)
3586 if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
3587 return iterator(hint.node_);
3589 return emplace_unique(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
3593 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
3594 emplace_return emplace_unique(
3595 const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS)
3597 std::size_t key_hash = this->hash(k);
3598 node_pointer pos = this->find_node(key_hash, k);
3600 return emplace_return(iterator(pos), false);
3602 return emplace_return(
3603 iterator(this->resize_and_add_node_unique(
3604 boost::unordered::detail::func::construct_node_from_args(
3605 this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
3611 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
3612 iterator emplace_hint_unique(
3613 c_iterator hint, no_key, BOOST_UNORDERED_EMPLACE_ARGS)
3615 node_tmp b(boost::unordered::detail::func::construct_node_from_args(
3616 this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
3617 this->node_alloc());
3618 const_key_type& k = this->get_key(b.node_);
3619 if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
3620 return iterator(hint.node_);
3622 std::size_t key_hash = this->hash(k);
3623 node_pointer pos = this->find_node(key_hash, k);
3625 return iterator(pos);
3628 this->resize_and_add_node_unique(b.release(), key_hash));
3632 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
3633 emplace_return emplace_unique(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
3635 node_tmp b(boost::unordered::detail::func::construct_node_from_args(
3636 this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
3637 this->node_alloc());
3638 const_key_type& k = this->get_key(b.node_);
3639 std::size_t key_hash = this->hash(k);
3640 node_pointer pos = this->find_node(key_hash, k);
3642 return emplace_return(iterator(pos), false);
3644 return emplace_return(
3645 iterator(this->resize_and_add_node_unique(b.release(), key_hash)),
3650 template <typename Key>
3651 emplace_return try_emplace_unique(BOOST_FWD_REF(Key) k)
3653 std::size_t key_hash = this->hash(k);
3654 node_pointer pos = this->find_node(key_hash, k);
3656 return emplace_return(iterator(pos), false);
3658 return emplace_return(
3659 iterator(this->resize_and_add_node_unique(
3660 boost::unordered::detail::func::construct_node_pair(
3661 this->node_alloc(), boost::forward<Key>(k)),
3667 template <typename Key>
3668 iterator try_emplace_hint_unique(c_iterator hint, BOOST_FWD_REF(Key) k)
3670 if (hint.node_ && this->key_eq()(hint->first, k)) {
3671 return iterator(hint.node_);
3673 return try_emplace_unique(k).first;
3677 template <typename Key, BOOST_UNORDERED_EMPLACE_TEMPLATE>
3678 emplace_return try_emplace_unique(
3679 BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS)
3681 std::size_t key_hash = this->hash(k);
3682 node_pointer pos = this->find_node(key_hash, k);
3684 return emplace_return(iterator(pos), false);
3686 return emplace_return(
3687 iterator(this->resize_and_add_node_unique(
3688 boost::unordered::detail::func::construct_node_pair_from_args(
3689 this->node_alloc(), boost::forward<Key>(k),
3690 BOOST_UNORDERED_EMPLACE_FORWARD),
3696 template <typename Key, BOOST_UNORDERED_EMPLACE_TEMPLATE>
3697 iterator try_emplace_hint_unique(
3698 c_iterator hint, BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS)
3700 if (hint.node_ && this->key_eq()(hint->first, k)) {
3701 return iterator(hint.node_);
3703 return try_emplace_unique(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
3707 template <typename Key, typename M>
3708 emplace_return insert_or_assign_unique(
3709 BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj)
3711 std::size_t key_hash = this->hash(k);
3712 node_pointer pos = this->find_node(key_hash, k);
3715 pos->value().second = boost::forward<M>(obj);
3716 return emplace_return(iterator(pos), false);
3718 return emplace_return(
3719 iterator(this->resize_and_add_node_unique(
3720 boost::unordered::detail::func::construct_node_pair(
3721 this->node_alloc(), boost::forward<Key>(k),
3722 boost::forward<M>(obj)),
3728 template <typename NodeType, typename InsertReturnType>
3729 void move_insert_node_type_unique(
3730 NodeType& np, InsertReturnType& result)
3733 const_key_type& k = this->get_key(np.ptr_);
3734 std::size_t key_hash = this->hash(k);
3735 node_pointer pos = this->find_node(key_hash, k);
3738 result.node = boost::move(np);
3739 result.position = iterator(pos);
3741 this->reserve_for_insert(this->size_ + 1);
3743 iterator(this->add_node_unique(np.ptr_, key_hash));
3744 result.inserted = true;
3745 np.ptr_ = node_pointer();
3750 template <typename NodeType>
3751 iterator move_insert_node_type_with_hint_unique(
3752 c_iterator hint, NodeType& np)
3757 const_key_type& k = this->get_key(np.ptr_);
3758 if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
3759 return iterator(hint.node_);
3761 std::size_t key_hash = this->hash(k);
3762 node_pointer pos = this->find_node(key_hash, k);
3764 this->reserve_for_insert(this->size_ + 1);
3765 pos = this->add_node_unique(np.ptr_, key_hash);
3766 np.ptr_ = node_pointer();
3768 return iterator(pos);
3771 template <typename Types2>
3772 void merge_unique(boost::unordered::detail::table<Types2>& other)
3774 typedef boost::unordered::detail::table<Types2> other_table;
3775 BOOST_STATIC_ASSERT(
3776 (boost::is_same<node, typename other_table::node>::value));
3777 BOOST_ASSERT(this->node_alloc() == other.node_alloc());
3780 link_pointer prev = other.get_previous_start();
3782 while (prev->next_) {
3783 node_pointer n = other_table::next_node(prev);
3784 const_key_type& k = this->get_key(n);
3785 std::size_t key_hash = this->hash(k);
3786 node_pointer pos = this->find_node(key_hash, k);
3791 this->reserve_for_insert(this->size_ + 1);
3792 node_pointer n2 = next_node(n);
3794 if (n2 && n->is_first_in_group()) {
3795 n2->set_first_in_group();
3798 other.fix_bucket(other.node_bucket(n), prev, n2);
3799 this->add_node_unique(n, key_hash);
3805 ////////////////////////////////////////////////////////////////////////
3806 // Insert range methods
3808 // if hash function throws, or inserting > 1 element, basic exception
3809 // safety strong otherwise
3811 template <class InputIt>
3812 void insert_range_unique(const_key_type& k, InputIt i, InputIt j)
3814 insert_range_unique2(k, i, j);
3817 // Note: can't use get_key as '*i' might not be value_type - it
3818 // could be a pair with first_types as key_type without const or
3819 // a different second_type.
3820 insert_range_unique2(extractor::extract(*i), i, j);
3824 template <class InputIt>
3825 void insert_range_unique2(const_key_type& k, InputIt i, InputIt j)
3827 // No side effects in this initial code
3828 std::size_t key_hash = this->hash(k);
3829 node_pointer pos = this->find_node(key_hash, k);
3832 node_tmp b(boost::unordered::detail::func::construct_node(
3833 this->node_alloc(), *i),
3834 this->node_alloc());
3835 if (this->size_ + 1 > this->max_load_)
3836 this->reserve_for_insert(
3837 this->size_ + boost::unordered::detail::insert_size(i, j));
3838 this->add_node_unique(b.release(), key_hash);
3842 template <class InputIt>
3843 void insert_range_unique(no_key, InputIt i, InputIt j)
3845 node_constructor a(this->node_alloc());
3851 BOOST_UNORDERED_CALL_CONSTRUCT1(
3852 node_allocator_traits, a.alloc_, a.node_->value_ptr(), *i);
3853 node_tmp b(a.release(), a.alloc_);
3855 const_key_type& k = this->get_key(b.node_);
3856 std::size_t key_hash = this->hash(k);
3857 node_pointer pos = this->find_node(key_hash, k);
3860 a.reclaim(b.release());
3862 // reserve has basic exception safety if the hash function
3863 // throws, strong otherwise.
3864 this->reserve_for_insert(this->size_ + 1);
3865 this->add_node_unique(b.release(), key_hash);
3870 ////////////////////////////////////////////////////////////////////////
3873 inline node_pointer extract_by_iterator_unique(c_iterator i)
3875 node_pointer n = i.node_;
3877 std::size_t bucket_index = this->node_bucket(n);
3878 link_pointer prev = this->get_previous_start(bucket_index);
3879 while (prev->next_ != n) {
3882 node_pointer n2 = next_node(n);
3885 this->fix_bucket(bucket_index, prev, n2);
3886 n->next_ = link_pointer();
3890 ////////////////////////////////////////////////////////////////////////
3895 std::size_t erase_key_unique(const_key_type& k)
3899 std::size_t key_hash = this->hash(k);
3900 std::size_t bucket_index = this->hash_to_bucket(key_hash);
3901 link_pointer prev = this->find_previous_node(k, bucket_index);
3904 node_pointer n = next_node(prev);
3905 node_pointer n2 = next_node(n);
3908 this->fix_bucket(bucket_index, prev, n2);
3909 this->destroy_node(n);
3913 void erase_nodes_unique(node_pointer i, node_pointer j)
3915 std::size_t bucket_index = this->node_bucket(i);
3917 // Find the node before i.
3918 link_pointer prev = this->get_previous_start(bucket_index);
3919 while (prev->next_ != i)
3922 // Delete the nodes.
3925 node_pointer next = next_node(i);
3928 bucket_index = this->fix_bucket(bucket_index, prev, next);
3933 ////////////////////////////////////////////////////////////////////////
3934 // fill_buckets_unique
3936 void copy_buckets(table const& src, true_type)
3938 this->create_buckets(this->bucket_count_);
3940 for (node_pointer n = src.begin(); n; n = next_node(n)) {
3941 std::size_t key_hash = this->hash(this->get_key(n));
3942 this->add_node_unique(
3943 boost::unordered::detail::func::construct_node(
3944 this->node_alloc(), n->value()),
3949 void assign_buckets(table const& src, true_type)
3951 node_holder<node_allocator> holder(*this);
3952 for (node_pointer n = src.begin(); n; n = next_node(n)) {
3953 std::size_t key_hash = this->hash(this->get_key(n));
3954 this->add_node_unique(holder.copy_of(n->value()), key_hash);
3958 void move_assign_buckets(table& src, true_type)
3960 node_holder<node_allocator> holder(*this);
3961 for (node_pointer n = src.begin(); n; n = next_node(n)) {
3962 std::size_t key_hash = this->hash(this->get_key(n));
3963 this->add_node_unique(holder.move_copy_of(n->value()), key_hash);
3967 ////////////////////////////////////////////////////////////////////////
3972 bool equals_equiv(table const& other) const
3974 if (this->size_ != other.size_)
3977 for (node_pointer n1 = this->begin(); n1;) {
3978 node_pointer n2 = other.find_node(other.get_key(n1));
3981 node_pointer end1 = next_group(n1);
3982 node_pointer end2 = next_group(n2);
3983 if (!group_equals_equiv(n1, end1, n2, end2))
3991 static bool group_equals_equiv(node_pointer n1, node_pointer end1,
3992 node_pointer n2, node_pointer end2)
3995 if (n1->value() != n2->value())
4007 for (node_pointer n1a = n1, n2a = n2;;) {
4008 n1a = next_node(n1a);
4009 n2a = next_node(n2a);
4022 node_pointer start = n1;
4023 for (; n1 != end1; n1 = next_node(n1)) {
4024 value_type const& v = n1->value();
4025 if (!find_equiv(start, n1, v)) {
4026 std::size_t matches = count_equal_equiv(n2, end2, v);
4029 if (matches != 1 + count_equal_equiv(next_node(n1), end1, v))
4037 static bool find_equiv(
4038 node_pointer n, node_pointer end, value_type const& v)
4040 for (; n != end; n = next_node(n))
4041 if (n->value() == v)
4046 static std::size_t count_equal_equiv(
4047 node_pointer n, node_pointer end, value_type const& v)
4049 std::size_t count = 0;
4050 for (; n != end; n = next_node(n))
4051 if (n->value() == v)
4058 inline node_pointer add_node_equiv(
4059 node_pointer n, std::size_t key_hash, node_pointer pos)
4061 std::size_t bucket_index = this->hash_to_bucket(key_hash);
4062 n->bucket_info_ = bucket_index;
4065 n->reset_first_in_group();
4066 n->next_ = pos->next_;
4069 std::size_t next_bucket = this->node_bucket(next_node(n));
4070 if (next_bucket != bucket_index) {
4071 this->get_bucket(next_bucket)->next_ = n;
4075 n->set_first_in_group();
4076 bucket_pointer b = this->get_bucket(bucket_index);
4079 link_pointer start_node = this->get_previous_start();
4081 if (start_node->next_) {
4082 this->get_bucket(this->node_bucket(next_node(start_node)))
4086 b->next_ = start_node;
4087 n->next_ = start_node->next_;
4088 start_node->next_ = n;
4090 n->next_ = b->next_->next_;
4091 b->next_->next_ = n;
4098 inline node_pointer add_using_hint_equiv(
4099 node_pointer n, node_pointer hint)
4101 n->bucket_info_ = hint->bucket_info_;
4102 n->reset_first_in_group();
4103 n->next_ = hint->next_;
4106 std::size_t next_bucket = this->node_bucket(next_node(n));
4107 if (next_bucket != this->node_bucket(n)) {
4108 this->get_bucket(next_bucket)->next_ = n;
4115 iterator emplace_equiv(node_pointer n)
4117 node_tmp a(n, this->node_alloc());
4118 const_key_type& k = this->get_key(a.node_);
4119 std::size_t key_hash = this->hash(k);
4120 node_pointer position = this->find_node(key_hash, k);
4121 this->reserve_for_insert(this->size_ + 1);
4123 this->add_node_equiv(a.release(), key_hash, position));
4126 iterator emplace_hint_equiv(c_iterator hint, node_pointer n)
4128 node_tmp a(n, this->node_alloc());
4129 const_key_type& k = this->get_key(a.node_);
4130 if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
4131 this->reserve_for_insert(this->size_ + 1);
4133 this->add_using_hint_equiv(a.release(), hint.node_));
4135 std::size_t key_hash = this->hash(k);
4136 node_pointer position = this->find_node(key_hash, k);
4137 this->reserve_for_insert(this->size_ + 1);
4139 this->add_node_equiv(a.release(), key_hash, position));
4143 void emplace_no_rehash_equiv(node_pointer n)
4145 node_tmp a(n, this->node_alloc());
4146 const_key_type& k = this->get_key(a.node_);
4147 std::size_t key_hash = this->hash(k);
4148 node_pointer position = this->find_node(key_hash, k);
4149 this->add_node_equiv(a.release(), key_hash, position);
4152 template <typename NodeType>
4153 iterator move_insert_node_type_equiv(NodeType& np)
4158 const_key_type& k = this->get_key(np.ptr_);
4159 std::size_t key_hash = this->hash(k);
4160 node_pointer pos = this->find_node(key_hash, k);
4161 this->reserve_for_insert(this->size_ + 1);
4162 result = iterator(this->add_node_equiv(np.ptr_, key_hash, pos));
4163 np.ptr_ = node_pointer();
4169 template <typename NodeType>
4170 iterator move_insert_node_type_with_hint_equiv(
4171 c_iterator hint, NodeType& np)
4176 const_key_type& k = this->get_key(np.ptr_);
4178 if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
4179 this->reserve_for_insert(this->size_ + 1);
4181 iterator(this->add_using_hint_equiv(np.ptr_, hint.node_));
4183 std::size_t key_hash = this->hash(k);
4184 node_pointer pos = this->find_node(key_hash, k);
4185 this->reserve_for_insert(this->size_ + 1);
4186 result = iterator(this->add_node_equiv(np.ptr_, key_hash, pos));
4188 np.ptr_ = node_pointer();
4194 ////////////////////////////////////////////////////////////////////////
4195 // Insert range methods
4197 // if hash function throws, or inserting > 1 element, basic exception
4198 // safety. Strong otherwise
4200 void insert_range_equiv(I i, I j,
4201 typename boost::unordered::detail::enable_if_forward<I, void*>::type =
4207 std::size_t distance = static_cast<std::size_t>(std::distance(i, j));
4208 if (distance == 1) {
4209 emplace_equiv(boost::unordered::detail::func::construct_node(
4210 this->node_alloc(), *i));
4212 // Only require basic exception safety here
4213 this->reserve_for_insert(this->size_ + distance);
4215 for (; i != j; ++i) {
4216 emplace_no_rehash_equiv(
4217 boost::unordered::detail::func::construct_node(
4218 this->node_alloc(), *i));
4224 void insert_range_equiv(I i, I j,
4225 typename boost::unordered::detail::disable_if_forward<I,
4228 for (; i != j; ++i) {
4229 emplace_equiv(boost::unordered::detail::func::construct_node(
4230 this->node_alloc(), *i));
4234 ////////////////////////////////////////////////////////////////////////
4237 inline node_pointer extract_by_iterator_equiv(c_iterator n)
4239 node_pointer i = n.node_;
4241 node_pointer j(next_node(i));
4242 std::size_t bucket_index = this->node_bucket(i);
4244 link_pointer prev = this->get_previous_start(bucket_index);
4245 while (prev->next_ != i) {
4246 prev = next_node(prev);
4250 if (j && i->is_first_in_group()) {
4251 j->set_first_in_group();
4254 this->fix_bucket(bucket_index, prev, j);
4255 i->next_ = link_pointer();
4260 ////////////////////////////////////////////////////////////////////////
4265 std::size_t erase_key_equiv(const_key_type& k)
4270 std::size_t key_hash = this->hash(k);
4271 std::size_t bucket_index = this->hash_to_bucket(key_hash);
4272 link_pointer prev = this->find_previous_node(k, bucket_index);
4276 std::size_t deleted_count = 0;
4277 node_pointer n = next_node(prev);
4279 node_pointer n2 = next_node(n);
4283 } while (n && !n->is_first_in_group());
4284 size_ -= deleted_count;
4286 this->fix_bucket(bucket_index, prev, n);
4287 return deleted_count;
4290 link_pointer erase_nodes_equiv(node_pointer i, node_pointer j)
4292 std::size_t bucket_index = this->node_bucket(i);
4294 link_pointer prev = this->get_previous_start(bucket_index);
4295 while (prev->next_ != i) {
4296 prev = next_node(prev);
4299 // Delete the nodes.
4300 // Is it inefficient to call fix_bucket for every node?
4301 bool includes_first = false;
4304 includes_first = includes_first || i->is_first_in_group();
4305 node_pointer next = next_node(i);
4308 bucket_index = this->fix_bucket(bucket_index, prev, next);
4311 if (j && includes_first) {
4312 j->set_first_in_group();
4318 ////////////////////////////////////////////////////////////////////////
4321 void copy_buckets(table const& src, false_type)
4323 this->create_buckets(this->bucket_count_);
4325 for (node_pointer n = src.begin(); n;) {
4326 std::size_t key_hash = this->hash(this->get_key(n));
4327 node_pointer group_end(next_group(n));
4328 node_pointer pos = this->add_node_equiv(
4329 boost::unordered::detail::func::construct_node(
4330 this->node_alloc(), n->value()),
4331 key_hash, node_pointer());
4332 for (n = next_node(n); n != group_end; n = next_node(n)) {
4333 this->add_node_equiv(
4334 boost::unordered::detail::func::construct_node(
4335 this->node_alloc(), n->value()),
4341 void assign_buckets(table const& src, false_type)
4343 node_holder<node_allocator> holder(*this);
4344 for (node_pointer n = src.begin(); n;) {
4345 std::size_t key_hash = this->hash(this->get_key(n));
4346 node_pointer group_end(next_group(n));
4347 node_pointer pos = this->add_node_equiv(
4348 holder.copy_of(n->value()), key_hash, node_pointer());
4349 for (n = next_node(n); n != group_end; n = next_node(n)) {
4350 this->add_node_equiv(holder.copy_of(n->value()), key_hash, pos);
4355 void move_assign_buckets(table& src, false_type)
4357 node_holder<node_allocator> holder(*this);
4358 for (node_pointer n = src.begin(); n;) {
4359 std::size_t key_hash = this->hash(this->get_key(n));
4360 node_pointer group_end(next_group(n));
4361 node_pointer pos = this->add_node_equiv(
4362 holder.move_copy_of(n->value()), key_hash, node_pointer());
4363 for (n = next_node(n); n != group_end; n = next_node(n)) {
4364 this->add_node_equiv(
4365 holder.move_copy_of(n->value()), key_hash, pos);
4371 //////////////////////////////////////////////////////////////////////////
4374 template <typename Types> inline void table<Types>::clear_impl()
4377 bucket_pointer end = get_bucket(bucket_count_);
4378 for (bucket_pointer it = buckets_; it != end; ++it) {
4379 it->next_ = node_pointer();
4382 link_pointer prev = end->first_from_start();
4383 node_pointer n = next_node(prev);
4384 prev->next_ = node_pointer();
4388 node_pointer next = next_node(n);
4395 //////////////////////////////////////////////////////////////////////////
4398 // basic exception safety
4399 template <typename Types>
4400 inline void table<Types>::reserve_for_insert(std::size_t size)
4403 create_buckets((std::max)(bucket_count_, min_buckets_for_size(size)));
4404 } else if (size > max_load_) {
4405 std::size_t num_buckets =
4406 min_buckets_for_size((std::max)(size, size_ + (size_ >> 1)));
4408 if (num_buckets != bucket_count_)
4409 this->rehash_impl(num_buckets);
4413 // if hash function throws, basic exception safety
4414 // strong otherwise.
4416 template <typename Types>
4417 inline void table<Types>::rehash(std::size_t min_buckets)
4419 using namespace std;
4423 bucket_count_ = policy::new_bucket_count(min_buckets);
4425 min_buckets = policy::new_bucket_count((std::max)(min_buckets,
4426 boost::unordered::detail::double_to_size(
4427 floor(static_cast<double>(size_) / static_cast<double>(mlf_))) +
4430 if (min_buckets != bucket_count_)
4431 this->rehash_impl(min_buckets);
4435 template <typename Types>
4436 inline void table<Types>::rehash_impl(std::size_t num_buckets)
4438 BOOST_ASSERT(this->buckets_);
4440 this->create_buckets(num_buckets);
4441 link_pointer prev = this->get_previous_start();
4444 while (prev->next_) {
4445 node_pointer n = next_node(prev);
4446 std::size_t key_hash = this->hash(this->get_key(n));
4447 std::size_t bucket_index = this->hash_to_bucket(key_hash);
4449 n->bucket_info_ = bucket_index;
4450 n->set_first_in_group();
4452 // Iterator through the rest of the group of equal nodes,
4453 // setting the bucket.
4455 node_pointer next = next_node(n);
4456 if (!next || next->is_first_in_group()) {
4460 n->bucket_info_ = bucket_index;
4461 n->reset_first_in_group();
4464 // n is now the last node in the group
4465 bucket_pointer b = this->get_bucket(bucket_index);
4470 link_pointer next = n->next_;
4471 n->next_ = b->next_->next_;
4472 b->next_->next_ = prev->next_;
4479 node_pointer n = next_node(prev);
4480 prev->next_ = node_pointer();
4482 node_pointer next = next_node(n);
4492 #if defined(BOOST_MSVC)
4493 #pragma warning(pop)
4496 ////////////////////////////////////////////////////////////////////////
4501 // 'extract_key' is called with the emplace parameters to return a
4502 // key if available or 'no_key' is one isn't and will need to be
4503 // constructed. This could be done by overloading the emplace
4505 // for the different cases, but that's a bit tricky on compilers without
4506 // variadic templates.
4508 template <typename Key, typename T> struct is_key
4510 template <typename T2> static choice1::type test(T2 const&);
4511 static choice2::type test(Key const&);
4515 value = sizeof(test(boost::unordered::detail::make<T>())) ==
4516 sizeof(choice2::type)
4519 typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE
4520 then<Key const&, no_key>::type type;
4523 template <class ValueType> struct set_extractor
4525 typedef ValueType value_type;
4526 typedef ValueType key_type;
4528 static key_type const& extract(value_type const& v) { return v; }
4530 static key_type const& extract(BOOST_UNORDERED_RV_REF(value_type) v)
4535 static no_key extract() { return no_key(); }
4537 template <class Arg> static no_key extract(Arg const&)
4542 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
4543 template <class Arg1, class Arg2, class... Args>
4544 static no_key extract(Arg1 const&, Arg2 const&, Args const&...)
4549 template <class Arg1, class Arg2>
4550 static no_key extract(Arg1 const&, Arg2 const&)
4557 template <class ValueType> struct map_extractor
4559 typedef ValueType value_type;
4560 typedef typename boost::remove_const<typename boost::unordered::detail::
4561 pair_traits<ValueType>::first_type>::type key_type;
4563 static key_type const& extract(value_type const& v) { return v.first; }
4565 template <class Second>
4566 static key_type const& extract(std::pair<key_type, Second> const& v)
4571 template <class Second>
4572 static key_type const& extract(
4573 std::pair<key_type const, Second> const& v)
4578 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
4579 template <class Second>
4580 static key_type const& extract(
4581 boost::rv<std::pair<key_type, Second> > const& v)
4586 template <class Second>
4587 static key_type const& extract(
4588 boost::rv<std::pair<key_type const, Second> > const& v)
4594 template <class Arg1>
4595 static key_type const& extract(key_type const& k, Arg1 const&)
4600 static no_key extract() { return no_key(); }
4602 template <class Arg> static no_key extract(Arg const&)
4607 template <class Arg1, class Arg2>
4608 static no_key extract(Arg1 const&, Arg2 const&)
4613 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
4614 template <class Arg1, class Arg2, class Arg3, class... Args>
4615 static no_key extract(
4616 Arg1 const&, Arg2 const&, Arg3 const&, Args const&...)
4622 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
4624 #define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
4625 template <typename T2> \
4626 static no_key extract(boost::unordered::piecewise_construct_t, \
4627 namespace_ tuple<> const&, T2 const&) \
4632 template <typename T, typename T2> \
4633 static typename is_key<key_type, T>::type extract( \
4634 boost::unordered::piecewise_construct_t, namespace_ tuple<T> const& k, \
4637 return typename is_key<key_type, T>::type(namespace_ get<0>(k)); \
4642 #define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
4643 static no_key extract( \
4644 boost::unordered::piecewise_construct_t, namespace_ tuple<> const&) \
4649 template <typename T> \
4650 static typename is_key<key_type, T>::type extract( \
4651 boost::unordered::piecewise_construct_t, namespace_ tuple<T> const& k) \
4653 return typename is_key<key_type, T>::type(namespace_ get<0>(k)); \
4658 BOOST_UNORDERED_KEY_FROM_TUPLE(boost::)
4660 #if BOOST_UNORDERED_TUPLE_ARGS
4661 BOOST_UNORDERED_KEY_FROM_TUPLE(std::)
4664 #undef BOOST_UNORDERED_KEY_FROM_TUPLE
4667 ////////////////////////////////////////////////////////////////////////
4670 template <typename A, typename T>
4671 struct node : boost::unordered::detail::value_base<T>
4674 typename ::boost::unordered::detail::rebind_wrap<A, node<A, T> >::type
4676 typedef typename ::boost::unordered::detail::allocator_traits<
4677 allocator>::pointer node_pointer;
4678 typedef node_pointer link_pointer;
4679 typedef typename ::boost::unordered::detail::rebind_wrap<A,
4680 bucket<node_pointer> >::type bucket_allocator;
4681 typedef typename ::boost::unordered::detail::allocator_traits<
4682 bucket_allocator>::pointer bucket_pointer;
4685 std::size_t bucket_info_;
4687 node() : next_(), bucket_info_(0) {}
4689 std::size_t get_bucket() const
4691 return bucket_info_ & ((std::size_t)-1 >> 1);
4694 std::size_t is_first_in_group() const
4696 return !(bucket_info_ & ~((std::size_t)-1 >> 1));
4699 void set_first_in_group()
4701 bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1);
4704 void reset_first_in_group()
4706 bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1);
4710 node& operator=(node const&);
4713 template <typename T>
4714 struct ptr_node : boost::unordered::detail::ptr_bucket
4716 typedef T value_type;
4717 typedef boost::unordered::detail::ptr_bucket bucket_base;
4718 typedef ptr_node<T>* node_pointer;
4719 typedef ptr_bucket* link_pointer;
4720 typedef ptr_bucket* bucket_pointer;
4722 std::size_t bucket_info_;
4723 boost::unordered::detail::value_base<T> value_base_;
4725 ptr_node() : bucket_base(), bucket_info_(0) {}
4727 void* address() { return value_base_.address(); }
4728 value_type& value() { return value_base_.value(); }
4729 value_type* value_ptr() { return value_base_.value_ptr(); }
4731 std::size_t get_bucket() const
4733 return bucket_info_ & ((std::size_t)-1 >> 1);
4736 std::size_t is_first_in_group() const
4738 return !(bucket_info_ & ~((std::size_t)-1 >> 1));
4741 void set_first_in_group()
4743 bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1);
4746 void reset_first_in_group()
4748 bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1);
4752 ptr_node& operator=(ptr_node const&);
4755 // If the allocator uses raw pointers use ptr_node
4756 // Otherwise use node.
4758 template <typename A, typename T, typename NodePtr, typename BucketPtr>
4761 typedef boost::unordered::detail::node<A, T> node;
4763 typedef typename boost::unordered::detail::allocator_traits<
4764 typename boost::unordered::detail::rebind_wrap<A,
4765 node>::type>::pointer node_pointer;
4767 typedef boost::unordered::detail::bucket<node_pointer> bucket;
4768 typedef node_pointer link_pointer;
4771 template <typename A, typename T>
4772 struct pick_node2<A, T, boost::unordered::detail::ptr_node<T>*,
4773 boost::unordered::detail::ptr_bucket*>
4775 typedef boost::unordered::detail::ptr_node<T> node;
4776 typedef boost::unordered::detail::ptr_bucket bucket;
4777 typedef bucket* link_pointer;
4780 template <typename A, typename T> struct pick_node
4782 typedef typename boost::remove_const<T>::type nonconst;
4784 typedef boost::unordered::detail::allocator_traits<
4785 typename boost::unordered::detail::rebind_wrap<A,
4786 boost::unordered::detail::ptr_node<nonconst> >::type>
4787 tentative_node_traits;
4789 typedef boost::unordered::detail::allocator_traits<
4790 typename boost::unordered::detail::rebind_wrap<A,
4791 boost::unordered::detail::ptr_bucket>::type>
4792 tentative_bucket_traits;
4794 typedef pick_node2<A, nonconst, typename tentative_node_traits::pointer,
4795 typename tentative_bucket_traits::pointer>
4798 typedef typename pick::node node;
4799 typedef typename pick::bucket bucket;
4800 typedef typename pick::link_pointer link_pointer;
4806 #undef BOOST_UNORDERED_EMPLACE_TEMPLATE
4807 #undef BOOST_UNORDERED_EMPLACE_ARGS
4808 #undef BOOST_UNORDERED_EMPLACE_FORWARD
4809 #undef BOOST_UNORDERED_CALL_CONSTRUCT1
4810 #undef BOOST_UNORDERED_CALL_DESTROY