diff options
Diffstat (limited to 'boost/unordered')
-rw-r--r-- | boost/unordered/detail/allocate.hpp | 1393 | ||||
-rw-r--r-- | boost/unordered/detail/buckets.hpp | 774 | ||||
-rw-r--r-- | boost/unordered/detail/equivalent.hpp | 735 | ||||
-rw-r--r-- | boost/unordered/detail/extract_key.hpp | 188 | ||||
-rw-r--r-- | boost/unordered/detail/fwd.hpp | 34 | ||||
-rw-r--r-- | boost/unordered/detail/implementation.hpp | 4986 | ||||
-rw-r--r-- | boost/unordered/detail/map.hpp | 174 | ||||
-rw-r--r-- | boost/unordered/detail/set.hpp | 168 | ||||
-rw-r--r-- | boost/unordered/detail/table.hpp | 794 | ||||
-rw-r--r-- | boost/unordered/detail/unique.hpp | 683 | ||||
-rw-r--r-- | boost/unordered/detail/util.hpp | 249 | ||||
-rw-r--r-- | boost/unordered/unordered_map.hpp | 3233 | ||||
-rw-r--r-- | boost/unordered/unordered_map_fwd.hpp | 86 | ||||
-rw-r--r-- | boost/unordered/unordered_set.hpp | 2826 | ||||
-rw-r--r-- | boost/unordered/unordered_set_fwd.hpp | 84 |
15 files changed, 8572 insertions, 7835 deletions
diff --git a/boost/unordered/detail/allocate.hpp b/boost/unordered/detail/allocate.hpp deleted file mode 100644 index 8e4f86941a..0000000000 --- a/boost/unordered/detail/allocate.hpp +++ /dev/null @@ -1,1393 +0,0 @@ - -// Copyright 2005-2011 Daniel James. -// Copyright 2009 Pablo Halpern. -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See http://www.boost.org/libs/unordered for documentation - -#ifndef BOOST_UNORDERED_ALLOCATE_HPP -#define BOOST_UNORDERED_ALLOCATE_HPP - -#include <boost/config.hpp> -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -// Some of these includes are required for other detail headers. -#include <boost/unordered/detail/fwd.hpp> -#include <boost/move/move.hpp> -#include <boost/preprocessor/cat.hpp> -#include <boost/preprocessor/repetition/enum.hpp> -#include <boost/preprocessor/repetition/enum_params.hpp> -#include <boost/preprocessor/repetition/enum_binary_params.hpp> -#include <boost/preprocessor/repetition/repeat_from_to.hpp> -#include <boost/type_traits/is_class.hpp> -#include <boost/type_traits/add_lvalue_reference.hpp> -#include <boost/type_traits/aligned_storage.hpp> -#include <boost/type_traits/alignment_of.hpp> -#include <boost/type_traits/is_nothrow_move_constructible.hpp> -#include <boost/type_traits/is_nothrow_move_assignable.hpp> -#include <boost/tuple/tuple.hpp> -#include <boost/utility/enable_if.hpp> -#include <boost/utility/addressof.hpp> -#include <boost/detail/no_exceptions_support.hpp> -#include <boost/detail/select_type.hpp> -#include <boost/swap.hpp> -#include <boost/assert.hpp> -#include <boost/limits.hpp> -#include <iterator> -#include <utility> -#include <cmath> - -#if !defined(BOOST_NO_CXX11_HDR_TUPLE) -#include <tuple> -#endif - -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4512) // assignment operator could not be generated. -#pragma warning(disable:4345) // behavior change: an object of POD type - // constructed with an initializer of the form () - // will be default-initialized. -#endif - -// Maximum number of arguments supported by emplace + 1. -#define BOOST_UNORDERED_EMPLACE_LIMIT 11 - -namespace boost { namespace unordered { namespace detail { - - //////////////////////////////////////////////////////////////////////////// - // Bits and pieces for implementing traits - - template <typename T> typename boost::add_lvalue_reference<T>::type make(); - struct choice9 { typedef char (&type)[9]; }; - struct choice8 : choice9 { typedef char (&type)[8]; }; - struct choice7 : choice8 { typedef char (&type)[7]; }; - struct choice6 : choice7 { typedef char (&type)[6]; }; - struct choice5 : choice6 { typedef char (&type)[5]; }; - struct choice4 : choice5 { typedef char (&type)[4]; }; - struct choice3 : choice4 { typedef char (&type)[3]; }; - struct choice2 : choice3 { typedef char (&type)[2]; }; - struct choice1 : choice2 { typedef char (&type)[1]; }; - choice1 choose(); - - typedef choice1::type yes_type; - typedef choice2::type no_type; - - struct private_type - { - private_type const &operator,(int) const; - }; - - template <typename T> - no_type is_private_type(T const&); - yes_type is_private_type(private_type const&); - - struct convert_from_anything { - template <typename T> - convert_from_anything(T const&); - }; - - namespace func { - // This is a bit nasty, when constructing the individual members - // of a std::pair, need to cast away 'const'. For modern compilers, - // should be able to use std::piecewise_construct instead. - template <typename T> T* const_cast_pointer(T* x) { return x; } - template <typename T> T* const_cast_pointer(T const* x) { - return const_cast<T*>(x); - } - } - - //////////////////////////////////////////////////////////////////////////// - // emplace_args - // - // Either forwarding variadic arguments, or storing the arguments in - // emplace_args##n - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -#define BOOST_UNORDERED_EMPLACE_ARGS1(a0) a0 -#define BOOST_UNORDERED_EMPLACE_ARGS2(a0, a1) a0, a1 -#define BOOST_UNORDERED_EMPLACE_ARGS3(a0, a1, a2) a0, a1, a2 - -#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args -#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args -#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)... - -#else - -#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args -#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args -#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args - -#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args -#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args -#define BOOST_UNORDERED_EMPLACE_FORWARD args - -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - -#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ - typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \ - BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); - -#else - -#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ - typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \ - BOOST_PP_CAT(Arg, n); \ - BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); - -#endif - -template <typename A0> -struct emplace_args1 -{ - BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) - - emplace_args1(Arg0 b0) : a0(b0) {} -}; - -template <typename A0> -inline emplace_args1<A0> create_emplace_args( - BOOST_FWD_REF(A0) b0) -{ - emplace_args1<A0> e(b0); - return e; -} - -template <typename A0, typename A1> -struct emplace_args2 -{ - BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) - BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) - - emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {} -}; - -template <typename A0, typename A1> -inline emplace_args2<A0, A1> create_emplace_args( - BOOST_FWD_REF(A0) b0, - BOOST_FWD_REF(A1) b1) -{ - emplace_args2<A0, A1> e(b0, b1); - return e; -} - -template <typename A0, typename A1, typename A2> -struct emplace_args3 -{ - BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) - BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) - BOOST_UNORDERED_EARGS_MEMBER(1, 2, _) - - emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {} -}; - -template <typename A0, typename A1, typename A2> -inline emplace_args3<A0, A1, A2> create_emplace_args( - BOOST_FWD_REF(A0) b0, - BOOST_FWD_REF(A1) b1, - BOOST_FWD_REF(A2) b2) -{ - emplace_args3<A0, A1, A2> e(b0, b1, b2); - return e; -} - -#define BOOST_UNORDERED_FWD_PARAM(z, n, a) \ - BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n) - -#define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \ - boost::forward<BOOST_PP_CAT(A,i)>(BOOST_PP_CAT(a,i)) - -#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ -BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n)) - -#define BOOST_UNORDERED_EARGS(z, n, _) \ - template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ - struct BOOST_PP_CAT(emplace_args, n) \ - { \ - BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) \ - BOOST_PP_CAT(emplace_args, n) ( \ - BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, b) \ - ) : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \ - {} \ - \ - }; \ - \ - template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ - inline BOOST_PP_CAT(emplace_args, n) < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, A) \ - > create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, b) \ - ) \ - { \ - BOOST_PP_CAT(emplace_args, n) < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, A) \ - > e(BOOST_PP_ENUM_PARAMS_Z(z, n, b)); \ - return e; \ - } - -BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, - _) - -#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS -#undef BOOST_UNORDERED_EARGS_MEMBER -#undef BOOST_UNORDERED_EARGS_INIT - -#endif - -}}} - -//////////////////////////////////////////////////////////////////////////////// -// -// Pick which version of allocator_traits to use -// -// 0 = Own partial implementation -// 1 = std::allocator_traits -// 2 = boost::container::allocator_traits - -#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) -# if !defined(BOOST_NO_CXX11_ALLOCATOR) -# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 -# elif defined(BOOST_MSVC) -# if BOOST_MSVC < 1400 - // Use container's allocator_traits for older versions of Visual - // C++ as I don't test with them. -# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2 -# endif -# endif -#endif - -#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) -# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 -#endif - -//////////////////////////////////////////////////////////////////////////////// -// -// Some utilities for implementing allocator_traits, but useful elsewhere so -// they're always defined. - -#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) -# include <type_traits> -#endif - -namespace boost { namespace unordered { namespace detail { - - //////////////////////////////////////////////////////////////////////////// - // Integral_constrant, true_type, false_type - // - // Uses the standard versions if available. - -#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) - - using std::integral_constant; - using std::true_type; - using std::false_type; - -#else - - template <typename T, T Value> - struct integral_constant { enum { value = Value }; }; - - typedef boost::unordered::detail::integral_constant<bool, true> true_type; - typedef boost::unordered::detail::integral_constant<bool, false> false_type; - -#endif - - //////////////////////////////////////////////////////////////////////////// - // Explicitly call a destructor - -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4100) // unreferenced formal parameter -#endif - - namespace func { - template <class T> - inline void destroy(T* x) { - x->~T(); - } - } - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - - //////////////////////////////////////////////////////////////////////////// - // Expression test mechanism - // - // When SFINAE expressions are available, define - // BOOST_UNORDERED_HAS_FUNCTION which can check if a function call is - // supported by a class, otherwise define BOOST_UNORDERED_HAS_MEMBER which - // can detect if a class has the specified member, but not that it has the - // correct type, this is good enough for a passable impression of - // allocator_traits. - -#if !defined(BOOST_NO_SFINAE_EXPR) - - template <typename T, long unsigned int> struct expr_test; - template <typename T> struct expr_test<T, sizeof(char)> : T {}; - -# define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ - template <typename U> \ - static typename boost::unordered::detail::expr_test< \ - BOOST_PP_CAT(choice, result), \ - sizeof(for_expr_test(( \ - (expression), \ - 0)))>::type test( \ - BOOST_PP_CAT(choice, count)) - -# define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \ - template <typename U> \ - static BOOST_PP_CAT(choice, result)::type test( \ - BOOST_PP_CAT(choice, count)) - -# define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \ - struct BOOST_PP_CAT(has_, name) \ - { \ - template <typename U> static char for_expr_test(U const&); \ - BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, \ - boost::unordered::detail::make< thing >().name args); \ - BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \ - \ - enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };\ - } - -#else - - template <typename T> struct identity { typedef T type; }; - -# define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ - \ - typedef typename boost::unordered::detail::identity<member>::type \ - BOOST_PP_CAT(check, count); \ - \ - template <BOOST_PP_CAT(check, count) e> \ - struct BOOST_PP_CAT(test, count) { \ - typedef BOOST_PP_CAT(choice, result) type; \ - }; \ - \ - template <class U> static typename \ - BOOST_PP_CAT(test, count)<&U::name>::type \ - test(BOOST_PP_CAT(choice, count)) - -# define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ - template <class U> static BOOST_PP_CAT(choice, result)::type \ - test(BOOST_PP_CAT(choice, count)) - -# define BOOST_UNORDERED_HAS_MEMBER(name) \ - struct BOOST_PP_CAT(has_, name) \ - { \ - struct impl { \ - struct base_mixin { int name; }; \ - struct base : public T, public base_mixin {}; \ - \ - BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, int base_mixin::*); \ - BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \ - \ - enum { value = sizeof(choice2::type) == \ - sizeof(test<base>(choose())) \ - }; \ - }; \ - \ - enum { value = impl::value }; \ - } - -#endif - -}}} - -//////////////////////////////////////////////////////////////////////////////// -// -// Allocator traits -// -// First our implementation, then later light wrappers around the alternatives - -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 - -# include <boost/limits.hpp> -# include <boost/utility/enable_if.hpp> -# include <boost/pointer_to_other.hpp> -# if defined(BOOST_NO_SFINAE_EXPR) -# include <boost/type_traits/is_same.hpp> -# endif - -# if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ - !defined(BOOST_NO_SFINAE_EXPR) -# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 -# else -# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 -# endif - -namespace boost { namespace unordered { namespace detail { - - template <typename Alloc, typename T> - struct rebind_alloc; - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - template <template<typename, typename...> class Alloc, - typename U, typename T, typename... Args> - struct rebind_alloc<Alloc<U, Args...>, T> - { - typedef Alloc<T, Args...> type; - }; - -#else - - template < - template<typename> class Alloc, - typename U, typename T> - struct rebind_alloc<Alloc<U>, T> - { - typedef Alloc<T> type; - }; - - template < - template<typename, typename> class Alloc, - typename U, typename T, - typename A0> - struct rebind_alloc<Alloc<U, A0>, T> - { - typedef Alloc<T, A0> type; - }; - - template < - template<typename, typename, typename> class Alloc, - typename U, typename T, - typename A0, typename A1> - struct rebind_alloc<Alloc<U, A0, A1>, T> - { - typedef Alloc<T, A0, A1> type; - }; - -#endif - - template <typename Alloc, typename T> - struct rebind_wrap - { - template <typename X> - static choice1::type test(choice1, - typename X::BOOST_NESTED_TEMPLATE rebind<T>::other* = 0); - template <typename X> - static choice2::type test(choice2, void* = 0); - - enum { value = (1 == sizeof(test<Alloc>(choose()))) }; - - struct fallback { - template <typename U> - struct rebind { - typedef typename rebind_alloc<Alloc, T>::type other; - }; - }; - - typedef typename boost::detail::if_true<value>:: - BOOST_NESTED_TEMPLATE then<Alloc, fallback> - ::type::BOOST_NESTED_TEMPLATE rebind<T>::other type; - }; - -# if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 - -# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ - template <typename Tp, typename Default> \ - struct default_type_ ## tname { \ - \ - template <typename X> \ - static choice1::type test(choice1, typename X::tname* = 0); \ - \ - template <typename X> \ - static choice2::type test(choice2, void* = 0); \ - \ - struct DefaultWrap { typedef Default tname; }; \ - \ - enum { value = (1 == sizeof(test<Tp>(choose()))) }; \ - \ - typedef typename boost::detail::if_true<value>:: \ - BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \ - ::type::tname type; \ - } - -# else - - template <typename T, typename T2> - struct sfinae : T2 {}; - -# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ - template <typename Tp, typename Default> \ - struct default_type_ ## tname { \ - \ - template <typename X> \ - static typename boost::unordered::detail::sfinae< \ - typename X::tname, choice1>::type \ - test(choice1); \ - \ - template <typename X> \ - static choice2::type test(choice2); \ - \ - struct DefaultWrap { typedef Default tname; }; \ - \ - enum { value = (1 == sizeof(test<Tp>(choose()))) }; \ - \ - typedef typename boost::detail::if_true<value>:: \ - BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \ - ::type::tname type; \ - } - -# endif - -# define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \ - typename default_type_ ## tname<T, arg>::type - - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer); - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer); - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(void_pointer); - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_void_pointer); - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(difference_type); - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(size_type); - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment); - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment); - BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap); - -# if !defined(BOOST_NO_SFINAE_EXPR) - - template <typename T> - BOOST_UNORDERED_HAS_FUNCTION( - select_on_container_copy_construction, U const, (), 0 - ); - - template <typename T> - BOOST_UNORDERED_HAS_FUNCTION( - max_size, U const, (), 0 - ); - -# if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - template <typename T, typename ValueType, typename... Args> - BOOST_UNORDERED_HAS_FUNCTION( - construct, U, ( - boost::unordered::detail::make<ValueType*>(), - boost::unordered::detail::make<Args const>()...), 2 - ); - -# else - - template <typename T, typename ValueType> - BOOST_UNORDERED_HAS_FUNCTION( - construct, U, ( - boost::unordered::detail::make<ValueType*>(), - boost::unordered::detail::make<ValueType const>()), 2 - ); - -# endif - - template <typename T, typename ValueType> - BOOST_UNORDERED_HAS_FUNCTION( - destroy, U, (boost::unordered::detail::make<ValueType*>()), 1 - ); - -# else - - template <typename T> - BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction); - - template <typename T> - BOOST_UNORDERED_HAS_MEMBER(max_size); - - template <typename T, typename ValueType> - BOOST_UNORDERED_HAS_MEMBER(construct); - - template <typename T, typename ValueType> - BOOST_UNORDERED_HAS_MEMBER(destroy); - -# endif - - namespace func - { - - template <typename Alloc> - inline Alloc call_select_on_container_copy_construction(const Alloc& rhs, - typename boost::enable_if_c< - boost::unordered::detail:: - has_select_on_container_copy_construction<Alloc>::value, void* - >::type = 0) - { - return rhs.select_on_container_copy_construction(); - } - - template <typename Alloc> - inline Alloc call_select_on_container_copy_construction(const Alloc& rhs, - typename boost::disable_if_c< - boost::unordered::detail:: - has_select_on_container_copy_construction<Alloc>::value, void* - >::type = 0) - { - return rhs; - } - - template <typename SizeType, typename Alloc> - inline SizeType call_max_size(const Alloc& a, - typename boost::enable_if_c< - boost::unordered::detail::has_max_size<Alloc>::value, void* - >::type = 0) - { - return a.max_size(); - } - - template <typename SizeType, typename Alloc> - inline SizeType call_max_size(const Alloc&, typename boost::disable_if_c< - boost::unordered::detail::has_max_size<Alloc>::value, void* - >::type = 0) - { - return (std::numeric_limits<SizeType>::max)(); - } - - } // namespace func. - - template <typename Alloc> - struct allocator_traits - { - typedef Alloc allocator_type; - typedef typename Alloc::value_type value_type; - - typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*) - pointer; - - template <typename T> - struct pointer_to_other : boost::pointer_to_other<pointer, T> {}; - - typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, - typename pointer_to_other<const value_type>::type) - const_pointer; - - //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer, - // typename pointer_to_other<void>::type) - // void_pointer; - // - //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer, - // typename pointer_to_other<const void>::type) - // const_void_pointer; - - typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, difference_type, - std::ptrdiff_t) difference_type; - - typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, size_type, std::size_t) - size_type; - -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) - template <typename T> - using rebind_alloc = typename rebind_wrap<Alloc, T>::type; - - template <typename T> - using rebind_traits = - boost::unordered::detail::allocator_traits<rebind_alloc<T> >; -#endif - - static pointer allocate(Alloc& a, size_type n) - { return a.allocate(n); } - - // I never use this, so I'll just comment it out for now. - // - //static pointer allocate(Alloc& a, size_type n, - // const_void_pointer hint) - // { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); } - - static void deallocate(Alloc& a, pointer p, size_type n) - { a.deallocate(p, n); } - - public: - -# if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - - template <typename T, typename... Args> - static typename boost::enable_if_c< - boost::unordered::detail::has_construct<Alloc, T, Args...> - ::value>::type - construct(Alloc& a, T* p, BOOST_FWD_REF(Args)... x) - { - a.construct(p, boost::forward<Args>(x)...); - } - - template <typename T, typename... Args> - static typename boost::disable_if_c< - boost::unordered::detail::has_construct<Alloc, T, Args...> - ::value>::type - construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x) - { - new (static_cast<void*>(p)) T(boost::forward<Args>(x)...); - } - - template <typename T> - static typename boost::enable_if_c< - boost::unordered::detail::has_destroy<Alloc, T>::value>::type - destroy(Alloc& a, T* p) - { - a.destroy(p); - } - - template <typename T> - static typename boost::disable_if_c< - boost::unordered::detail::has_destroy<Alloc, T>::value>::type - destroy(Alloc&, T* p) - { - boost::unordered::detail::func::destroy(p); - } - -# elif !defined(BOOST_NO_SFINAE_EXPR) - - template <typename T> - static typename boost::enable_if_c< - boost::unordered::detail::has_construct<Alloc, T>::value>::type - construct(Alloc& a, T* p, T const& x) - { - a.construct(p, x); - } - - template <typename T> - static typename boost::disable_if_c< - boost::unordered::detail::has_construct<Alloc, T>::value>::type - construct(Alloc&, T* p, T const& x) - { - new (static_cast<void*>(p)) T(x); - } - - template <typename T> - static typename boost::enable_if_c< - boost::unordered::detail::has_destroy<Alloc, T>::value>::type - destroy(Alloc& a, T* p) - { - a.destroy(p); - } - - template <typename T> - static typename boost::disable_if_c< - boost::unordered::detail::has_destroy<Alloc, T>::value>::type - destroy(Alloc&, T* p) - { - boost::unordered::detail::func::destroy(p); - } - -# else - - // If we don't have SFINAE expressions, only call construct for the - // copy constructor for the allocator's value_type - as that's - // the only construct method that old fashioned allocators support. - - template <typename T> - static void construct(Alloc& a, T* p, T const& x, - typename boost::enable_if_c< - boost::unordered::detail::has_construct<Alloc, T>::value && - boost::is_same<T, value_type>::value, - void*>::type = 0) - { - a.construct(p, x); - } - - template <typename T> - static void construct(Alloc&, T* p, T const& x, - typename boost::disable_if_c< - boost::unordered::detail::has_construct<Alloc, T>::value && - boost::is_same<T, value_type>::value, - void*>::type = 0) - { - new (static_cast<void*>(p)) T(x); - } - - template <typename T> - static void destroy(Alloc& a, T* p, - typename boost::enable_if_c< - boost::unordered::detail::has_destroy<Alloc, T>::value && - boost::is_same<T, value_type>::value, - void*>::type = 0) - { - a.destroy(p); - } - - template <typename T> - static void destroy(Alloc&, T* p, - typename boost::disable_if_c< - boost::unordered::detail::has_destroy<Alloc, T>::value && - boost::is_same<T, value_type>::value, - void*>::type = 0) - { - boost::unordered::detail::func::destroy(p); - } - -# endif - - static size_type max_size(const Alloc& a) - { - return boost::unordered::detail::func:: - call_max_size<size_type>(a); - } - - // Allocator propagation on construction - - static Alloc select_on_container_copy_construction(Alloc const& rhs) - { - return boost::unordered::detail::func:: - call_select_on_container_copy_construction(rhs); - } - - // Allocator propagation on assignment and swap. - // Return true if lhs is modified. - typedef BOOST_UNORDERED_DEFAULT_TYPE( - Alloc, propagate_on_container_copy_assignment, false_type) - propagate_on_container_copy_assignment; - typedef BOOST_UNORDERED_DEFAULT_TYPE( - Alloc,propagate_on_container_move_assignment, false_type) - propagate_on_container_move_assignment; - typedef BOOST_UNORDERED_DEFAULT_TYPE( - Alloc,propagate_on_container_swap,false_type) - propagate_on_container_swap; - }; -}}} - -# undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT -# undef BOOST_UNORDERED_DEFAULT_TYPE - -//////////////////////////////////////////////////////////////////////////////// -// -// std::allocator_traits - -#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 - -# include <memory> - -# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 - -namespace boost { namespace unordered { namespace detail { - - template <typename Alloc> - struct allocator_traits : std::allocator_traits<Alloc> {}; - - template <typename Alloc, typename T> - struct rebind_wrap - { - typedef typename std::allocator_traits<Alloc>:: - template rebind_alloc<T> type; - }; -}}} - -//////////////////////////////////////////////////////////////////////////////// -// -// boost::container::allocator_traits - -#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 - -# include <boost/container/allocator_traits.hpp> - -# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 - -namespace boost { namespace unordered { namespace detail { - - template <typename Alloc> - struct allocator_traits : - boost::container::allocator_traits<Alloc> {}; - - template <typename Alloc, typename T> - struct rebind_wrap : - boost::container::allocator_traits<Alloc>:: - template portable_rebind_alloc<T> - {}; - -}}} - -#else - -#error "Invalid BOOST_UNORDERED_USE_ALLOCATOR_TRAITS value." - -#endif - - -namespace boost { namespace unordered { namespace detail { namespace func { - - //////////////////////////////////////////////////////////////////////////// - // call_construct - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -# if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - - template <typename Alloc, typename T, typename... Args> - inline void call_construct(Alloc& alloc, T* address, - BOOST_FWD_REF(Args)... args) - { - boost::unordered::detail::allocator_traits<Alloc>::construct(alloc, - address, boost::forward<Args>(args)...); - } - - template <typename Alloc, typename T> - inline void call_destroy(Alloc& alloc, T* x) { - boost::unordered::detail::allocator_traits<Alloc>::destroy(alloc, x); - } - - -# else - - template <typename Alloc, typename T, typename... Args> - inline void call_construct(Alloc&, T* address, - BOOST_FWD_REF(Args)... args) - { - new((void*) address) T(boost::forward<Args>(args)...); - } - - template <typename Alloc, typename T> - inline void call_destroy(Alloc&, T* x) { - boost::unordered::detail::func::destroy(x); - } - - -# endif - -#else - template <typename Alloc, typename T> - inline void call_construct(Alloc&, T* address) - { - new ((void*) address) T(); - } - - template <typename Alloc, typename T, typename A0> - inline void call_construct(Alloc&, T* address, - BOOST_FWD_REF(A0) a0) - { - new ((void*) address) T(boost::forward<A0>(a0)); - } - - template <typename Alloc, typename T> - inline void call_destroy(Alloc&, T* x) { - boost::unordered::detail::func::destroy(x); - } - -#endif - - //////////////////////////////////////////////////////////////////////////// - // Construct from tuple - // - // Used for piecewise construction. - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template<typename Alloc, typename T> \ - void construct_from_tuple(Alloc& alloc, T* ptr, namespace_ tuple<>) \ - { \ - boost::unordered::detail::func::call_construct(alloc, ptr); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO(1, n, \ - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ - template<typename Alloc, typename T, \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ - void construct_from_tuple(Alloc& alloc, T* ptr, \ - namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ - { \ - boost::unordered::detail::func::call_construct(alloc, ptr, \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ - ); \ - } - -# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ - namespace_ get<n>(x) - -#elif !defined(__SUNPRO_CC) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template<typename Alloc, typename T> \ - void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \ - { \ - new ((void*) ptr) T(); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO(1, n, \ - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ - template<typename Alloc, typename T, \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ - void construct_from_tuple(Alloc&, T* ptr, \ - namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ - { \ - new ((void*) ptr) T( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ - ); \ - } - -# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ - namespace_ get<n>(x) - -#else - - template <int N> struct length {}; - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template<typename Alloc, typename T> \ - void construct_from_tuple_impl( \ - boost::unordered::detail::func::length<0>, Alloc&, T* ptr, \ - namespace_ tuple<>) \ - { \ - new ((void*) ptr) T(); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO(1, n, \ - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ - template<typename Alloc, typename T, \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ - void construct_from_tuple_impl( \ - boost::unordered::detail::func::length<n>, Alloc&, T* ptr, \ - namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ - { \ - new ((void*) ptr) T( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ - ); \ - } - -# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ - namespace_ get<n>(x) - -#endif - -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) - -#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE) - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) -#endif - -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL -#undef BOOST_UNORDERED_GET_TUPLE_ARG - -#if defined(__SUNPRO_CC) - - template <typename Alloc, typename T, typename Tuple> - void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x) - { - construct_from_tuple_impl( - boost::unordered::detail::func::length< - boost::tuples::length<Tuple>::value>(), - alloc, ptr, x); - } - -#endif - - //////////////////////////////////////////////////////////////////////////// - // Trait to check for piecewise construction. - - template <typename A0> - struct use_piecewise { - static choice1::type test(choice1, - boost::unordered::piecewise_construct_t); - - static choice2::type test(choice2, ...); - - enum { value = sizeof(choice1::type) == - sizeof(test(choose(), boost::unordered::detail::make<A0>())) }; - }; - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - //////////////////////////////////////////////////////////////////////////// - // Construct from variadic parameters - - // For the standard pair constructor. - - template <typename Alloc, typename T, typename... Args> - inline void construct_from_args(Alloc& alloc, T* address, - BOOST_FWD_REF(Args)... args) - { - boost::unordered::detail::func::call_construct(alloc, - address, boost::forward<Args>(args)...); - } - - // Special case for piece_construct - // - // TODO: When possible, it might be better to use std::pair's - // constructor for std::piece_construct with std::tuple. - - template <typename Alloc, typename A, typename B, - typename A0, typename A1, typename A2> - inline typename enable_if<use_piecewise<A0>, void>::type - construct_from_args(Alloc& alloc, std::pair<A, B>* address, - BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - boost::unordered::detail::func::construct_from_tuple(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->first)), - boost::forward<A1>(a1)); - boost::unordered::detail::func::construct_from_tuple(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->second)), - boost::forward<A2>(a2)); - } - -#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES - - //////////////////////////////////////////////////////////////////////////// - // Construct from emplace_args - - // Explicitly write out first three overloads for the sake of sane - // error messages. - - template <typename Alloc, typename T, typename A0> - inline void construct_from_args(Alloc&, T* address, - emplace_args1<A0> const& args) - { - new((void*) address) T(boost::forward<A0>(args.a0)); - } - - template <typename Alloc, typename T, typename A0, typename A1> - inline void construct_from_args(Alloc&, T* address, - emplace_args2<A0, A1> const& args) - { - new((void*) address) T( - boost::forward<A0>(args.a0), - boost::forward<A1>(args.a1) - ); - } - - template <typename Alloc, typename T, typename A0, typename A1, typename A2> - inline void construct_from_args(Alloc&, T* address, - emplace_args3<A0, A1, A2> const& args) - { - new((void*) address) T( - boost::forward<A0>(args.a0), - boost::forward<A1>(args.a1), - boost::forward<A2>(args.a2) - ); - } - - // Use a macro for the rest. - -#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ - template < \ - typename Alloc, typename T, \ - BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \ - > \ - inline void construct_from_args(Alloc&, T* address, \ - boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \ - BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \ - > const& args) \ - { \ - new((void*) address) T( \ - BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_FORWARD, \ - args.a)); \ - } - - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_CONSTRUCT_IMPL, _) - -#undef BOOST_UNORDERED_CONSTRUCT_IMPL - - // Construct with piece_construct - - template <typename Alloc, typename A, typename B, - typename A0, typename A1, typename A2> - inline void construct_from_args(Alloc& alloc, std::pair<A, B>* address, - boost::unordered::detail::emplace_args3<A0, A1, A2> const& args, - typename enable_if<use_piecewise<A0>, void*>::type = 0) - { - boost::unordered::detail::func::construct_from_tuple(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->first)), - args.a1); - boost::unordered::detail::func::construct_from_tuple(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->second)), - args.a2); - } - -#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES - -}}}} - -namespace boost { namespace unordered { namespace detail { - - /////////////////////////////////////////////////////////////////// - // - // Node construction - - template <typename NodeAlloc> - struct node_constructor - { - typedef NodeAlloc node_allocator; - typedef boost::unordered::detail::allocator_traits<NodeAlloc> - node_allocator_traits; - typedef typename node_allocator_traits::value_type node; - typedef typename node_allocator_traits::pointer node_pointer; - typedef typename node::value_type value_type; - - node_allocator& alloc_; - node_pointer node_; - bool node_constructed_; - - node_constructor(node_allocator& n) : - alloc_(n), - node_(), - node_constructed_(false) - { - } - - ~node_constructor(); - - void create_node(); - - // no throw - node_pointer release() - { - BOOST_ASSERT(node_ && node_constructed_); - node_pointer p = node_; - node_ = node_pointer(); - return p; - } - - void reclaim(node_pointer p) { - BOOST_ASSERT(!node_); - node_ = p; - node_constructed_ = true; - boost::unordered::detail::func::call_destroy(alloc_, - node_->value_ptr()); - } - - private: - node_constructor(node_constructor const&); - node_constructor& operator=(node_constructor const&); - }; - - template <typename Alloc> - node_constructor<Alloc>::~node_constructor() - { - if (node_) { - if (node_constructed_) { - boost::unordered::detail::func::destroy( - boost::addressof(*node_)); - } - - node_allocator_traits::deallocate(alloc_, node_, 1); - } - } - - template <typename Alloc> - void node_constructor<Alloc>::create_node() - { - BOOST_ASSERT(!node_); - node_constructed_ = false; - - node_ = node_allocator_traits::allocate(alloc_, 1); - - new ((void*) boost::addressof(*node_)) node(); - node_->init(node_); - node_constructed_ = true; - } - - template <typename NodeAlloc> - struct node_tmp - { - typedef boost::unordered::detail::allocator_traits<NodeAlloc> - node_allocator_traits; - typedef typename node_allocator_traits::pointer node_pointer; - - NodeAlloc& alloc_; - node_pointer node_; - - explicit node_tmp(node_pointer n, NodeAlloc& a): - alloc_(a), - node_(n) - { - } - - ~node_tmp(); - - // no throw - node_pointer release() - { - node_pointer p = node_; - node_ = node_pointer(); - return p; - } - }; - - template <typename Alloc> - node_tmp<Alloc>::~node_tmp() - { - if (node_) { - boost::unordered::detail::func::call_destroy(alloc_, - node_->value_ptr()); - boost::unordered::detail::func::destroy( - boost::addressof(*node_)); - node_allocator_traits::deallocate(alloc_, node_, 1); - } - } -}}} - -namespace boost { namespace unordered { namespace detail { namespace func { - - // Some nicer construct_node functions, might try to - // improve implementation later. - - template <typename Alloc, BOOST_UNORDERED_EMPLACE_TEMPLATE> - inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer - construct_node_from_args(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS) - { - node_constructor<Alloc> a(alloc); - a.create_node(); - construct_from_args(alloc, a.node_->value_ptr(), - BOOST_UNORDERED_EMPLACE_FORWARD); - return a.release(); - } - - template <typename Alloc, typename U> - inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer - construct_node(Alloc& alloc, BOOST_FWD_REF(U) x) - { - node_constructor<Alloc> a(alloc); - a.create_node(); - boost::unordered::detail::func::call_construct( - alloc, a.node_->value_ptr(), boost::forward<U>(x)); - return a.release(); - } - - // TODO: When possible, it might be better to use std::pair's - // constructor for std::piece_construct with std::tuple. - template <typename Alloc, typename Key> - inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer - construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) - { - node_constructor<Alloc> a(alloc); - a.create_node(); - boost::unordered::detail::func::call_construct(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->first)), - boost::forward<Key>(k)); - boost::unordered::detail::func::call_construct(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->second))); - return a.release(); - } - - template <typename Alloc, typename Key, typename Mapped> - inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer - construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) - { - node_constructor<Alloc> a(alloc); - a.create_node(); - boost::unordered::detail::func::call_construct(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->first)), - boost::forward<Key>(k)); - boost::unordered::detail::func::call_construct(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->second)), - boost::forward<Mapped>(m)); - return a.release(); - } -}}}} - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - -#endif diff --git a/boost/unordered/detail/buckets.hpp b/boost/unordered/detail/buckets.hpp deleted file mode 100644 index bd9a5cbb1e..0000000000 --- a/boost/unordered/detail/buckets.hpp +++ /dev/null @@ -1,774 +0,0 @@ - -// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2011 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED - -#include <boost/config.hpp> -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include <boost/unordered/detail/util.hpp> -#include <boost/unordered/detail/allocate.hpp> - -namespace boost { namespace unordered { namespace detail { - - template <typename Types> struct table; - template <typename NodePointer> struct bucket; - struct ptr_bucket; - template <typename Types> struct table_impl; - template <typename Types> struct grouped_table_impl; - -}}} - -// The 'iterator_detail' namespace was a misguided attempt at avoiding ADL -// in the detail namespace. It didn't work because the template parameters -// were in detail. I'm not changing it at the moment to be safe. I might -// do in the future if I change the iterator types. -namespace boost { namespace unordered { namespace iterator_detail { - - //////////////////////////////////////////////////////////////////////////// - // Iterators - // - // all no throw - - template <typename Node> struct iterator; - template <typename Node> struct c_iterator; - template <typename Node, typename Policy> struct l_iterator; - template <typename Node, typename Policy> - struct cl_iterator; - - // Local Iterators - // - // all no throw - - template <typename Node, typename Policy> - struct l_iterator - : public std::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - typename Node::value_type*, - typename Node::value_type&> - { -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template <typename Node2, typename Policy2> - friend struct boost::unordered::iterator_detail::cl_iterator; - private: -#endif - typedef typename Node::node_pointer node_pointer; - node_pointer ptr_; - std::size_t bucket_; - std::size_t bucket_count_; - - public: - - typedef typename Node::value_type value_type; - - l_iterator() BOOST_NOEXCEPT : ptr_() {} - - l_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT - : ptr_(n), bucket_(b), bucket_count_(c) {} - - value_type& operator*() const { - return ptr_->value(); - } - - value_type* operator->() const { - return ptr_->value_ptr(); - } - - l_iterator& operator++() { - ptr_ = static_cast<node_pointer>(ptr_->next_); - if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) - != bucket_) - ptr_ = node_pointer(); - return *this; - } - - l_iterator operator++(int) { - l_iterator tmp(*this); - ++(*this); - return tmp; - } - - bool operator==(l_iterator x) const BOOST_NOEXCEPT { - return ptr_ == x.ptr_; - } - - bool operator!=(l_iterator x) const BOOST_NOEXCEPT { - return ptr_ != x.ptr_; - } - }; - - template <typename Node, typename Policy> - struct cl_iterator - : public std::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - typename Node::value_type const*, - typename Node::value_type const&> - { - friend struct boost::unordered::iterator_detail::l_iterator - <Node, Policy>; - private: - - typedef typename Node::node_pointer node_pointer; - node_pointer ptr_; - std::size_t bucket_; - std::size_t bucket_count_; - - public: - - typedef typename Node::value_type value_type; - - cl_iterator() BOOST_NOEXCEPT : ptr_() {} - - cl_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT : - ptr_(n), bucket_(b), bucket_count_(c) {} - - cl_iterator(boost::unordered::iterator_detail::l_iterator< - Node, Policy> const& x) BOOST_NOEXCEPT : - ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) - {} - - value_type const& operator*() const { - return ptr_->value(); - } - - value_type const* operator->() const { - return ptr_->value_ptr(); - } - - cl_iterator& operator++() { - ptr_ = static_cast<node_pointer>(ptr_->next_); - if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) - != bucket_) - ptr_ = node_pointer(); - return *this; - } - - cl_iterator operator++(int) { - cl_iterator tmp(*this); - ++(*this); - return tmp; - } - - friend bool operator==(cl_iterator const& x, cl_iterator const& y) - BOOST_NOEXCEPT - { - return x.ptr_ == y.ptr_; - } - - friend bool operator!=(cl_iterator const& x, cl_iterator const& y) - BOOST_NOEXCEPT - { - return x.ptr_ != y.ptr_; - } - }; - - template <typename Node> - struct iterator - : public std::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - typename Node::value_type*, - typename Node::value_type&> - { -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template <typename> - friend struct boost::unordered::iterator_detail::c_iterator; - template <typename> - friend struct boost::unordered::detail::table; - template <typename> - friend struct boost::unordered::detail::table_impl; - template <typename> - friend struct boost::unordered::detail::grouped_table_impl; - private: -#endif - typedef typename Node::node_pointer node_pointer; - node_pointer node_; - - public: - - typedef typename Node::value_type value_type; - - iterator() BOOST_NOEXCEPT : node_() {} - - explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT : - node_(static_cast<node_pointer>(x)) {} - - value_type& operator*() const { - return node_->value(); - } - - value_type* operator->() const { - return node_->value_ptr(); - } - - iterator& operator++() { - node_ = static_cast<node_pointer>(node_->next_); - return *this; - } - - iterator operator++(int) { - iterator tmp(node_); - node_ = static_cast<node_pointer>(node_->next_); - return tmp; - } - - bool operator==(iterator const& x) const BOOST_NOEXCEPT { - return node_ == x.node_; - } - - bool operator!=(iterator const& x) const BOOST_NOEXCEPT { - return node_ != x.node_; - } - }; - - template <typename Node> - struct c_iterator - : public std::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - typename Node::value_type const*, - typename Node::value_type const&> - { - friend struct boost::unordered::iterator_detail::iterator<Node>; - -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template <typename> - friend struct boost::unordered::detail::table; - template <typename> - friend struct boost::unordered::detail::table_impl; - template <typename> - friend struct boost::unordered::detail::grouped_table_impl; - - private: -#endif - typedef typename Node::node_pointer node_pointer; - typedef boost::unordered::iterator_detail::iterator<Node> n_iterator; - node_pointer node_; - - public: - - typedef typename Node::value_type value_type; - - c_iterator() BOOST_NOEXCEPT : node_() {} - - explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT : - node_(static_cast<node_pointer>(x)) {} - - c_iterator(n_iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} - - value_type const& operator*() const { - return node_->value(); - } - - value_type const* operator->() const { - return node_->value_ptr(); - } - - c_iterator& operator++() { - node_ = static_cast<node_pointer>(node_->next_); - return *this; - } - - c_iterator operator++(int) { - c_iterator tmp(node_); - node_ = static_cast<node_pointer>(node_->next_); - return tmp; - } - - friend bool operator==(c_iterator const& x, c_iterator const& y) - BOOST_NOEXCEPT - { - return x.node_ == y.node_; - } - - friend bool operator!=(c_iterator const& x, c_iterator const& y) - BOOST_NOEXCEPT - { - return x.node_ != y.node_; - } - }; -}}} - -namespace boost { namespace unordered { namespace detail { - - /////////////////////////////////////////////////////////////////// - // - // Node Holder - // - // Temporary store for nodes. Deletes any that aren't used. - - template <typename NodeAlloc> - struct node_holder - { - private: - typedef NodeAlloc node_allocator; - typedef boost::unordered::detail::allocator_traits<NodeAlloc> - node_allocator_traits; - typedef typename node_allocator_traits::value_type node; - typedef typename node_allocator_traits::pointer node_pointer; - typedef typename node::value_type value_type; - typedef typename node::link_pointer link_pointer; - typedef boost::unordered::iterator_detail::iterator<node> iterator; - - node_constructor<NodeAlloc> constructor_; - node_pointer nodes_; - - public: - - template <typename Table> - explicit node_holder(Table& b) : - constructor_(b.node_alloc()), - nodes_() - { - if (b.size_) { - typename Table::link_pointer prev = b.get_previous_start(); - nodes_ = static_cast<node_pointer>(prev->next_); - prev->next_ = link_pointer(); - b.size_ = 0; - } - } - - ~node_holder(); - - node_pointer pop_node() - { - node_pointer n = nodes_; - nodes_ = static_cast<node_pointer>(nodes_->next_); - n->init(n); - n->next_ = link_pointer(); - return n; - } - - template <typename T> - inline node_pointer copy_of(T const& v) { - if (nodes_) { - constructor_.reclaim(pop_node()); - } - else { - constructor_.create_node(); - } - boost::unordered::detail::func::call_construct( - constructor_.alloc_, constructor_.node_->value_ptr(), v); - return constructor_.release(); - } - - template <typename T> - inline node_pointer move_copy_of(T& v) { - if (nodes_) { - constructor_.reclaim(pop_node()); - } - else { - constructor_.create_node(); - } - boost::unordered::detail::func::call_construct( - constructor_.alloc_, constructor_.node_->value_ptr(), - boost::move(v)); - return constructor_.release(); - } - - iterator begin() const - { - return iterator(nodes_); - } - }; - - template <typename Alloc> - node_holder<Alloc>::~node_holder() - { - while (nodes_) { - node_pointer p = nodes_; - nodes_ = static_cast<node_pointer>(p->next_); - - boost::unordered::detail::func::call_destroy(constructor_.alloc_, - p->value_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*p)); - node_allocator_traits::deallocate(constructor_.alloc_, p, 1); - } - } - - /////////////////////////////////////////////////////////////////// - // - // Bucket - - template <typename NodePointer> - struct bucket - { - typedef NodePointer link_pointer; - link_pointer next_; - - bucket() : next_() {} - - link_pointer first_from_start() - { - return next_; - } - - enum { extra_node = true }; - }; - - struct ptr_bucket - { - typedef ptr_bucket* link_pointer; - link_pointer next_; - - ptr_bucket() : next_(0) {} - - link_pointer first_from_start() - { - return this; - } - - enum { extra_node = false }; - }; - - /////////////////////////////////////////////////////////////////// - // - // Hash Policy - - template <typename SizeT> - struct prime_policy - { - template <typename Hash, typename T> - static inline SizeT apply_hash(Hash const& hf, T const& x) { - return hf(x); - } - - static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { - return hash % bucket_count; - } - - static inline SizeT new_bucket_count(SizeT min) { - return boost::unordered::detail::next_prime(min); - } - - static inline SizeT prev_bucket_count(SizeT max) { - return boost::unordered::detail::prev_prime(max); - } - }; - - template <typename SizeT> - struct mix64_policy - { - template <typename Hash, typename T> - static inline SizeT apply_hash(Hash const& hf, T const& x) { - SizeT key = hf(x); - key = (~key) + (key << 21); // key = (key << 21) - key - 1; - key = key ^ (key >> 24); - key = (key + (key << 3)) + (key << 8); // key * 265 - key = key ^ (key >> 14); - key = (key + (key << 2)) + (key << 4); // key * 21 - key = key ^ (key >> 28); - key = key + (key << 31); - return key; - } - - static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { - return hash & (bucket_count - 1); - } - - static inline SizeT new_bucket_count(SizeT min) { - if (min <= 4) return 4; - --min; - min |= min >> 1; - min |= min >> 2; - min |= min >> 4; - min |= min >> 8; - min |= min >> 16; - min |= min >> 32; - return min + 1; - } - - static inline SizeT prev_bucket_count(SizeT max) { - max |= max >> 1; - max |= max >> 2; - max |= max >> 4; - max |= max >> 8; - max |= max >> 16; - max |= max >> 32; - return (max >> 1) + 1; - } - }; - - template <int digits, int radix> - struct pick_policy_impl { - typedef prime_policy<std::size_t> type; - }; - - template <> - struct pick_policy_impl<64, 2> { - typedef mix64_policy<std::size_t> type; - }; - - template <typename T> - struct pick_policy : - pick_policy_impl< - std::numeric_limits<std::size_t>::digits, - std::numeric_limits<std::size_t>::radix> {}; - - // While the mix policy is generally faster, the prime policy is a lot - // faster when a large number consecutive integers are used, because - // there are no collisions. Since that is probably quite common, use - // prime policy for integeral types. But not the smaller ones, as they - // don't have enough unique values for this to be an issue. - - template <> - struct pick_policy<int> { - typedef prime_policy<std::size_t> type; - }; - - template <> - struct pick_policy<unsigned int> { - typedef prime_policy<std::size_t> type; - }; - - template <> - struct pick_policy<long> { - typedef prime_policy<std::size_t> type; - }; - - template <> - struct pick_policy<unsigned long> { - typedef prime_policy<std::size_t> type; - }; - - // TODO: Maybe not if std::size_t is smaller than long long. -#if !defined(BOOST_NO_LONG_LONG) - template <> - struct pick_policy<boost::long_long_type> { - typedef prime_policy<std::size_t> type; - }; - - template <> - struct pick_policy<boost::ulong_long_type> { - typedef prime_policy<std::size_t> type; - }; -#endif - - //////////////////////////////////////////////////////////////////////////// - // Functions - - // Assigning and swapping the equality and hash function objects - // needs strong exception safety. To implement that normally we'd - // require one of them to be known to not throw and the other to - // guarantee strong exception safety. Unfortunately they both only - // have basic exception safety. So to acheive strong exception - // safety we have storage space for two copies, and assign the new - // copies to the unused space. Then switch to using that to use - // them. This is implemented in 'set_hash_functions' which - // atomically assigns the new function objects in a strongly - // exception safe manner. - - template <class H, class P, bool NoThrowMoveAssign> - class set_hash_functions; - - template <class H, class P> - class functions - { - public: - static const bool nothrow_move_assignable = - boost::is_nothrow_move_assignable<H>::value && - boost::is_nothrow_move_assignable<P>::value; - static const bool nothrow_move_constructible = - boost::is_nothrow_move_constructible<H>::value && - boost::is_nothrow_move_constructible<P>::value; - - private: - friend class boost::unordered::detail::set_hash_functions<H, P, - nothrow_move_assignable>; - functions& operator=(functions const&); - - typedef compressed<H, P> function_pair; - - typedef typename boost::aligned_storage< - sizeof(function_pair), - boost::alignment_of<function_pair>::value>::type aligned_function; - - bool current_; // The currently active functions. - aligned_function funcs_[2]; - - function_pair const& current() const { - return *static_cast<function_pair const*>( - static_cast<void const*>(&funcs_[current_])); - } - - function_pair& current() { - return *static_cast<function_pair*>( - static_cast<void*>(&funcs_[current_])); - } - - void construct(bool which, H const& hf, P const& eq) - { - new((void*) &funcs_[which]) function_pair(hf, eq); - } - - void construct(bool which, function_pair const& f, - boost::unordered::detail::false_type = - boost::unordered::detail::false_type()) - { - new((void*) &funcs_[which]) function_pair(f); - } - - void construct(bool which, function_pair& f, - boost::unordered::detail::true_type) - { - new((void*) &funcs_[which]) function_pair(f, - boost::unordered::detail::move_tag()); - } - - void destroy(bool which) - { - boost::unordered::detail::func::destroy((function_pair*)(&funcs_[which])); - } - - public: - - typedef boost::unordered::detail::set_hash_functions<H, P, - nothrow_move_assignable> set_hash_functions; - - functions(H const& hf, P const& eq) - : current_(false) - { - construct(current_, hf, eq); - } - - functions(functions const& bf) - : current_(false) - { - construct(current_, bf.current()); - } - - functions(functions& bf, boost::unordered::detail::move_tag) - : current_(false) - { - construct(current_, bf.current(), - boost::unordered::detail::integral_constant<bool, - nothrow_move_constructible>()); - } - - ~functions() { - this->destroy(current_); - } - - H const& hash_function() const { - return current().first(); - } - - P const& key_eq() const { - return current().second(); - } - }; - - template <class H, class P> - class set_hash_functions<H, P, false> - { - set_hash_functions(set_hash_functions const&); - set_hash_functions& operator=(set_hash_functions const&); - - typedef functions<H, P> functions_type; - - functions_type& functions_; - bool tmp_functions_; - - public: - - set_hash_functions(functions_type& f, H const& h, P const& p) - : functions_(f), - tmp_functions_(!f.current_) - { - f.construct(tmp_functions_, h, p); - } - - set_hash_functions(functions_type& f, functions_type const& other) - : functions_(f), - tmp_functions_(!f.current_) - { - f.construct(tmp_functions_, other.current()); - } - - ~set_hash_functions() - { - functions_.destroy(tmp_functions_); - } - - void commit() - { - functions_.current_ = tmp_functions_; - tmp_functions_ = !tmp_functions_; - } - }; - - template <class H, class P> - class set_hash_functions<H, P, true> - { - set_hash_functions(set_hash_functions const&); - set_hash_functions& operator=(set_hash_functions const&); - - typedef functions<H, P> functions_type; - - functions_type& functions_; - H hash_; - P pred_; - - public: - - set_hash_functions(functions_type& f, H const& h, P const& p) : - functions_(f), - hash_(h), - pred_(p) {} - - set_hash_functions(functions_type& f, functions_type const& other) : - functions_(f), - hash_(other.hash_function()), - pred_(other.key_eq()) {} - - void commit() - { - functions_.current().first() = boost::move(hash_); - functions_.current().second() = boost::move(pred_); - } - }; - - //////////////////////////////////////////////////////////////////////////// - // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter - // e.g. for int - -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) -#else - struct please_ignore_this_overload { - typedef please_ignore_this_overload type; - }; - - template <typename T> - struct rv_ref_impl { - typedef BOOST_RV_REF(T) type; - }; - - template <typename T> - struct rv_ref : - boost::detail::if_true< - boost::is_class<T>::value - >::BOOST_NESTED_TEMPLATE then < - boost::unordered::detail::rv_ref_impl<T>, - please_ignore_this_overload - >::type - {}; - -# define BOOST_UNORDERED_RV_REF(T) \ - typename boost::unordered::detail::rv_ref<T>::type -#endif -}}} - -#endif diff --git a/boost/unordered/detail/equivalent.hpp b/boost/unordered/detail/equivalent.hpp deleted file mode 100644 index 618d3af9b9..0000000000 --- a/boost/unordered/detail/equivalent.hpp +++ /dev/null @@ -1,735 +0,0 @@ - -// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2011 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED - -#include <boost/config.hpp> -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include <boost/unordered/detail/extract_key.hpp> - -namespace boost { namespace unordered { namespace detail { - - template <typename A, typename T> struct grouped_node; - template <typename T> struct grouped_ptr_node; - template <typename Types> struct grouped_table_impl; - - template <typename A, typename T> - struct grouped_node : - boost::unordered::detail::value_base<T> - { - typedef typename ::boost::unordered::detail::rebind_wrap< - A, grouped_node<A, T> >::type allocator; - typedef typename ::boost::unordered::detail:: - allocator_traits<allocator>::pointer node_pointer; - typedef node_pointer link_pointer; - - link_pointer next_; - node_pointer group_prev_; - std::size_t hash_; - - grouped_node() : - next_(), - group_prev_(), - hash_(0) - {} - - void init(node_pointer self) - { - group_prev_ = self; - } - - private: - grouped_node& operator=(grouped_node const&); - }; - - template <typename T> - struct grouped_ptr_node : - boost::unordered::detail::ptr_bucket - { - typedef T value_type; - typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef grouped_ptr_node<T>* node_pointer; - typedef ptr_bucket* link_pointer; - - node_pointer group_prev_; - std::size_t hash_; - boost::unordered::detail::value_base<T> value_base_; - - grouped_ptr_node() : - bucket_base(), - group_prev_(0), - hash_(0) - {} - - void init(node_pointer self) - { - group_prev_ = self; - } - - void* address() { return value_base_.address(); } - value_type& value() { return value_base_.value(); } - value_type* value_ptr() { return value_base_.value_ptr(); } - - private: - grouped_ptr_node& operator=(grouped_ptr_node const&); - }; - - // If the allocator uses raw pointers use grouped_ptr_node - // Otherwise use grouped_node. - - template <typename A, typename T, typename NodePtr, typename BucketPtr> - struct pick_grouped_node2 - { - typedef boost::unordered::detail::grouped_node<A, T> node; - - typedef typename boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap<A, node>::type - >::pointer node_pointer; - - typedef boost::unordered::detail::bucket<node_pointer> bucket; - typedef node_pointer link_pointer; - }; - - template <typename A, typename T> - struct pick_grouped_node2<A, T, - boost::unordered::detail::grouped_ptr_node<T>*, - boost::unordered::detail::ptr_bucket*> - { - typedef boost::unordered::detail::grouped_ptr_node<T> node; - typedef boost::unordered::detail::ptr_bucket bucket; - typedef bucket* link_pointer; - }; - - template <typename A, typename T> - struct pick_grouped_node - { - typedef typename boost::remove_const<T>::type nonconst; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap<A, - boost::unordered::detail::grouped_ptr_node<nonconst> >::type - > tentative_node_traits; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap<A, - boost::unordered::detail::ptr_bucket >::type - > tentative_bucket_traits; - - typedef pick_grouped_node2<A, nonconst, - typename tentative_node_traits::pointer, - typename tentative_bucket_traits::pointer> pick; - - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - }; - - template <typename Types> - struct grouped_table_impl : boost::unordered::detail::table<Types> - { - typedef boost::unordered::detail::table<Types> table; - typedef typename table::value_type value_type; - typedef typename table::bucket bucket; - typedef typename table::policy policy; - typedef typename table::node_pointer node_pointer; - typedef typename table::node_allocator node_allocator; - typedef typename table::node_allocator_traits node_allocator_traits; - typedef typename table::bucket_pointer bucket_pointer; - typedef typename table::link_pointer link_pointer; - typedef typename table::hasher hasher; - typedef typename table::key_equal key_equal; - typedef typename table::key_type key_type; - typedef typename table::node_constructor node_constructor; - typedef typename table::node_tmp node_tmp; - typedef typename table::extractor extractor; - typedef typename table::iterator iterator; - typedef typename table::c_iterator c_iterator; - - // Constructors - - grouped_table_impl(std::size_t n, - hasher const& hf, - key_equal const& eq, - node_allocator const& a) - : table(n, hf, eq, a) - {} - - grouped_table_impl(grouped_table_impl const& x) - : table(x, node_allocator_traits:: - select_on_container_copy_construction(x.node_alloc())) - { - this->init(x); - } - - grouped_table_impl(grouped_table_impl const& x, - node_allocator const& a) - : table(x, a) - { - this->init(x); - } - - grouped_table_impl(grouped_table_impl& x, - boost::unordered::detail::move_tag m) - : table(x, m) - {} - - grouped_table_impl(grouped_table_impl& x, - node_allocator const& a, - boost::unordered::detail::move_tag m) - : table(x, a, m) - { - this->move_init(x); - } - - // Node functions. - - static inline node_pointer next_node(link_pointer n) { - return static_cast<node_pointer>(n->next_); - } - - static inline node_pointer next_group(node_pointer n) { - return static_cast<node_pointer>(n->group_prev_->next_); - } - - // Accessors - - template <class Key, class Pred> - node_pointer find_node_impl( - std::size_t key_hash, - Key const& k, - Pred const& eq) const - { - std::size_t bucket_index = this->hash_to_bucket(key_hash); - node_pointer n = this->begin(bucket_index); - - for (;;) - { - if (!n) return n; - - std::size_t node_hash = n->hash_; - if (key_hash == node_hash) - { - if (eq(k, this->get_key(n->value()))) - return n; - } - else - { - if (this->hash_to_bucket(node_hash) != bucket_index) - return node_pointer(); - } - - n = next_group(n); - } - } - - std::size_t count(key_type const& k) const - { - node_pointer n = this->find_node(k); - if (!n) return 0; - - std::size_t x = 0; - node_pointer it = n; - do { - it = it->group_prev_; - ++x; - } while(it != n); - - return x; - } - - std::pair<iterator, iterator> - equal_range(key_type const& k) const - { - node_pointer n = this->find_node(k); - return std::make_pair(iterator(n), iterator(n ? next_group(n) : n)); - } - - // Equality - - bool equals(grouped_table_impl const& other) const - { - if(this->size_ != other.size_) return false; - - for(node_pointer n1 = this->begin(); n1;) - { - node_pointer n2 = other.find_node(other.get_key(n1->value())); - if (!n2) return false; - node_pointer end1 = next_group(n1); - node_pointer end2 = next_group(n2); - if (!group_equals(n1, end1, n2, end2)) return false; - n1 = end1; - } - - return true; - } - - static bool group_equals(node_pointer n1, node_pointer end1, - node_pointer n2, node_pointer end2) - { - for(;;) - { - if (n1->value() != n2->value()) break; - - n1 = next_node(n1); - n2 = next_node(n2); - - if (n1 == end1) return n2 == end2; - if (n2 == end2) return false; - } - - for(node_pointer n1a = n1, n2a = n2;;) - { - n1a = next_node(n1a); - n2a = next_node(n2a); - - if (n1a == end1) - { - if (n2a == end2) break; - else return false; - } - - if (n2a == end2) return false; - } - - node_pointer start = n1; - for(;n1 != end1; n1 = next_node(n1)) - { - value_type const& v = n1->value(); - if (!find(start, n1, v)) { - std::size_t matches = count_equal(n2, end2, v); - if (!matches) return false; - if (matches != 1 + count_equal(next_node(n1), end1, v)) return false; - } - } - - return true; - } - - static bool find(node_pointer n, node_pointer end, value_type const& v) - { - for(;n != end; n = next_node(n)) - if (n->value() == v) - return true; - return false; - } - - static std::size_t count_equal(node_pointer n, node_pointer end, - value_type const& v) - { - std::size_t count = 0; - for(;n != end; n = next_node(n)) - if (n->value() == v) ++count; - return count; - } - - // Emplace/Insert - - // Add node 'n' to the group containing 'pos'. - // If 'pos' is the first node in group, add to the end of the group, - // otherwise add before 'pos'. - static inline void add_to_node_group( - node_pointer n, - node_pointer pos) - { - n->next_ = pos->group_prev_->next_; - n->group_prev_ = pos->group_prev_; - pos->group_prev_->next_ = n; - pos->group_prev_ = n; - } - - inline node_pointer add_node( - node_pointer n, - std::size_t key_hash, - node_pointer pos) - { - n->hash_ = key_hash; - if (pos) { - this->add_to_node_group(n, pos); - if (n->next_) { - std::size_t next_bucket = this->hash_to_bucket( - next_node(n)->hash_); - if (next_bucket != this->hash_to_bucket(key_hash)) { - this->get_bucket(next_bucket)->next_ = n; - } - } - } - else { - bucket_pointer b = this->get_bucket( - this->hash_to_bucket(key_hash)); - - if (!b->next_) - { - link_pointer start_node = this->get_previous_start(); - - if (start_node->next_) { - this->get_bucket(this->hash_to_bucket( - next_node(start_node)->hash_ - ))->next_ = n; - } - - b->next_ = start_node; - n->next_ = start_node->next_; - start_node->next_ = n; - } - else - { - n->next_ = b->next_->next_; - b->next_->next_ = n; - } - } - ++this->size_; - return n; - } - - inline node_pointer add_using_hint( - node_pointer n, - node_pointer hint) - { - n->hash_ = hint->hash_; - this->add_to_node_group(n, hint); - if (n->next_ != hint && n->next_) { - std::size_t next_bucket = this->hash_to_bucket( - next_node(n)->hash_); - if (next_bucket != this->hash_to_bucket(n->hash_)) { - this->get_bucket(next_bucket)->next_ = n; - } - } - ++this->size_; - return n; - } - - -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - iterator emplace(boost::unordered::detail::emplace_args1< - boost::unordered::detail::please_ignore_this_overload> const&) - { - BOOST_ASSERT(false); - return iterator(); - } - - iterator emplace_hint(c_iterator, boost::unordered::detail::emplace_args1< - boost::unordered::detail::please_ignore_this_overload> const&) - { - BOOST_ASSERT(false); - return iterator(); - } -# else - iterator emplace( - boost::unordered::detail::please_ignore_this_overload const&) - { - BOOST_ASSERT(false); - return iterator(); - } - - iterator emplace_hint(c_iterator, - boost::unordered::detail::please_ignore_this_overload const&) - { - BOOST_ASSERT(false); - return iterator(); - } -# endif -#endif - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) - { - return iterator(emplace_impl( - boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); - } - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS) - { - return iterator(emplace_hint_impl(hint, - boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); - } - - iterator emplace_impl(node_pointer n) - { - node_tmp a(n, this->node_alloc()); - key_type const& k = this->get_key(a.node_->value()); - std::size_t key_hash = this->hash(k); - node_pointer position = this->find_node(key_hash, k); - this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_node(a.release(), key_hash, position)); - } - - iterator emplace_hint_impl(c_iterator hint, node_pointer n) - { - node_tmp a(n, this->node_alloc()); - key_type const& k = this->get_key(a.node_->value()); - if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { - this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_using_hint(a.release(), hint.node_)); - } - else { - std::size_t key_hash = this->hash(k); - node_pointer position = this->find_node(key_hash, k); - this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_node(a.release(), key_hash, position)); - } - } - - void emplace_impl_no_rehash(node_pointer n) - { - node_tmp a(n, this->node_alloc()); - key_type const& k = this->get_key(a.node_->value()); - std::size_t key_hash = this->hash(k); - node_pointer position = this->find_node(key_hash, k); - this->add_node(a.release(), key_hash, position); - } - - //////////////////////////////////////////////////////////////////////// - // Insert range methods - - // if hash function throws, or inserting > 1 element, basic exception - // safety. Strong otherwise - template <class I> - void insert_range(I i, I j, typename - boost::unordered::detail::enable_if_forward<I, void*>::type = 0) - { - if(i == j) return; - - std::size_t distance = static_cast<std::size_t>(std::distance(i, j)); - if(distance == 1) { - emplace_impl( - boost::unordered::detail::func::construct_node( - this->node_alloc(), *i)); - } - else { - // Only require basic exception safety here - this->reserve_for_insert(this->size_ + distance); - - for (; i != j; ++i) { - emplace_impl_no_rehash( - boost::unordered::detail::func::construct_node( - this->node_alloc(), *i)); - } - } - } - - template <class I> - void insert_range(I i, I j, typename - boost::unordered::detail::disable_if_forward<I, void*>::type = 0) - { - for (; i != j; ++i) { - emplace_impl( - boost::unordered::detail::func::construct_node( - this->node_alloc(), *i)); - } - } - - //////////////////////////////////////////////////////////////////////// - // Erase - // - // no throw - - std::size_t erase_key(key_type const& k) - { - if(!this->size_) return 0; - - std::size_t key_hash = this->hash(k); - std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->get_previous_start(bucket_index); - if (!prev) return 0; - - node_pointer first_node; - - for (;;) - { - if (!prev->next_) return 0; - first_node = next_node(prev); - std::size_t node_hash = first_node->hash_; - if (this->hash_to_bucket(node_hash) != bucket_index) - return 0; - if (node_hash == key_hash && - this->key_eq()(k, this->get_key(first_node->value()))) - break; - prev = first_node->group_prev_; - } - - link_pointer end = first_node->group_prev_->next_; - - std::size_t deleted_count = this->delete_nodes(prev, end); - this->fix_bucket(bucket_index, prev); - return deleted_count; - } - - iterator erase(c_iterator r) - { - BOOST_ASSERT(r.node_); - node_pointer next = next_node(r.node_); - erase_nodes(r.node_, next); - return iterator(next); - } - - iterator erase_range(c_iterator r1, c_iterator r2) - { - if (r1 == r2) return iterator(r2.node_); - erase_nodes(r1.node_, r2.node_); - return iterator(r2.node_); - } - - link_pointer erase_nodes(node_pointer i, node_pointer j) - { - std::size_t bucket_index = this->hash_to_bucket(i->hash_); - - // Split the groups containing 'i' and 'j'. - // And get the pointer to the node before i while - // we're at it. - link_pointer prev = split_groups(i, j); - - // If we don't have a 'prev' it means that i is at the - // beginning of a block, so search through the blocks in the - // same bucket. - if (!prev) { - prev = this->get_previous_start(bucket_index); - while (prev->next_ != i) - prev = next_node(prev)->group_prev_; - } - - // Delete the nodes. - do { - link_pointer group_end = next_group(next_node(prev)); - this->delete_nodes(prev, group_end); - bucket_index = this->fix_bucket(bucket_index, prev); - } while(prev->next_ != j); - - return prev; - } - - static link_pointer split_groups(node_pointer i, node_pointer j) - { - node_pointer prev = i->group_prev_; - if (prev->next_ != i) prev = node_pointer(); - - if (j) { - node_pointer first = j; - while (first != i && first->group_prev_->next_ == first) { - first = first->group_prev_; - } - - boost::swap(first->group_prev_, j->group_prev_); - if (first == i) return prev; - } - - if (prev) { - node_pointer first = prev; - while (first->group_prev_->next_ == first) { - first = first->group_prev_; - } - boost::swap(first->group_prev_, i->group_prev_); - } - - return prev; - } - - //////////////////////////////////////////////////////////////////////// - // fill_buckets - - void copy_buckets(table const& src) { - this->create_buckets(this->bucket_count_); - - for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; - node_pointer group_end(next_group(n)); - node_pointer pos = this->add_node( - boost::unordered::detail::func::construct_node( - this->node_alloc(), n->value()), key_hash, node_pointer()); - for (n = next_node(n); n != group_end; n = next_node(n)) - { - this->add_node( - boost::unordered::detail::func::construct_node( - this->node_alloc(), n->value()), key_hash, pos); - } - } - } - - void move_buckets(table const& src) { - this->create_buckets(this->bucket_count_); - - for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; - node_pointer group_end(next_group(n)); - node_pointer pos = this->add_node( - boost::unordered::detail::func::construct_node( - this->node_alloc(), boost::move(n->value())), key_hash, node_pointer()); - for (n = next_node(n); n != group_end; n = next_node(n)) - { - this->add_node( - boost::unordered::detail::func::construct_node( - this->node_alloc(), boost::move(n->value())), key_hash, pos); - } - } - } - - void assign_buckets(table const& src) { - node_holder<node_allocator> holder(*this); - for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; - node_pointer group_end(next_group(n)); - node_pointer pos = this->add_node(holder.copy_of(n->value()), key_hash, node_pointer()); - for (n = next_node(n); n != group_end; n = next_node(n)) - { - this->add_node(holder.copy_of(n->value()), key_hash, pos); - } - } - } - - void move_assign_buckets(table& src) { - node_holder<node_allocator> holder(*this); - for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; - node_pointer group_end(next_group(n)); - node_pointer pos = this->add_node(holder.move_copy_of(n->value()), key_hash, node_pointer()); - for (n = next_node(n); n != group_end; n = next_node(n)) - { - this->add_node(holder.move_copy_of(n->value()), key_hash, pos); - } - } - } - - // strong otherwise exception safety - void rehash_impl(std::size_t num_buckets) - { - BOOST_ASSERT(this->buckets_); - - this->create_buckets(num_buckets); - link_pointer prev = this->get_previous_start(); - while (prev->next_) - prev = place_in_bucket(*this, prev, next_node(prev)->group_prev_); - } - - // Iterate through the nodes placing them in the correct buckets. - // pre: prev->next_ is not null. - static link_pointer place_in_bucket(table& dst, - link_pointer prev, node_pointer end) - { - bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_)); - - if (!b->next_) { - b->next_ = prev; - return end; - } - else { - link_pointer next = end->next_; - end->next_ = b->next_->next_; - b->next_->next_ = prev->next_; - prev->next_ = next; - return prev; - } - } - }; -}}} - -#endif diff --git a/boost/unordered/detail/extract_key.hpp b/boost/unordered/detail/extract_key.hpp deleted file mode 100644 index 338e918ca9..0000000000 --- a/boost/unordered/detail/extract_key.hpp +++ /dev/null @@ -1,188 +0,0 @@ - -// Copyright (C) 2005-2011 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED - -#include <boost/config.hpp> -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include <boost/unordered/detail/table.hpp> - -namespace boost { -namespace unordered { -namespace detail { - - // key extractors - // - // no throw - // - // 'extract_key' is called with the emplace parameters to return a - // key if available or 'no_key' is one isn't and will need to be - // constructed. This could be done by overloading the emplace implementation - // for the different cases, but that's a bit tricky on compilers without - // variadic templates. - - struct no_key { - no_key() {} - template <class T> no_key(T const&) {} - }; - - template <typename Key, typename T> - struct is_key { - template <typename T2> - static choice1::type test(T2 const&); - static choice2::type test(Key const&); - - enum { value = sizeof(test(boost::unordered::detail::make<T>())) == - sizeof(choice2::type) }; - - typedef typename boost::detail::if_true<value>:: - BOOST_NESTED_TEMPLATE then<Key const&, no_key>::type type; - }; - - template <class ValueType> - struct set_extractor - { - typedef ValueType value_type; - typedef ValueType key_type; - - static key_type const& extract(value_type const& v) - { - return v; - } - - static no_key extract() - { - return no_key(); - } - - template <class Arg> - static no_key extract(Arg const&) - { - return no_key(); - } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <class Arg1, class Arg2, class... Args> - static no_key extract(Arg1 const&, Arg2 const&, Args const&...) - { - return no_key(); - } -#else - template <class Arg1, class Arg2> - static no_key extract(Arg1 const&, Arg2 const&) - { - return no_key(); - } -#endif - }; - - template <class Key, class ValueType> - struct map_extractor - { - typedef ValueType value_type; - typedef typename boost::remove_const<Key>::type key_type; - - static key_type const& extract(value_type const& v) - { - return v.first; - } - - template <class Second> - static key_type const& extract(std::pair<key_type, Second> const& v) - { - return v.first; - } - - template <class Second> - static key_type const& extract( - std::pair<key_type const, Second> const& v) - { - return v.first; - } - - template <class Arg1> - static key_type const& extract(key_type const& k, Arg1 const&) - { - return k; - } - - static no_key extract() - { - return no_key(); - } - - template <class Arg> - static no_key extract(Arg const&) - { - return no_key(); - } - - template <class Arg1, class Arg2> - static no_key extract(Arg1 const&, Arg2 const&) - { - return no_key(); - } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <class Arg1, class Arg2, class Arg3, class... Args> - static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&, - Args const&...) - { - return no_key(); - } -#endif - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ - template <typename T2> \ - static no_key extract(boost::unordered::piecewise_construct_t, \ - namespace_ tuple<> const&, T2 const&) \ - { \ - return no_key(); \ - } \ - \ - template <typename T, typename T2> \ - static typename is_key<key_type, T>::type \ - extract(boost::unordered::piecewise_construct_t, \ - namespace_ tuple<T> const& k, T2 const&) \ - { \ - return typename is_key<key_type, T>::type( \ - namespace_ get<0>(k)); \ - } - -#else - -#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ - static no_key extract(boost::unordered::piecewise_construct_t, \ - namespace_ tuple<> const&) \ - { \ - return no_key(); \ - } \ - \ - template <typename T> \ - static typename is_key<key_type, T>::type \ - extract(boost::unordered::piecewise_construct_t, \ - namespace_ tuple<T> const& k) \ - { \ - return typename is_key<key_type, T>::type( \ - namespace_ get<0>(k)); \ - } - -#endif - -BOOST_UNORDERED_KEY_FROM_TUPLE(boost::) - -#if !defined(BOOST_NO_CXX11_HDR_TUPLE) -BOOST_UNORDERED_KEY_FROM_TUPLE(std::) -#endif - }; -}}} - -#endif diff --git a/boost/unordered/detail/fwd.hpp b/boost/unordered/detail/fwd.hpp index 7441906234..6a84204200 100644 --- a/boost/unordered/detail/fwd.hpp +++ b/boost/unordered/detail/fwd.hpp @@ -15,21 +15,21 @@ // Already defined. #elif defined(BOOST_LIBSTDCXX11) // https://github.com/gcc-mirror/gcc/blob/gcc-4_6-branch/libstdc++-v3/include/bits/stl_pair.h#L70 -# if BOOST_LIBSTDCXX_VERSION > 40600 -# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 -# endif +#if BOOST_LIBSTDCXX_VERSION > 40600 +#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +#endif #elif defined(_LIBCPP_VERSION) // https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206 -# if LIBCPP_VERSION >= 3000 -# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 -# endif +#if LIBCPP_VERSION >= 3000 +#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +#endif #elif defined(BOOST_MSVC) // Apparently C++11 standard supported in Visual Studio 2012 // https://msdn.microsoft.com/en-us/library/hh567368.aspx#stl // 2012 = VC+11 = BOOST_MSVC 1700 Hopefully! -# if BOOST_MSVC >= 1700 -# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 -# endif +#if BOOST_MSVC >= 1700 +#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +#endif #endif #if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT) @@ -40,16 +40,16 @@ #include <utility> #endif -namespace boost -{ -namespace unordered -{ +namespace boost { +namespace unordered { #if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT - using std::piecewise_construct_t; - using std::piecewise_construct; +using std::piecewise_construct_t; +using std::piecewise_construct; #else - struct piecewise_construct_t {}; - const piecewise_construct_t piecewise_construct = piecewise_construct_t(); +struct piecewise_construct_t +{ +}; +const piecewise_construct_t piecewise_construct = piecewise_construct_t(); #endif } } diff --git a/boost/unordered/detail/implementation.hpp b/boost/unordered/detail/implementation.hpp new file mode 100644 index 0000000000..c293ae2f50 --- /dev/null +++ b/boost/unordered/detail/implementation.hpp @@ -0,0 +1,4986 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2016 Daniel James +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP +#define BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP + +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/detail/no_exceptions_support.hpp> +#include <boost/detail/select_type.hpp> +#include <boost/iterator/iterator_categories.hpp> +#include <boost/limits.hpp> +#include <boost/move/move.hpp> +#include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/repetition/enum.hpp> +#include <boost/preprocessor/repetition/enum_binary_params.hpp> +#include <boost/preprocessor/repetition/enum_params.hpp> +#include <boost/preprocessor/repetition/repeat_from_to.hpp> +#include <boost/preprocessor/seq/enum.hpp> +#include <boost/preprocessor/seq/size.hpp> +#include <boost/swap.hpp> +#include <boost/throw_exception.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/type_traits/add_lvalue_reference.hpp> +#include <boost/type_traits/aligned_storage.hpp> +#include <boost/type_traits/alignment_of.hpp> +#include <boost/type_traits/is_class.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/type_traits/is_empty.hpp> +#include <boost/type_traits/is_nothrow_move_assignable.hpp> +#include <boost/type_traits/is_nothrow_move_constructible.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/remove_const.hpp> +#include <boost/unordered/detail/fwd.hpp> +#include <boost/utility/addressof.hpp> +#include <boost/utility/enable_if.hpp> +#include <cmath> +#include <iterator> +#include <stdexcept> +#include <utility> + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) +#include <tuple> +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#include <type_traits> +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Configuration +// +// Unless documented elsewhere these configuration macros should be considered +// an implementation detail, I'll try not to break them, but you never know. + +// BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters in emplace +// (not including things like hints). Don't set it to a lower value, as that +// might break something. + +#if !defined BOOST_UNORDERED_EMPLACE_LIMIT +#define BOOST_UNORDERED_EMPLACE_LIMIT 11 +#endif + +// BOOST_UNORDERED_INTEROPERABLE_NODES - Use the same node type for +// containers with unique and equivalent keys. +// +// 0 = Use different nodes +// 1 = Use ungrouped nodes everywhere +// +// Might add an extra value to use grouped nodes everywhere later. + +#if !defined(BOOST_UNORDERED_INTEROPERABLE_NODES) +#define BOOST_UNORDERED_INTEROPERABLE_NODES 0 +#endif + +// BOOST_UNORDERED_USE_ALLOCATOR_TRAITS - Pick which version of +// allocator_traits to use. +// +// 0 = Own partial implementation +// 1 = std::allocator_traits +// 2 = boost::container::allocator_traits + +#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) +#if !defined(BOOST_NO_CXX11_ALLOCATOR) +#define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 +#elif defined(BOOST_MSVC) +#if BOOST_MSVC < 1400 +// Use container's allocator_traits for older versions of Visual +// C++ as I don't test with them. +#define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2 +#endif +#endif +#endif + +#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) +#define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 +#endif + +namespace boost { +namespace unordered { +namespace iterator_detail { +template <typename Node> struct iterator; +template <typename Node> struct c_iterator; +template <typename Node, typename Policy> struct l_iterator; +template <typename Node, typename Policy> struct cl_iterator; +} +} +} + +namespace boost { +namespace unordered { +namespace detail { + +template <typename Types> struct table; +template <typename NodePointer> struct bucket; +struct ptr_bucket; +template <typename Types> struct table_impl; +template <typename Types> struct grouped_table_impl; + +template <typename A, typename T> struct unique_node; +template <typename T> struct ptr_node; +template <typename Types> struct table_impl; + +template <typename A, typename T> struct grouped_node; +template <typename T> struct grouped_ptr_node; +template <typename Types> struct grouped_table_impl; +template <typename N> struct node_algo; +template <typename N> struct grouped_node_algo; + +static const float minimum_max_load_factor = 1e-3f; +static const std::size_t default_bucket_count = 11; +struct move_tag +{ +}; +struct empty_emplace +{ +}; + +namespace func { +template <class T> inline void ignore_unused_variable_warning(T const&) {} +} + +//////////////////////////////////////////////////////////////////////////// +// iterator SFINAE + +template <typename I> +struct is_forward + : boost::is_convertible<typename boost::iterator_traversal<I>::type, + boost::forward_traversal_tag> +{ +}; + +template <typename I, typename ReturnType> +struct enable_if_forward + : boost::enable_if_c<boost::unordered::detail::is_forward<I>::value, + ReturnType> +{ +}; + +template <typename I, typename ReturnType> +struct disable_if_forward + : boost::disable_if_c<boost::unordered::detail::is_forward<I>::value, + ReturnType> +{ +}; + +//////////////////////////////////////////////////////////////////////////// +// primes + +// clang-format off +#define BOOST_UNORDERED_PRIMES \ + (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ + (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ + (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ + (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ + (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ + (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ + (1610612741ul)(3221225473ul)(4294967291ul) +// clang-format on + +template <class T> struct prime_list_template +{ + static std::size_t const value[]; + +#if !defined(SUNPRO_CC) + static std::ptrdiff_t const length; +#else + static std::ptrdiff_t const length = + BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); +#endif +}; + +template <class T> +std::size_t const prime_list_template<T>::value[] = { + BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)}; + +#if !defined(SUNPRO_CC) +template <class T> +std::ptrdiff_t const prime_list_template<T>::length = BOOST_PP_SEQ_SIZE( + BOOST_UNORDERED_PRIMES); +#endif + +#undef BOOST_UNORDERED_PRIMES + +typedef prime_list_template<std::size_t> prime_list; + +// no throw +inline std::size_t next_prime(std::size_t num) +{ + std::size_t const* const prime_list_begin = prime_list::value; + std::size_t const* const prime_list_end = + prime_list_begin + prime_list::length; + std::size_t const* bound = + std::lower_bound(prime_list_begin, prime_list_end, num); + if (bound == prime_list_end) + bound--; + return *bound; +} + +// no throw +inline std::size_t prev_prime(std::size_t num) +{ + std::size_t const* const prime_list_begin = prime_list::value; + std::size_t const* const prime_list_end = + prime_list_begin + prime_list::length; + std::size_t const* bound = + std::upper_bound(prime_list_begin, prime_list_end, num); + if (bound != prime_list_begin) + bound--; + return *bound; +} + +//////////////////////////////////////////////////////////////////////////// +// insert_size/initial_size + +template <class I> +inline std::size_t insert_size(I i, I j, + typename boost::unordered::detail::enable_if_forward<I, void*>::type = 0) +{ + return static_cast<std::size_t>(std::distance(i, j)); +} + +template <class I> +inline std::size_t insert_size(I, I, + typename boost::unordered::detail::disable_if_forward<I, void*>::type = 0) +{ + return 1; +} + +template <class I> +inline std::size_t initial_size(I i, I j, + std::size_t num_buckets = boost::unordered::detail::default_bucket_count) +{ + // TODO: Why +1? + return (std::max)( + boost::unordered::detail::insert_size(i, j) + 1, num_buckets); +} + +//////////////////////////////////////////////////////////////////////////// +// compressed + +template <typename T, int Index> struct compressed_base : private T +{ + compressed_base(T const& x) : T(x) {} + compressed_base(T& x, move_tag) : T(boost::move(x)) {} + + T& get() { return *this; } + T const& get() const { return *this; } +}; + +template <typename T, int Index> struct uncompressed_base +{ + uncompressed_base(T const& x) : value_(x) {} + uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {} + + T& get() { return value_; } + T const& get() const { return value_; } + private: + T value_; +}; + +template <typename T, int Index> +struct generate_base + : boost::detail::if_true<boost::is_empty<T>::value>::BOOST_NESTED_TEMPLATE + then<boost::unordered::detail::compressed_base<T, Index>, + boost::unordered::detail::uncompressed_base<T, Index> > +{ +}; + +template <typename T1, typename T2> +struct compressed + : private boost::unordered::detail::generate_base<T1, 1>::type, + private boost::unordered::detail::generate_base<T2, 2>::type +{ + typedef typename generate_base<T1, 1>::type base1; + typedef typename generate_base<T2, 2>::type base2; + + typedef T1 first_type; + typedef T2 second_type; + + first_type& first() { return static_cast<base1*>(this)->get(); } + + first_type const& first() const + { + return static_cast<base1 const*>(this)->get(); + } + + second_type& second() { return static_cast<base2*>(this)->get(); } + + second_type const& second() const + { + return static_cast<base2 const*>(this)->get(); + } + + template <typename First, typename Second> + compressed(First const& x1, Second const& x2) : base1(x1), base2(x2) + { + } + + compressed(compressed const& x) : base1(x.first()), base2(x.second()) {} + + compressed(compressed& x, move_tag m) + : base1(x.first(), m), base2(x.second(), m) + { + } + + void assign(compressed const& x) + { + first() = x.first(); + second() = x.second(); + } + + void move_assign(compressed& x) + { + first() = boost::move(x.first()); + second() = boost::move(x.second()); + } + + void swap(compressed& x) + { + boost::swap(first(), x.first()); + boost::swap(second(), x.second()); + } + + private: + // Prevent assignment just to make use of assign or + // move_assign explicit. + compressed& operator=(compressed const&); +}; + +//////////////////////////////////////////////////////////////////////////// +// pair_traits +// +// Used to get the types from a pair without instantiating it. + +template <typename Pair> struct pair_traits +{ + typedef typename Pair::first_type first_type; + typedef typename Pair::second_type second_type; +}; + +template <typename T1, typename T2> struct pair_traits<std::pair<T1, T2> > +{ + typedef T1 first_type; + typedef T2 second_type; +}; + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable : 4512) // assignment operator could not be generated. +#pragma warning(disable : 4345) // behavior change: an object of POD type +// constructed with an initializer of the form () +// will be default-initialized. +#endif + +//////////////////////////////////////////////////////////////////////////// +// Bits and pieces for implementing traits + +template <typename T> typename boost::add_lvalue_reference<T>::type make(); +struct choice9 +{ + typedef char (&type)[9]; +}; +struct choice8 : choice9 +{ + typedef char (&type)[8]; +}; +struct choice7 : choice8 +{ + typedef char (&type)[7]; +}; +struct choice6 : choice7 +{ + typedef char (&type)[6]; +}; +struct choice5 : choice6 +{ + typedef char (&type)[5]; +}; +struct choice4 : choice5 +{ + typedef char (&type)[4]; +}; +struct choice3 : choice4 +{ + typedef char (&type)[3]; +}; +struct choice2 : choice3 +{ + typedef char (&type)[2]; +}; +struct choice1 : choice2 +{ + typedef char (&type)[1]; +}; +choice1 choose(); + +typedef choice1::type yes_type; +typedef choice2::type no_type; + +struct private_type +{ + private_type const& operator,(int) const; +}; + +template <typename T> no_type is_private_type(T const&); +yes_type is_private_type(private_type const&); + +struct convert_from_anything +{ + template <typename T> convert_from_anything(T const&); +}; + +namespace func { +// This is a bit nasty, when constructing the individual members +// of a std::pair, need to cast away 'const'. For modern compilers, +// should be able to use std::piecewise_construct instead. +template <typename T> T* const_cast_pointer(T* x) { return x; } +template <typename T> T* const_cast_pointer(T const* x) +{ + return const_cast<T*>(x); +} +} + +//////////////////////////////////////////////////////////////////////////// +// emplace_args +// +// Either forwarding variadic arguments, or storing the arguments in +// emplace_args##n + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#define BOOST_UNORDERED_EMPLACE_ARGS1(a0) a0 +#define BOOST_UNORDERED_EMPLACE_ARGS2(a0, a1) a0, a1 +#define BOOST_UNORDERED_EMPLACE_ARGS3(a0, a1, a2) a0, a1, a2 + +#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args +#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args +#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)... + +#else + +#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args +#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args +#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args + +#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args +#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args +#define BOOST_UNORDERED_EMPLACE_FORWARD args + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ + typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \ + BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); + +#else + +#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ + typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \ + BOOST_PP_CAT(Arg, n); \ + BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); + +#endif + +template <typename A0> struct emplace_args1 +{ + BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) + + explicit emplace_args1(Arg0 b0) : a0(b0) {} +}; + +template <typename A0> +inline emplace_args1<A0> create_emplace_args(BOOST_FWD_REF(A0) b0) +{ + emplace_args1<A0> e(b0); + return e; +} + +template <typename A0, typename A1> struct emplace_args2 +{ + BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) + BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) + + emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {} +}; + +template <typename A0, typename A1> +inline emplace_args2<A0, A1> create_emplace_args( + BOOST_FWD_REF(A0) b0, BOOST_FWD_REF(A1) b1) +{ + emplace_args2<A0, A1> e(b0, b1); + return e; +} + +template <typename A0, typename A1, typename A2> struct emplace_args3 +{ + BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) + BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) + BOOST_UNORDERED_EARGS_MEMBER(1, 2, _) + + emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {} +}; + +template <typename A0, typename A1, typename A2> +inline emplace_args3<A0, A1, A2> create_emplace_args( + BOOST_FWD_REF(A0) b0, BOOST_FWD_REF(A1) b1, BOOST_FWD_REF(A2) b2) +{ + emplace_args3<A0, A1, A2> e(b0, b1, b2); + return e; +} + +#define BOOST_UNORDERED_FWD_PARAM(z, n, a) \ + BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n) + +#define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \ + boost::forward<BOOST_PP_CAT(A, i)>(BOOST_PP_CAT(a, i)) + +#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ + BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n)) + +#define BOOST_UNORDERED_EARGS(z, n, _) \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + struct BOOST_PP_CAT(emplace_args, n) \ + { \ + BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) BOOST_PP_CAT( \ + emplace_args, n)(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, b)) \ + : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \ + { \ + } \ + }; \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + inline BOOST_PP_CAT(emplace_args, n)<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> \ + create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, b)) \ + { \ + BOOST_PP_CAT(emplace_args, n)<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> e( \ + BOOST_PP_ENUM_PARAMS_Z(z, n, b)); \ + return e; \ + } + +BOOST_PP_REPEAT_FROM_TO( + 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, _) + +#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS +#undef BOOST_UNORDERED_EARGS_MEMBER +#undef BOOST_UNORDERED_EARGS_INIT + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +// Some utilities for implementing allocator_traits, but useful elsewhere so +// they're always defined. + +//////////////////////////////////////////////////////////////////////////// +// Integral_constrant, true_type, false_type +// +// Uses the standard versions if available. + +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) + +using std::integral_constant; +using std::true_type; +using std::false_type; + +#else + +template <typename T, T Value> struct integral_constant +{ + enum + { + value = Value + }; +}; + +typedef boost::unordered::detail::integral_constant<bool, true> true_type; +typedef boost::unordered::detail::integral_constant<bool, false> false_type; + +#endif + +//////////////////////////////////////////////////////////////////////////// +// Explicitly call a destructor + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable : 4100) // unreferenced formal parameter +#endif + +namespace func { +template <class T> inline void destroy(T* x) { x->~T(); } +} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +//////////////////////////////////////////////////////////////////////////// +// Expression test mechanism +// +// When SFINAE expressions are available, define +// BOOST_UNORDERED_HAS_FUNCTION which can check if a function call is +// supported by a class, otherwise define BOOST_UNORDERED_HAS_MEMBER which +// can detect if a class has the specified member, but not that it has the +// correct type, this is good enough for a passable impression of +// allocator_traits. + +#if !defined(BOOST_NO_SFINAE_EXPR) + +template <typename T, long unsigned int> struct expr_test; +template <typename T> struct expr_test<T, sizeof(char)> : T +{ +}; + +#define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ + template <typename U> \ + static typename boost::unordered::detail::expr_test<BOOST_PP_CAT( \ + choice, result), \ + sizeof(for_expr_test(((expression), 0)))>::type \ + test(BOOST_PP_CAT(choice, count)) + +#define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \ + template <typename U> \ + static BOOST_PP_CAT(choice, result)::type test( \ + BOOST_PP_CAT(choice, count)) + +#define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \ + struct BOOST_PP_CAT(has_, name) \ + { \ + template <typename U> static char for_expr_test(U const&); \ + BOOST_UNORDERED_CHECK_EXPRESSION( \ + 1, 1, boost::unordered::detail::make<thing>().name args); \ + BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \ + \ + enum \ + { \ + value = sizeof(test<T>(choose())) == sizeof(choice1::type) \ + }; \ + } + +#else + +template <typename T> struct identity +{ + typedef T type; +}; + +#define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ + \ + typedef typename boost::unordered::detail::identity<member>::type \ + BOOST_PP_CAT(check, count); \ + \ + template <BOOST_PP_CAT(check, count) e> struct BOOST_PP_CAT(test, count) \ + { \ + typedef BOOST_PP_CAT(choice, result) type; \ + }; \ + \ + template <class U> \ + static typename BOOST_PP_CAT(test, count)<&U::name>::type test( \ + BOOST_PP_CAT(choice, count)) + +#define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ + template <class U> \ + static BOOST_PP_CAT(choice, result)::type test( \ + BOOST_PP_CAT(choice, count)) + +#define BOOST_UNORDERED_HAS_MEMBER(name) \ + struct BOOST_PP_CAT(has_, name) \ + { \ + struct impl \ + { \ + struct base_mixin \ + { \ + int name; \ + }; \ + struct base : public T, public base_mixin \ + { \ + }; \ + \ + BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, int base_mixin::*); \ + BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \ + \ + enum \ + { \ + value = sizeof(choice2::type) == sizeof(test<base>(choose())) \ + }; \ + }; \ + \ + enum \ + { \ + value = impl::value \ + }; \ + } + +#endif +} +} +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Allocator traits +// +// First our implementation, then later light wrappers around the alternatives + +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 + +#include <boost/limits.hpp> +#include <boost/pointer_to_other.hpp> +#include <boost/utility/enable_if.hpp> + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_SFINAE_EXPR) +#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 +#else +#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 +#endif + +namespace boost { +namespace unordered { +namespace detail { + +template <typename Alloc, typename T> struct rebind_alloc; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template <template <typename, typename...> class Alloc, typename U, typename T, + typename... Args> +struct rebind_alloc<Alloc<U, Args...>, T> +{ + typedef Alloc<T, Args...> type; +}; + +#else + +template <template <typename> class Alloc, typename U, typename T> +struct rebind_alloc<Alloc<U>, T> +{ + typedef Alloc<T> type; +}; + +template <template <typename, typename> class Alloc, typename U, typename T, + typename A0> +struct rebind_alloc<Alloc<U, A0>, T> +{ + typedef Alloc<T, A0> type; +}; + +template <template <typename, typename, typename> class Alloc, typename U, + typename T, typename A0, typename A1> +struct rebind_alloc<Alloc<U, A0, A1>, T> +{ + typedef Alloc<T, A0, A1> type; +}; + +#endif + +template <typename Alloc, typename T> struct rebind_wrap +{ + template <typename X> + static choice1::type test( + choice1, typename X::BOOST_NESTED_TEMPLATE rebind<T>::other* = 0); + template <typename X> static choice2::type test(choice2, void* = 0); + + enum + { + value = (1 == sizeof(test<Alloc>(choose()))) + }; + + struct fallback + { + template <typename U> struct rebind + { + typedef typename rebind_alloc<Alloc, T>::type other; + }; + }; + + typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE then< + Alloc, fallback>::type::BOOST_NESTED_TEMPLATE rebind<T>::other type; +}; + +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 + +#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ + template <typename Tp, typename Default> struct default_type_##tname \ + { \ + \ + template <typename X> \ + static choice1::type test(choice1, typename X::tname* = 0); \ + \ + template <typename X> static choice2::type test(choice2, void* = 0); \ + \ + struct DefaultWrap \ + { \ + typedef Default tname; \ + }; \ + \ + enum \ + { \ + value = (1 == sizeof(test<Tp>(choose()))) \ + }; \ + \ + typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE \ + then<Tp, DefaultWrap>::type::tname type; \ + } + +#else + +template <typename T, typename T2> struct sfinae : T2 +{ +}; + +#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ + template <typename Tp, typename Default> struct default_type_##tname \ + { \ + \ + template <typename X> \ + static typename boost::unordered::detail::sfinae<typename X::tname, \ + choice1>::type test(choice1); \ + \ + template <typename X> static choice2::type test(choice2); \ + \ + struct DefaultWrap \ + { \ + typedef Default tname; \ + }; \ + \ + enum \ + { \ + value = (1 == sizeof(test<Tp>(choose()))) \ + }; \ + \ + typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE \ + then<Tp, DefaultWrap>::type::tname type; \ + } + +#endif + +#define BOOST_UNORDERED_DEFAULT_TYPE(T, tname, arg) \ + typename default_type_##tname<T, arg>::type + +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer); +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer); +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(void_pointer); +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_void_pointer); +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(difference_type); +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(size_type); +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment); +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment); +BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap); + +#if !defined(BOOST_NO_SFINAE_EXPR) + +template <typename T> +BOOST_UNORDERED_HAS_FUNCTION( + select_on_container_copy_construction, U const, (), 0); + +template <typename T> BOOST_UNORDERED_HAS_FUNCTION(max_size, U const, (), 0); + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template <typename T, typename ValueType, typename... Args> +BOOST_UNORDERED_HAS_FUNCTION( + construct, U, (boost::unordered::detail::make<ValueType*>(), + boost::unordered::detail::make<Args const>()...), + 2); + +#else + +template <typename T, typename ValueType> +BOOST_UNORDERED_HAS_FUNCTION( + construct, U, (boost::unordered::detail::make<ValueType*>(), + boost::unordered::detail::make<ValueType const>()), + 2); + +#endif + +template <typename T, typename ValueType> +BOOST_UNORDERED_HAS_FUNCTION( + destroy, U, (boost::unordered::detail::make<ValueType*>()), 1); + +#else + +template <typename T> +BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction); + +template <typename T> BOOST_UNORDERED_HAS_MEMBER(max_size); + +template <typename T, typename ValueType> BOOST_UNORDERED_HAS_MEMBER(construct); + +template <typename T, typename ValueType> BOOST_UNORDERED_HAS_MEMBER(destroy); + +#endif + +namespace func { + +template <typename Alloc> +inline Alloc call_select_on_container_copy_construction(const Alloc& rhs, + typename boost::enable_if_c< + boost::unordered::detail::has_select_on_container_copy_construction< + Alloc>::value, + void*>::type = 0) +{ + return rhs.select_on_container_copy_construction(); +} + +template <typename Alloc> +inline Alloc call_select_on_container_copy_construction(const Alloc& rhs, + typename boost::disable_if_c< + boost::unordered::detail::has_select_on_container_copy_construction< + Alloc>::value, + void*>::type = 0) +{ + return rhs; +} + +template <typename SizeType, typename Alloc> +inline SizeType call_max_size(const Alloc& a, + typename boost::enable_if_c< + boost::unordered::detail::has_max_size<Alloc>::value, void*>::type = 0) +{ + return a.max_size(); +} + +template <typename SizeType, typename Alloc> +inline SizeType call_max_size(const Alloc&, + typename boost::disable_if_c< + boost::unordered::detail::has_max_size<Alloc>::value, void*>::type = 0) +{ + return (std::numeric_limits<SizeType>::max)(); +} + +} // namespace func. + +template <typename Alloc> struct allocator_traits +{ + typedef Alloc allocator_type; + typedef typename Alloc::value_type value_type; + + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*) pointer; + + template <typename T> + struct pointer_to_other : boost::pointer_to_other<pointer, T> + { + }; + + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, + typename pointer_to_other<const value_type>::type) const_pointer; + + // typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer, + // typename pointer_to_other<void>::type) + // void_pointer; + // + // typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer, + // typename pointer_to_other<const void>::type) + // const_void_pointer; + + typedef BOOST_UNORDERED_DEFAULT_TYPE( + Alloc, difference_type, std::ptrdiff_t) difference_type; + + typedef BOOST_UNORDERED_DEFAULT_TYPE( + Alloc, size_type, std::size_t) size_type; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + template <typename T> + using rebind_alloc = typename rebind_wrap<Alloc, T>::type; + + template <typename T> + using rebind_traits = + boost::unordered::detail::allocator_traits<rebind_alloc<T> >; +#endif + + static pointer allocate(Alloc& a, size_type n) { return a.allocate(n); } + + // I never use this, so I'll just comment it out for now. + // + // static pointer allocate(Alloc& a, size_type n, + // const_void_pointer hint) + // { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); } + + static void deallocate(Alloc& a, pointer p, size_type n) + { + a.deallocate(p, n); + } + + public: +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + + template <typename T, typename... Args> + static typename boost::enable_if_c< + boost::unordered::detail::has_construct<Alloc, T, Args...>::value>::type + construct(Alloc& a, T* p, BOOST_FWD_REF(Args)... x) + { + a.construct(p, boost::forward<Args>(x)...); + } + + template <typename T, typename... Args> + static typename boost::disable_if_c< + boost::unordered::detail::has_construct<Alloc, T, Args...>::value>::type + construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x) + { + new (static_cast<void*>(p)) T(boost::forward<Args>(x)...); + } + + template <typename T> + static typename boost::enable_if_c< + boost::unordered::detail::has_destroy<Alloc, T>::value>::type + destroy(Alloc& a, T* p) + { + a.destroy(p); + } + + template <typename T> + static typename boost::disable_if_c< + boost::unordered::detail::has_destroy<Alloc, T>::value>::type + destroy(Alloc&, T* p) + { + boost::unordered::detail::func::destroy(p); + } + +#elif !defined(BOOST_NO_SFINAE_EXPR) + + template <typename T> + static typename boost::enable_if_c< + boost::unordered::detail::has_construct<Alloc, T>::value>::type + construct(Alloc& a, T* p, T const& x) + { + a.construct(p, x); + } + + template <typename T> + static typename boost::disable_if_c< + boost::unordered::detail::has_construct<Alloc, T>::value>::type + construct(Alloc&, T* p, T const& x) + { + new (static_cast<void*>(p)) T(x); + } + + template <typename T> + static typename boost::enable_if_c< + boost::unordered::detail::has_destroy<Alloc, T>::value>::type + destroy(Alloc& a, T* p) + { + a.destroy(p); + } + + template <typename T> + static typename boost::disable_if_c< + boost::unordered::detail::has_destroy<Alloc, T>::value>::type + destroy(Alloc&, T* p) + { + boost::unordered::detail::func::destroy(p); + } + +#else + + // If we don't have SFINAE expressions, only call construct for the + // copy constructor for the allocator's value_type - as that's + // the only construct method that old fashioned allocators support. + + template <typename T> + static void construct(Alloc& a, T* p, T const& x, + typename boost::enable_if_c< + boost::unordered::detail::has_construct<Alloc, T>::value && + boost::is_same<T, value_type>::value, + void*>::type = 0) + { + a.construct(p, x); + } + + template <typename T> + static void construct(Alloc&, T* p, T const& x, + typename boost::disable_if_c< + boost::unordered::detail::has_construct<Alloc, T>::value && + boost::is_same<T, value_type>::value, + void*>::type = 0) + { + new (static_cast<void*>(p)) T(x); + } + + template <typename T> + static void destroy(Alloc& a, T* p, + typename boost::enable_if_c< + boost::unordered::detail::has_destroy<Alloc, T>::value && + boost::is_same<T, value_type>::value, + void*>::type = 0) + { + a.destroy(p); + } + + template <typename T> + static void destroy(Alloc&, T* p, + typename boost::disable_if_c< + boost::unordered::detail::has_destroy<Alloc, T>::value && + boost::is_same<T, value_type>::value, + void*>::type = 0) + { + boost::unordered::detail::func::destroy(p); + } + +#endif + + static size_type max_size(const Alloc& a) + { + return boost::unordered::detail::func::call_max_size<size_type>(a); + } + + // Allocator propagation on construction + + static Alloc select_on_container_copy_construction(Alloc const& rhs) + { + return boost::unordered::detail::func:: + call_select_on_container_copy_construction(rhs); + } + + // Allocator propagation on assignment and swap. + // Return true if lhs is modified. + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, + propagate_on_container_copy_assignment, + false_type) propagate_on_container_copy_assignment; + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, + propagate_on_container_move_assignment, + false_type) propagate_on_container_move_assignment; + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, propagate_on_container_swap, + false_type) propagate_on_container_swap; +}; +} +} +} + +#undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT +#undef BOOST_UNORDERED_DEFAULT_TYPE + +//////////////////////////////////////////////////////////////////////////////// +// +// std::allocator_traits + +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 + +#include <memory> + +#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 + +namespace boost { +namespace unordered { +namespace detail { + +template <typename Alloc> struct allocator_traits : std::allocator_traits<Alloc> +{ +}; + +template <typename Alloc, typename T> struct rebind_wrap +{ + typedef typename std::allocator_traits<Alloc>::template rebind_alloc<T> + type; +}; +} +} +} + +//////////////////////////////////////////////////////////////////////////////// +// +// boost::container::allocator_traits + +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 + +#include <boost/container/allocator_traits.hpp> + +#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 + +namespace boost { +namespace unordered { +namespace detail { + +template <typename Alloc> +struct allocator_traits : boost::container::allocator_traits<Alloc> +{ +}; + +template <typename Alloc, typename T> +struct rebind_wrap : boost::container::allocator_traits< + Alloc>::template portable_rebind_alloc<T> +{ +}; +} +} +} + +#else + +#error "Invalid BOOST_UNORDERED_USE_ALLOCATOR_TRAITS value." + +#endif + +//////////////////////////////////////////////////////////////////////////// +// Functions used to construct nodes. Emulates variadic construction, +// piecewise construction etc. + +namespace boost { +namespace unordered { +namespace detail { +namespace func { + +//////////////////////////////////////////////////////////////////////////// +// call_construct + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + +template <typename Alloc, typename T, typename... Args> +inline void call_construct( + Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) +{ + boost::unordered::detail::allocator_traits<Alloc>::construct( + alloc, address, boost::forward<Args>(args)...); +} + +template <typename Alloc, typename T> +inline void call_destroy(Alloc& alloc, T* x) +{ + boost::unordered::detail::allocator_traits<Alloc>::destroy(alloc, x); +} + +#else + +template <typename Alloc, typename T, typename... Args> +inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(Args)... args) +{ + new ((void*)address) T(boost::forward<Args>(args)...); +} + +template <typename Alloc, typename T> inline void call_destroy(Alloc&, T* x) +{ + boost::unordered::detail::func::destroy(x); +} + +#endif + +#else +template <typename Alloc, typename T> +inline void call_construct(Alloc&, T* address) +{ + new ((void*)address) T(); +} + +template <typename Alloc, typename T, typename A0> +inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(A0) a0) +{ + new ((void*)address) T(boost::forward<A0>(a0)); +} + +template <typename Alloc, typename T> inline void call_destroy(Alloc&, T* x) +{ + boost::unordered::detail::func::destroy(x); +} + +#endif + +//////////////////////////////////////////////////////////////////////////// +// Construct from tuple +// +// Used for piecewise construction. + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template <typename Alloc, typename T> \ + void construct_from_tuple(Alloc& alloc, T* ptr, namespace_ tuple<>) \ + { \ + boost::unordered::detail::func::call_construct(alloc, ptr); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO( \ + 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template <typename Alloc, typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + void construct_from_tuple(Alloc& alloc, T* ptr, \ + namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ + { \ + boost::unordered::detail::func::call_construct(alloc, ptr, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \ + } + +#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get<n>(x) + +#elif !defined(__SUNPRO_CC) + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template <typename Alloc, typename T> \ + void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \ + { \ + new ((void*)ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO( \ + 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template <typename Alloc, typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + void construct_from_tuple(Alloc&, T* ptr, \ + namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ + { \ + new ((void*)ptr) T( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \ + } + +#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get<n>(x) + +#else + +template <int N> struct length +{ +}; + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template <typename Alloc, typename T> \ + void construct_from_tuple_impl(boost::unordered::detail::func::length<0>, \ + Alloc&, T* ptr, namespace_ tuple<>) \ + { \ + new ((void*)ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO( \ + 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template <typename Alloc, typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + void construct_from_tuple_impl(boost::unordered::detail::func::length<n>, \ + Alloc&, T* ptr, \ + namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ + { \ + new ((void*)ptr) T( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \ + } + +#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get<n>(x) + +#endif + +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) + +#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) +#endif + +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL +#undef BOOST_UNORDERED_GET_TUPLE_ARG + +#if defined(__SUNPRO_CC) + +template <typename Alloc, typename T, typename Tuple> +void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x) +{ + construct_from_tuple_impl(boost::unordered::detail::func::length< + boost::tuples::length<Tuple>::value>(), + alloc, ptr, x); +} + +#endif + +//////////////////////////////////////////////////////////////////////////// +// Trait to check for piecewise construction. + +template <typename A0> struct use_piecewise +{ + static choice1::type test(choice1, boost::unordered::piecewise_construct_t); + + static choice2::type test(choice2, ...); + + enum + { + value = sizeof(choice1::type) == + sizeof(test(choose(), boost::unordered::detail::make<A0>())) + }; +}; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +//////////////////////////////////////////////////////////////////////////// +// Construct from variadic parameters + +// For the standard pair constructor. + +template <typename Alloc, typename T, typename... Args> +inline void construct_from_args( + Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) +{ + boost::unordered::detail::func::call_construct( + alloc, address, boost::forward<Args>(args)...); +} + +// Special case for piece_construct +// +// TODO: When possible, it might be better to use std::pair's +// constructor for std::piece_construct with std::tuple. + +template <typename Alloc, typename A, typename B, typename A0, typename A1, + typename A2> +inline typename enable_if<use_piecewise<A0>, void>::type construct_from_args( + Alloc& alloc, std::pair<A, B>* address, BOOST_FWD_REF(A0), + BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) +{ + boost::unordered::detail::func::construct_from_tuple( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->first)), + boost::forward<A1>(a1)); + BOOST_TRY + { + boost::unordered::detail::func::construct_from_tuple( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->second)), + boost::forward<A2>(a2)); + } + BOOST_CATCH(...) + { + boost::unordered::detail::func::call_destroy( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END +} + +#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +//////////////////////////////////////////////////////////////////////////// +// Construct from emplace_args + +// Explicitly write out first three overloads for the sake of sane +// error messages. + +template <typename Alloc, typename T, typename A0> +inline void construct_from_args( + Alloc&, T* address, emplace_args1<A0> const& args) +{ + new ((void*)address) T(boost::forward<A0>(args.a0)); +} + +template <typename Alloc, typename T, typename A0, typename A1> +inline void construct_from_args( + Alloc&, T* address, emplace_args2<A0, A1> const& args) +{ + new ((void*)address) + T(boost::forward<A0>(args.a0), boost::forward<A1>(args.a1)); +} + +template <typename Alloc, typename T, typename A0, typename A1, typename A2> +inline void construct_from_args( + Alloc&, T* address, emplace_args3<A0, A1, A2> const& args) +{ + new ((void*)address) T(boost::forward<A0>(args.a0), + boost::forward<A1>(args.a1), boost::forward<A2>(args.a2)); +} + +// Use a macro for the rest. + +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ + template <typename Alloc, typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A)> \ + inline void construct_from_args(Alloc&, T* address, \ + boost::unordered::detail::BOOST_PP_CAT(emplace_args, num_params) < \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) > const& args) \ + { \ + new ((void*)address) T(BOOST_PP_ENUM_##z( \ + num_params, BOOST_UNORDERED_CALL_FORWARD, args.a)); \ + } + +BOOST_PP_REPEAT_FROM_TO( + 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_CONSTRUCT_IMPL, _) + +#undef BOOST_UNORDERED_CONSTRUCT_IMPL + +// Construct with piece_construct + +template <typename Alloc, typename A, typename B, typename A0, typename A1, + typename A2> +inline void construct_from_args(Alloc& alloc, std::pair<A, B>* address, + boost::unordered::detail::emplace_args3<A0, A1, A2> const& args, + typename enable_if<use_piecewise<A0>, void*>::type = 0) +{ + boost::unordered::detail::func::construct_from_tuple( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->first)), + args.a1); + BOOST_TRY + { + boost::unordered::detail::func::construct_from_tuple( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->second)), + args.a2); + } + BOOST_CATCH(...) + { + boost::unordered::detail::func::call_destroy( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END +} + +#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES +} +} +} +} + +namespace boost { +namespace unordered { +namespace detail { + +/////////////////////////////////////////////////////////////////// +// +// Node construction + +template <typename NodeAlloc> struct node_constructor +{ + typedef NodeAlloc node_allocator; + typedef boost::unordered::detail::allocator_traits<NodeAlloc> + node_allocator_traits; + typedef typename node_allocator_traits::value_type node; + typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node::value_type value_type; + + node_allocator& alloc_; + node_pointer node_; + bool node_constructed_; + + node_constructor(node_allocator& n) + : alloc_(n), node_(), node_constructed_(false) + { + } + + ~node_constructor(); + + void create_node(); + + // no throw + node_pointer release() + { + BOOST_ASSERT(node_ && node_constructed_); + node_pointer p = node_; + node_ = node_pointer(); + return p; + } + + void reclaim(node_pointer p) + { + BOOST_ASSERT(!node_); + node_ = p; + node_constructed_ = true; + boost::unordered::detail::func::call_destroy( + alloc_, node_->value_ptr()); + } + + private: + node_constructor(node_constructor const&); + node_constructor& operator=(node_constructor const&); +}; + +template <typename Alloc> node_constructor<Alloc>::~node_constructor() +{ + if (node_) { + if (node_constructed_) { + boost::unordered::detail::func::destroy(boost::addressof(*node_)); + } + + node_allocator_traits::deallocate(alloc_, node_, 1); + } +} + +template <typename Alloc> void node_constructor<Alloc>::create_node() +{ + BOOST_ASSERT(!node_); + node_constructed_ = false; + + node_ = node_allocator_traits::allocate(alloc_, 1); + + new ((void*)boost::addressof(*node_)) node(); + node_->init(node_); + node_constructed_ = true; +} + +template <typename NodeAlloc> struct node_tmp +{ + typedef boost::unordered::detail::allocator_traits<NodeAlloc> + node_allocator_traits; + typedef typename node_allocator_traits::pointer node_pointer; + + NodeAlloc& alloc_; + node_pointer node_; + + explicit node_tmp(node_pointer n, NodeAlloc& a) : alloc_(a), node_(n) {} + + ~node_tmp(); + + // no throw + node_pointer release() + { + node_pointer p = node_; + node_ = node_pointer(); + return p; + } +}; + +template <typename Alloc> node_tmp<Alloc>::~node_tmp() +{ + if (node_) { + boost::unordered::detail::func::call_destroy( + alloc_, node_->value_ptr()); + boost::unordered::detail::func::destroy(boost::addressof(*node_)); + node_allocator_traits::deallocate(alloc_, node_, 1); + } +} +} +} +} + +namespace boost { +namespace unordered { +namespace detail { +namespace func { + +// Some nicer construct_node functions, might try to +// improve implementation later. + +template <typename Alloc, BOOST_UNORDERED_EMPLACE_TEMPLATE> +inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer +construct_node_from_args(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS) +{ + node_constructor<Alloc> a(alloc); + a.create_node(); + construct_from_args( + alloc, a.node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + return a.release(); +} + +template <typename Alloc, typename U> +inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer +construct_node(Alloc& alloc, BOOST_FWD_REF(U) x) +{ + node_constructor<Alloc> a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct( + alloc, a.node_->value_ptr(), boost::forward<U>(x)); + return a.release(); +} + +// TODO: When possible, it might be better to use std::pair's +// constructor for std::piece_construct with std::tuple. +template <typename Alloc, typename Key> +inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer +construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) +{ + node_constructor<Alloc> a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->first)), + boost::forward<Key>(k)); + BOOST_TRY + { + boost::unordered::detail::func::call_construct( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->second))); + } + BOOST_CATCH(...) + { + boost::unordered::detail::func::call_destroy( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END + return a.release(); +} + +template <typename Alloc, typename Key, typename Mapped> +inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer +construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) +{ + node_constructor<Alloc> a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->first)), + boost::forward<Key>(k)); + BOOST_TRY + { + boost::unordered::detail::func::call_construct( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->second)), + boost::forward<Mapped>(m)); + } + BOOST_CATCH(...) + { + boost::unordered::detail::func::call_destroy( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END + return a.release(); +} + +template <typename Alloc, typename Key, BOOST_UNORDERED_EMPLACE_TEMPLATE> +inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer +construct_node_pair_from_args( + Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) +{ + node_constructor<Alloc> a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->first)), + boost::forward<Key>(k)); + BOOST_TRY + { + boost::unordered::detail::func::construct_from_args( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->second)), + BOOST_UNORDERED_EMPLACE_FORWARD); + } + BOOST_CATCH(...) + { + boost::unordered::detail::func::call_destroy( + alloc, boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END + return a.release(); +} +} +} +} +} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +// The 'iterator_detail' namespace was a misguided attempt at avoiding ADL +// in the detail namespace. It didn't work because the template parameters +// were in detail. I'm not changing it at the moment to be safe. I might +// do in the future if I change the iterator types. +namespace boost { +namespace unordered { +namespace iterator_detail { + +//////////////////////////////////////////////////////////////////////////// +// Iterators +// +// all no throw + +template <typename Node, typename Policy> +struct l_iterator : public std::iterator<std::forward_iterator_tag, + typename Node::value_type, std::ptrdiff_t, + typename Node::value_type*, typename Node::value_type&> +{ +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template <typename Node2, typename Policy2> + friend struct boost::unordered::iterator_detail::cl_iterator; + + private: +#endif + typedef typename Node::node_pointer node_pointer; + node_pointer ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + typedef typename Node::value_type value_type; + + l_iterator() BOOST_NOEXCEPT : ptr_() {} + + l_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT + : ptr_(n), + bucket_(b), + bucket_count_(c) + { + } + + value_type& operator*() const { return ptr_->value(); } + + value_type* operator->() const { return ptr_->value_ptr(); } + + l_iterator& operator++() + { + ptr_ = static_cast<node_pointer>(ptr_->next_); + if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_) + ptr_ = node_pointer(); + return *this; + } + + l_iterator operator++(int) + { + l_iterator tmp(*this); + ++(*this); + return tmp; + } + + bool operator==(l_iterator x) const BOOST_NOEXCEPT + { + return ptr_ == x.ptr_; + } + + bool operator!=(l_iterator x) const BOOST_NOEXCEPT + { + return ptr_ != x.ptr_; + } +}; + +template <typename Node, typename Policy> +struct cl_iterator + : public std::iterator<std::forward_iterator_tag, typename Node::value_type, + std::ptrdiff_t, typename Node::value_type const*, + typename Node::value_type const&> +{ + friend struct boost::unordered::iterator_detail::l_iterator<Node, Policy>; + + private: + typedef typename Node::node_pointer node_pointer; + node_pointer ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + typedef typename Node::value_type value_type; + + cl_iterator() BOOST_NOEXCEPT : ptr_() {} + + cl_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT + : ptr_(n), + bucket_(b), + bucket_count_(c) + { + } + + cl_iterator( + boost::unordered::iterator_detail::l_iterator<Node, Policy> const& x) + BOOST_NOEXCEPT : ptr_(x.ptr_), + bucket_(x.bucket_), + bucket_count_(x.bucket_count_) + { + } + + value_type const& operator*() const { return ptr_->value(); } + + value_type const* operator->() const { return ptr_->value_ptr(); } + + cl_iterator& operator++() + { + ptr_ = static_cast<node_pointer>(ptr_->next_); + if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_) + ptr_ = node_pointer(); + return *this; + } + + cl_iterator operator++(int) + { + cl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==( + cl_iterator const& x, cl_iterator const& y) BOOST_NOEXCEPT + { + return x.ptr_ == y.ptr_; + } + + friend bool operator!=( + cl_iterator const& x, cl_iterator const& y) BOOST_NOEXCEPT + { + return x.ptr_ != y.ptr_; + } +}; + +template <typename Node> +struct iterator : public std::iterator<std::forward_iterator_tag, + typename Node::value_type, std::ptrdiff_t, + typename Node::value_type*, typename Node::value_type&> +{ +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template <typename> + friend struct boost::unordered::iterator_detail::c_iterator; + template <typename> friend struct boost::unordered::detail::table; + template <typename> friend struct boost::unordered::detail::table_impl; + template <typename> + friend struct boost::unordered::detail::grouped_table_impl; + + private: +#endif + typedef typename Node::node_pointer node_pointer; + node_pointer node_; + + public: + typedef typename Node::value_type value_type; + + iterator() BOOST_NOEXCEPT : node_() {} + + explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT + : node_(static_cast<node_pointer>(x)) + { + } + + value_type& operator*() const { return node_->value(); } + + value_type* operator->() const { return node_->value_ptr(); } + + iterator& operator++() + { + node_ = static_cast<node_pointer>(node_->next_); + return *this; + } + + iterator operator++(int) + { + iterator tmp(node_); + node_ = static_cast<node_pointer>(node_->next_); + return tmp; + } + + bool operator==(iterator const& x) const BOOST_NOEXCEPT + { + return node_ == x.node_; + } + + bool operator!=(iterator const& x) const BOOST_NOEXCEPT + { + return node_ != x.node_; + } +}; + +template <typename Node> +struct c_iterator + : public std::iterator<std::forward_iterator_tag, typename Node::value_type, + std::ptrdiff_t, typename Node::value_type const*, + typename Node::value_type const&> +{ + friend struct boost::unordered::iterator_detail::iterator<Node>; + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template <typename> friend struct boost::unordered::detail::table; + template <typename> friend struct boost::unordered::detail::table_impl; + template <typename> + friend struct boost::unordered::detail::grouped_table_impl; + + private: +#endif + typedef typename Node::node_pointer node_pointer; + typedef boost::unordered::iterator_detail::iterator<Node> n_iterator; + node_pointer node_; + + public: + typedef typename Node::value_type value_type; + + c_iterator() BOOST_NOEXCEPT : node_() {} + + explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT + : node_(static_cast<node_pointer>(x)) + { + } + + c_iterator(n_iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} + + value_type const& operator*() const { return node_->value(); } + + value_type const* operator->() const { return node_->value_ptr(); } + + c_iterator& operator++() + { + node_ = static_cast<node_pointer>(node_->next_); + return *this; + } + + c_iterator operator++(int) + { + c_iterator tmp(node_); + node_ = static_cast<node_pointer>(node_->next_); + return tmp; + } + + friend bool operator==( + c_iterator const& x, c_iterator const& y) BOOST_NOEXCEPT + { + return x.node_ == y.node_; + } + + friend bool operator!=( + c_iterator const& x, c_iterator const& y) BOOST_NOEXCEPT + { + return x.node_ != y.node_; + } +}; +} +} +} + +namespace boost { +namespace unordered { +namespace detail { + +/////////////////////////////////////////////////////////////////// +// +// Node Holder +// +// Temporary store for nodes. Deletes any that aren't used. + +template <typename NodeAlloc> struct node_holder +{ + private: + typedef NodeAlloc node_allocator; + typedef boost::unordered::detail::allocator_traits<NodeAlloc> + node_allocator_traits; + typedef typename node_allocator_traits::value_type node; + typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node::value_type value_type; + typedef typename node::link_pointer link_pointer; + typedef boost::unordered::iterator_detail::iterator<node> iterator; + + node_constructor<NodeAlloc> constructor_; + node_pointer nodes_; + + public: + template <typename Table> + explicit node_holder(Table& b) : constructor_(b.node_alloc()), nodes_() + { + if (b.size_) { + typename Table::link_pointer prev = b.get_previous_start(); + nodes_ = static_cast<node_pointer>(prev->next_); + prev->next_ = link_pointer(); + b.size_ = 0; + } + } + + ~node_holder(); + + node_pointer pop_node() + { + node_pointer n = nodes_; + nodes_ = static_cast<node_pointer>(nodes_->next_); + n->init(n); + n->next_ = link_pointer(); + return n; + } + + template <typename T> inline node_pointer copy_of(T const& v) + { + if (nodes_) { + constructor_.reclaim(pop_node()); + } else { + constructor_.create_node(); + } + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), v); + return constructor_.release(); + } + + template <typename T> inline node_pointer move_copy_of(T& v) + { + if (nodes_) { + constructor_.reclaim(pop_node()); + } else { + constructor_.create_node(); + } + boost::unordered::detail::func::call_construct(constructor_.alloc_, + constructor_.node_->value_ptr(), boost::move(v)); + return constructor_.release(); + } + + iterator begin() const { return iterator(nodes_); } +}; + +template <typename Alloc> node_holder<Alloc>::~node_holder() +{ + while (nodes_) { + node_pointer p = nodes_; + nodes_ = static_cast<node_pointer>(p->next_); + + boost::unordered::detail::func::call_destroy( + constructor_.alloc_, p->value_ptr()); + boost::unordered::detail::func::destroy(boost::addressof(*p)); + node_allocator_traits::deallocate(constructor_.alloc_, p, 1); + } +} + +/////////////////////////////////////////////////////////////////// +// +// Bucket + +template <typename NodePointer> struct bucket +{ + typedef NodePointer link_pointer; + link_pointer next_; + + bucket() : next_() {} + + link_pointer first_from_start() { return next_; } + + enum + { + extra_node = true + }; +}; + +struct ptr_bucket +{ + typedef ptr_bucket* link_pointer; + link_pointer next_; + + ptr_bucket() : next_(0) {} + + link_pointer first_from_start() { return this; } + + enum + { + extra_node = false + }; +}; + +/////////////////////////////////////////////////////////////////// +// +// Hash Policy + +template <typename SizeT> struct prime_policy +{ + template <typename Hash, typename T> + static inline SizeT apply_hash(Hash const& hf, T const& x) + { + return hf(x); + } + + static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) + { + return hash % bucket_count; + } + + static inline SizeT new_bucket_count(SizeT min) + { + return boost::unordered::detail::next_prime(min); + } + + static inline SizeT prev_bucket_count(SizeT max) + { + return boost::unordered::detail::prev_prime(max); + } +}; + +template <typename SizeT> struct mix64_policy +{ + template <typename Hash, typename T> + static inline SizeT apply_hash(Hash const& hf, T const& x) + { + SizeT key = hf(x); + key = (~key) + (key << 21); // key = (key << 21) - key - 1; + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); // key * 265 + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); // key * 21 + key = key ^ (key >> 28); + key = key + (key << 31); + return key; + } + + static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) + { + return hash & (bucket_count - 1); + } + + static inline SizeT new_bucket_count(SizeT min) + { + if (min <= 4) + return 4; + --min; + min |= min >> 1; + min |= min >> 2; + min |= min >> 4; + min |= min >> 8; + min |= min >> 16; + min |= min >> 32; + return min + 1; + } + + static inline SizeT prev_bucket_count(SizeT max) + { + max |= max >> 1; + max |= max >> 2; + max |= max >> 4; + max |= max >> 8; + max |= max >> 16; + max |= max >> 32; + return (max >> 1) + 1; + } +}; + +template <int digits, int radix> struct pick_policy_impl +{ + typedef prime_policy<std::size_t> type; +}; + +template <> struct pick_policy_impl<64, 2> +{ + typedef mix64_policy<std::size_t> type; +}; + +template <typename T> +struct pick_policy2 : pick_policy_impl<std::numeric_limits<std::size_t>::digits, + std::numeric_limits<std::size_t>::radix> +{ +}; + +// While the mix policy is generally faster, the prime policy is a lot +// faster when a large number consecutive integers are used, because +// there are no collisions. Since that is probably quite common, use +// prime policy for integeral types. But not the smaller ones, as they +// don't have enough unique values for this to be an issue. + +template <> struct pick_policy2<int> +{ + typedef prime_policy<std::size_t> type; +}; + +template <> struct pick_policy2<unsigned int> +{ + typedef prime_policy<std::size_t> type; +}; + +template <> struct pick_policy2<long> +{ + typedef prime_policy<std::size_t> type; +}; + +template <> struct pick_policy2<unsigned long> +{ + typedef prime_policy<std::size_t> type; +}; + +// TODO: Maybe not if std::size_t is smaller than long long. +#if !defined(BOOST_NO_LONG_LONG) +template <> struct pick_policy2<boost::long_long_type> +{ + typedef prime_policy<std::size_t> type; +}; + +template <> struct pick_policy2<boost::ulong_long_type> +{ + typedef prime_policy<std::size_t> type; +}; +#endif + +template <typename T> +struct pick_policy : pick_policy2<typename boost::remove_cv<T>::type> +{ +}; + +//////////////////////////////////////////////////////////////////////////// +// Functions + +// Assigning and swapping the equality and hash function objects +// needs strong exception safety. To implement that normally we'd +// require one of them to be known to not throw and the other to +// guarantee strong exception safety. Unfortunately they both only +// have basic exception safety. So to acheive strong exception +// safety we have storage space for two copies, and assign the new +// copies to the unused space. Then switch to using that to use +// them. This is implemented in 'set_hash_functions' which +// atomically assigns the new function objects in a strongly +// exception safe manner. + +template <class H, class P, bool NoThrowMoveAssign> class set_hash_functions; + +template <class H, class P> class functions +{ + public: + static const bool nothrow_move_assignable = + boost::is_nothrow_move_assignable<H>::value && + boost::is_nothrow_move_assignable<P>::value; + static const bool nothrow_move_constructible = + boost::is_nothrow_move_constructible<H>::value && + boost::is_nothrow_move_constructible<P>::value; + + private: + friend class boost::unordered::detail::set_hash_functions<H, P, + nothrow_move_assignable>; + functions& operator=(functions const&); + + typedef compressed<H, P> function_pair; + + typedef typename boost::aligned_storage<sizeof(function_pair), + boost::alignment_of<function_pair>::value>::type aligned_function; + + bool current_; // The currently active functions. + aligned_function funcs_[2]; + + function_pair const& current() const + { + return *static_cast<function_pair const*>( + static_cast<void const*>(&funcs_[current_])); + } + + function_pair& current() + { + return *static_cast<function_pair*>( + static_cast<void*>(&funcs_[current_])); + } + + void construct(bool which, H const& hf, P const& eq) + { + new ((void*)&funcs_[which]) function_pair(hf, eq); + } + + void construct(bool which, function_pair const& f, + boost::unordered::detail::false_type = + boost::unordered::detail::false_type()) + { + new ((void*)&funcs_[which]) function_pair(f); + } + + void construct( + bool which, function_pair& f, boost::unordered::detail::true_type) + { + new ((void*)&funcs_[which]) + function_pair(f, boost::unordered::detail::move_tag()); + } + + void destroy(bool which) + { + boost::unordered::detail::func::destroy( + (function_pair*)(&funcs_[which])); + } + + public: + typedef boost::unordered::detail::set_hash_functions<H, P, + nothrow_move_assignable> + set_hash_functions; + + functions(H const& hf, P const& eq) : current_(false) + { + construct(current_, hf, eq); + } + + functions(functions const& bf) : current_(false) + { + construct(current_, bf.current()); + } + + functions(functions& bf, boost::unordered::detail::move_tag) + : current_(false) + { + construct(current_, bf.current(), + boost::unordered::detail::integral_constant<bool, + nothrow_move_constructible>()); + } + + ~functions() { this->destroy(current_); } + + H const& hash_function() const { return current().first(); } + + P const& key_eq() const { return current().second(); } +}; + +template <class H, class P> class set_hash_functions<H, P, false> +{ + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef functions<H, P> functions_type; + + functions_type& functions_; + bool tmp_functions_; + + public: + set_hash_functions(functions_type& f, H const& h, P const& p) + : functions_(f), tmp_functions_(!f.current_) + { + f.construct(tmp_functions_, h, p); + } + + set_hash_functions(functions_type& f, functions_type const& other) + : functions_(f), tmp_functions_(!f.current_) + { + f.construct(tmp_functions_, other.current()); + } + + ~set_hash_functions() { functions_.destroy(tmp_functions_); } + + void commit() + { + functions_.current_ = tmp_functions_; + tmp_functions_ = !tmp_functions_; + } +}; + +template <class H, class P> class set_hash_functions<H, P, true> +{ + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef functions<H, P> functions_type; + + functions_type& functions_; + H hash_; + P pred_; + + public: + set_hash_functions(functions_type& f, H const& h, P const& p) + : functions_(f), hash_(h), pred_(p) + { + } + + set_hash_functions(functions_type& f, functions_type const& other) + : functions_(f), hash_(other.hash_function()), pred_(other.key_eq()) + { + } + + void commit() + { + functions_.current().first() = boost::move(hash_); + functions_.current().second() = boost::move(pred_); + } +}; + +//////////////////////////////////////////////////////////////////////////// +// rvalue parameters when type can't be a BOOST_RV_REF(T) parameter +// e.g. for int + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) +#else +struct please_ignore_this_overload +{ + typedef please_ignore_this_overload type; +}; + +template <typename T> struct rv_ref_impl +{ + typedef BOOST_RV_REF(T) type; +}; + +template <typename T> +struct rv_ref + : boost::detail::if_true<boost::is_class<T>::value>::BOOST_NESTED_TEMPLATE + then<boost::unordered::detail::rv_ref_impl<T>, + please_ignore_this_overload>::type +{ +}; + +#define BOOST_UNORDERED_RV_REF(T) \ + typename boost::unordered::detail::rv_ref<T>::type +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +//////////////////////////////////////////////////////////////////////////// +// convert double to std::size_t + +inline std::size_t double_to_size(double f) +{ + return f >= static_cast<double>((std::numeric_limits<std::size_t>::max)()) + ? (std::numeric_limits<std::size_t>::max)() + : static_cast<std::size_t>(f); +} + +// The space used to store values in a node. + +template <typename ValueType> struct value_base +{ + typedef ValueType value_type; + + typename boost::aligned_storage<sizeof(value_type), + boost::alignment_of<value_type>::value>::type data_; + + value_base() : data_() {} + + void* address() { return this; } + + value_type& value() { return *(ValueType*)this; } + + value_type const& value() const { return *(ValueType const*)this; } + + value_type* value_ptr() { return (ValueType*)this; } + + value_type const* value_ptr() const { return (ValueType const*)this; } + + private: + value_base& operator=(value_base const&); +}; + +template <typename Types> +struct table : boost::unordered::detail::functions<typename Types::hasher, + typename Types::key_equal> +{ + private: + table(table const&); + table& operator=(table const&); + + public: + typedef typename Types::node node; + typedef typename Types::bucket bucket; + typedef typename Types::hasher hasher; + typedef typename Types::key_equal key_equal; + typedef typename Types::const_key_type const_key_type; + typedef typename Types::extractor extractor; + typedef typename Types::value_type value_type; + typedef typename Types::table table_impl; + typedef typename Types::link_pointer link_pointer; + typedef typename Types::policy policy; + typedef typename Types::iterator iterator; + typedef typename Types::c_iterator c_iterator; + typedef typename Types::l_iterator l_iterator; + typedef typename Types::cl_iterator cl_iterator; + typedef typename Types::node_algo node_algo; + + typedef boost::unordered::detail::functions<typename Types::hasher, + typename Types::key_equal> + functions; + typedef typename functions::set_hash_functions set_hash_functions; + + typedef typename Types::value_allocator value_allocator; + typedef typename boost::unordered::detail::rebind_wrap<value_allocator, + node>::type node_allocator; + typedef typename boost::unordered::detail::rebind_wrap<value_allocator, + bucket>::type bucket_allocator; + typedef boost::unordered::detail::allocator_traits<node_allocator> + node_allocator_traits; + typedef boost::unordered::detail::allocator_traits<bucket_allocator> + bucket_allocator_traits; + typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node_allocator_traits::const_pointer const_node_pointer; + typedef typename bucket_allocator_traits::pointer bucket_pointer; + typedef boost::unordered::detail::node_constructor<node_allocator> + node_constructor; + typedef boost::unordered::detail::node_tmp<node_allocator> node_tmp; + + //////////////////////////////////////////////////////////////////////// + // Members + + boost::unordered::detail::compressed<bucket_allocator, node_allocator> + allocators_; + std::size_t bucket_count_; + std::size_t size_; + float mlf_; + std::size_t max_load_; + bucket_pointer buckets_; + + //////////////////////////////////////////////////////////////////////// + // Data access + + bucket_allocator const& bucket_alloc() const { return allocators_.first(); } + + node_allocator const& node_alloc() const { return allocators_.second(); } + + bucket_allocator& bucket_alloc() { return allocators_.first(); } + + node_allocator& node_alloc() { return allocators_.second(); } + + std::size_t max_bucket_count() const + { + // -1 to account for the start bucket. + return policy::prev_bucket_count( + bucket_allocator_traits::max_size(bucket_alloc()) - 1); + } + + bucket_pointer get_bucket(std::size_t bucket_index) const + { + BOOST_ASSERT(buckets_); + return buckets_ + static_cast<std::ptrdiff_t>(bucket_index); + } + + link_pointer get_previous_start() const + { + return get_bucket(bucket_count_)->first_from_start(); + } + + link_pointer get_previous_start(std::size_t bucket_index) const + { + return get_bucket(bucket_index)->next_; + } + + node_pointer begin() const + { + return size_ ? node_algo::next_node(get_previous_start()) + : node_pointer(); + } + + node_pointer begin(std::size_t bucket_index) const + { + if (!size_) + return node_pointer(); + link_pointer prev = get_previous_start(bucket_index); + return prev ? node_algo::next_node(prev) : node_pointer(); + } + + std::size_t hash_to_bucket(std::size_t hash_value) const + { + return policy::to_bucket(bucket_count_, hash_value); + } + + float load_factor() const + { + BOOST_ASSERT(bucket_count_ != 0); + return static_cast<float>(size_) / static_cast<float>(bucket_count_); + } + + std::size_t bucket_size(std::size_t index) const + { + node_pointer n = begin(index); + if (!n) + return 0; + + std::size_t count = 0; + while (n && hash_to_bucket(n->hash_) == index) { + ++count; + n = node_algo::next_node(n); + } + + return count; + } + + //////////////////////////////////////////////////////////////////////// + // Load methods + + std::size_t max_size() const + { + using namespace std; + + // size < mlf_ * count + return boost::unordered::detail::double_to_size( + ceil(static_cast<double>(mlf_) * + static_cast<double>(max_bucket_count()))) - + 1; + } + + void recalculate_max_load() + { + using namespace std; + + // From 6.3.1/13: + // Only resize when size >= mlf_ * count + max_load_ = buckets_ ? boost::unordered::detail::double_to_size( + ceil(static_cast<double>(mlf_) * + static_cast<double>(bucket_count_))) + : 0; + } + + void max_load_factor(float z) + { + BOOST_ASSERT(z > 0); + mlf_ = (std::max)(z, minimum_max_load_factor); + recalculate_max_load(); + } + + std::size_t min_buckets_for_size(std::size_t size) const + { + BOOST_ASSERT(mlf_ >= minimum_max_load_factor); + + using namespace std; + + // From insert/emplace requirements: + // + // size <= mlf_ * count + // => count >= size / mlf_ + // + // Or from rehash post-condition: + // + // count >= size / mlf_ + + return policy::new_bucket_count( + boost::unordered::detail::double_to_size( + floor(static_cast<double>(size) / static_cast<double>(mlf_)) + + 1)); + } + + //////////////////////////////////////////////////////////////////////// + // Constructors + + table(std::size_t num_buckets, hasher const& hf, key_equal const& eq, + node_allocator const& a) + : functions(hf, eq), allocators_(a, a), + bucket_count_(policy::new_bucket_count(num_buckets)), size_(0), + mlf_(1.0f), max_load_(0), buckets_() + { + } + + table(table const& x, node_allocator const& a) + : functions(x), allocators_(a, a), + bucket_count_(x.min_buckets_for_size(x.size_)), size_(0), + mlf_(x.mlf_), max_load_(0), buckets_() + { + } + + table(table& x, boost::unordered::detail::move_tag m) + : functions(x, m), allocators_(x.allocators_, m), + bucket_count_(x.bucket_count_), size_(x.size_), mlf_(x.mlf_), + max_load_(x.max_load_), buckets_(x.buckets_) + { + x.buckets_ = bucket_pointer(); + x.size_ = 0; + x.max_load_ = 0; + } + + table( + table& x, node_allocator const& a, boost::unordered::detail::move_tag m) + : functions(x, m), allocators_(a, a), bucket_count_(x.bucket_count_), + size_(0), mlf_(x.mlf_), max_load_(x.max_load_), buckets_() + { + } + + //////////////////////////////////////////////////////////////////////// + // Initialisation. + + void init(table const& x) + { + if (x.size_) { + static_cast<table_impl*>(this)->copy_buckets(x); + } + } + + void move_init(table& x) + { + if (node_alloc() == x.node_alloc()) { + move_buckets_from(x); + } else if (x.size_) { + // TODO: Could pick new bucket size? + static_cast<table_impl*>(this)->move_buckets(x); + } + } + + //////////////////////////////////////////////////////////////////////// + // Create buckets + + void create_buckets(std::size_t new_count) + { + std::size_t length = new_count + 1; + bucket_pointer new_buckets = + bucket_allocator_traits::allocate(bucket_alloc(), length); + bucket_pointer constructed = new_buckets; + + BOOST_TRY + { + bucket_pointer end = + new_buckets + static_cast<std::ptrdiff_t>(length); + for (; constructed != end; ++constructed) { + new ((void*)boost::addressof(*constructed)) bucket(); + } + + if (buckets_) { + // Copy the nodes to the new buckets, including the dummy + // node if there is one. + (new_buckets + static_cast<std::ptrdiff_t>(new_count))->next_ = + (buckets_ + static_cast<std::ptrdiff_t>(bucket_count_)) + ->next_; + destroy_buckets(); + } else if (bucket::extra_node) { + node_constructor a(node_alloc()); + a.create_node(); + + (new_buckets + static_cast<std::ptrdiff_t>(new_count))->next_ = + a.release(); + } + } + BOOST_CATCH(...) + { + for (bucket_pointer p = new_buckets; p != constructed; ++p) { + boost::unordered::detail::func::destroy(boost::addressof(*p)); + } + + bucket_allocator_traits::deallocate( + bucket_alloc(), new_buckets, length); + + BOOST_RETHROW; + } + BOOST_CATCH_END + + bucket_count_ = new_count; + buckets_ = new_buckets; + recalculate_max_load(); + } + + //////////////////////////////////////////////////////////////////////// + // Swap and Move + + void swap_allocators(table& other, false_type) + { + boost::unordered::detail::func::ignore_unused_variable_warning(other); + + // According to 23.2.1.8, if propagate_on_container_swap is + // false the behaviour is undefined unless the allocators + // are equal. + BOOST_ASSERT(node_alloc() == other.node_alloc()); + } + + void swap_allocators(table& other, true_type) + { + allocators_.swap(other.allocators_); + } + + // Only swaps the allocators if propagate_on_container_swap + void swap(table& x) + { + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); + + // I think swap can throw if Propagate::value, + // since the allocators' swap can throw. Not sure though. + swap_allocators(x, boost::unordered::detail::integral_constant<bool, + allocator_traits<node_allocator>:: + propagate_on_container_swap::value>()); + + boost::swap(buckets_, x.buckets_); + boost::swap(bucket_count_, x.bucket_count_); + boost::swap(size_, x.size_); + std::swap(mlf_, x.mlf_); + std::swap(max_load_, x.max_load_); + op1.commit(); + op2.commit(); + } + + // Only call with nodes allocated with the currect allocator, or + // one that is equal to it. (Can't assert because other's + // allocators might have already been moved). + void move_buckets_from(table& other) + { + BOOST_ASSERT(!buckets_); + buckets_ = other.buckets_; + bucket_count_ = other.bucket_count_; + size_ = other.size_; + other.buckets_ = bucket_pointer(); + other.size_ = 0; + other.max_load_ = 0; + } + + //////////////////////////////////////////////////////////////////////// + // Delete/destruct + + ~table() { delete_buckets(); } + + void delete_node(link_pointer prev) + { + node_pointer n = static_cast<node_pointer>(prev->next_); + prev->next_ = n->next_; + + boost::unordered::detail::func::call_destroy( + node_alloc(), n->value_ptr()); + boost::unordered::detail::func::destroy(boost::addressof(*n)); + node_allocator_traits::deallocate(node_alloc(), n, 1); + --size_; + } + + std::size_t delete_nodes(link_pointer prev, link_pointer end) + { + BOOST_ASSERT(prev->next_ != end); + + std::size_t count = 0; + + do { + delete_node(prev); + ++count; + } while (prev->next_ != end); + + return count; + } + + void delete_buckets() + { + if (buckets_) { + if (size_) + delete_nodes(get_previous_start(), link_pointer()); + + if (bucket::extra_node) { + node_pointer n = + static_cast<node_pointer>(get_bucket(bucket_count_)->next_); + boost::unordered::detail::func::destroy(boost::addressof(*n)); + node_allocator_traits::deallocate(node_alloc(), n, 1); + } + + destroy_buckets(); + buckets_ = bucket_pointer(); + max_load_ = 0; + } + + BOOST_ASSERT(!size_); + } + + void clear() + { + if (!size_) + return; + + delete_nodes(get_previous_start(), link_pointer()); + clear_buckets(); + + BOOST_ASSERT(!size_); + } + + void clear_buckets() + { + bucket_pointer end = get_bucket(bucket_count_); + for (bucket_pointer it = buckets_; it != end; ++it) { + it->next_ = node_pointer(); + } + } + + void destroy_buckets() + { + bucket_pointer end = get_bucket(bucket_count_ + 1); + for (bucket_pointer it = buckets_; it != end; ++it) { + boost::unordered::detail::func::destroy(boost::addressof(*it)); + } + + bucket_allocator_traits::deallocate( + bucket_alloc(), buckets_, bucket_count_ + 1); + } + + //////////////////////////////////////////////////////////////////////// + // Fix buckets after delete + // + + std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev) + { + link_pointer end = prev->next_; + std::size_t bucket_index2 = bucket_index; + + if (end) { + bucket_index2 = + hash_to_bucket(static_cast<node_pointer>(end)->hash_); + + // If begin and end are in the same bucket, then + // there's nothing to do. + if (bucket_index == bucket_index2) + return bucket_index2; + + // Update the bucket containing end. + get_bucket(bucket_index2)->next_ = prev; + } + + // Check if this bucket is now empty. + bucket_pointer this_bucket = get_bucket(bucket_index); + if (this_bucket->next_ == prev) + this_bucket->next_ = link_pointer(); + + return bucket_index2; + } + + //////////////////////////////////////////////////////////////////////// + // Assignment + + void assign(table const& x) + { + if (this != boost::addressof(x)) { + assign(x, boost::unordered::detail::integral_constant<bool, + allocator_traits<node_allocator>:: + propagate_on_container_copy_assignment::value>()); + } + } + + void assign(table const& x, false_type) + { + // Strong exception safety. + set_hash_functions new_func_this(*this, x); + mlf_ = x.mlf_; + recalculate_max_load(); + + if (!size_ && !x.size_) { + new_func_this.commit(); + return; + } + + if (x.size_ >= max_load_) { + create_buckets(min_buckets_for_size(x.size_)); + } else { + clear_buckets(); + } + + new_func_this.commit(); + static_cast<table_impl*>(this)->assign_buckets(x); + } + + void assign(table const& x, true_type) + { + if (node_alloc() == x.node_alloc()) { + allocators_.assign(x.allocators_); + assign(x, false_type()); + } else { + set_hash_functions new_func_this(*this, x); + + // Delete everything with current allocators before assigning + // the new ones. + delete_buckets(); + allocators_.assign(x.allocators_); + + // Copy over other data, all no throw. + new_func_this.commit(); + mlf_ = x.mlf_; + bucket_count_ = min_buckets_for_size(x.size_); + max_load_ = 0; + + // Finally copy the elements. + if (x.size_) { + static_cast<table_impl*>(this)->copy_buckets(x); + } + } + } + + void move_assign(table& x) + { + if (this != boost::addressof(x)) { + move_assign( + x, boost::unordered::detail::integral_constant<bool, + allocator_traits<node_allocator>:: + propagate_on_container_move_assignment::value>()); + } + } + + void move_assign(table& x, true_type) + { + delete_buckets(); + set_hash_functions new_func_this(*this, x); + allocators_.move_assign(x.allocators_); + // No throw from here. + mlf_ = x.mlf_; + max_load_ = x.max_load_; + move_buckets_from(x); + new_func_this.commit(); + } + + void move_assign(table& x, false_type) + { + if (node_alloc() == x.node_alloc()) { + delete_buckets(); + set_hash_functions new_func_this(*this, x); + // No throw from here. + mlf_ = x.mlf_; + max_load_ = x.max_load_; + move_buckets_from(x); + new_func_this.commit(); + } else { + set_hash_functions new_func_this(*this, x); + mlf_ = x.mlf_; + recalculate_max_load(); + + if (!size_ && !x.size_) { + new_func_this.commit(); + return; + } + + if (x.size_ >= max_load_) { + create_buckets(min_buckets_for_size(x.size_)); + } else { + clear_buckets(); + } + + new_func_this.commit(); + static_cast<table_impl*>(this)->move_assign_buckets(x); + } + } + + // Accessors + + const_key_type& get_key(value_type const& x) const + { + return extractor::extract(x); + } + + std::size_t hash(const_key_type& k) const + { + return policy::apply_hash(this->hash_function(), k); + } + + // Find Node + + template <typename Key, typename Hash, typename Pred> + node_pointer generic_find_node( + Key const& k, Hash const& hf, Pred const& eq) const + { + return this->find_node_impl(policy::apply_hash(hf, k), k, eq); + } + + node_pointer find_node(std::size_t key_hash, const_key_type& k) const + { + return this->find_node_impl(key_hash, k, this->key_eq()); + } + + node_pointer find_node(const_key_type& k) const + { + return this->find_node_impl(hash(k), k, this->key_eq()); + } + + template <class Key, class Pred> + node_pointer find_node_impl( + std::size_t key_hash, Key const& k, Pred const& eq) const + { + std::size_t bucket_index = this->hash_to_bucket(key_hash); + node_pointer n = this->begin(bucket_index); + + for (;;) { + if (!n) + return n; + + std::size_t node_hash = n->hash_; + if (key_hash == node_hash) { + if (eq(k, this->get_key(n->value()))) + return n; + } else { + if (this->hash_to_bucket(node_hash) != bucket_index) + return node_pointer(); + } + + n = node_algo::next_for_find(n); + } + } + + // Find the node before the key, so that it can be erased. + link_pointer find_previous_node( + const_key_type& k, std::size_t key_hash, std::size_t bucket_index) + { + link_pointer prev = this->get_previous_start(bucket_index); + if (!prev) { + return prev; + } + + for (;;) { + if (!prev->next_) { + return link_pointer(); + } + std::size_t node_hash = node_algo::next_node(prev)->hash_; + if (this->hash_to_bucket(node_hash) != bucket_index) { + return link_pointer(); + } + if (node_hash == key_hash && + this->key_eq()( + k, this->get_key(node_algo::next_node(prev)->value()))) { + return prev; + } + prev = node_algo::next_for_erase(prev); + } + } + + // Extract and erase + + inline node_pointer extract_by_key(const_key_type& k) + { + if (!this->size_) { + return node_pointer(); + } + std::size_t key_hash = this->hash(k); + std::size_t bucket_index = this->hash_to_bucket(key_hash); + link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + if (!prev) { + return node_pointer(); + } + node_pointer n = node_algo::extract_first_node(prev); + --this->size_; + this->fix_bucket(bucket_index, prev); + n->next_ = link_pointer(); + + return n; + } + + // Reserve and rehash + + void reserve_for_insert(std::size_t); + void rehash(std::size_t); + void reserve(std::size_t); + void rehash_impl(std::size_t); +}; + +//////////////////////////////////////////////////////////////////////////// +// Reserve & Rehash + +// basic exception safety +template <typename Types> +inline void table<Types>::reserve_for_insert(std::size_t size) +{ + if (!buckets_) { + create_buckets((std::max)(bucket_count_, min_buckets_for_size(size))); + } else if (size > max_load_) { + std::size_t num_buckets = + min_buckets_for_size((std::max)(size, size_ + (size_ >> 1))); + + if (num_buckets != bucket_count_) + this->rehash_impl(num_buckets); + } +} + +// if hash function throws, basic exception safety +// strong otherwise. + +template <typename Types> +inline void table<Types>::rehash(std::size_t min_buckets) +{ + using namespace std; + + if (!size_) { + delete_buckets(); + bucket_count_ = policy::new_bucket_count(min_buckets); + } else { + min_buckets = policy::new_bucket_count((std::max)(min_buckets, + boost::unordered::detail::double_to_size( + floor(static_cast<double>(size_) / static_cast<double>(mlf_))) + + 1)); + + if (min_buckets != bucket_count_) + this->rehash_impl(min_buckets); + } +} + +template <typename Types> +inline void table<Types>::reserve(std::size_t num_elements) +{ + rehash(static_cast<std::size_t>( + std::ceil(static_cast<double>(num_elements) / mlf_))); +} + +template <typename Types> +inline void table<Types>::rehash_impl(std::size_t num_buckets) +{ + BOOST_ASSERT(this->buckets_); + + this->create_buckets(num_buckets); + link_pointer prev = this->get_previous_start(); + while (prev->next_) { + node_pointer group_last = node_algo::last_for_rehash(prev); + bucket_pointer b = + this->get_bucket(this->hash_to_bucket(group_last->hash_)); + if (!b->next_) { + b->next_ = prev; + prev = group_last; + } else { + link_pointer next = group_last->next_; + group_last->next_ = b->next_->next_; + b->next_->next_ = prev->next_; + prev->next_ = next; + } + } +} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +//////////////////////////////////////////////////////////////////////// +// key extractors +// +// no throw +// +// 'extract_key' is called with the emplace parameters to return a +// key if available or 'no_key' is one isn't and will need to be +// constructed. This could be done by overloading the emplace implementation +// for the different cases, but that's a bit tricky on compilers without +// variadic templates. + +struct no_key +{ + no_key() {} + template <class T> no_key(T const&) {} +}; + +template <typename Key, typename T> struct is_key +{ + template <typename T2> static choice1::type test(T2 const&); + static choice2::type test(Key const&); + + enum + { + value = sizeof(test(boost::unordered::detail::make<T>())) == + sizeof(choice2::type) + }; + + typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE + then<Key const&, no_key>::type type; +}; + +template <class ValueType> struct set_extractor +{ + typedef ValueType value_type; + typedef ValueType key_type; + + static key_type const& extract(value_type const& v) { return v; } + + static no_key extract() { return no_key(); } + + template <class Arg> static no_key extract(Arg const&) { return no_key(); } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class Arg1, class Arg2, class... Args> + static no_key extract(Arg1 const&, Arg2 const&, Args const&...) + { + return no_key(); + } +#else + template <class Arg1, class Arg2> + static no_key extract(Arg1 const&, Arg2 const&) + { + return no_key(); + } +#endif +}; + +template <class ValueType> struct map_extractor +{ + typedef ValueType value_type; + typedef typename boost::remove_const<typename boost::unordered::detail:: + pair_traits<ValueType>::first_type>::type key_type; + + static key_type const& extract(value_type const& v) { return v.first; } + + template <class Second> + static key_type const& extract(std::pair<key_type, Second> const& v) + { + return v.first; + } + + template <class Second> + static key_type const& extract(std::pair<key_type const, Second> const& v) + { + return v.first; + } + + template <class Arg1> + static key_type const& extract(key_type const& k, Arg1 const&) + { + return k; + } + + static no_key extract() { return no_key(); } + + template <class Arg> static no_key extract(Arg const&) { return no_key(); } + + template <class Arg1, class Arg2> + static no_key extract(Arg1 const&, Arg2 const&) + { + return no_key(); + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class Arg1, class Arg2, class Arg3, class... Args> + static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&, Args const&...) + { + return no_key(); + } +#endif + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ + template <typename T2> \ + static no_key extract(boost::unordered::piecewise_construct_t, \ + namespace_ tuple<> const&, T2 const&) \ + { \ + return no_key(); \ + } \ + \ + template <typename T, typename T2> \ + static typename is_key<key_type, T>::type extract( \ + boost::unordered::piecewise_construct_t, namespace_ tuple<T> const& k, \ + T2 const&) \ + { \ + return typename is_key<key_type, T>::type(namespace_ get<0>(k)); \ + } + +#else + +#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ + static no_key extract( \ + boost::unordered::piecewise_construct_t, namespace_ tuple<> const&) \ + { \ + return no_key(); \ + } \ + \ + template <typename T> \ + static typename is_key<key_type, T>::type extract( \ + boost::unordered::piecewise_construct_t, namespace_ tuple<T> const& k) \ + { \ + return typename is_key<key_type, T>::type(namespace_ get<0>(k)); \ + } + +#endif + + BOOST_UNORDERED_KEY_FROM_TUPLE(boost::) + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) + BOOST_UNORDERED_KEY_FROM_TUPLE(std::) +#endif +}; + +//////////////////////////////////////////////////////////////////////// +// Unique nodes + +template <typename A, typename T> +struct unique_node : boost::unordered::detail::value_base<T> +{ + typedef typename ::boost::unordered::detail::rebind_wrap<A, + unique_node<A, T> >::type allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + allocator>::pointer node_pointer; + typedef node_pointer link_pointer; + typedef typename ::boost::unordered::detail::rebind_wrap<A, + bucket<node_pointer> >::type bucket_allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + bucket_allocator>::pointer bucket_pointer; + + link_pointer next_; + std::size_t hash_; + + unique_node() : next_(), hash_(0) {} + + void init(node_pointer) {} + + private: + unique_node& operator=(unique_node const&); +}; + +template <typename T> struct ptr_node : boost::unordered::detail::ptr_bucket +{ + typedef T value_type; + typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef ptr_node<T>* node_pointer; + typedef ptr_bucket* link_pointer; + typedef ptr_bucket* bucket_pointer; + + std::size_t hash_; + boost::unordered::detail::value_base<T> value_base_; + + ptr_node() : bucket_base(), hash_(0) {} + + void init(node_pointer) {} + + void* address() { return value_base_.address(); } + value_type& value() { return value_base_.value(); } + value_type* value_ptr() { return value_base_.value_ptr(); } + + private: + ptr_node& operator=(ptr_node const&); +}; + +template <typename N> struct node_algo +{ + typedef typename N::node_pointer node_pointer; + typedef typename N::link_pointer link_pointer; + typedef typename N::bucket_pointer bucket_pointer; + + static node_pointer next_node(link_pointer n) + { + return static_cast<node_pointer>(n->next_); + } + + static node_pointer next_for_find(node_pointer n) + { + return static_cast<node_pointer>(n->next_); + } + + static link_pointer next_for_erase(link_pointer prev) + { + return prev->next_; + } + + // Group together all nodes with equal hash value, this may + // include nodes with different keys, but that's okay because + // they will end up in the same bucket. + static node_pointer last_for_rehash(link_pointer prev) + { + node_pointer n = next_node(prev); + std::size_t hash = n->hash_; + for (;;) { + node_pointer next = next_node(n); + if (!next || next->hash_ != hash) { + return n; + } + n = next; + } + } + + template <typename Table> + static node_pointer next_group(node_pointer n, Table const* t) + { + node_pointer n1 = n; + do { + n1 = next_node(n1); + } while ( + n1 && t->key_eq()(t->get_key(n->value()), t->get_key(n1->value()))); + return n1; + } + + template <typename Table> + static std::size_t count(node_pointer n, Table const* t) + { + std::size_t x = 0; + node_pointer it = n; + do { + ++x; + it = next_node(it); + } while ( + it && t->key_eq()(t->get_key(n->value()), t->get_key(it->value()))); + + return x; + } + + // Add node 'n' after 'pos'. + // This results in a different order to the grouped implementation. + static inline void add_to_node_group(node_pointer n, node_pointer pos) + { + n->next_ = pos->next_; + pos->next_ = n; + } + + static inline node_pointer extract_first_node(link_pointer prev) + { + node_pointer n = next_node(prev); + prev->next_ = n->next_; + return n; + } + + static link_pointer split_groups(node_pointer, node_pointer) + { + return link_pointer(); + } +}; + +// If the allocator uses raw pointers use ptr_node +// Otherwise use node. + +template <typename A, typename T, typename NodePtr, typename BucketPtr> +struct pick_node2 +{ + typedef boost::unordered::detail::unique_node<A, T> node; + + typedef typename boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap<A, node>::type>::pointer + node_pointer; + + typedef boost::unordered::detail::bucket<node_pointer> bucket; + typedef node_pointer link_pointer; +}; + +template <typename A, typename T> +struct pick_node2<A, T, boost::unordered::detail::ptr_node<T>*, + boost::unordered::detail::ptr_bucket*> +{ + typedef boost::unordered::detail::ptr_node<T> node; + typedef boost::unordered::detail::ptr_bucket bucket; + typedef bucket* link_pointer; +}; + +template <typename A, typename T> struct pick_node +{ + typedef typename boost::remove_const<T>::type nonconst; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap<A, + boost::unordered::detail::ptr_node<nonconst> >::type> + tentative_node_traits; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap<A, + boost::unordered::detail::ptr_bucket>::type> + tentative_bucket_traits; + + typedef pick_node2<A, nonconst, typename tentative_node_traits::pointer, + typename tentative_bucket_traits::pointer> + pick; + + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + typedef boost::unordered::detail::node_algo<node> node_algo; +}; + +template <typename Types> +struct table_impl : boost::unordered::detail::table<Types> +{ + typedef boost::unordered::detail::table<Types> table; + typedef typename table::value_type value_type; + typedef typename table::node node; + typedef typename table::bucket bucket; + typedef typename table::policy policy; + typedef typename table::node_pointer node_pointer; + typedef typename table::node_allocator node_allocator; + typedef typename table::node_allocator_traits node_allocator_traits; + typedef typename table::bucket_pointer bucket_pointer; + typedef typename table::link_pointer link_pointer; + typedef typename table::hasher hasher; + typedef typename table::key_equal key_equal; + typedef typename table::const_key_type const_key_type; + typedef typename table::node_constructor node_constructor; + typedef typename table::node_tmp node_tmp; + typedef typename table::extractor extractor; + typedef typename table::iterator iterator; + typedef typename table::c_iterator c_iterator; + typedef typename table::node_algo node_algo; + + typedef std::pair<iterator, bool> emplace_return; + + // Constructors + + table_impl(std::size_t n, hasher const& hf, key_equal const& eq, + node_allocator const& a) + : table(n, hf, eq, a) + { + } + + table_impl(table_impl const& x) + : table(x, node_allocator_traits::select_on_container_copy_construction( + x.node_alloc())) + { + this->init(x); + } + + table_impl(table_impl const& x, node_allocator const& a) : table(x, a) + { + this->init(x); + } + + table_impl(table_impl& x, boost::unordered::detail::move_tag m) + : table(x, m) + { + } + + table_impl(table_impl& x, node_allocator const& a, + boost::unordered::detail::move_tag m) + : table(x, a, m) + { + this->move_init(x); + } + + // Accessors + + std::size_t count(const_key_type& k) const + { + return this->find_node(k) ? 1 : 0; + } + + value_type& at(const_key_type& k) const + { + if (this->size_) { + node_pointer n = this->find_node(k); + if (n) + return n->value(); + } + + boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); + } + + std::pair<iterator, iterator> equal_range(const_key_type& k) const + { + node_pointer n = this->find_node(k); + return std::make_pair( + iterator(n), iterator(n ? node_algo::next_node(n) : n)); + } + + // equals + + bool equals(table_impl const& other) const + { + if (this->size_ != other.size_) + return false; + + for (node_pointer n1 = this->begin(); n1; + n1 = node_algo::next_node(n1)) { + node_pointer n2 = other.find_node(other.get_key(n1->value())); + + if (!n2 || n1->value() != n2->value()) + return false; + } + + return true; + } + + // Emplace/Insert + + inline node_pointer add_node(node_pointer n, std::size_t key_hash) + { + n->hash_ = key_hash; + + bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); + + if (!b->next_) { + link_pointer start_node = this->get_previous_start(); + + if (start_node->next_) { + this->get_bucket(this->hash_to_bucket( + node_algo::next_node(start_node)->hash_)) + ->next_ = n; + } + + b->next_ = start_node; + n->next_ = start_node->next_; + start_node->next_ = n; + } else { + n->next_ = b->next_->next_; + b->next_->next_ = n; + } + + ++this->size_; + return n; + } + + inline node_pointer resize_and_add_node( + node_pointer n, std::size_t key_hash) + { + node_tmp b(n, this->node_alloc()); + this->reserve_for_insert(this->size_ + 1); + return this->add_node(b.release(), key_hash); + } + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + emplace_return emplace(boost::unordered::detail::emplace_args1< + boost::unordered::detail::please_ignore_this_overload> const&) + { + BOOST_ASSERT(false); + return emplace_return(iterator(), false); + } + + iterator emplace_hint( + c_iterator, + boost::unordered::detail::emplace_args1< + boost::unordered::detail::please_ignore_this_overload> const&) + { + BOOST_ASSERT(false); + return iterator(); + } +#else + emplace_return emplace( + boost::unordered::detail::please_ignore_this_overload const&) + { + BOOST_ASSERT(false); + return emplace_return(iterator(), false); + } + + iterator emplace_hint(c_iterator, + boost::unordered::detail::please_ignore_this_overload const&) + { + BOOST_ASSERT(false); + return iterator(); + } +#endif +#endif + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS) + { +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + return emplace_impl(extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), + BOOST_UNORDERED_EMPLACE_FORWARD); +#else + return emplace_impl(extractor::extract(args.a0, args.a1), + BOOST_UNORDERED_EMPLACE_FORWARD); +#endif + } + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS) + { +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + return emplace_hint_impl(hint, + extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), + BOOST_UNORDERED_EMPLACE_FORWARD); +#else + return emplace_hint_impl(hint, extractor::extract(args.a0, args.a1), + BOOST_UNORDERED_EMPLACE_FORWARD); +#endif + } + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <typename A0> + emplace_return emplace( + boost::unordered::detail::emplace_args1<A0> const& args) + { + return emplace_impl(extractor::extract(args.a0), args); + } + + template <typename A0> + iterator emplace_hint(c_iterator hint, + boost::unordered::detail::emplace_args1<A0> const& args) + { + return emplace_hint_impl(hint, extractor::extract(args.a0), args); + } +#endif + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + iterator emplace_hint_impl( + c_iterator hint, const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) + { + if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + return iterator(hint.node_); + } else { + return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; + } + } + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + emplace_return emplace_impl(const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) + { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node( + boost::unordered::detail::func::construct_node_from_args( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + key_hash)), + true); + } + } + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + iterator emplace_hint_impl( + c_iterator hint, no_key, BOOST_UNORDERED_EMPLACE_ARGS) + { + node_tmp b(boost::unordered::detail::func::construct_node_from_args( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); + const_key_type& k = this->get_key(b.node_->value()); + if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + return iterator(hint.node_); + } + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return iterator(pos); + } else { + return iterator(this->resize_and_add_node(b.release(), key_hash)); + } + } + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) + { + node_tmp b(boost::unordered::detail::func::construct_node_from_args( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); + const_key_type& k = this->get_key(b.node_->value()); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node(b.release(), key_hash)), + true); + } + } + + template <typename Key> + emplace_return try_emplace_impl(BOOST_FWD_REF(Key) k) + { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node( + boost::unordered::detail::func::construct_node_pair( + this->node_alloc(), boost::forward<Key>(k)), + key_hash)), + true); + } + } + + template <typename Key> + iterator try_emplace_hint_impl(c_iterator hint, BOOST_FWD_REF(Key) k) + { + if (hint.node_ && this->key_eq()(hint->first, k)) { + return iterator(hint.node_); + } else { + return try_emplace_impl(k).first; + } + } + + template <typename Key, BOOST_UNORDERED_EMPLACE_TEMPLATE> + emplace_return try_emplace_impl( + BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) + { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node( + boost::unordered::detail::func:: + construct_node_pair_from_args(this->node_alloc(), + boost::forward<Key>(k), + BOOST_UNORDERED_EMPLACE_FORWARD), + key_hash)), + true); + } + } + + template <typename Key, BOOST_UNORDERED_EMPLACE_TEMPLATE> + iterator try_emplace_hint_impl( + c_iterator hint, BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) + { + if (hint.node_ && this->key_eq()(hint->first, k)) { + return iterator(hint.node_); + } else { + return try_emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; + } + } + + template <typename Key, typename M> + emplace_return insert_or_assign_impl( + BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) + { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (pos) { + pos->value().second = boost::forward<M>(obj); + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node( + boost::unordered::detail::func::construct_node_pair( + this->node_alloc(), boost::forward<Key>(k), + boost::forward<M>(obj)), + key_hash)), + true); + } + } + + template <typename NodeType, typename InsertReturnType> + void move_insert_node_type(NodeType& np, InsertReturnType& result) + { + if (np) { + const_key_type& k = this->get_key(np.ptr_->value()); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (pos) { + result.node = boost::move(np); + result.position = iterator(pos); + } else { + this->reserve_for_insert(this->size_ + 1); + result.position = iterator(this->add_node(np.ptr_, key_hash)); + result.inserted = true; + np.ptr_ = node_pointer(); + } + } + } + + template <typename NodeType> + iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np) + { + if (!np) { + return iterator(); + } + const_key_type& k = this->get_key(np.ptr_->value()); + if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + return iterator(hint.node_); + } + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (!pos) { + this->reserve_for_insert(this->size_ + 1); + pos = this->add_node(np.ptr_, key_hash); + np.ptr_ = node_pointer(); + } + return iterator(pos); + } + + template <typename Types2> + void merge_impl(boost::unordered::detail::table<Types2>& other) + { + typedef boost::unordered::detail::table<Types2> other_table; + BOOST_STATIC_ASSERT( + (boost::is_same<node, typename other_table::node>::value)); + BOOST_ASSERT(this->node_alloc() == other.node_alloc()); + + if (other.size_) { + link_pointer prev = other.get_previous_start(); + + while (prev->next_) { + node_pointer n = other_table::node_algo::next_node(prev); + const_key_type& k = this->get_key(n->value()); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (pos) { + prev = n; + } else { + this->reserve_for_insert(this->size_ + 1); + other_table::node_algo::split_groups( + n, other_table::node_algo::next_node(n)); + prev->next_ = n->next_; + --other.size_; + other.fix_bucket(other.hash_to_bucket(n->hash_), prev); + this->add_node(n, key_hash); + } + } + } + } + + //////////////////////////////////////////////////////////////////////// + // Insert range methods + // + // if hash function throws, or inserting > 1 element, basic exception + // safety strong otherwise + + template <class InputIt> void insert_range(InputIt i, InputIt j) + { + if (i != j) + return insert_range_impl(extractor::extract(*i), i, j); + } + + template <class InputIt> + void insert_range_impl(const_key_type& k, InputIt i, InputIt j) + { + insert_range_impl2(k, i, j); + + while (++i != j) { + // Note: can't use get_key as '*i' might not be value_type - it + // could be a pair with first_types as key_type without const or + // a different second_type. + // + // TODO: Might be worth storing the value_type instead of the + // key here. Could be more efficient if '*i' is expensive. Could + // be less efficient if copying the full value_type is + // expensive. + insert_range_impl2(extractor::extract(*i), i, j); + } + } + + template <class InputIt> + void insert_range_impl2(const_key_type& k, InputIt i, InputIt j) + { + // No side effects in this initial code + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (!pos) { + node_tmp b(boost::unordered::detail::func::construct_node( + this->node_alloc(), *i), + this->node_alloc()); + if (this->size_ + 1 > this->max_load_) + this->reserve_for_insert( + this->size_ + boost::unordered::detail::insert_size(i, j)); + this->add_node(b.release(), key_hash); + } + } + + template <class InputIt> + void insert_range_impl(no_key, InputIt i, InputIt j) + { + node_constructor a(this->node_alloc()); + + do { + if (!a.node_) { + a.create_node(); + } + boost::unordered::detail::func::call_construct( + a.alloc_, a.node_->value_ptr(), *i); + node_tmp b(a.release(), a.alloc_); + + const_key_type& k = this->get_key(b.node_->value()); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (pos) { + a.reclaim(b.release()); + } else { + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + this->reserve_for_insert(this->size_ + 1); + this->add_node(b.release(), key_hash); + } + } while (++i != j); + } + + //////////////////////////////////////////////////////////////////////// + // Extract + + inline node_pointer extract_by_iterator(c_iterator i) + { + node_pointer n = i.node_; + BOOST_ASSERT(n); + std::size_t key_hash = n->hash_; + std::size_t bucket_index = this->hash_to_bucket(key_hash); + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != n) { + prev = prev->next_; + } + prev->next_ = n->next_; + --this->size_; + this->fix_bucket(bucket_index, prev); + n->next_ = link_pointer(); + return n; + } + + //////////////////////////////////////////////////////////////////////// + // Erase + // + // no throw + + std::size_t erase_key(const_key_type& k) + { + if (!this->size_) + return 0; + std::size_t key_hash = this->hash(k); + std::size_t bucket_index = this->hash_to_bucket(key_hash); + link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + if (!prev) + return 0; + link_pointer end = node_algo::next_node(prev)->next_; + this->delete_nodes(prev, end); + this->fix_bucket(bucket_index, prev); + return 1; + } + + iterator erase(c_iterator r) + { + BOOST_ASSERT(r.node_); + node_pointer next = node_algo::next_node(r.node_); + erase_nodes(r.node_, next); + return iterator(next); + } + + iterator erase_range(c_iterator r1, c_iterator r2) + { + if (r1 == r2) + return iterator(r2.node_); + erase_nodes(r1.node_, r2.node_); + return iterator(r2.node_); + } + + void erase_nodes(node_pointer i, node_pointer j) + { + std::size_t bucket_index = this->hash_to_bucket(i->hash_); + + // Find the node before i. + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) + prev = prev->next_; + + // Delete the nodes. + do { + this->delete_node(prev); + bucket_index = this->fix_bucket(bucket_index, prev); + } while (prev->next_ != j); + } + + //////////////////////////////////////////////////////////////////////// + // fill_buckets + + void copy_buckets(table const& src) + { + this->create_buckets(this->bucket_count_); + + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + this->add_node(boost::unordered::detail::func::construct_node( + this->node_alloc(), n->value()), + n->hash_); + } + } + + void move_buckets(table const& src) + { + this->create_buckets(this->bucket_count_); + + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + this->add_node(boost::unordered::detail::func::construct_node( + this->node_alloc(), boost::move(n->value())), + n->hash_); + } + } + + void assign_buckets(table const& src) + { + node_holder<node_allocator> holder(*this); + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + this->add_node(holder.copy_of(n->value()), n->hash_); + } + } + + void move_assign_buckets(table& src) + { + node_holder<node_allocator> holder(*this); + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + this->add_node(holder.move_copy_of(n->value()), n->hash_); + } + } +}; + +//////////////////////////////////////////////////////////////////////// +// Grouped nodes + +template <typename A, typename T> +struct grouped_node : boost::unordered::detail::value_base<T> +{ + typedef typename ::boost::unordered::detail::rebind_wrap<A, + grouped_node<A, T> >::type allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + allocator>::pointer node_pointer; + typedef node_pointer link_pointer; + typedef typename ::boost::unordered::detail::rebind_wrap<A, + bucket<node_pointer> >::type bucket_allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + bucket_allocator>::pointer bucket_pointer; + + link_pointer next_; + node_pointer group_prev_; + std::size_t hash_; + + grouped_node() : next_(), group_prev_(), hash_(0) {} + + void init(node_pointer self) { group_prev_ = self; } + + private: + grouped_node& operator=(grouped_node const&); +}; + +template <typename T> +struct grouped_ptr_node : boost::unordered::detail::ptr_bucket +{ + typedef T value_type; + typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef grouped_ptr_node<T>* node_pointer; + typedef ptr_bucket* link_pointer; + typedef ptr_bucket* bucket_pointer; + + node_pointer group_prev_; + std::size_t hash_; + boost::unordered::detail::value_base<T> value_base_; + + grouped_ptr_node() : bucket_base(), group_prev_(0), hash_(0) {} + + void init(node_pointer self) { group_prev_ = self; } + + void* address() { return value_base_.address(); } + value_type& value() { return value_base_.value(); } + value_type* value_ptr() { return value_base_.value_ptr(); } + + private: + grouped_ptr_node& operator=(grouped_ptr_node const&); +}; + +template <typename N> struct grouped_node_algo +{ + typedef typename N::node_pointer node_pointer; + typedef typename N::link_pointer link_pointer; + typedef typename N::bucket_pointer bucket_pointer; + + static node_pointer next_node(link_pointer n) + { + return static_cast<node_pointer>(n->next_); + } + + static node_pointer next_for_find(node_pointer n) + { + return static_cast<node_pointer>(n->group_prev_->next_); + } + + static link_pointer next_for_erase(link_pointer prev) + { + return static_cast<node_pointer>(prev->next_)->group_prev_; + } + + static node_pointer last_for_rehash(link_pointer prev) + { + return static_cast<node_pointer>(prev->next_)->group_prev_; + } + + // The 'void*' arguments are pointers to the table, which we + // will ignore, but without groups they could be used to + // access the various functions for dealing with values and keys. + static node_pointer next_group(node_pointer n, void const*) + { + return static_cast<node_pointer>(n->group_prev_->next_); + } + + static std::size_t count(node_pointer n, void const*) + { + std::size_t x = 0; + node_pointer it = n; + do { + it = it->group_prev_; + ++x; + } while (it != n); + + return x; + } + + // Adds node 'n' to the group containing 'pos'. + // If 'pos' is the first node in group, add to the end of the group, + // otherwise add before 'pos'. Other versions will probably behave + // differently. + static inline void add_to_node_group(node_pointer n, node_pointer pos) + { + n->next_ = pos->group_prev_->next_; + n->group_prev_ = pos->group_prev_; + pos->group_prev_->next_ = n; + pos->group_prev_ = n; + } + + static inline node_pointer extract_first_node(link_pointer prev) + { + node_pointer n = next_node(prev); + if (n->group_prev_ != n) { + node_pointer next = next_node(n); + next->group_prev_ = n->group_prev_; + n->group_prev_ = n; + } + prev->next_ = n->next_; + return n; + } + + // Split the groups containing 'i' and 'j' so that they can + // be safely erased/extracted. + static link_pointer split_groups(node_pointer i, node_pointer j) + { + node_pointer prev = i->group_prev_; + if (prev->next_ != i) + prev = node_pointer(); + + if (j) { + node_pointer first = j; + while (first != i && first->group_prev_->next_ == first) { + first = first->group_prev_; + } + + boost::swap(first->group_prev_, j->group_prev_); + if (first == i) + return prev; + } + + if (prev) { + node_pointer first = prev; + while (first->group_prev_->next_ == first) { + first = first->group_prev_; + } + boost::swap(first->group_prev_, i->group_prev_); + } + + return prev; + } +}; + +// If the allocator uses raw pointers use grouped_ptr_node +// Otherwise use grouped_node. + +template <typename A, typename T, typename NodePtr, typename BucketPtr> +struct pick_grouped_node2 +{ + typedef boost::unordered::detail::grouped_node<A, T> node; + + typedef typename boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap<A, node>::type>::pointer + node_pointer; + + typedef boost::unordered::detail::bucket<node_pointer> bucket; + typedef node_pointer link_pointer; +}; + +template <typename A, typename T> +struct pick_grouped_node2<A, T, boost::unordered::detail::grouped_ptr_node<T>*, + boost::unordered::detail::ptr_bucket*> +{ + typedef boost::unordered::detail::grouped_ptr_node<T> node; + typedef boost::unordered::detail::ptr_bucket bucket; + typedef bucket* link_pointer; +}; + +template <typename A, typename T> struct pick_grouped_node +{ + typedef typename boost::remove_const<T>::type nonconst; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap<A, + boost::unordered::detail::grouped_ptr_node<nonconst> >::type> + tentative_node_traits; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap<A, + boost::unordered::detail::ptr_bucket>::type> + tentative_bucket_traits; + + typedef pick_grouped_node2<A, nonconst, + typename tentative_node_traits::pointer, + typename tentative_bucket_traits::pointer> + pick; + + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + typedef boost::unordered::detail::grouped_node_algo<node> node_algo; +}; + +template <typename Types> +struct grouped_table_impl : boost::unordered::detail::table<Types> +{ + typedef boost::unordered::detail::table<Types> table; + typedef typename table::value_type value_type; + typedef typename table::bucket bucket; + typedef typename table::policy policy; + typedef typename table::node_pointer node_pointer; + typedef typename table::node_allocator node_allocator; + typedef typename table::node_allocator_traits node_allocator_traits; + typedef typename table::bucket_pointer bucket_pointer; + typedef typename table::link_pointer link_pointer; + typedef typename table::hasher hasher; + typedef typename table::key_equal key_equal; + typedef typename table::const_key_type const_key_type; + typedef typename table::node_constructor node_constructor; + typedef typename table::node_tmp node_tmp; + typedef typename table::extractor extractor; + typedef typename table::iterator iterator; + typedef typename table::c_iterator c_iterator; + typedef typename table::node_algo node_algo; + + // Constructors + + grouped_table_impl(std::size_t n, hasher const& hf, key_equal const& eq, + node_allocator const& a) + : table(n, hf, eq, a) + { + } + + grouped_table_impl(grouped_table_impl const& x) + : table(x, node_allocator_traits::select_on_container_copy_construction( + x.node_alloc())) + { + this->init(x); + } + + grouped_table_impl(grouped_table_impl const& x, node_allocator const& a) + : table(x, a) + { + this->init(x); + } + + grouped_table_impl( + grouped_table_impl& x, boost::unordered::detail::move_tag m) + : table(x, m) + { + } + + grouped_table_impl(grouped_table_impl& x, node_allocator const& a, + boost::unordered::detail::move_tag m) + : table(x, a, m) + { + this->move_init(x); + } + + // Accessors + + std::size_t count(const_key_type& k) const + { + node_pointer n = this->find_node(k); + return n ? node_algo::count(n, this) : 0; + } + + std::pair<iterator, iterator> equal_range(const_key_type& k) const + { + node_pointer n = this->find_node(k); + return std::make_pair( + iterator(n), iterator(n ? node_algo::next_group(n, this) : n)); + } + + // Equality + + bool equals(grouped_table_impl const& other) const + { + if (this->size_ != other.size_) + return false; + + for (node_pointer n1 = this->begin(); n1;) { + node_pointer n2 = other.find_node(other.get_key(n1->value())); + if (!n2) + return false; + node_pointer end1 = node_algo::next_group(n1, this); + node_pointer end2 = node_algo::next_group(n2, this); + if (!group_equals(n1, end1, n2, end2)) + return false; + n1 = end1; + } + + return true; + } + + static bool group_equals( + node_pointer n1, node_pointer end1, node_pointer n2, node_pointer end2) + { + for (;;) { + if (n1->value() != n2->value()) + break; + + n1 = node_algo::next_node(n1); + n2 = node_algo::next_node(n2); + + if (n1 == end1) + return n2 == end2; + if (n2 == end2) + return false; + } + + for (node_pointer n1a = n1, n2a = n2;;) { + n1a = node_algo::next_node(n1a); + n2a = node_algo::next_node(n2a); + + if (n1a == end1) { + if (n2a == end2) + break; + else + return false; + } + + if (n2a == end2) + return false; + } + + node_pointer start = n1; + for (; n1 != end1; n1 = node_algo::next_node(n1)) { + value_type const& v = n1->value(); + if (!find(start, n1, v)) { + std::size_t matches = count_equal(n2, end2, v); + if (!matches) + return false; + if (matches != + 1 + count_equal(node_algo::next_node(n1), end1, v)) + return false; + } + } + + return true; + } + + static bool find(node_pointer n, node_pointer end, value_type const& v) + { + for (; n != end; n = node_algo::next_node(n)) + if (n->value() == v) + return true; + return false; + } + + static std::size_t count_equal( + node_pointer n, node_pointer end, value_type const& v) + { + std::size_t count = 0; + for (; n != end; n = node_algo::next_node(n)) + if (n->value() == v) + ++count; + return count; + } + + // Emplace/Insert + + inline node_pointer add_node( + node_pointer n, std::size_t key_hash, node_pointer pos) + { + n->hash_ = key_hash; + if (pos) { + node_algo::add_to_node_group(n, pos); + if (n->next_) { + std::size_t next_bucket = + this->hash_to_bucket(node_algo::next_node(n)->hash_); + if (next_bucket != this->hash_to_bucket(key_hash)) { + this->get_bucket(next_bucket)->next_ = n; + } + } + } else { + bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); + + if (!b->next_) { + link_pointer start_node = this->get_previous_start(); + + if (start_node->next_) { + this->get_bucket( + this->hash_to_bucket( + node_algo::next_node(start_node)->hash_)) + ->next_ = n; + } + + b->next_ = start_node; + n->next_ = start_node->next_; + start_node->next_ = n; + } else { + n->next_ = b->next_->next_; + b->next_->next_ = n; + } + } + ++this->size_; + return n; + } + + inline node_pointer add_using_hint(node_pointer n, node_pointer hint) + { + n->hash_ = hint->hash_; + node_algo::add_to_node_group(n, hint); + if (n->next_ != hint && n->next_) { + std::size_t next_bucket = + this->hash_to_bucket(node_algo::next_node(n)->hash_); + if (next_bucket != this->hash_to_bucket(n->hash_)) { + this->get_bucket(next_bucket)->next_ = n; + } + } + ++this->size_; + return n; + } + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + iterator emplace(boost::unordered::detail::emplace_args1< + boost::unordered::detail::please_ignore_this_overload> const&) + { + BOOST_ASSERT(false); + return iterator(); + } + + iterator emplace_hint( + c_iterator, + boost::unordered::detail::emplace_args1< + boost::unordered::detail::please_ignore_this_overload> const&) + { + BOOST_ASSERT(false); + return iterator(); + } +#else + iterator emplace( + boost::unordered::detail::please_ignore_this_overload const&) + { + BOOST_ASSERT(false); + return iterator(); + } + + iterator emplace_hint(c_iterator, + boost::unordered::detail::please_ignore_this_overload const&) + { + BOOST_ASSERT(false); + return iterator(); + } +#endif +#endif + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) + { + return iterator(emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); + } + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS) + { + return iterator(emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); + } + + iterator emplace_impl(node_pointer n) + { + node_tmp a(n, this->node_alloc()); + const_key_type& k = this->get_key(a.node_->value()); + std::size_t key_hash = this->hash(k); + node_pointer position = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + return iterator(this->add_node(a.release(), key_hash, position)); + } + + iterator emplace_hint_impl(c_iterator hint, node_pointer n) + { + node_tmp a(n, this->node_alloc()); + const_key_type& k = this->get_key(a.node_->value()); + if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + this->reserve_for_insert(this->size_ + 1); + return iterator(this->add_using_hint(a.release(), hint.node_)); + } else { + std::size_t key_hash = this->hash(k); + node_pointer position = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + return iterator(this->add_node(a.release(), key_hash, position)); + } + } + + void emplace_impl_no_rehash(node_pointer n) + { + node_tmp a(n, this->node_alloc()); + const_key_type& k = this->get_key(a.node_->value()); + std::size_t key_hash = this->hash(k); + node_pointer position = this->find_node(key_hash, k); + this->add_node(a.release(), key_hash, position); + } + + template <typename NodeType> iterator move_insert_node_type(NodeType& np) + { + iterator result; + + if (np) { + const_key_type& k = this->get_key(np.ptr_->value()); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + result = iterator(this->add_node(np.ptr_, key_hash, pos)); + np.ptr_ = node_pointer(); + } + + return result; + } + + template <typename NodeType> + iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np) + { + iterator result; + + if (np) { + const_key_type& k = this->get_key(np.ptr_->value()); + + if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + this->reserve_for_insert(this->size_ + 1); + result = iterator(this->add_using_hint(np.ptr_, hint.node_)); + } else { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + result = iterator(this->add_node(np.ptr_, key_hash, pos)); + } + np.ptr_ = node_pointer(); + } + + return result; + } + + //////////////////////////////////////////////////////////////////////// + // Insert range methods + + // if hash function throws, or inserting > 1 element, basic exception + // safety. Strong otherwise + template <class I> + void insert_range(I i, I j, + typename boost::unordered::detail::enable_if_forward<I, void*>::type = + 0) + { + if (i == j) + return; + + std::size_t distance = static_cast<std::size_t>(std::distance(i, j)); + if (distance == 1) { + emplace_impl(boost::unordered::detail::func::construct_node( + this->node_alloc(), *i)); + } else { + // Only require basic exception safety here + this->reserve_for_insert(this->size_ + distance); + + for (; i != j; ++i) { + emplace_impl_no_rehash( + boost::unordered::detail::func::construct_node( + this->node_alloc(), *i)); + } + } + } + + template <class I> + void insert_range(I i, I j, + typename boost::unordered::detail::disable_if_forward<I, void*>::type = + 0) + { + for (; i != j; ++i) { + emplace_impl(boost::unordered::detail::func::construct_node( + this->node_alloc(), *i)); + } + } + + //////////////////////////////////////////////////////////////////////// + // Extract + + inline node_pointer extract_by_iterator(c_iterator n) + { + node_pointer i = n.node_; + BOOST_ASSERT(i); + node_pointer j(node_algo::next_node(i)); + std::size_t bucket_index = this->hash_to_bucket(i->hash_); + // Split the groups containing 'i' and 'j'. + // And get the pointer to the node before i while + // we're at it. + link_pointer prev = node_algo::split_groups(i, j); + + // If we don't have a 'prev' it means that i is at the + // beginning of a block, so search through the blocks in the + // same bucket. + if (!prev) { + prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) { + prev = node_algo::next_for_erase(prev); + } + } + + prev->next_ = i->next_; + --this->size_; + this->fix_bucket(bucket_index, prev); + i->next_ = link_pointer(); + + return i; + } + + //////////////////////////////////////////////////////////////////////// + // Erase + // + // no throw + + std::size_t erase_key(const_key_type& k) + { + if (!this->size_) + return 0; + + std::size_t key_hash = this->hash(k); + std::size_t bucket_index = this->hash_to_bucket(key_hash); + link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + if (!prev) + return 0; + + node_pointer first_node = node_algo::next_node(prev); + link_pointer end = node_algo::next_group(first_node, this); + + std::size_t deleted_count = this->delete_nodes(prev, end); + this->fix_bucket(bucket_index, prev); + return deleted_count; + } + + iterator erase(c_iterator r) + { + BOOST_ASSERT(r.node_); + node_pointer next = node_algo::next_node(r.node_); + erase_nodes(r.node_, next); + return iterator(next); + } + + iterator erase_range(c_iterator r1, c_iterator r2) + { + if (r1 == r2) + return iterator(r2.node_); + erase_nodes(r1.node_, r2.node_); + return iterator(r2.node_); + } + + link_pointer erase_nodes(node_pointer i, node_pointer j) + { + std::size_t bucket_index = this->hash_to_bucket(i->hash_); + + // Split the groups containing 'i' and 'j'. + // And get the pointer to the node before i while + // we're at it. + link_pointer prev = node_algo::split_groups(i, j); + + // If we don't have a 'prev' it means that i is at the + // beginning of a block, so search through the blocks in the + // same bucket. + if (!prev) { + prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) { + prev = node_algo::next_for_erase(prev); + } + } + + // Delete the nodes. + // Is it inefficient to call fix_bucket for every node? + do { + this->delete_node(prev); + bucket_index = this->fix_bucket(bucket_index, prev); + } while (prev->next_ != j); + + return prev; + } + + //////////////////////////////////////////////////////////////////////// + // fill_buckets + + void copy_buckets(table const& src) + { + this->create_buckets(this->bucket_count_); + + for (node_pointer n = src.begin(); n;) { + std::size_t key_hash = n->hash_; + node_pointer group_end(node_algo::next_group(n, this)); + node_pointer pos = + this->add_node(boost::unordered::detail::func::construct_node( + this->node_alloc(), n->value()), + key_hash, node_pointer()); + for (n = node_algo::next_node(n); n != group_end; + n = node_algo::next_node(n)) { + this->add_node(boost::unordered::detail::func::construct_node( + this->node_alloc(), n->value()), + key_hash, pos); + } + } + } + + void move_buckets(table const& src) + { + this->create_buckets(this->bucket_count_); + + for (node_pointer n = src.begin(); n;) { + std::size_t key_hash = n->hash_; + node_pointer group_end(node_algo::next_group(n, this)); + node_pointer pos = + this->add_node(boost::unordered::detail::func::construct_node( + this->node_alloc(), boost::move(n->value())), + key_hash, node_pointer()); + for (n = node_algo::next_node(n); n != group_end; + n = node_algo::next_node(n)) { + this->add_node(boost::unordered::detail::func::construct_node( + this->node_alloc(), boost::move(n->value())), + key_hash, pos); + } + } + } + + void assign_buckets(table const& src) + { + node_holder<node_allocator> holder(*this); + for (node_pointer n = src.begin(); n;) { + std::size_t key_hash = n->hash_; + node_pointer group_end(node_algo::next_group(n, this)); + node_pointer pos = this->add_node( + holder.copy_of(n->value()), key_hash, node_pointer()); + for (n = node_algo::next_node(n); n != group_end; + n = node_algo::next_node(n)) { + this->add_node(holder.copy_of(n->value()), key_hash, pos); + } + } + } + + void move_assign_buckets(table& src) + { + node_holder<node_allocator> holder(*this); + for (node_pointer n = src.begin(); n;) { + std::size_t key_hash = n->hash_; + node_pointer group_end(node_algo::next_group(n, this)); + node_pointer pos = this->add_node( + holder.move_copy_of(n->value()), key_hash, node_pointer()); + for (n = node_algo::next_node(n); n != group_end; + n = node_algo::next_node(n)) { + this->add_node(holder.move_copy_of(n->value()), key_hash, pos); + } + } + } +}; +} +} +} + +#endif diff --git a/boost/unordered/detail/map.hpp b/boost/unordered/detail/map.hpp index 14253ef49a..cb9a954bb2 100644 --- a/boost/unordered/detail/map.hpp +++ b/boost/unordered/detail/map.hpp @@ -3,77 +3,105 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/unordered/detail/implementation.hpp> #include <boost/unordered/unordered_map_fwd.hpp> -#include <boost/unordered/detail/equivalent.hpp> -#include <boost/unordered/detail/unique.hpp> - -namespace boost { namespace unordered { namespace detail { - template <typename A, typename K, typename M, typename H, typename P> - struct map - { - typedef boost::unordered::detail::map<A, K, M, H, P> types; - - typedef A allocator; - typedef std::pair<K const, M> value_type; - typedef H hasher; - typedef P key_equal; - typedef K key_type; - - typedef boost::unordered::detail::allocator_traits<allocator> - traits; - typedef boost::unordered::detail::pick_node<allocator, value_type> pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::table_impl<types> table; - typedef boost::unordered::detail::map_extractor<key_type, value_type> - extractor; - - typedef typename boost::unordered::detail::pick_policy<K>::type policy; - - typedef boost::unordered::iterator_detail:: - iterator<node> iterator; - typedef boost::unordered::iterator_detail:: - c_iterator<node> c_iterator; - typedef boost::unordered::iterator_detail:: - l_iterator<node, policy> l_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator<node, policy> cl_iterator; - }; - - template <typename A, typename K, typename M, typename H, typename P> - struct multimap - { - typedef boost::unordered::detail::multimap<A, K, M, H, P> types; - - typedef A allocator; - typedef std::pair<K const, M> value_type; - typedef H hasher; - typedef P key_equal; - typedef K key_type; - - typedef boost::unordered::detail::allocator_traits<allocator> traits; - typedef boost::unordered::detail::pick_grouped_node<allocator, - value_type> pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::grouped_table_impl<types> table; - typedef boost::unordered::detail::map_extractor<key_type, value_type> - extractor; - - typedef typename boost::unordered::detail::pick_policy<K>::type policy; - - typedef boost::unordered::iterator_detail:: - iterator<node> iterator; - typedef boost::unordered::iterator_detail:: - c_iterator<node> c_iterator; - typedef boost::unordered::iterator_detail:: - l_iterator<node, policy> l_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator<node, policy> cl_iterator; - }; - -}}} + +namespace boost { +namespace unordered { +namespace detail { +template <typename A, typename K, typename M, typename H, typename P> struct map +{ + typedef boost::unordered::detail::map<A, K, M, H, P> types; + + typedef std::pair<K const, M> value_type; + typedef H hasher; + typedef P key_equal; + typedef K const const_key_type; + + typedef typename ::boost::unordered::detail::rebind_wrap<A, + value_type>::type value_allocator; + typedef boost::unordered::detail::allocator_traits<value_allocator> + value_allocator_traits; + + typedef boost::unordered::detail::pick_node<A, value_type> pick; + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + typedef typename pick::node_algo node_algo; + + typedef boost::unordered::detail::table_impl<types> table; + typedef boost::unordered::detail::map_extractor<value_type> extractor; + + typedef typename boost::unordered::detail::pick_policy<K>::type policy; + + typedef boost::unordered::iterator_detail::iterator<node> iterator; + typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator; + typedef boost::unordered::iterator_detail::l_iterator<node, policy> + l_iterator; + typedef boost::unordered::iterator_detail::cl_iterator<node, policy> + cl_iterator; + + typedef boost::unordered::node_handle_map<node, K, M, A> node_type; + typedef boost::unordered::insert_return_type_map<node, K, M, A> + insert_return_type; +}; + +template <typename A, typename K, typename M, typename H, typename P> +struct multimap +{ + typedef boost::unordered::detail::multimap<A, K, M, H, P> types; + + typedef std::pair<K const, M> value_type; + typedef H hasher; + typedef P key_equal; + typedef K const const_key_type; + + typedef typename ::boost::unordered::detail::rebind_wrap<A, + value_type>::type value_allocator; + typedef boost::unordered::detail::allocator_traits<value_allocator> + value_allocator_traits; + +#if BOOST_UNORDERED_INTEROPERABLE_NODES + typedef boost::unordered::detail::pick_node<A, value_type> pick; +#else + typedef boost::unordered::detail::pick_grouped_node<A, value_type> pick; +#endif + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + typedef typename pick::node_algo node_algo; + + typedef boost::unordered::detail::grouped_table_impl<types> table; + typedef boost::unordered::detail::map_extractor<value_type> extractor; + + typedef typename boost::unordered::detail::pick_policy<K>::type policy; + + typedef boost::unordered::iterator_detail::iterator<node> iterator; + typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator; + typedef boost::unordered::iterator_detail::l_iterator<node, policy> + l_iterator; + typedef boost::unordered::iterator_detail::cl_iterator<node, policy> + cl_iterator; + + typedef boost::unordered::node_handle_map<node, K, M, A> node_type; +}; + +template <typename K, typename M, typename H, typename P, typename A> +class instantiate_map +{ + typedef boost::unordered_map<K, M, H, P, A> container; + container x; + typename container::node_type node_type; + typename container::insert_return_type insert_return_type; +}; + +template <typename K, typename M, typename H, typename P, typename A> +class instantiate_multimap +{ + typedef boost::unordered_multimap<K, M, H, P, A> container; + container x; + typename container::node_type node_type; +}; +} +} +} diff --git a/boost/unordered/detail/set.hpp b/boost/unordered/detail/set.hpp index ccbc4c99a3..42e9cad7b5 100644 --- a/boost/unordered/detail/set.hpp +++ b/boost/unordered/detail/set.hpp @@ -3,73 +3,103 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/unordered/detail/implementation.hpp> #include <boost/unordered/unordered_set_fwd.hpp> -#include <boost/unordered/detail/equivalent.hpp> -#include <boost/unordered/detail/unique.hpp> - -namespace boost { namespace unordered { namespace detail { - template <typename A, typename T, typename H, typename P> - struct set - { - typedef boost::unordered::detail::set<A, T, H, P> types; - - typedef A allocator; - typedef T value_type; - typedef H hasher; - typedef P key_equal; - typedef T key_type; - - typedef boost::unordered::detail::allocator_traits<allocator> traits; - typedef boost::unordered::detail::pick_node<allocator, value_type> pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::table_impl<types> table; - typedef boost::unordered::detail::set_extractor<value_type> extractor; - - typedef typename boost::unordered::detail::pick_policy<T>::type policy; - - typedef boost::unordered::iterator_detail:: - c_iterator<node> iterator; - typedef boost::unordered::iterator_detail:: - c_iterator<node> c_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator<node, policy> l_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator<node, policy> cl_iterator; - }; - - template <typename A, typename T, typename H, typename P> - struct multiset - { - typedef boost::unordered::detail::multiset<A, T, H, P> types; - - typedef A allocator; - typedef T value_type; - typedef H hasher; - typedef P key_equal; - typedef T key_type; - - typedef boost::unordered::detail::allocator_traits<allocator> traits; - typedef boost::unordered::detail::pick_grouped_node<allocator, - value_type> pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::grouped_table_impl<types> table; - typedef boost::unordered::detail::set_extractor<value_type> extractor; - - typedef typename boost::unordered::detail::pick_policy<T>::type policy; - - typedef boost::unordered::iterator_detail:: - c_iterator<node> iterator; - typedef boost::unordered::iterator_detail:: - c_iterator<node> c_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator<node, policy> l_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator<node, policy> cl_iterator; - }; -}}} + +namespace boost { +namespace unordered { +namespace detail { +template <typename A, typename T, typename H, typename P> struct set +{ + typedef boost::unordered::detail::set<A, T, H, P> types; + + typedef T value_type; + typedef H hasher; + typedef P key_equal; + typedef T const const_key_type; + + typedef typename ::boost::unordered::detail::rebind_wrap<A, + value_type>::type value_allocator; + typedef boost::unordered::detail::allocator_traits<value_allocator> + value_allocator_traits; + + typedef boost::unordered::detail::pick_node<A, value_type> pick; + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + typedef typename pick::node_algo node_algo; + + typedef boost::unordered::detail::table_impl<types> table; + typedef boost::unordered::detail::set_extractor<value_type> extractor; + + typedef typename boost::unordered::detail::pick_policy<T>::type policy; + + typedef boost::unordered::iterator_detail::c_iterator<node> iterator; + typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator; + typedef boost::unordered::iterator_detail::cl_iterator<node, policy> + l_iterator; + typedef boost::unordered::iterator_detail::cl_iterator<node, policy> + cl_iterator; + + typedef boost::unordered::node_handle_set<node, T, A> node_type; + typedef boost::unordered::insert_return_type_set<node, T, A> + insert_return_type; +}; + +template <typename A, typename T, typename H, typename P> struct multiset +{ + typedef boost::unordered::detail::multiset<A, T, H, P> types; + + typedef T value_type; + typedef H hasher; + typedef P key_equal; + typedef T const const_key_type; + + typedef typename ::boost::unordered::detail::rebind_wrap<A, + value_type>::type value_allocator; + typedef boost::unordered::detail::allocator_traits<value_allocator> + value_allocator_traits; + +#if BOOST_UNORDERED_INTEROPERABLE_NODES + typedef boost::unordered::detail::pick_node<A, value_type> pick; +#else + typedef boost::unordered::detail::pick_grouped_node<A, value_type> pick; +#endif + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + typedef typename pick::node_algo node_algo; + + typedef boost::unordered::detail::grouped_table_impl<types> table; + typedef boost::unordered::detail::set_extractor<value_type> extractor; + + typedef typename boost::unordered::detail::pick_policy<T>::type policy; + + typedef boost::unordered::iterator_detail::c_iterator<node> iterator; + typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator; + typedef boost::unordered::iterator_detail::cl_iterator<node, policy> + l_iterator; + typedef boost::unordered::iterator_detail::cl_iterator<node, policy> + cl_iterator; + + typedef boost::unordered::node_handle_set<node, T, A> node_type; +}; + +template <typename T, typename H, typename P, typename A> class instantiate_set +{ + typedef boost::unordered_set<T, H, P, A> container; + container x; + typename container::node_type node_type; + typename container::insert_return_type insert_return_type; +}; + +template <typename T, typename H, typename P, typename A> +class instantiate_multiset +{ + typedef boost::unordered_multiset<T, H, P, A> container; + container x; + typename container::node_type node_type; +}; +} +} +} diff --git a/boost/unordered/detail/table.hpp b/boost/unordered/detail/table.hpp deleted file mode 100644 index 1092d31f9f..0000000000 --- a/boost/unordered/detail/table.hpp +++ /dev/null @@ -1,794 +0,0 @@ - -// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2011 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED - -#include <boost/config.hpp> -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include <boost/unordered/detail/buckets.hpp> - -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant -#endif - -namespace boost { namespace unordered { namespace detail { - - //////////////////////////////////////////////////////////////////////////// - // convert double to std::size_t - - inline std::size_t double_to_size(double f) - { - return f >= static_cast<double>( - (std::numeric_limits<std::size_t>::max)()) ? - (std::numeric_limits<std::size_t>::max)() : - static_cast<std::size_t>(f); - } - - // The space used to store values in a node. - - template <typename ValueType> - struct value_base - { - typedef ValueType value_type; - - typename boost::aligned_storage< - sizeof(value_type), - boost::alignment_of<value_type>::value>::type data_; - - value_base() : - data_() - {} - - void* address() { - return this; - } - - value_type& value() { - return *(ValueType*) this; - } - - value_type* value_ptr() { - return (ValueType*) this; - } - - private: - - value_base& operator=(value_base const&); - }; - - template <typename Types> - struct table : - boost::unordered::detail::functions< - typename Types::hasher, - typename Types::key_equal> - { - private: - table(table const&); - table& operator=(table const&); - public: - typedef typename Types::node node; - typedef typename Types::bucket bucket; - typedef typename Types::hasher hasher; - typedef typename Types::key_equal key_equal; - typedef typename Types::key_type key_type; - typedef typename Types::extractor extractor; - typedef typename Types::value_type value_type; - typedef typename Types::table table_impl; - typedef typename Types::link_pointer link_pointer; - typedef typename Types::policy policy; - typedef typename Types::iterator iterator; - typedef typename Types::c_iterator c_iterator; - typedef typename Types::l_iterator l_iterator; - typedef typename Types::cl_iterator cl_iterator; - - typedef boost::unordered::detail::functions< - typename Types::hasher, - typename Types::key_equal> functions; - typedef typename functions::set_hash_functions set_hash_functions; - - typedef typename Types::allocator allocator; - typedef typename boost::unordered::detail:: - rebind_wrap<allocator, node>::type node_allocator; - typedef typename boost::unordered::detail:: - rebind_wrap<allocator, bucket>::type bucket_allocator; - typedef boost::unordered::detail::allocator_traits<node_allocator> - node_allocator_traits; - typedef boost::unordered::detail::allocator_traits<bucket_allocator> - bucket_allocator_traits; - typedef typename node_allocator_traits::pointer - node_pointer; - typedef typename node_allocator_traits::const_pointer - const_node_pointer; - typedef typename bucket_allocator_traits::pointer - bucket_pointer; - typedef boost::unordered::detail::node_constructor<node_allocator> - node_constructor; - typedef boost::unordered::detail::node_tmp<node_allocator> - node_tmp; - - //////////////////////////////////////////////////////////////////////// - // Members - - boost::unordered::detail::compressed<bucket_allocator, node_allocator> - allocators_; - std::size_t bucket_count_; - std::size_t size_; - float mlf_; - std::size_t max_load_; - bucket_pointer buckets_; - - //////////////////////////////////////////////////////////////////////// - // Node functions - - static inline node_pointer next_node(link_pointer n) { - return static_cast<node_pointer>(n->next_); - } - - //////////////////////////////////////////////////////////////////////// - // Data access - - bucket_allocator const& bucket_alloc() const - { - return allocators_.first(); - } - - node_allocator const& node_alloc() const - { - return allocators_.second(); - } - - bucket_allocator& bucket_alloc() - { - return allocators_.first(); - } - - node_allocator& node_alloc() - { - return allocators_.second(); - } - - std::size_t max_bucket_count() const - { - // -1 to account for the start bucket. - return policy::prev_bucket_count( - bucket_allocator_traits::max_size(bucket_alloc()) - 1); - } - - bucket_pointer get_bucket(std::size_t bucket_index) const - { - BOOST_ASSERT(buckets_); - return buckets_ + static_cast<std::ptrdiff_t>(bucket_index); - } - - link_pointer get_previous_start() const - { - return get_bucket(bucket_count_)->first_from_start(); - } - - link_pointer get_previous_start(std::size_t bucket_index) const - { - return get_bucket(bucket_index)->next_; - } - - node_pointer begin() const - { - return size_ ? next_node(get_previous_start()) : node_pointer(); - } - - node_pointer begin(std::size_t bucket_index) const - { - if (!size_) return node_pointer(); - link_pointer prev = get_previous_start(bucket_index); - return prev ? next_node(prev) : node_pointer(); - } - - std::size_t hash_to_bucket(std::size_t hash_value) const - { - return policy::to_bucket(bucket_count_, hash_value); - } - - float load_factor() const - { - BOOST_ASSERT(bucket_count_ != 0); - return static_cast<float>(size_) - / static_cast<float>(bucket_count_); - } - - std::size_t bucket_size(std::size_t index) const - { - node_pointer n = begin(index); - if (!n) return 0; - - std::size_t count = 0; - while(n && hash_to_bucket(n->hash_) == index) - { - ++count; - n = next_node(n); - } - - return count; - } - - //////////////////////////////////////////////////////////////////////// - // Load methods - - std::size_t max_size() const - { - using namespace std; - - // size < mlf_ * count - return boost::unordered::detail::double_to_size(ceil( - static_cast<double>(mlf_) * - static_cast<double>(max_bucket_count()) - )) - 1; - } - - void recalculate_max_load() - { - using namespace std; - - // From 6.3.1/13: - // Only resize when size >= mlf_ * count - max_load_ = buckets_ ? boost::unordered::detail::double_to_size(ceil( - static_cast<double>(mlf_) * - static_cast<double>(bucket_count_) - )) : 0; - - } - - void max_load_factor(float z) - { - BOOST_ASSERT(z > 0); - mlf_ = (std::max)(z, minimum_max_load_factor); - recalculate_max_load(); - } - - std::size_t min_buckets_for_size(std::size_t size) const - { - BOOST_ASSERT(mlf_ >= minimum_max_load_factor); - - using namespace std; - - // From 6.3.1/13: - // size < mlf_ * count - // => count > size / mlf_ - // - // Or from rehash post-condition: - // count > size / mlf_ - - return policy::new_bucket_count( - boost::unordered::detail::double_to_size(floor( - static_cast<double>(size) / - static_cast<double>(mlf_)) + 1)); - } - - //////////////////////////////////////////////////////////////////////// - // Constructors - - table(std::size_t num_buckets, - hasher const& hf, - key_equal const& eq, - node_allocator const& a) : - functions(hf, eq), - allocators_(a,a), - bucket_count_(policy::new_bucket_count(num_buckets)), - size_(0), - mlf_(1.0f), - max_load_(0), - buckets_() - {} - - table(table const& x, node_allocator const& a) : - functions(x), - allocators_(a,a), - bucket_count_(x.min_buckets_for_size(x.size_)), - size_(0), - mlf_(x.mlf_), - max_load_(0), - buckets_() - {} - - table(table& x, boost::unordered::detail::move_tag m) : - functions(x, m), - allocators_(x.allocators_, m), - bucket_count_(x.bucket_count_), - size_(x.size_), - mlf_(x.mlf_), - max_load_(x.max_load_), - buckets_(x.buckets_) - { - x.buckets_ = bucket_pointer(); - x.size_ = 0; - x.max_load_ = 0; - } - - table(table& x, node_allocator const& a, - boost::unordered::detail::move_tag m) : - functions(x, m), - allocators_(a, a), - bucket_count_(x.bucket_count_), - size_(0), - mlf_(x.mlf_), - max_load_(x.max_load_), - buckets_() - {} - - //////////////////////////////////////////////////////////////////////// - // Initialisation. - - void init(table const& x) - { - if (x.size_) { - static_cast<table_impl*>(this)->copy_buckets(x); - } - } - - void move_init(table& x) - { - if(node_alloc() == x.node_alloc()) { - move_buckets_from(x); - } - else if(x.size_) { - // TODO: Could pick new bucket size? - static_cast<table_impl*>(this)->move_buckets(x); - } - } - - //////////////////////////////////////////////////////////////////////// - // Create buckets - - void create_buckets(std::size_t new_count) - { - std::size_t length = new_count + 1; - bucket_pointer new_buckets = bucket_allocator_traits::allocate( - bucket_alloc(), length); - bucket_pointer constructed = new_buckets; - - BOOST_TRY { - bucket_pointer end = new_buckets - + static_cast<std::ptrdiff_t>(length); - for(; constructed != end; ++constructed) { - new ((void*) boost::addressof(*constructed)) bucket(); - } - - if (buckets_) - { - // Copy the nodes to the new buckets, including the dummy - // node if there is one. - (new_buckets + - static_cast<std::ptrdiff_t>(new_count))->next_ = - (buckets_ + static_cast<std::ptrdiff_t>( - bucket_count_))->next_; - destroy_buckets(); - } - else if (bucket::extra_node) - { - node_constructor a(node_alloc()); - a.create_node(); - - (new_buckets + - static_cast<std::ptrdiff_t>(new_count))->next_ = - a.release(); - } - } - BOOST_CATCH(...) { - for(bucket_pointer p = new_buckets; p != constructed; ++p) { - boost::unordered::detail::func::destroy( - boost::addressof(*p)); - } - - bucket_allocator_traits::deallocate(bucket_alloc(), - new_buckets, length); - - BOOST_RETHROW; - } - BOOST_CATCH_END - - bucket_count_ = new_count; - buckets_ = new_buckets; - recalculate_max_load(); - } - - //////////////////////////////////////////////////////////////////////// - // Swap and Move - - void swap_allocators(table& other, false_type) - { - boost::unordered::detail::func::ignore_unused_variable_warning(other); - - // According to 23.2.1.8, if propagate_on_container_swap is - // false the behaviour is undefined unless the allocators - // are equal. - BOOST_ASSERT(node_alloc() == other.node_alloc()); - } - - void swap_allocators(table& other, true_type) - { - allocators_.swap(other.allocators_); - } - - // Only swaps the allocators if propagate_on_container_swap - void swap(table& x) - { - set_hash_functions op1(*this, x); - set_hash_functions op2(x, *this); - - // I think swap can throw if Propagate::value, - // since the allocators' swap can throw. Not sure though. - swap_allocators(x, - boost::unordered::detail::integral_constant<bool, - allocator_traits<node_allocator>:: - propagate_on_container_swap::value>()); - - boost::swap(buckets_, x.buckets_); - boost::swap(bucket_count_, x.bucket_count_); - boost::swap(size_, x.size_); - std::swap(mlf_, x.mlf_); - std::swap(max_load_, x.max_load_); - op1.commit(); - op2.commit(); - } - - // Only call with nodes allocated with the currect allocator, or - // one that is equal to it. (Can't assert because other's - // allocators might have already been moved). - void move_buckets_from(table& other) - { - BOOST_ASSERT(!buckets_); - buckets_ = other.buckets_; - bucket_count_ = other.bucket_count_; - size_ = other.size_; - other.buckets_ = bucket_pointer(); - other.size_ = 0; - other.max_load_ = 0; - } - - //////////////////////////////////////////////////////////////////////// - // Delete/destruct - - ~table() - { - delete_buckets(); - } - - void delete_node(link_pointer prev) - { - node_pointer n = static_cast<node_pointer>(prev->next_); - prev->next_ = n->next_; - - boost::unordered::detail::func::call_destroy(node_alloc(), - n->value_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*n)); - node_allocator_traits::deallocate(node_alloc(), n, 1); - --size_; - } - - std::size_t delete_nodes(link_pointer prev, link_pointer end) - { - BOOST_ASSERT(prev->next_ != end); - - std::size_t count = 0; - - do { - delete_node(prev); - ++count; - } while (prev->next_ != end); - - return count; - } - - void delete_buckets() - { - if(buckets_) { - if (size_) delete_nodes(get_previous_start(), link_pointer()); - - if (bucket::extra_node) { - node_pointer n = static_cast<node_pointer>( - get_bucket(bucket_count_)->next_); - boost::unordered::detail::func::destroy( - boost::addressof(*n)); - node_allocator_traits::deallocate(node_alloc(), n, 1); - } - - destroy_buckets(); - buckets_ = bucket_pointer(); - max_load_ = 0; - } - - BOOST_ASSERT(!size_); - } - - void clear() - { - if (!size_) return; - - delete_nodes(get_previous_start(), link_pointer()); - clear_buckets(); - - BOOST_ASSERT(!size_); - } - - void clear_buckets() - { - bucket_pointer end = get_bucket(bucket_count_); - for(bucket_pointer it = buckets_; it != end; ++it) - { - it->next_ = node_pointer(); - } - } - - void destroy_buckets() - { - bucket_pointer end = get_bucket(bucket_count_ + 1); - for(bucket_pointer it = buckets_; it != end; ++it) - { - boost::unordered::detail::func::destroy( - boost::addressof(*it)); - } - - bucket_allocator_traits::deallocate(bucket_alloc(), - buckets_, bucket_count_ + 1); - } - - //////////////////////////////////////////////////////////////////////// - // Fix buckets after delete - // - - std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev) - { - link_pointer end = prev->next_; - std::size_t bucket_index2 = bucket_index; - - if (end) - { - bucket_index2 = hash_to_bucket( - static_cast<node_pointer>(end)->hash_); - - // If begin and end are in the same bucket, then - // there's nothing to do. - if (bucket_index == bucket_index2) return bucket_index2; - - // Update the bucket containing end. - get_bucket(bucket_index2)->next_ = prev; - } - - // Check if this bucket is now empty. - bucket_pointer this_bucket = get_bucket(bucket_index); - if (this_bucket->next_ == prev) - this_bucket->next_ = link_pointer(); - - return bucket_index2; - } - - //////////////////////////////////////////////////////////////////////// - // Assignment - - void assign(table const& x) - { - if (this != boost::addressof(x)) - { - assign(x, - boost::unordered::detail::integral_constant<bool, - allocator_traits<node_allocator>:: - propagate_on_container_copy_assignment::value>()); - } - } - - void assign(table const& x, false_type) - { - // Strong exception safety. - set_hash_functions new_func_this(*this, x); - mlf_ = x.mlf_; - recalculate_max_load(); - - if (!size_ && !x.size_) { - new_func_this.commit(); - return; - } - - if (x.size_ >= max_load_) { - create_buckets(min_buckets_for_size(x.size_)); - } - else { - clear_buckets(); - } - - new_func_this.commit(); - static_cast<table_impl*>(this)->assign_buckets(x); - } - - void assign(table const& x, true_type) - { - if (node_alloc() == x.node_alloc()) { - allocators_.assign(x.allocators_); - assign(x, false_type()); - } - else { - set_hash_functions new_func_this(*this, x); - - // Delete everything with current allocators before assigning - // the new ones. - delete_buckets(); - allocators_.assign(x.allocators_); - - // Copy over other data, all no throw. - new_func_this.commit(); - mlf_ = x.mlf_; - bucket_count_ = min_buckets_for_size(x.size_); - max_load_ = 0; - - // Finally copy the elements. - if (x.size_) { - static_cast<table_impl*>(this)->copy_buckets(x); - } - } - } - - void move_assign(table& x) - { - if (this != boost::addressof(x)) - { - move_assign(x, - boost::unordered::detail::integral_constant<bool, - allocator_traits<node_allocator>:: - propagate_on_container_move_assignment::value>()); - } - } - - void move_assign(table& x, true_type) - { - delete_buckets(); - set_hash_functions new_func_this(*this, x); - allocators_.move_assign(x.allocators_); - // No throw from here. - mlf_ = x.mlf_; - max_load_ = x.max_load_; - move_buckets_from(x); - new_func_this.commit(); - } - - void move_assign(table& x, false_type) - { - if (node_alloc() == x.node_alloc()) { - delete_buckets(); - set_hash_functions new_func_this(*this, x); - // No throw from here. - mlf_ = x.mlf_; - max_load_ = x.max_load_; - move_buckets_from(x); - new_func_this.commit(); - } - else { - set_hash_functions new_func_this(*this, x); - mlf_ = x.mlf_; - recalculate_max_load(); - - if (!size_ && !x.size_) { - new_func_this.commit(); - return; - } - - if (x.size_ >= max_load_) { - create_buckets(min_buckets_for_size(x.size_)); - } - else { - clear_buckets(); - } - - new_func_this.commit(); - static_cast<table_impl*>(this)->move_assign_buckets(x); - } - } - - // Accessors - - key_type const& get_key(value_type const& x) const - { - return extractor::extract(x); - } - - std::size_t hash(key_type const& k) const - { - return policy::apply_hash(this->hash_function(), k); - } - - // Find Node - - template <typename Key, typename Hash, typename Pred> - node_pointer generic_find_node( - Key const& k, - Hash const& hf, - Pred const& eq) const - { - return static_cast<table_impl const*>(this)-> - find_node_impl(policy::apply_hash(hf, k), k, eq); - } - - node_pointer find_node( - std::size_t key_hash, - key_type const& k) const - { - return static_cast<table_impl const*>(this)-> - find_node_impl(key_hash, k, this->key_eq()); - } - - node_pointer find_node(key_type const& k) const - { - return static_cast<table_impl const*>(this)-> - find_node_impl(hash(k), k, this->key_eq()); - } - - // Reserve and rehash - - void reserve_for_insert(std::size_t); - void rehash(std::size_t); - void reserve(std::size_t); - }; - - //////////////////////////////////////////////////////////////////////////// - // Reserve & Rehash - - // basic exception safety - template <typename Types> - inline void table<Types>::reserve_for_insert(std::size_t size) - { - if (!buckets_) { - create_buckets((std::max)(bucket_count_, - min_buckets_for_size(size))); - } - // According to the standard this should be 'size >= max_load_', - // but I think this is better, defect report filed. - else if(size > max_load_) { - std::size_t num_buckets - = min_buckets_for_size((std::max)(size, - size_ + (size_ >> 1))); - - if (num_buckets != bucket_count_) - static_cast<table_impl*>(this)->rehash_impl(num_buckets); - } - } - - // if hash function throws, basic exception safety - // strong otherwise. - - template <typename Types> - inline void table<Types>::rehash(std::size_t min_buckets) - { - using namespace std; - - if(!size_) { - delete_buckets(); - bucket_count_ = policy::new_bucket_count(min_buckets); - } - else { - min_buckets = policy::new_bucket_count((std::max)(min_buckets, - boost::unordered::detail::double_to_size(floor( - static_cast<double>(size_) / - static_cast<double>(mlf_))) + 1)); - - if(min_buckets != bucket_count_) - static_cast<table_impl*>(this)->rehash_impl(min_buckets); - } - } - - template <typename Types> - inline void table<Types>::reserve(std::size_t num_elements) - { - rehash(static_cast<std::size_t>( - std::ceil(static_cast<double>(num_elements) / mlf_))); - } -}}} - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - -#endif diff --git a/boost/unordered/detail/unique.hpp b/boost/unordered/detail/unique.hpp deleted file mode 100644 index e77b4c149e..0000000000 --- a/boost/unordered/detail/unique.hpp +++ /dev/null @@ -1,683 +0,0 @@ - -// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2011 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED - -#include <boost/config.hpp> -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include <boost/unordered/detail/extract_key.hpp> -#include <boost/throw_exception.hpp> -#include <stdexcept> - -namespace boost { namespace unordered { namespace detail { - - template <typename A, typename T> struct unique_node; - template <typename T> struct ptr_node; - template <typename Types> struct table_impl; - - template <typename A, typename T> - struct unique_node : - boost::unordered::detail::value_base<T> - { - typedef typename ::boost::unordered::detail::rebind_wrap< - A, unique_node<A, T> >::type allocator; - typedef typename ::boost::unordered::detail:: - allocator_traits<allocator>::pointer node_pointer; - typedef node_pointer link_pointer; - - link_pointer next_; - std::size_t hash_; - - unique_node() : - next_(), - hash_(0) - {} - - void init(node_pointer) - { - } - - private: - unique_node& operator=(unique_node const&); - }; - - template <typename T> - struct ptr_node : - boost::unordered::detail::ptr_bucket - { - typedef T value_type; - typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef ptr_node<T>* node_pointer; - typedef ptr_bucket* link_pointer; - - std::size_t hash_; - boost::unordered::detail::value_base<T> value_base_; - - ptr_node() : - bucket_base(), - hash_(0) - {} - - void init(node_pointer) - { - } - - void* address() { return value_base_.address(); } - value_type& value() { return value_base_.value(); } - value_type* value_ptr() { return value_base_.value_ptr(); } - - private: - ptr_node& operator=(ptr_node const&); - }; - - // If the allocator uses raw pointers use ptr_node - // Otherwise use node. - - template <typename A, typename T, typename NodePtr, typename BucketPtr> - struct pick_node2 - { - typedef boost::unordered::detail::unique_node<A, T> node; - - typedef typename boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap<A, node>::type - >::pointer node_pointer; - - typedef boost::unordered::detail::bucket<node_pointer> bucket; - typedef node_pointer link_pointer; - }; - - template <typename A, typename T> - struct pick_node2<A, T, - boost::unordered::detail::ptr_node<T>*, - boost::unordered::detail::ptr_bucket*> - { - typedef boost::unordered::detail::ptr_node<T> node; - typedef boost::unordered::detail::ptr_bucket bucket; - typedef bucket* link_pointer; - }; - - template <typename A, typename T> - struct pick_node - { - typedef typename boost::remove_const<T>::type nonconst; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap<A, - boost::unordered::detail::ptr_node<nonconst> >::type - > tentative_node_traits; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap<A, - boost::unordered::detail::ptr_bucket >::type - > tentative_bucket_traits; - - typedef pick_node2<A, nonconst, - typename tentative_node_traits::pointer, - typename tentative_bucket_traits::pointer> pick; - - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - }; - - template <typename Types> - struct table_impl : boost::unordered::detail::table<Types> - { - typedef boost::unordered::detail::table<Types> table; - typedef typename table::value_type value_type; - typedef typename table::bucket bucket; - typedef typename table::policy policy; - typedef typename table::node_pointer node_pointer; - typedef typename table::node_allocator node_allocator; - typedef typename table::node_allocator_traits node_allocator_traits; - typedef typename table::bucket_pointer bucket_pointer; - typedef typename table::link_pointer link_pointer; - typedef typename table::hasher hasher; - typedef typename table::key_equal key_equal; - typedef typename table::key_type key_type; - typedef typename table::node_constructor node_constructor; - typedef typename table::node_tmp node_tmp; - typedef typename table::extractor extractor; - typedef typename table::iterator iterator; - typedef typename table::c_iterator c_iterator; - - typedef std::pair<iterator, bool> emplace_return; - - // Constructors - - table_impl(std::size_t n, - hasher const& hf, - key_equal const& eq, - node_allocator const& a) - : table(n, hf, eq, a) - {} - - table_impl(table_impl const& x) - : table(x, node_allocator_traits:: - select_on_container_copy_construction(x.node_alloc())) - { - this->init(x); - } - - table_impl(table_impl const& x, - node_allocator const& a) - : table(x, a) - { - this->init(x); - } - - table_impl(table_impl& x, - boost::unordered::detail::move_tag m) - : table(x, m) - {} - - table_impl(table_impl& x, - node_allocator const& a, - boost::unordered::detail::move_tag m) - : table(x, a, m) - { - this->move_init(x); - } - - // Node functions. - - static inline node_pointer next_node(link_pointer n) { - return static_cast<node_pointer>(n->next_); - } - - // Accessors - - template <class Key, class Pred> - node_pointer find_node_impl( - std::size_t key_hash, - Key const& k, - Pred const& eq) const - { - std::size_t bucket_index = this->hash_to_bucket(key_hash); - node_pointer n = this->begin(bucket_index); - - for (;;) - { - if (!n) return n; - - std::size_t node_hash = n->hash_; - if (key_hash == node_hash) - { - if (eq(k, this->get_key(n->value()))) - return n; - } - else - { - if (this->hash_to_bucket(node_hash) != bucket_index) - return node_pointer(); - } - - n = next_node(n); - } - } - - std::size_t count(key_type const& k) const - { - return this->find_node(k) ? 1 : 0; - } - - value_type& at(key_type const& k) const - { - if (this->size_) { - node_pointer n = this->find_node(k); - if (n) return n->value(); - } - - boost::throw_exception( - std::out_of_range("Unable to find key in unordered_map.")); - } - - std::pair<iterator, iterator> - equal_range(key_type const& k) const - { - node_pointer n = this->find_node(k); - return std::make_pair(iterator(n), iterator(n ? next_node(n) : n)); - } - - // equals - - bool equals(table_impl const& other) const - { - if(this->size_ != other.size_) return false; - - for(node_pointer n1 = this->begin(); n1; n1 = next_node(n1)) - { - node_pointer n2 = other.find_node(other.get_key(n1->value())); - - if (!n2 || n1->value() != n2->value()) - return false; - } - - return true; - } - - // Emplace/Insert - - inline node_pointer add_node( - node_pointer n, - std::size_t key_hash) - { - n->hash_ = key_hash; - - bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); - - if (!b->next_) - { - link_pointer start_node = this->get_previous_start(); - - if (start_node->next_) { - this->get_bucket(this->hash_to_bucket( - next_node(start_node)->hash_) - )->next_ = n; - } - - b->next_ = start_node; - n->next_ = start_node->next_; - start_node->next_ = n; - } - else - { - n->next_ = b->next_->next_; - b->next_->next_ = n; - } - - ++this->size_; - return n; - } - - inline node_pointer resize_and_add_node(node_pointer n, std::size_t key_hash) - { - node_tmp b(n, this->node_alloc()); - this->reserve_for_insert(this->size_ + 1); - return this->add_node(b.release(), key_hash); - } - - value_type& operator[](key_type const& k) - { - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return pos->value(); - } - else { - return this->resize_and_add_node( - boost::unordered::detail::func::construct_node_pair(this->node_alloc(), k), - key_hash)->value(); - } - } - -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - emplace_return emplace(boost::unordered::detail::emplace_args1< - boost::unordered::detail::please_ignore_this_overload> const&) - { - BOOST_ASSERT(false); - return emplace_return(iterator(), false); - } - - iterator emplace_hint(c_iterator, - boost::unordered::detail::emplace_args1< - boost::unordered::detail::please_ignore_this_overload> const&) - { - BOOST_ASSERT(false); - return iterator(); - } -# else - emplace_return emplace( - boost::unordered::detail::please_ignore_this_overload const&) - { - BOOST_ASSERT(false); - return emplace_return(iterator(), false); - } - - iterator emplace_hint(c_iterator, - boost::unordered::detail::please_ignore_this_overload const&) - { - BOOST_ASSERT(false); - return iterator(); - } -# endif -#endif - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS) - { -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - return emplace_impl( - extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), - BOOST_UNORDERED_EMPLACE_FORWARD); -#else - return emplace_impl( - extractor::extract(args.a0, args.a1), - BOOST_UNORDERED_EMPLACE_FORWARD); -#endif - } - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - iterator emplace_hint(c_iterator hint, - BOOST_UNORDERED_EMPLACE_ARGS) - { -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - return emplace_hint_impl(hint, - extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), - BOOST_UNORDERED_EMPLACE_FORWARD); -#else - return emplace_hint_impl(hint, - extractor::extract(args.a0, args.a1), - BOOST_UNORDERED_EMPLACE_FORWARD); -#endif - } - -#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <typename A0> - emplace_return emplace( - boost::unordered::detail::emplace_args1<A0> const& args) - { - return emplace_impl(extractor::extract(args.a0), args); - } - - template <typename A0> - iterator emplace_hint(c_iterator hint, - boost::unordered::detail::emplace_args1<A0> const& args) - { - return emplace_hint_impl(hint, extractor::extract(args.a0), args); - } -#endif - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - iterator emplace_hint_impl(c_iterator hint, key_type const& k, - BOOST_UNORDERED_EMPLACE_ARGS) - { - if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { - return iterator(hint.node_); - } - else { - return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; - } - } - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - emplace_return emplace_impl(key_type const& k, - BOOST_UNORDERED_EMPLACE_ARGS) - { - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return emplace_return(iterator(pos), false); - } - else { - return emplace_return( - iterator(this->resize_and_add_node( - boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - key_hash)), - true); - } - } - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - iterator emplace_hint_impl(c_iterator hint, no_key, - BOOST_UNORDERED_EMPLACE_ARGS) - { - node_tmp b( - boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - this->node_alloc()); - key_type const& k = this->get_key(b.node_->value()); - if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { - return iterator(hint.node_); - } - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return iterator(pos); - } - else { - return iterator(this->resize_and_add_node(b.release(), key_hash)); - } - } - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) - { - node_tmp b( - boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - this->node_alloc()); - key_type const& k = this->get_key(b.node_->value()); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return emplace_return(iterator(pos), false); - } - else { - return emplace_return( - iterator(this->resize_and_add_node(b.release(), key_hash)), - true); - } - } - - //////////////////////////////////////////////////////////////////////// - // Insert range methods - // - // if hash function throws, or inserting > 1 element, basic exception - // safety strong otherwise - - template <class InputIt> - void insert_range(InputIt i, InputIt j) - { - if(i != j) - return insert_range_impl(extractor::extract(*i), i, j); - } - - template <class InputIt> - void insert_range_impl(key_type const& k, InputIt i, InputIt j) - { - insert_range_impl2(k, i, j); - - while(++i != j) { - // Note: can't use get_key as '*i' might not be value_type - it - // could be a pair with first_types as key_type without const or - // a different second_type. - // - // TODO: Might be worth storing the value_type instead of the - // key here. Could be more efficient if '*i' is expensive. Could - // be less efficient if copying the full value_type is - // expensive. - insert_range_impl2(extractor::extract(*i), i, j); - } - } - - template <class InputIt> - void insert_range_impl2(key_type const& k, InputIt i, InputIt j) - { - // No side effects in this initial code - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - - if (!pos) { - node_tmp b( - boost::unordered::detail::func::construct_node(this->node_alloc(), *i), - this->node_alloc()); - if(this->size_ + 1 > this->max_load_) - this->reserve_for_insert(this->size_ + - boost::unordered::detail::insert_size(i, j)); - this->add_node(b.release(), key_hash); - } - } - - template <class InputIt> - void insert_range_impl(no_key, InputIt i, InputIt j) - { - node_constructor a(this->node_alloc()); - - do { - if (!a.node_) { a.create_node(); } - boost::unordered::detail::func::call_construct( - a.alloc_, a.node_->value_ptr(), *i); - node_tmp b(a.release(), a.alloc_); - - key_type const& k = this->get_key(b.node_->value()); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - - if (pos) { - a.reclaim(b.release()); - } - else { - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - this->reserve_for_insert(this->size_ + 1); - this->add_node(b.release(), key_hash); - } - } while(++i != j); - } - - //////////////////////////////////////////////////////////////////////// - // Erase - // - // no throw - - std::size_t erase_key(key_type const& k) - { - if(!this->size_) return 0; - - std::size_t key_hash = this->hash(k); - std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->get_previous_start(bucket_index); - if (!prev) return 0; - - for (;;) - { - if (!prev->next_) return 0; - std::size_t node_hash = next_node(prev)->hash_; - if (this->hash_to_bucket(node_hash) != bucket_index) - return 0; - if (node_hash == key_hash && - this->key_eq()(k, this->get_key( - next_node(prev)->value()))) - break; - prev = prev->next_; - } - - link_pointer end = next_node(prev)->next_; - - std::size_t deleted_count = this->delete_nodes(prev, end); - this->fix_bucket(bucket_index, prev); - return deleted_count; - } - - iterator erase(c_iterator r) - { - BOOST_ASSERT(r.node_); - node_pointer next = next_node(r.node_); - erase_nodes(r.node_, next); - return iterator(next); - } - - iterator erase_range(c_iterator r1, c_iterator r2) - { - if (r1 == r2) return iterator(r2.node_); - erase_nodes(r1.node_, r2.node_); - return iterator(r2.node_); - } - - void erase_nodes(node_pointer i, node_pointer j) - { - std::size_t bucket_index = this->hash_to_bucket(i->hash_); - - // Find the node before i. - link_pointer prev = this->get_previous_start(bucket_index); - while(prev->next_ != i) prev = prev->next_; - - // Delete the nodes. - do { - this->delete_node(prev); - bucket_index = this->fix_bucket(bucket_index, prev); - } while (prev->next_ != j); - } - - //////////////////////////////////////////////////////////////////////// - // fill_buckets - - void copy_buckets(table const& src) { - this->create_buckets(this->bucket_count_); - - for(node_pointer n = src.begin(); n; n = next_node(n)) { - this->add_node( - boost::unordered::detail::func::construct_node( - this->node_alloc(), n->value()), n->hash_); - } - } - - void move_buckets(table const& src) { - this->create_buckets(this->bucket_count_); - - for(node_pointer n = src.begin(); n; n = next_node(n)) { - this->add_node( - boost::unordered::detail::func::construct_node( - this->node_alloc(), boost::move(n->value())), n->hash_); - } - } - - void assign_buckets(table const& src) - { - node_holder<node_allocator> holder(*this); - for(node_pointer n = src.begin(); n; n = next_node(n)) { - this->add_node(holder.copy_of(n->value()), n->hash_); - } - } - - void move_assign_buckets(table& src) - { - node_holder<node_allocator> holder(*this); - for(node_pointer n = src.begin(); n; n = next_node(n)) { - this->add_node(holder.move_copy_of(n->value()), n->hash_); - } - } - - // strong otherwise exception safety - void rehash_impl(std::size_t num_buckets) - { - BOOST_ASSERT(this->buckets_); - - this->create_buckets(num_buckets); - link_pointer prev = this->get_previous_start(); - while (prev->next_) - prev = place_in_bucket(*this, prev); - } - - // Iterate through the nodes placing them in the correct buckets. - // pre: prev->next_ is not null. - static link_pointer place_in_bucket(table& dst, link_pointer prev) - { - node_pointer n = next_node(prev); - bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_)); - - if (!b->next_) { - b->next_ = prev; - return n; - } - else { - prev->next_ = n->next_; - n->next_ = b->next_->next_; - b->next_->next_ = n; - return prev; - } - } - }; -}}} - -#endif diff --git a/boost/unordered/detail/util.hpp b/boost/unordered/detail/util.hpp deleted file mode 100644 index cd722e4410..0000000000 --- a/boost/unordered/detail/util.hpp +++ /dev/null @@ -1,249 +0,0 @@ - -// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2011 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED - -#include <boost/config.hpp> -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include <boost/type_traits/is_convertible.hpp> -#include <boost/type_traits/is_empty.hpp> -#include <boost/iterator/iterator_categories.hpp> -#include <boost/utility/enable_if.hpp> -#include <boost/detail/select_type.hpp> -#include <boost/move/move.hpp> -#include <boost/preprocessor/seq/size.hpp> -#include <boost/preprocessor/seq/enum.hpp> -#include <boost/swap.hpp> - -namespace boost { namespace unordered { namespace detail { - - static const float minimum_max_load_factor = 1e-3f; - static const std::size_t default_bucket_count = 11; - struct move_tag {}; - struct empty_emplace {}; - - namespace func { - template <class T> - inline void ignore_unused_variable_warning(T const&) {} - } - - //////////////////////////////////////////////////////////////////////////// - // iterator SFINAE - - template <typename I> - struct is_forward : - boost::is_convertible< - typename boost::iterator_traversal<I>::type, - boost::forward_traversal_tag> - {}; - - template <typename I, typename ReturnType> - struct enable_if_forward : - boost::enable_if_c< - boost::unordered::detail::is_forward<I>::value, - ReturnType> - {}; - - template <typename I, typename ReturnType> - struct disable_if_forward : - boost::disable_if_c< - boost::unordered::detail::is_forward<I>::value, - ReturnType> - {}; - - //////////////////////////////////////////////////////////////////////////// - // primes - -#define BOOST_UNORDERED_PRIMES \ - (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ - (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ - (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ - (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ - (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ - (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ - (1610612741ul)(3221225473ul)(4294967291ul) - - template<class T> struct prime_list_template - { - static std::size_t const value[]; - -#if !defined(SUNPRO_CC) - static std::ptrdiff_t const length; -#else - static std::ptrdiff_t const length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); -#endif - }; - - template<class T> - std::size_t const prime_list_template<T>::value[] = { - BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) - }; - -#if !defined(SUNPRO_CC) - template<class T> - std::ptrdiff_t const prime_list_template<T>::length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); -#endif - -#undef BOOST_UNORDERED_PRIMES - - typedef prime_list_template<std::size_t> prime_list; - - // no throw - inline std::size_t next_prime(std::size_t num) { - std::size_t const* const prime_list_begin = prime_list::value; - std::size_t const* const prime_list_end = prime_list_begin + - prime_list::length; - std::size_t const* bound = - std::lower_bound(prime_list_begin, prime_list_end, num); - if(bound == prime_list_end) - bound--; - return *bound; - } - - // no throw - inline std::size_t prev_prime(std::size_t num) { - std::size_t const* const prime_list_begin = prime_list::value; - std::size_t const* const prime_list_end = prime_list_begin + - prime_list::length; - std::size_t const* bound = - std::upper_bound(prime_list_begin,prime_list_end, num); - if(bound != prime_list_begin) - bound--; - return *bound; - } - - //////////////////////////////////////////////////////////////////////////// - // insert_size/initial_size - - template <class I> - inline std::size_t insert_size(I i, I j, typename - boost::unordered::detail::enable_if_forward<I, void*>::type = 0) - { - return static_cast<std::size_t>(std::distance(i, j)); - } - - template <class I> - inline std::size_t insert_size(I, I, typename - boost::unordered::detail::disable_if_forward<I, void*>::type = 0) - { - return 1; - } - - template <class I> - inline std::size_t initial_size(I i, I j, - std::size_t num_buckets = - boost::unordered::detail::default_bucket_count) - { - // TODO: Why +1? - return (std::max)( - boost::unordered::detail::insert_size(i, j) + 1, - num_buckets); - } - - //////////////////////////////////////////////////////////////////////////// - // compressed - - template <typename T, int Index> - struct compressed_base : private T - { - compressed_base(T const& x) : T(x) {} - compressed_base(T& x, move_tag) : T(boost::move(x)) {} - - T& get() { return *this; } - T const& get() const { return *this; } - }; - - template <typename T, int Index> - struct uncompressed_base - { - uncompressed_base(T const& x) : value_(x) {} - uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {} - - T& get() { return value_; } - T const& get() const { return value_; } - private: - T value_; - }; - - template <typename T, int Index> - struct generate_base - : boost::detail::if_true< - boost::is_empty<T>::value - >:: BOOST_NESTED_TEMPLATE then< - boost::unordered::detail::compressed_base<T, Index>, - boost::unordered::detail::uncompressed_base<T, Index> - > - {}; - - template <typename T1, typename T2> - struct compressed - : private boost::unordered::detail::generate_base<T1, 1>::type, - private boost::unordered::detail::generate_base<T2, 2>::type - { - typedef typename generate_base<T1, 1>::type base1; - typedef typename generate_base<T2, 2>::type base2; - - typedef T1 first_type; - typedef T2 second_type; - - first_type& first() { - return static_cast<base1*>(this)->get(); - } - - first_type const& first() const { - return static_cast<base1 const*>(this)->get(); - } - - second_type& second() { - return static_cast<base2*>(this)->get(); - } - - second_type const& second() const { - return static_cast<base2 const*>(this)->get(); - } - - template <typename First, typename Second> - compressed(First const& x1, Second const& x2) - : base1(x1), base2(x2) {} - - compressed(compressed const& x) - : base1(x.first()), base2(x.second()) {} - - compressed(compressed& x, move_tag m) - : base1(x.first(), m), base2(x.second(), m) {} - - void assign(compressed const& x) - { - first() = x.first(); - second() = x.second(); - } - - void move_assign(compressed& x) - { - first() = boost::move(x.first()); - second() = boost::move(x.second()); - } - - void swap(compressed& x) - { - boost::swap(first(), x.first()); - boost::swap(second(), x.second()); - } - - private: - // Prevent assignment just to make use of assign or - // move_assign explicit. - compressed& operator=(compressed const&); - }; -}}} - -#endif diff --git a/boost/unordered/unordered_map.hpp b/boost/unordered/unordered_map.hpp index 101b1c1c91..64e5b1fdf8 100644 --- a/boost/unordered/unordered_map.hpp +++ b/boost/unordered/unordered_map.hpp @@ -14,10 +14,10 @@ #pragma once #endif -#include <boost/unordered/unordered_map_fwd.hpp> -#include <boost/unordered/detail/map.hpp> +#include <boost/core/explicit_operator_bool.hpp> #include <boost/functional/hash.hpp> #include <boost/move/move.hpp> +#include <boost/unordered/detail/map.hpp> #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) #include <initializer_list> @@ -26,1817 +26,2186 @@ #if defined(BOOST_MSVC) #pragma warning(push) #if BOOST_MSVC >= 1400 -#pragma warning(disable:4396) //the inline specifier cannot be used when a - // friend declaration refers to a specialization - // of a function template +#pragma warning(disable : 4396) // the inline specifier cannot be used when a +// friend declaration refers to a specialization +// of a function template #endif #endif -namespace boost -{ -namespace unordered +namespace boost { +namespace unordered { +template <class K, class T, class H, class P, class A> class unordered_map { - template <class K, class T, class H, class P, class A> - class unordered_map - { #if defined(BOOST_UNORDERED_USE_MOVE) - BOOST_COPYABLE_AND_MOVABLE(unordered_map) -#endif - - public: - - typedef K key_type; - typedef std::pair<const K, T> value_type; - typedef T mapped_type; - typedef H hasher; - typedef P key_equal; - typedef A allocator_type; - - private: - - typedef boost::unordered::detail::map<A, K, T, H, P> types; - typedef typename types::traits allocator_traits; - typedef typename types::table table; - - public: + BOOST_COPYABLE_AND_MOVABLE(unordered_map) +#endif + template <typename, typename, typename, typename, typename> + friend class unordered_multimap; - typedef typename allocator_traits::pointer pointer; - typedef typename allocator_traits::const_pointer const_pointer; + public: + typedef K key_type; + typedef std::pair<const K, T> value_type; + typedef T mapped_type; + typedef H hasher; + typedef P key_equal; + typedef A allocator_type; - typedef value_type& reference; - typedef value_type const& const_reference; + private: + typedef boost::unordered::detail::map<A, K, T, H, P> types; + typedef typename types::value_allocator_traits value_allocator_traits; + typedef typename types::table table; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + public: + typedef typename value_allocator_traits::pointer pointer; + typedef typename value_allocator_traits::const_pointer const_pointer; - typedef typename table::cl_iterator const_local_iterator; - typedef typename table::l_iterator local_iterator; - typedef typename table::c_iterator const_iterator; - typedef typename table::iterator iterator; + typedef value_type& reference; + typedef value_type const& const_reference; - private: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; - table table_; + typedef typename table::cl_iterator const_local_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::iterator iterator; + typedef typename types::node_type node_type; + typedef typename types::insert_return_type insert_return_type; - public: + private: + table table_; - // constructors + public: + // constructors - unordered_map(); + unordered_map(); - explicit unordered_map( - size_type, - const hasher& = hasher(), - const key_equal& = key_equal(), - const allocator_type& = allocator_type()); + explicit unordered_map(size_type, const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_map( - size_type, - const allocator_type&); + explicit unordered_map(size_type, const allocator_type&); - explicit unordered_map( - size_type, - const hasher&, - const allocator_type&); + explicit unordered_map(size_type, const hasher&, const allocator_type&); - explicit unordered_map(allocator_type const&); + explicit unordered_map(allocator_type const&); - template <class InputIt> - unordered_map(InputIt, InputIt); + template <class InputIt> unordered_map(InputIt, InputIt); - template <class InputIt> - unordered_map( - InputIt, InputIt, - size_type, - const hasher& = hasher(), - const key_equal& = key_equal()); + template <class InputIt> + unordered_map(InputIt, InputIt, size_type, const hasher& = hasher(), + const key_equal& = key_equal()); - template <class InputIt> - unordered_map( - InputIt, InputIt, - size_type, - const hasher&, - const key_equal&, - const allocator_type&); + template <class InputIt> + unordered_map(InputIt, InputIt, size_type, const hasher&, const key_equal&, + const allocator_type&); - template <class InputIt> - unordered_map( - InputIt, InputIt, - size_type, - const hasher&, - const allocator_type&); + template <class InputIt> + unordered_map( + InputIt, InputIt, size_type, const hasher&, const allocator_type&); - template <class InputIt> - unordered_map( - InputIt, InputIt, - size_type, - const allocator_type&); + template <class InputIt> + unordered_map(InputIt, InputIt, size_type, const allocator_type&); - // copy/move constructors + // copy/move constructors - unordered_map(unordered_map const&); + unordered_map(unordered_map const&); - unordered_map(unordered_map const&, allocator_type const&); - unordered_map(BOOST_RV_REF(unordered_map), allocator_type const&); + unordered_map(unordered_map const&, allocator_type const&); + unordered_map(BOOST_RV_REF(unordered_map), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) - unordered_map(BOOST_RV_REF(unordered_map) other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } + unordered_map(BOOST_RV_REF(unordered_map) other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) + : table_(other.table_, boost::unordered::detail::move_tag()) + { + } #elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_map(unordered_map&& other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } + unordered_map(unordered_map&& other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) + : table_(other.table_, boost::unordered::detail::move_tag()) + { + } #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - unordered_map( - std::initializer_list<value_type>, - size_type = boost::unordered::detail::default_bucket_count, - const hasher& = hasher(), - const key_equal&l = key_equal(), - const allocator_type& = allocator_type()); - unordered_map( - std::initializer_list<value_type>, - size_type, - const hasher&, - const allocator_type&); - unordered_map( - std::initializer_list<value_type>, - size_type, - const allocator_type&); + unordered_map(std::initializer_list<value_type>, + size_type = boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), const key_equal& l = key_equal(), + const allocator_type& = allocator_type()); + unordered_map(std::initializer_list<value_type>, size_type, const hasher&, + const allocator_type&); + unordered_map( + std::initializer_list<value_type>, size_type, const allocator_type&); #endif - // Destructor + // Destructor - ~unordered_map() BOOST_NOEXCEPT; + ~unordered_map() BOOST_NOEXCEPT; - // Assign +// Assign #if defined(BOOST_UNORDERED_USE_MOVE) - unordered_map& operator=(BOOST_COPY_ASSIGN_REF(unordered_map) x) - { - table_.assign(x.table_); - return *this; - } + unordered_map& operator=(BOOST_COPY_ASSIGN_REF(unordered_map) x) + { + table_.assign(x.table_); + return *this; + } - unordered_map& operator=(BOOST_RV_REF(unordered_map) x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_map& operator=(BOOST_RV_REF(unordered_map) x) + { + table_.move_assign(x.table_); + return *this; + } #else - unordered_map& operator=(unordered_map const& x) - { - table_.assign(x.table_); - return *this; - } + unordered_map& operator=(unordered_map const& x) + { + table_.assign(x.table_); + return *this; + } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_map& operator=(unordered_map&& x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_map& operator=(unordered_map&& x) + { + table_.move_assign(x.table_); + return *this; + } #endif #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - unordered_map& operator=(std::initializer_list<value_type>); + unordered_map& operator=(std::initializer_list<value_type>); #endif - allocator_type get_allocator() const BOOST_NOEXCEPT - { - return table_.node_alloc(); - } + allocator_type get_allocator() const BOOST_NOEXCEPT + { + return table_.node_alloc(); + } - // size and capacity + // size and capacity - bool empty() const BOOST_NOEXCEPT - { - return table_.size_ == 0; - } + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - size_type size() const BOOST_NOEXCEPT - { - return table_.size_; - } + size_type size() const BOOST_NOEXCEPT { return table_.size_; } - size_type max_size() const BOOST_NOEXCEPT; + size_type max_size() const BOOST_NOEXCEPT; - // iterators + // iterators - iterator begin() BOOST_NOEXCEPT - { - return iterator(table_.begin()); - } + iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } - const_iterator begin() const BOOST_NOEXCEPT - { - return const_iterator(table_.begin()); - } + const_iterator begin() const BOOST_NOEXCEPT + { + return const_iterator(table_.begin()); + } - iterator end() BOOST_NOEXCEPT - { - return iterator(); - } + iterator end() BOOST_NOEXCEPT { return iterator(); } - const_iterator end() const BOOST_NOEXCEPT - { - return const_iterator(); - } + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(); } - const_iterator cbegin() const BOOST_NOEXCEPT - { - return const_iterator(table_.begin()); - } + const_iterator cbegin() const BOOST_NOEXCEPT + { + return const_iterator(table_.begin()); + } - const_iterator cend() const BOOST_NOEXCEPT - { - return const_iterator(); - } + const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } - // emplace + // extract + + node_type extract(const_iterator position) + { + return node_type( + table_.extract_by_iterator(position), table_.node_alloc()); + } + + node_type extract(const key_type& k) + { + return node_type(table_.extract_by_key(k), table_.node_alloc()); + } + +// emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <class... Args> - std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args) - { - return table_.emplace(boost::forward<Args>(args)...); - } + template <class... Args> + std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args) + { + return table_.emplace(boost::forward<Args>(args)...); + } - template <class... Args> - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) - { - return table_.emplace_hint(hint, boost::forward<Args>(args)...); - } + template <class... Args> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return table_.emplace_hint(hint, boost::forward<Args>(args)...); + } + + template <class... Args> + std::pair<iterator, bool> try_emplace( + key_type const& k, BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_impl(k, boost::forward<Args>(args)...); + } + + template <class... Args> + iterator try_emplace( + const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_hint_impl( + hint, k, boost::forward<Args>(args)...); + } + + template <class... Args> + std::pair<iterator, bool> try_emplace( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_impl( + boost::move(k), boost::forward<Args>(args)...); + } + + template <class... Args> + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_hint_impl( + hint, boost::move(k), boost::forward<Args>(args)...); + } #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - // 0 argument emplace requires special treatment in case - // the container is instantiated with a value type that - // doesn't have a default constructor. + // 0 argument emplace requires special treatment in case + // the container is instantiated with a value type that + // doesn't have a default constructor. - std::pair<iterator, bool> emplace( - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type()) - { - return this->emplace(boost::move(v)); - } + std::pair<iterator, bool> emplace( + boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace(boost::move(v)); + } - iterator emplace_hint(const_iterator hint, - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ) - { - return this->emplace_hint(hint, boost::move(v)); - } + iterator emplace_hint(const_iterator hint, + boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace_hint(hint, boost::move(v)); + } #endif - template <typename A0> - std::pair<iterator, bool> emplace(BOOST_FWD_REF(A0) a0) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0)) - ); - } + template <typename Key> + std::pair<iterator, bool> try_emplace(BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_impl(boost::forward<Key>(k)); + } - template <typename A0> - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0)) - ); - } + template <typename Key> + iterator try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_hint_impl(hint, boost::forward<Key>(k)); + } - template <typename A0, typename A1> - std::pair<iterator, bool> emplace( - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1)) - ); - } + template <typename A0> + std::pair<iterator, bool> emplace(BOOST_FWD_REF(A0) a0) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0, typename A1> - iterator emplace_hint(const_iterator hint, - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1)) - ); - } + template <typename A0> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0, typename A1, typename A2> - std::pair<iterator, bool> emplace( - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1, - BOOST_FWD_REF(A2) a2) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1), - boost::forward<A2>(a2)) - ); - } + template <typename A0> + std::pair<iterator, bool> try_emplace( + key_type const& k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_impl( + k, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0, typename A1, typename A2> - iterator emplace_hint(const_iterator hint, - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1, - BOOST_FWD_REF(A2) a2) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1), - boost::forward<A2>(a2)) - ); - } + template <typename A0> + iterator try_emplace( + const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_impl( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ - > \ - std::pair<iterator, bool> emplace( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ - ) \ - { \ - return table_.emplace( \ - boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ - a) \ - )); \ - } \ - \ - template < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ - > \ - iterator emplace_hint( \ - const_iterator hint, \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ - ) \ - { \ - return table_.emplace_hint(hint, \ - boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ - a) \ - )); \ - } + template <typename A0> + std::pair<iterator, bool> try_emplace( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_impl( + boost::move(k), boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_EMPLACE, _) + template <typename A0> + iterator try_emplace( + const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_impl( + hint, boost::move(k), boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } + + template <typename A0, typename A1> + std::pair<iterator, bool> emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } + + template <typename A0, typename A1> + iterator emplace_hint( + const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } + + template <typename A0, typename A1> + std::pair<iterator, bool> try_emplace( + key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_impl( + k, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } + + template <typename A0, typename A1> + iterator try_emplace(const_iterator hint, key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_impl( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } + + template <typename A0, typename A1> + std::pair<iterator, bool> try_emplace( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_impl( + boost::move(k), + boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } + + template <typename A0, typename A1> + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_impl( + hint, boost::move(k), + boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } + + template <typename A0, typename A1, typename A2> + std::pair<iterator, bool> emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } + + template <typename A0, typename A1, typename A2> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, + BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } + + template <typename A0, typename A1, typename A2> + std::pair<iterator, bool> try_emplace(key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_impl( + k, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } + + template <typename A0, typename A1, typename A2> + iterator try_emplace(const_iterator hint, key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_ + .try_emplace_impl_( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))) + .first; + } + + template <typename A0, typename A1, typename A2> + std::pair<iterator, bool> try_emplace(BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_impl( + boost::move(k), boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } + + template <typename A0, typename A1, typename A2> + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_hint_impl( + hint, boost::move(k), + boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + std::pair<iterator, bool> emplace( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.emplace(boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + iterator emplace_hint(const_iterator hint, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.emplace_hint( \ + hint, boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + std::pair<iterator, bool> try_emplace( \ + key_type const& k, BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.try_emplace_impl( \ + k, boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + iterator try_emplace(const_iterator hint, key_type const& k, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.try_emplace_hint_impl(hint, k, \ + boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ + n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + std::pair<iterator, bool> try_emplace(BOOST_RV_REF(key_type) k, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.try_emplace_impl(boost::move(k), \ + boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ + n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.try_emplace_hint_impl(hint, boost::move(k), \ + boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ + n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } + + BOOST_PP_REPEAT_FROM_TO( + 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE #endif - std::pair<iterator, bool> insert(value_type const& x) - { - return this->emplace(x); - } + std::pair<iterator, bool> insert(value_type const& x) + { + return this->emplace(x); + } - std::pair<iterator, bool> insert(BOOST_RV_REF(value_type) x) - { - return this->emplace(boost::move(x)); - } + std::pair<iterator, bool> insert(BOOST_RV_REF(value_type) x) + { + return this->emplace(boost::move(x)); + } - iterator insert(const_iterator hint, value_type const& x) - { - return this->emplace_hint(hint, x); - } + iterator insert(const_iterator hint, value_type const& x) + { + return this->emplace_hint(hint, x); + } - iterator insert(const_iterator hint, BOOST_RV_REF(value_type) x) - { - return this->emplace_hint(hint, boost::move(x)); - } + iterator insert(const_iterator hint, BOOST_RV_REF(value_type) x) + { + return this->emplace_hint(hint, boost::move(x)); + } + + template <class M> + std::pair<iterator, bool> insert_or_assign( + key_type const& k, BOOST_FWD_REF(M) obj) + { + return table_.insert_or_assign_impl(k, boost::forward<M>(obj)); + } + + template <class M> + iterator insert_or_assign( + const_iterator, key_type const& k, BOOST_FWD_REF(M) obj) + { + return table_.insert_or_assign_impl(k, boost::forward<M>(obj)).first; + } + + template <class M> + std::pair<iterator, bool> insert_or_assign( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) + { + return table_.insert_or_assign_impl( + boost::move(k), boost::forward<M>(obj)); + } + + template <class M> + iterator insert_or_assign( + const_iterator, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) + { + return table_ + .insert_or_assign_impl(boost::move(k), boost::forward<M>(obj)) + .first; + } - template <class InputIt> void insert(InputIt, InputIt); + template <class InputIt> void insert(InputIt, InputIt); #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - void insert(std::initializer_list<value_type>); + void insert(std::initializer_list<value_type>); #endif - iterator erase(const_iterator); - size_type erase(const key_type&); - iterator erase(const_iterator, const_iterator); - void quick_erase(const_iterator it) { erase(it); } - void erase_return_void(const_iterator it) { erase(it); } + insert_return_type insert(BOOST_RV_REF(node_type) np) + { + insert_return_type result; + table_.move_insert_node_type(np, result); + return boost::move(result); + } - void clear(); - void swap(unordered_map&); + iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) + { + return table_.move_insert_node_type_with_hint(hint, np); + } - // observers +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + private: + // Note: Use r-value node_type to insert. + insert_return_type insert(node_type&); + iterator insert(const_iterator, node_type& np); - hasher hash_function() const; - key_equal key_eq() const; + public: +#endif - mapped_type& operator[](const key_type&); - mapped_type& at(const key_type&); - mapped_type const& at(const key_type&) const; + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } - // lookup + void clear(); + void swap(unordered_map&); - iterator find(const key_type&); - const_iterator find(const key_type&) const; + template <typename H2, typename P2> + void merge(boost::unordered_map<K, T, H2, P2, A>& source); - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - iterator find( - CompatibleKey const&, - CompatibleHash const&, - CompatiblePredicate const&); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename H2, typename P2> + void merge(boost::unordered_map<K, T, H2, P2, A>&& source); +#endif - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - const_iterator find( - CompatibleKey const&, - CompatibleHash const&, - CompatiblePredicate const&) const; +#if BOOST_UNORDERED_INTEROPERABLE_NODES + template <typename H2, typename P2> + void merge(boost::unordered_multimap<K, T, H2, P2, A>& source); - size_type count(const key_type&) const; +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename H2, typename P2> + void merge(boost::unordered_multimap<K, T, H2, P2, A>&& source); +#endif +#endif - std::pair<iterator, iterator> - equal_range(const key_type&); - std::pair<const_iterator, const_iterator> - equal_range(const key_type&) const; + // observers - // bucket interface + hasher hash_function() const; + key_equal key_eq() const; - size_type bucket_count() const BOOST_NOEXCEPT - { - return table_.bucket_count_; - } + mapped_type& operator[](const key_type&); + mapped_type& at(const key_type&); + mapped_type const& at(const key_type&) const; - size_type max_bucket_count() const BOOST_NOEXCEPT - { - return table_.max_bucket_count(); - } + // lookup - size_type bucket_size(size_type) const; + iterator find(const key_type&); + const_iterator find(const key_type&) const; - size_type bucket(const key_type& k) const - { - return table_.hash_to_bucket(table_.hash(k)); - } + template <class CompatibleKey, class CompatibleHash, + class CompatiblePredicate> + iterator find(CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&); - local_iterator begin(size_type n) - { - return local_iterator( - table_.begin(n), n, table_.bucket_count_); - } + template <class CompatibleKey, class CompatibleHash, + class CompatiblePredicate> + const_iterator find(CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&) const; - const_local_iterator begin(size_type n) const - { - return const_local_iterator( - table_.begin(n), n, table_.bucket_count_); - } + size_type count(const key_type&) const; - local_iterator end(size_type) - { - return local_iterator(); - } + std::pair<iterator, iterator> equal_range(const key_type&); + std::pair<const_iterator, const_iterator> equal_range( + const key_type&) const; - const_local_iterator end(size_type) const - { - return const_local_iterator(); - } + // bucket interface - const_local_iterator cbegin(size_type n) const - { - return const_local_iterator( - table_.begin(n), n, table_.bucket_count_); - } + size_type bucket_count() const BOOST_NOEXCEPT + { + return table_.bucket_count_; + } - const_local_iterator cend(size_type) const - { - return const_local_iterator(); - } + size_type max_bucket_count() const BOOST_NOEXCEPT + { + return table_.max_bucket_count(); + } - // hash policy + size_type bucket_size(size_type) const; - float max_load_factor() const BOOST_NOEXCEPT - { - return table_.mlf_; - } + size_type bucket(const key_type& k) const + { + return table_.hash_to_bucket(table_.hash(k)); + } - float load_factor() const BOOST_NOEXCEPT; - void max_load_factor(float) BOOST_NOEXCEPT; - void rehash(size_type); - void reserve(size_type); + local_iterator begin(size_type n) + { + return local_iterator(table_.begin(n), n, table_.bucket_count_); + } -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==<K,T,H,P,A>( - unordered_map const&, unordered_map const&); - friend bool operator!=<K,T,H,P,A>( - unordered_map const&, unordered_map const&); -#endif - }; // class template unordered_map + const_local_iterator begin(size_type n) const + { + return const_local_iterator(table_.begin(n), n, table_.bucket_count_); + } + + local_iterator end(size_type) { return local_iterator(); } - template <class K, class T, class H, class P, class A> - class unordered_multimap + const_local_iterator end(size_type) const { return const_local_iterator(); } + + const_local_iterator cbegin(size_type n) const { -#if defined(BOOST_UNORDERED_USE_MOVE) - BOOST_COPYABLE_AND_MOVABLE(unordered_multimap) -#endif - public: + return const_local_iterator(table_.begin(n), n, table_.bucket_count_); + } - typedef K key_type; - typedef std::pair<const K, T> value_type; - typedef T mapped_type; - typedef H hasher; - typedef P key_equal; - typedef A allocator_type; + const_local_iterator cend(size_type) const + { + return const_local_iterator(); + } - private: + // hash policy - typedef boost::unordered::detail::multimap<A, K, T, H, P> types; - typedef typename types::traits allocator_traits; - typedef typename types::table table; + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - public: + float load_factor() const BOOST_NOEXCEPT; + void max_load_factor(float) BOOST_NOEXCEPT; + void rehash(size_type); + void reserve(size_type); - typedef typename allocator_traits::pointer pointer; - typedef typename allocator_traits::const_pointer const_pointer; +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + friend bool operator== + <K, T, H, P, A>(unordered_map const&, unordered_map const&); + friend bool operator!= + <K, T, H, P, A>(unordered_map const&, unordered_map const&); +#endif +}; // class template unordered_map - typedef value_type& reference; - typedef value_type const& const_reference; +template <class K, class T, class H, class P, class A> class unordered_multimap +{ +#if defined(BOOST_UNORDERED_USE_MOVE) + BOOST_COPYABLE_AND_MOVABLE(unordered_multimap) +#endif + template <typename, typename, typename, typename, typename> + friend class unordered_map; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + public: + typedef K key_type; + typedef std::pair<const K, T> value_type; + typedef T mapped_type; + typedef H hasher; + typedef P key_equal; + typedef A allocator_type; - typedef typename table::cl_iterator const_local_iterator; - typedef typename table::l_iterator local_iterator; - typedef typename table::c_iterator const_iterator; - typedef typename table::iterator iterator; + private: + typedef boost::unordered::detail::multimap<A, K, T, H, P> types; + typedef typename types::value_allocator_traits value_allocator_traits; + typedef typename types::table table; - private: + public: + typedef typename value_allocator_traits::pointer pointer; + typedef typename value_allocator_traits::const_pointer const_pointer; - table table_; - - public: + typedef value_type& reference; + typedef value_type const& const_reference; - // constructors + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; - unordered_multimap(); + typedef typename table::cl_iterator const_local_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::iterator iterator; + typedef typename types::node_type node_type; - explicit unordered_multimap( - size_type, - const hasher& = hasher(), - const key_equal& = key_equal(), - const allocator_type& = allocator_type()); + private: + table table_; - explicit unordered_multimap( - size_type, - const allocator_type&); + public: + // constructors - explicit unordered_multimap( - size_type, - const hasher&, - const allocator_type&); + unordered_multimap(); - explicit unordered_multimap(allocator_type const&); + explicit unordered_multimap(size_type, const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - template <class InputIt> - unordered_multimap(InputIt, InputIt); + explicit unordered_multimap(size_type, const allocator_type&); - template <class InputIt> - unordered_multimap( - InputIt, InputIt, - size_type, - const hasher& = hasher(), - const key_equal& = key_equal()); + explicit unordered_multimap( + size_type, const hasher&, const allocator_type&); - template <class InputIt> - unordered_multimap( - InputIt, InputIt, - size_type, - const hasher&, - const key_equal&, - const allocator_type&); + explicit unordered_multimap(allocator_type const&); - template <class InputIt> - unordered_multimap( - InputIt, InputIt, - size_type, - const hasher&, - const allocator_type&); + template <class InputIt> unordered_multimap(InputIt, InputIt); - template <class InputIt> - unordered_multimap( - InputIt, InputIt, - size_type, - const allocator_type&); + template <class InputIt> + unordered_multimap(InputIt, InputIt, size_type, const hasher& = hasher(), + const key_equal& = key_equal()); - // copy/move constructors + template <class InputIt> + unordered_multimap(InputIt, InputIt, size_type, const hasher&, + const key_equal&, const allocator_type&); + + template <class InputIt> + unordered_multimap( + InputIt, InputIt, size_type, const hasher&, const allocator_type&); + + template <class InputIt> + unordered_multimap(InputIt, InputIt, size_type, const allocator_type&); - unordered_multimap(unordered_multimap const&); + // copy/move constructors - unordered_multimap(unordered_multimap const&, allocator_type const&); - unordered_multimap(BOOST_RV_REF(unordered_multimap), allocator_type const&); + unordered_multimap(unordered_multimap const&); + + unordered_multimap(unordered_multimap const&, allocator_type const&); + unordered_multimap(BOOST_RV_REF(unordered_multimap), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) - unordered_multimap(BOOST_RV_REF(unordered_multimap) other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } + unordered_multimap(BOOST_RV_REF(unordered_multimap) other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) + : table_(other.table_, boost::unordered::detail::move_tag()) + { + } #elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multimap(unordered_multimap&& other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } + unordered_multimap(unordered_multimap&& other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) + : table_(other.table_, boost::unordered::detail::move_tag()) + { + } #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - unordered_multimap( - std::initializer_list<value_type>, - size_type = boost::unordered::detail::default_bucket_count, - const hasher& = hasher(), - const key_equal&l = key_equal(), - const allocator_type& = allocator_type()); - unordered_multimap( - std::initializer_list<value_type>, - size_type, - const hasher&, - const allocator_type&); - unordered_multimap( - std::initializer_list<value_type>, - size_type, - const allocator_type&); + unordered_multimap(std::initializer_list<value_type>, + size_type = boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), const key_equal& l = key_equal(), + const allocator_type& = allocator_type()); + unordered_multimap(std::initializer_list<value_type>, size_type, + const hasher&, const allocator_type&); + unordered_multimap( + std::initializer_list<value_type>, size_type, const allocator_type&); #endif - // Destructor + // Destructor - ~unordered_multimap() BOOST_NOEXCEPT; + ~unordered_multimap() BOOST_NOEXCEPT; - // Assign +// Assign #if defined(BOOST_UNORDERED_USE_MOVE) - unordered_multimap& operator=( - BOOST_COPY_ASSIGN_REF(unordered_multimap) x) - { - table_.assign(x.table_); - return *this; - } + unordered_multimap& operator=(BOOST_COPY_ASSIGN_REF(unordered_multimap) x) + { + table_.assign(x.table_); + return *this; + } - unordered_multimap& operator=(BOOST_RV_REF(unordered_multimap) x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_multimap& operator=(BOOST_RV_REF(unordered_multimap) x) + { + table_.move_assign(x.table_); + return *this; + } #else - unordered_multimap& operator=(unordered_multimap const& x) - { - table_.assign(x.table_); - return *this; - } + unordered_multimap& operator=(unordered_multimap const& x) + { + table_.assign(x.table_); + return *this; + } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multimap& operator=(unordered_multimap&& x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_multimap& operator=(unordered_multimap&& x) + { + table_.move_assign(x.table_); + return *this; + } #endif #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - unordered_multimap& operator=(std::initializer_list<value_type>); + unordered_multimap& operator=(std::initializer_list<value_type>); #endif - allocator_type get_allocator() const BOOST_NOEXCEPT - { - return table_.node_alloc(); - } + allocator_type get_allocator() const BOOST_NOEXCEPT + { + return table_.node_alloc(); + } - // size and capacity + // size and capacity - bool empty() const BOOST_NOEXCEPT - { - return table_.size_ == 0; - } + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - size_type size() const BOOST_NOEXCEPT - { - return table_.size_; - } + size_type size() const BOOST_NOEXCEPT { return table_.size_; } - size_type max_size() const BOOST_NOEXCEPT; + size_type max_size() const BOOST_NOEXCEPT; - // iterators + // iterators - iterator begin() BOOST_NOEXCEPT - { - return iterator(table_.begin()); - } + iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } - const_iterator begin() const BOOST_NOEXCEPT - { - return const_iterator(table_.begin()); - } + const_iterator begin() const BOOST_NOEXCEPT + { + return const_iterator(table_.begin()); + } - iterator end() BOOST_NOEXCEPT - { - return iterator(); - } + iterator end() BOOST_NOEXCEPT { return iterator(); } - const_iterator end() const BOOST_NOEXCEPT - { - return const_iterator(); - } + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(); } - const_iterator cbegin() const BOOST_NOEXCEPT - { - return const_iterator(table_.begin()); - } + const_iterator cbegin() const BOOST_NOEXCEPT + { + return const_iterator(table_.begin()); + } - const_iterator cend() const BOOST_NOEXCEPT - { - return const_iterator(); - } + const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } + + // extract + + node_type extract(const_iterator position) + { + return node_type( + table_.extract_by_iterator(position), table_.node_alloc()); + } - // emplace + node_type extract(const key_type& k) + { + return node_type(table_.extract_by_key(k), table_.node_alloc()); + } + +// emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <class... Args> - iterator emplace(BOOST_FWD_REF(Args)... args) - { - return table_.emplace(boost::forward<Args>(args)...); - } + template <class... Args> iterator emplace(BOOST_FWD_REF(Args)... args) + { + return table_.emplace(boost::forward<Args>(args)...); + } - template <class... Args> - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) - { - return table_.emplace_hint(hint, boost::forward<Args>(args)...); - } + template <class... Args> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return table_.emplace_hint(hint, boost::forward<Args>(args)...); + } #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - // 0 argument emplace requires special treatment in case - // the container is instantiated with a value type that - // doesn't have a default constructor. + // 0 argument emplace requires special treatment in case + // the container is instantiated with a value type that + // doesn't have a default constructor. - iterator emplace( - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type()) - { - return this->emplace(boost::move(v)); - } + iterator emplace(boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace(boost::move(v)); + } - iterator emplace_hint(const_iterator hint, - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ) - { - return this->emplace_hint(hint, boost::move(v)); - } + iterator emplace_hint(const_iterator hint, + boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace_hint(hint, boost::move(v)); + } #endif - template <typename A0> - iterator emplace(BOOST_FWD_REF(A0) a0) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0)) - ); - } + template <typename A0> iterator emplace(BOOST_FWD_REF(A0) a0) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0> - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0)) - ); - } + template <typename A0> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0, typename A1> - iterator emplace( - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1)) - ); - } + template <typename A0, typename A1> + iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } - template <typename A0, typename A1> - iterator emplace_hint(const_iterator hint, - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1)) - ); - } + template <typename A0, typename A1> + iterator emplace_hint( + const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } - template <typename A0, typename A1, typename A2> - iterator emplace( - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1, - BOOST_FWD_REF(A2) a2) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1), - boost::forward<A2>(a2)) - ); - } + template <typename A0, typename A1, typename A2> + iterator emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } - template <typename A0, typename A1, typename A2> - iterator emplace_hint(const_iterator hint, - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1, - BOOST_FWD_REF(A2) a2) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1), - boost::forward<A2>(a2)) - ); - } + template <typename A0, typename A1, typename A2> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, + BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ - > \ - iterator emplace( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ - ) \ - { \ - return table_.emplace( \ - boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ - a) \ - )); \ - } \ - \ - template < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ - > \ - iterator emplace_hint( \ - const_iterator hint, \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ - ) \ - { \ - return table_.emplace_hint(hint, \ - boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ - a) \ - )); \ - } +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.emplace(boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + iterator emplace_hint(const_iterator hint, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.emplace_hint( \ + hint, boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_EMPLACE, _) + BOOST_PP_REPEAT_FROM_TO( + 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE #endif - iterator insert(value_type const& x) - { - return this->emplace(x); - } + iterator insert(value_type const& x) { return this->emplace(x); } - iterator insert(BOOST_RV_REF(value_type) x) - { - return this->emplace(boost::move(x)); - } + iterator insert(BOOST_RV_REF(value_type) x) + { + return this->emplace(boost::move(x)); + } - iterator insert(const_iterator hint, value_type const& x) - { - return this->emplace_hint(hint, x); - } + iterator insert(const_iterator hint, value_type const& x) + { + return this->emplace_hint(hint, x); + } - iterator insert(const_iterator hint, BOOST_RV_REF(value_type) x) - { - return this->emplace_hint(hint, boost::move(x)); - } + iterator insert(const_iterator hint, BOOST_RV_REF(value_type) x) + { + return this->emplace_hint(hint, boost::move(x)); + } - template <class InputIt> void insert(InputIt, InputIt); + template <class InputIt> void insert(InputIt, InputIt); #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - void insert(std::initializer_list<value_type>); + void insert(std::initializer_list<value_type>); #endif - iterator erase(const_iterator); - size_type erase(const key_type&); - iterator erase(const_iterator, const_iterator); - void quick_erase(const_iterator it) { erase(it); } - void erase_return_void(const_iterator it) { erase(it); } - - void clear(); - void swap(unordered_multimap&); - - // observers - - hasher hash_function() const; - key_equal key_eq() const; - - // lookup - - iterator find(const key_type&); - const_iterator find(const key_type&) const; + iterator insert(BOOST_RV_REF(node_type) np) + { + return table_.move_insert_node_type(np); + } - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - iterator find( - CompatibleKey const&, - CompatibleHash const&, - CompatiblePredicate const&); + iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) + { + return table_.move_insert_node_type_with_hint(hint, np); + } - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - const_iterator find( - CompatibleKey const&, - CompatibleHash const&, - CompatiblePredicate const&) const; +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + private: + // Note: Use r-value node_type to insert. + iterator insert(node_type&); + iterator insert(const_iterator, node_type& np); - size_type count(const key_type&) const; + public: +#endif - std::pair<iterator, iterator> - equal_range(const key_type&); - std::pair<const_iterator, const_iterator> - equal_range(const key_type&) const; + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } - // bucket interface + void clear(); + void swap(unordered_multimap&); - size_type bucket_count() const BOOST_NOEXCEPT - { - return table_.bucket_count_; - } + template <typename H2, typename P2> + void merge(boost::unordered_multimap<K, T, H2, P2, A>& source); - size_type max_bucket_count() const BOOST_NOEXCEPT - { - return table_.max_bucket_count(); - } - - size_type bucket_size(size_type) const; - - size_type bucket(const key_type& k) const - { - return table_.hash_to_bucket(table_.hash(k)); - } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename H2, typename P2> + void merge(boost::unordered_multimap<K, T, H2, P2, A>&& source); +#endif - local_iterator begin(size_type n) - { - return local_iterator( - table_.begin(n), n, table_.bucket_count_); - } +#if BOOST_UNORDERED_INTEROPERABLE_NODES + template <typename H2, typename P2> + void merge(boost::unordered_map<K, T, H2, P2, A>& source); - const_local_iterator begin(size_type n) const - { - return const_local_iterator( - table_.begin(n), n, table_.bucket_count_); - } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename H2, typename P2> + void merge(boost::unordered_map<K, T, H2, P2, A>&& source); +#endif +#endif - local_iterator end(size_type) - { - return local_iterator(); - } + // observers - const_local_iterator end(size_type) const - { - return const_local_iterator(); - } + hasher hash_function() const; + key_equal key_eq() const; - const_local_iterator cbegin(size_type n) const - { - return const_local_iterator( - table_.begin(n), n, table_.bucket_count_); - } + // lookup - const_local_iterator cend(size_type) const - { - return const_local_iterator(); - } + iterator find(const key_type&); + const_iterator find(const key_type&) const; - // hash policy + template <class CompatibleKey, class CompatibleHash, + class CompatiblePredicate> + iterator find(CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&); - float max_load_factor() const BOOST_NOEXCEPT - { - return table_.mlf_; - } + template <class CompatibleKey, class CompatibleHash, + class CompatiblePredicate> + const_iterator find(CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&) const; - float load_factor() const BOOST_NOEXCEPT; - void max_load_factor(float) BOOST_NOEXCEPT; - void rehash(size_type); - void reserve(size_type); + size_type count(const key_type&) const; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==<K,T,H,P,A>( - unordered_multimap const&, unordered_multimap const&); - friend bool operator!=<K,T,H,P,A>( - unordered_multimap const&, unordered_multimap const&); -#endif - }; // class template unordered_multimap + std::pair<iterator, iterator> equal_range(const key_type&); + std::pair<const_iterator, const_iterator> equal_range( + const key_type&) const; -//////////////////////////////////////////////////////////////////////////////// + // bucket interface - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map() - : table_(boost::unordered::detail::default_bucket_count, hasher(), - key_equal(), allocator_type()) + size_type bucket_count() const BOOST_NOEXCEPT { + return table_.bucket_count_; } - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - size_type n, const hasher &hf, const key_equal &eql, - const allocator_type &a) - : table_(n, hf, eql, a) + size_type max_bucket_count() const BOOST_NOEXCEPT { + return table_.max_bucket_count(); } - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - size_type n, const allocator_type &a) - : table_(n, hasher(), key_equal(), a) - { - } + size_type bucket_size(size_type) const; - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - size_type n, const hasher &hf, const allocator_type &a) - : table_(n, hf, key_equal(), a) + size_type bucket(const key_type& k) const { + return table_.hash_to_bucket(table_.hash(k)); } - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map(allocator_type const& a) - : table_(boost::unordered::detail::default_bucket_count, - hasher(), key_equal(), a) + local_iterator begin(size_type n) { + return local_iterator(table_.begin(n), n, table_.bucket_count_); } - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - unordered_map const& other, allocator_type const& a) - : table_(other.table_, a) + const_local_iterator begin(size_type n) const { + return const_local_iterator(table_.begin(n), n, table_.bucket_count_); } - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_map<K,T,H,P,A>::unordered_map(InputIt f, InputIt l) - : table_(boost::unordered::detail::initial_size(f, l), - hasher(), key_equal(), allocator_type()) - { - table_.insert_range(f, l); - } + local_iterator end(size_type) { return local_iterator(); } - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_map<K,T,H,P,A>::unordered_map( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, eql, allocator_type()) - { - table_.insert_range(f, l); - } - - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_map<K,T,H,P,A>::unordered_map( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) - { - table_.insert_range(f, l); - } - - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_map<K,T,H,P,A>::unordered_map( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, key_equal(), a) + const_local_iterator end(size_type) const { return const_local_iterator(); } + + const_local_iterator cbegin(size_type n) const { - table_.insert_range(f, l); + return const_local_iterator(table_.begin(n), n, table_.bucket_count_); } - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_map<K,T,H,P,A>::unordered_map( - InputIt f, InputIt l, - size_type n, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hasher(), key_equal(), a) + const_local_iterator cend(size_type) const { - table_.insert_range(f, l); + return const_local_iterator(); } - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::~unordered_map() BOOST_NOEXCEPT {} + // hash policy - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - unordered_map const& other) - : table_(other.table_) - { - } + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - BOOST_RV_REF(unordered_map) other, allocator_type const& a) - : table_(other.table_, a, boost::unordered::detail::move_tag()) - { - } + float load_factor() const BOOST_NOEXCEPT; + void max_load_factor(float) BOOST_NOEXCEPT; + void rehash(size_type); + void reserve(size_type); -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + friend bool operator== + <K, T, H, P, A>(unordered_multimap const&, unordered_multimap const&); + friend bool operator!= + <K, T, H, P, A>(unordered_multimap const&, unordered_multimap const&); +#endif +}; // class template unordered_multimap - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - std::initializer_list<value_type> list, size_type n, - const hasher &hf, const key_equal &eql, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, eql, a) - { - table_.insert_range(list.begin(), list.end()); - } +//////////////////////////////////////////////////////////////////////////////// - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - std::initializer_list<value_type> list, size_type n, - const hasher &hf, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map() + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), allocator_type()) +{ +} - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::unordered_map( - std::initializer_list<value_type> list, size_type n, - const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hasher(), key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map(size_type n, const hasher& hf, + const key_equal& eql, const allocator_type& a) + : table_(n, hf, eql, a) +{ +} - template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>& unordered_map<K,T,H,P,A>::operator=( - std::initializer_list<value_type> list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map( + size_type n, const allocator_type& a) + : table_(n, hasher(), key_equal(), a) +{ +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map( + size_type n, const hasher& hf, const allocator_type& a) + : table_(n, hf, key_equal(), a) +{ +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map(allocator_type const& a) + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), a) +{ +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map( + unordered_map const& other, allocator_type const& a) + : table_(other.table_, a) +{ +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_map<K, T, H, P, A>::unordered_map(InputIt f, InputIt l) + : table_(boost::unordered::detail::initial_size(f, l), hasher(), + key_equal(), allocator_type()) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_map<K, T, H, P, A>::unordered_map( + InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, + allocator_type()) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_map<K, T, H, P, A>::unordered_map(InputIt f, InputIt l, size_type n, + const hasher& hf, const key_equal& eql, const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_map<K, T, H, P, A>::unordered_map(InputIt f, InputIt l, size_type n, + const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(f, l, n), hf, key_equal(), a) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_map<K, T, H, P, A>::unordered_map( + InputIt f, InputIt l, size_type n, const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hasher(), + key_equal(), a) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::~unordered_map() BOOST_NOEXCEPT +{ +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map(unordered_map const& other) + : table_(other.table_) +{ +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map( + BOOST_RV_REF(unordered_map) other, allocator_type const& a) + : table_(other.table_, a, boost::unordered::detail::move_tag()) +{ +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map( + std::initializer_list<value_type> list, size_type n, const hasher& hf, + const key_equal& eql, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hf, eql, a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map( + std::initializer_list<value_type> list, size_type n, const hasher& hf, + const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hf, key_equal(), a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>::unordered_map( + std::initializer_list<value_type> list, size_type n, + const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hasher(), key_equal(), a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class K, class T, class H, class P, class A> +unordered_map<K, T, H, P, A>& unordered_map<K, T, H, P, A>::operator=( + std::initializer_list<value_type> list) +{ + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; +} #endif - // size and capacity +// size and capacity - template <class K, class T, class H, class P, class A> - std::size_t unordered_map<K,T,H,P,A>::max_size() const BOOST_NOEXCEPT - { - return table_.max_size(); - } +template <class K, class T, class H, class P, class A> +std::size_t unordered_map<K, T, H, P, A>::max_size() const BOOST_NOEXCEPT +{ + return table_.max_size(); +} - // modifiers +// modifiers - template <class K, class T, class H, class P, class A> - template <class InputIt> - void unordered_map<K,T,H,P,A>::insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } +template <class K, class T, class H, class P, class A> +template <class InputIt> +void unordered_map<K, T, H, P, A>::insert(InputIt first, InputIt last) +{ + table_.insert_range(first, last); +} #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - template <class K, class T, class H, class P, class A> - void unordered_map<K,T,H,P,A>::insert( - std::initializer_list<value_type> list) - { - table_.insert_range(list.begin(), list.end()); - } +template <class K, class T, class H, class P, class A> +void unordered_map<K, T, H, P, A>::insert( + std::initializer_list<value_type> list) +{ + table_.insert_range(list.begin(), list.end()); +} #endif - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::iterator - unordered_map<K,T,H,P,A>::erase(const_iterator position) - { - return table_.erase(position); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::iterator +unordered_map<K, T, H, P, A>::erase(const_iterator position) +{ + return table_.erase(position); +} - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::size_type - unordered_map<K,T,H,P,A>::erase(const key_type& k) - { - return table_.erase_key(k); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::size_type +unordered_map<K, T, H, P, A>::erase(const key_type& k) +{ + return table_.erase_key(k); +} - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::iterator - unordered_map<K,T,H,P,A>::erase( - const_iterator first, const_iterator last) - { - return table_.erase_range(first, last); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::iterator +unordered_map<K, T, H, P, A>::erase(const_iterator first, const_iterator last) +{ + return table_.erase_range(first, last); +} - template <class K, class T, class H, class P, class A> - void unordered_map<K,T,H,P,A>::clear() - { - table_.clear(); - } +template <class K, class T, class H, class P, class A> +void unordered_map<K, T, H, P, A>::clear() +{ + table_.clear(); +} - template <class K, class T, class H, class P, class A> - void unordered_map<K,T,H,P,A>::swap(unordered_map& other) - { - table_.swap(other.table_); - } +template <class K, class T, class H, class P, class A> +void unordered_map<K, T, H, P, A>::swap(unordered_map& other) +{ + table_.swap(other.table_); +} - // observers +template <class K, class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_map<K, T, H, P, A>::merge( + boost::unordered_map<K, T, H2, P2, A>& source) +{ + table_.merge_impl(source.table_); +} - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::hasher - unordered_map<K,T,H,P,A>::hash_function() const - { - return table_.hash_function(); - } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template <class K, class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_map<K, T, H, P, A>::merge( + boost::unordered_map<K, T, H2, P2, A>&& source) +{ + table_.merge_impl(source.table_); +} +#endif - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::key_equal - unordered_map<K,T,H,P,A>::key_eq() const - { - return table_.key_eq(); - } +#if BOOST_UNORDERED_INTEROPERABLE_NODES +template <class K, class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_map<K, T, H, P, A>::merge( + boost::unordered_multimap<K, T, H2, P2, A>& source) +{ + table_.merge_impl(source.table_); +} - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::mapped_type& - unordered_map<K,T,H,P,A>::operator[](const key_type &k) - { - return table_[k].second; - } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template <class K, class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_map<K, T, H, P, A>::merge( + boost::unordered_multimap<K, T, H2, P2, A>&& source) +{ + table_.merge_impl(source.table_); +} +#endif +#endif - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::mapped_type& - unordered_map<K,T,H,P,A>::at(const key_type& k) - { - return table_.at(k).second; - } +// observers - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::mapped_type const& - unordered_map<K,T,H,P,A>::at(const key_type& k) const - { - return table_.at(k).second; - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::hasher +unordered_map<K, T, H, P, A>::hash_function() const +{ + return table_.hash_function(); +} - // lookup +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::key_equal +unordered_map<K, T, H, P, A>::key_eq() const +{ + return table_.key_eq(); +} - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::iterator - unordered_map<K,T,H,P,A>::find(const key_type& k) - { - return iterator(table_.find_node(k)); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::mapped_type& + unordered_map<K, T, H, P, A>::operator[](const key_type& k) +{ + return table_.try_emplace_impl(k).first->second; +} - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::const_iterator - unordered_map<K,T,H,P,A>::find(const key_type& k) const - { - return const_iterator(table_.find_node(k)); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::mapped_type& +unordered_map<K, T, H, P, A>::at(const key_type& k) +{ + return table_.at(k).second; +} - template <class K, class T, class H, class P, class A> - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - typename unordered_map<K,T,H,P,A>::iterator - unordered_map<K,T,H,P,A>::find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) - { - return iterator(table_.generic_find_node(k, hash, eq)); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::mapped_type const& +unordered_map<K, T, H, P, A>::at(const key_type& k) const +{ + return table_.at(k).second; +} - template <class K, class T, class H, class P, class A> - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - typename unordered_map<K,T,H,P,A>::const_iterator - unordered_map<K,T,H,P,A>::find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const - { - return const_iterator(table_.generic_find_node(k, hash, eq)); - } +// lookup - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::size_type - unordered_map<K,T,H,P,A>::count(const key_type& k) const - { - return table_.count(k); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::iterator +unordered_map<K, T, H, P, A>::find(const key_type& k) +{ + return iterator(table_.find_node(k)); +} - template <class K, class T, class H, class P, class A> - std::pair< - typename unordered_map<K,T,H,P,A>::iterator, - typename unordered_map<K,T,H,P,A>::iterator> - unordered_map<K,T,H,P,A>::equal_range(const key_type& k) - { - return table_.equal_range(k); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::const_iterator +unordered_map<K, T, H, P, A>::find(const key_type& k) const +{ + return const_iterator(table_.find_node(k)); +} + +template <class K, class T, class H, class P, class A> +template <class CompatibleKey, class CompatibleHash, class CompatiblePredicate> +typename unordered_map<K, T, H, P, A>::iterator +unordered_map<K, T, H, P, A>::find(CompatibleKey const& k, + CompatibleHash const& hash, CompatiblePredicate const& eq) +{ + return iterator(table_.generic_find_node(k, hash, eq)); +} + +template <class K, class T, class H, class P, class A> +template <class CompatibleKey, class CompatibleHash, class CompatiblePredicate> +typename unordered_map<K, T, H, P, A>::const_iterator +unordered_map<K, T, H, P, A>::find(CompatibleKey const& k, + CompatibleHash const& hash, CompatiblePredicate const& eq) const +{ + return const_iterator(table_.generic_find_node(k, hash, eq)); +} - template <class K, class T, class H, class P, class A> - std::pair< - typename unordered_map<K,T,H,P,A>::const_iterator, - typename unordered_map<K,T,H,P,A>::const_iterator> - unordered_map<K,T,H,P,A>::equal_range(const key_type& k) const - { - return table_.equal_range(k); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::size_type +unordered_map<K, T, H, P, A>::count(const key_type& k) const +{ + return table_.count(k); +} - template <class K, class T, class H, class P, class A> - typename unordered_map<K,T,H,P,A>::size_type - unordered_map<K,T,H,P,A>::bucket_size(size_type n) const - { - return table_.bucket_size(n); - } +template <class K, class T, class H, class P, class A> +std::pair<typename unordered_map<K, T, H, P, A>::iterator, + typename unordered_map<K, T, H, P, A>::iterator> +unordered_map<K, T, H, P, A>::equal_range(const key_type& k) +{ + return table_.equal_range(k); +} - // hash policy +template <class K, class T, class H, class P, class A> +std::pair<typename unordered_map<K, T, H, P, A>::const_iterator, + typename unordered_map<K, T, H, P, A>::const_iterator> +unordered_map<K, T, H, P, A>::equal_range(const key_type& k) const +{ + return table_.equal_range(k); +} - template <class K, class T, class H, class P, class A> - float unordered_map<K,T,H,P,A>::load_factor() const BOOST_NOEXCEPT - { - return table_.load_factor(); - } +template <class K, class T, class H, class P, class A> +typename unordered_map<K, T, H, P, A>::size_type +unordered_map<K, T, H, P, A>::bucket_size(size_type n) const +{ + return table_.bucket_size(n); +} - template <class K, class T, class H, class P, class A> - void unordered_map<K,T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT - { - table_.max_load_factor(m); - } +// hash policy - template <class K, class T, class H, class P, class A> - void unordered_map<K,T,H,P,A>::rehash(size_type n) - { - table_.rehash(n); - } +template <class K, class T, class H, class P, class A> +float unordered_map<K, T, H, P, A>::load_factor() const BOOST_NOEXCEPT +{ + return table_.load_factor(); +} - template <class K, class T, class H, class P, class A> - void unordered_map<K,T,H,P,A>::reserve(size_type n) - { - table_.reserve(n); - } +template <class K, class T, class H, class P, class A> +void unordered_map<K, T, H, P, A>::max_load_factor(float m) BOOST_NOEXCEPT +{ + table_.max_load_factor(m); +} - template <class K, class T, class H, class P, class A> - inline bool operator==( - unordered_map<K,T,H,P,A> const& m1, - unordered_map<K,T,H,P,A> const& m2) - { +template <class K, class T, class H, class P, class A> +void unordered_map<K, T, H, P, A>::rehash(size_type n) +{ + table_.rehash(n); +} + +template <class K, class T, class H, class P, class A> +void unordered_map<K, T, H, P, A>::reserve(size_type n) +{ + table_.reserve(n); +} + +template <class K, class T, class H, class P, class A> +inline bool operator==(unordered_map<K, T, H, P, A> const& m1, + unordered_map<K, T, H, P, A> const& m2) +{ #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_map<K,T,H,P,A> x; }; + struct dummy + { + unordered_map<K, T, H, P, A> x; + }; #endif - return m1.table_.equals(m2.table_); - } + return m1.table_.equals(m2.table_); +} - template <class K, class T, class H, class P, class A> - inline bool operator!=( - unordered_map<K,T,H,P,A> const& m1, - unordered_map<K,T,H,P,A> const& m2) - { +template <class K, class T, class H, class P, class A> +inline bool operator!=(unordered_map<K, T, H, P, A> const& m1, + unordered_map<K, T, H, P, A> const& m2) +{ #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_map<K,T,H,P,A> x; }; + struct dummy + { + unordered_map<K, T, H, P, A> x; + }; #endif - return !m1.table_.equals(m2.table_); - } + return !m1.table_.equals(m2.table_); +} - template <class K, class T, class H, class P, class A> - inline void swap( - unordered_map<K,T,H,P,A> &m1, - unordered_map<K,T,H,P,A> &m2) - { +template <class K, class T, class H, class P, class A> +inline void swap( + unordered_map<K, T, H, P, A>& m1, unordered_map<K, T, H, P, A>& m2) +{ #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_map<K,T,H,P,A> x; }; + struct dummy + { + unordered_map<K, T, H, P, A> x; + }; #endif - m1.swap(m2); - } + m1.swap(m2); +} //////////////////////////////////////////////////////////////////////////////// - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap() - : table_(boost::unordered::detail::default_bucket_count, hasher(), - key_equal(), allocator_type()) - { - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap() + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), allocator_type()) +{ +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - size_type n, const hasher &hf, const key_equal &eql, - const allocator_type &a) - : table_(n, hf, eql, a) - { - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap(size_type n, + const hasher& hf, const key_equal& eql, const allocator_type& a) + : table_(n, hf, eql, a) +{ +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - size_type n, const allocator_type &a) - : table_(n, hasher(), key_equal(), a) - { - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + size_type n, const allocator_type& a) + : table_(n, hasher(), key_equal(), a) +{ +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - size_type n, const hasher &hf, const allocator_type &a) - : table_(n, hf, key_equal(), a) - { - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + size_type n, const hasher& hf, const allocator_type& a) + : table_(n, hf, key_equal(), a) +{ +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap(allocator_type const& a) - : table_(boost::unordered::detail::default_bucket_count, - hasher(), key_equal(), a) - { - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap(allocator_type const& a) + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), a) +{ +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - unordered_multimap const& other, allocator_type const& a) - : table_(other.table_, a) - { - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + unordered_multimap const& other, allocator_type const& a) + : table_(other.table_, a) +{ +} - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_multimap<K,T,H,P,A>::unordered_multimap(InputIt f, InputIt l) - : table_(boost::unordered::detail::initial_size(f, l), - hasher(), key_equal(), allocator_type()) - { - table_.insert_range(f, l); - } +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_multimap<K, T, H, P, A>::unordered_multimap(InputIt f, InputIt l) + : table_(boost::unordered::detail::initial_size(f, l), hasher(), + key_equal(), allocator_type()) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, + allocator_type()) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_multimap<K, T, H, P, A>::unordered_multimap(InputIt f, InputIt l, + size_type n, const hasher& hf, const key_equal& eql, + const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_multimap<K, T, H, P, A>::unordered_multimap(InputIt f, InputIt l, + size_type n, const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(f, l, n), hf, key_equal(), a) +{ + table_.insert_range(f, l); +} + +template <class K, class T, class H, class P, class A> +template <class InputIt> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + InputIt f, InputIt l, size_type n, const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hasher(), + key_equal(), a) +{ + table_.insert_range(f, l); +} - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, eql, allocator_type()) - { - table_.insert_range(f, l); - } - - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) - { - table_.insert_range(f, l); - } - - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, key_equal(), a) - { - table_.insert_range(f, l); - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::~unordered_multimap() BOOST_NOEXCEPT +{ +} - template <class K, class T, class H, class P, class A> - template <class InputIt> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - InputIt f, InputIt l, - size_type n, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hasher(), key_equal(), a) - { - table_.insert_range(f, l); - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + unordered_multimap const& other) + : table_(other.table_) +{ +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::~unordered_multimap() BOOST_NOEXCEPT {} +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + BOOST_RV_REF(unordered_multimap) other, allocator_type const& a) + : table_(other.table_, a, boost::unordered::detail::move_tag()) +{ +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - unordered_multimap const& other) - : table_(other.table_) - { - } +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - BOOST_RV_REF(unordered_multimap) other, allocator_type const& a) - : table_(other.table_, a, boost::unordered::detail::move_tag()) - { - } +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + std::initializer_list<value_type> list, size_type n, const hasher& hf, + const key_equal& eql, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hf, eql, a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + std::initializer_list<value_type> list, size_type n, const hasher& hf, + const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hf, key_equal(), a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>::unordered_multimap( + std::initializer_list<value_type> list, size_type n, + const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hasher(), key_equal(), a) +{ + table_.insert_range(list.begin(), list.end()); +} -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +template <class K, class T, class H, class P, class A> +unordered_multimap<K, T, H, P, A>& unordered_multimap<K, T, H, P, A>::operator=( + std::initializer_list<value_type> list) +{ + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - std::initializer_list<value_type> list, size_type n, - const hasher &hf, const key_equal &eql, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, eql, a) - { - table_.insert_range(list.begin(), list.end()); - } +#endif - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - std::initializer_list<value_type> list, size_type n, - const hasher &hf, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } +// size and capacity - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::unordered_multimap( - std::initializer_list<value_type> list, size_type n, - const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hasher(), key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } +template <class K, class T, class H, class P, class A> +std::size_t unordered_multimap<K, T, H, P, A>::max_size() const BOOST_NOEXCEPT +{ + return table_.max_size(); +} - template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>& unordered_multimap<K,T,H,P,A>::operator=( - std::initializer_list<value_type> list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } +// modifiers +template <class K, class T, class H, class P, class A> +template <class InputIt> +void unordered_multimap<K, T, H, P, A>::insert(InputIt first, InputIt last) +{ + table_.insert_range(first, last); +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +template <class K, class T, class H, class P, class A> +void unordered_multimap<K, T, H, P, A>::insert( + std::initializer_list<value_type> list) +{ + table_.insert_range(list.begin(), list.end()); +} #endif - // size and capacity +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::iterator +unordered_multimap<K, T, H, P, A>::erase(const_iterator position) +{ + return table_.erase(position); +} - template <class K, class T, class H, class P, class A> - std::size_t unordered_multimap<K,T,H,P,A>::max_size() const BOOST_NOEXCEPT - { - return table_.max_size(); - } +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::size_type +unordered_multimap<K, T, H, P, A>::erase(const key_type& k) +{ + return table_.erase_key(k); +} - // modifiers +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::iterator +unordered_multimap<K, T, H, P, A>::erase( + const_iterator first, const_iterator last) +{ + return table_.erase_range(first, last); +} - template <class K, class T, class H, class P, class A> - template <class InputIt> - void unordered_multimap<K,T,H,P,A>::insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); +template <class K, class T, class H, class P, class A> +void unordered_multimap<K, T, H, P, A>::clear() +{ + table_.clear(); +} + +template <class K, class T, class H, class P, class A> +void unordered_multimap<K, T, H, P, A>::swap(unordered_multimap& other) +{ + table_.swap(other.table_); +} + +// observers + +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::hasher +unordered_multimap<K, T, H, P, A>::hash_function() const +{ + return table_.hash_function(); +} + +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::key_equal +unordered_multimap<K, T, H, P, A>::key_eq() const +{ + return table_.key_eq(); +} + +template <class K, class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_multimap<K, T, H, P, A>::merge( + boost::unordered_multimap<K, T, H2, P2, A>& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); } +} -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - template <class K, class T, class H, class P, class A> - void unordered_multimap<K,T,H,P,A>::insert( - std::initializer_list<value_type> list) - { - table_.insert_range(list.begin(), list.end()); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template <class K, class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_multimap<K, T, H, P, A>::merge( + boost::unordered_multimap<K, T, H2, P2, A>&& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); } +} #endif - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::iterator - unordered_multimap<K,T,H,P,A>::erase(const_iterator position) - { - return table_.erase(position); +#if BOOST_UNORDERED_INTEROPERABLE_NODES +template <class K, class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_multimap<K, T, H, P, A>::merge( + boost::unordered_map<K, T, H2, P2, A>& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); } +} - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::size_type - unordered_multimap<K,T,H,P,A>::erase(const key_type& k) - { - return table_.erase_key(k); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template <class K, class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_multimap<K, T, H, P, A>::merge( + boost::unordered_map<K, T, H2, P2, A>&& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); } +} +#endif +#endif - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::iterator - unordered_multimap<K,T,H,P,A>::erase( - const_iterator first, const_iterator last) - { - return table_.erase_range(first, last); - } +// lookup - template <class K, class T, class H, class P, class A> - void unordered_multimap<K,T,H,P,A>::clear() - { - table_.clear(); - } +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::iterator +unordered_multimap<K, T, H, P, A>::find(const key_type& k) +{ + return iterator(table_.find_node(k)); +} - template <class K, class T, class H, class P, class A> - void unordered_multimap<K,T,H,P,A>::swap(unordered_multimap& other) - { - table_.swap(other.table_); - } +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::const_iterator +unordered_multimap<K, T, H, P, A>::find(const key_type& k) const +{ + return const_iterator(table_.find_node(k)); +} + +template <class K, class T, class H, class P, class A> +template <class CompatibleKey, class CompatibleHash, class CompatiblePredicate> +typename unordered_multimap<K, T, H, P, A>::iterator +unordered_multimap<K, T, H, P, A>::find(CompatibleKey const& k, + CompatibleHash const& hash, CompatiblePredicate const& eq) +{ + return iterator(table_.generic_find_node(k, hash, eq)); +} + +template <class K, class T, class H, class P, class A> +template <class CompatibleKey, class CompatibleHash, class CompatiblePredicate> +typename unordered_multimap<K, T, H, P, A>::const_iterator +unordered_multimap<K, T, H, P, A>::find(CompatibleKey const& k, + CompatibleHash const& hash, CompatiblePredicate const& eq) const +{ + return const_iterator(table_.generic_find_node(k, hash, eq)); +} - // observers +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::size_type +unordered_multimap<K, T, H, P, A>::count(const key_type& k) const +{ + return table_.count(k); +} - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::hasher - unordered_multimap<K,T,H,P,A>::hash_function() const - { - return table_.hash_function(); - } +template <class K, class T, class H, class P, class A> +std::pair<typename unordered_multimap<K, T, H, P, A>::iterator, + typename unordered_multimap<K, T, H, P, A>::iterator> +unordered_multimap<K, T, H, P, A>::equal_range(const key_type& k) +{ + return table_.equal_range(k); +} - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::key_equal - unordered_multimap<K,T,H,P,A>::key_eq() const - { - return table_.key_eq(); - } +template <class K, class T, class H, class P, class A> +std::pair<typename unordered_multimap<K, T, H, P, A>::const_iterator, + typename unordered_multimap<K, T, H, P, A>::const_iterator> +unordered_multimap<K, T, H, P, A>::equal_range(const key_type& k) const +{ + return table_.equal_range(k); +} - // lookup +template <class K, class T, class H, class P, class A> +typename unordered_multimap<K, T, H, P, A>::size_type +unordered_multimap<K, T, H, P, A>::bucket_size(size_type n) const +{ + return table_.bucket_size(n); +} + +// hash policy + +template <class K, class T, class H, class P, class A> +float unordered_multimap<K, T, H, P, A>::load_factor() const BOOST_NOEXCEPT +{ + return table_.load_factor(); +} + +template <class K, class T, class H, class P, class A> +void unordered_multimap<K, T, H, P, A>::max_load_factor(float m) BOOST_NOEXCEPT +{ + table_.max_load_factor(m); +} + +template <class K, class T, class H, class P, class A> +void unordered_multimap<K, T, H, P, A>::rehash(size_type n) +{ + table_.rehash(n); +} - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::iterator - unordered_multimap<K,T,H,P,A>::find(const key_type& k) +template <class K, class T, class H, class P, class A> +void unordered_multimap<K, T, H, P, A>::reserve(size_type n) +{ + table_.reserve(n); +} + +template <class K, class T, class H, class P, class A> +inline bool operator==(unordered_multimap<K, T, H, P, A> const& m1, + unordered_multimap<K, T, H, P, A> const& m2) +{ +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { - return iterator(table_.find_node(k)); - } + unordered_multimap<K, T, H, P, A> x; + }; +#endif + return m1.table_.equals(m2.table_); +} - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::const_iterator - unordered_multimap<K,T,H,P,A>::find(const key_type& k) const +template <class K, class T, class H, class P, class A> +inline bool operator!=(unordered_multimap<K, T, H, P, A> const& m1, + unordered_multimap<K, T, H, P, A> const& m2) +{ +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { - return const_iterator(table_.find_node(k)); - } + unordered_multimap<K, T, H, P, A> x; + }; +#endif + return !m1.table_.equals(m2.table_); +} - template <class K, class T, class H, class P, class A> - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - typename unordered_multimap<K,T,H,P,A>::iterator - unordered_multimap<K,T,H,P,A>::find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) +template <class K, class T, class H, class P, class A> +inline void swap(unordered_multimap<K, T, H, P, A>& m1, + unordered_multimap<K, T, H, P, A>& m2) +{ +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { - return iterator(table_.generic_find_node(k, hash, eq)); - } + unordered_multimap<K, T, H, P, A> x; + }; +#endif + m1.swap(m2); +} - template <class K, class T, class H, class P, class A> - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - typename unordered_multimap<K,T,H,P,A>::const_iterator - unordered_multimap<K,T,H,P,A>::find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const +template <typename N, class K, class T, class A> class node_handle_map +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_map) + + template <typename Types> + friend struct ::boost::unordered::detail::table_impl; + template <typename Types> + friend struct ::boost::unordered::detail::grouped_table_impl; + + typedef typename boost::unordered::detail::rebind_wrap<A, + std::pair<K const, T> >::type value_allocator; + typedef boost::unordered::detail::allocator_traits<value_allocator> + value_allocator_traits; + typedef N node; + typedef typename boost::unordered::detail::rebind_wrap<A, node>::type + node_allocator; + typedef boost::unordered::detail::allocator_traits<node_allocator> + node_allocator_traits; + typedef typename node_allocator_traits::pointer node_pointer; + + public: + typedef K key_type; + typedef T mapped_type; + typedef A allocator_type; + + private: + node_pointer ptr_; + bool has_alloc_; + boost::unordered::detail::value_base<value_allocator> alloc_; + + public: + BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(), has_alloc_(false) { - return const_iterator(table_.generic_find_node(k, hash, eq)); } - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::size_type - unordered_multimap<K,T,H,P,A>::count(const key_type& k) const + /*BOOST_CONSTEXPR */ node_handle_map( + node_pointer ptr, allocator_type const& a) + : ptr_(ptr), has_alloc_(false) { - return table_.count(k); + if (ptr_) { + new ((void*)&alloc_) value_allocator(a); + has_alloc_ = true; + } } - template <class K, class T, class H, class P, class A> - std::pair< - typename unordered_multimap<K,T,H,P,A>::iterator, - typename unordered_multimap<K,T,H,P,A>::iterator> - unordered_multimap<K,T,H,P,A>::equal_range(const key_type& k) + ~node_handle_map() { - return table_.equal_range(k); + if (has_alloc_ && ptr_) { + node_allocator node_alloc(alloc_.value()); + boost::unordered::detail::node_tmp<node_allocator> tmp( + ptr_, node_alloc); + } + if (has_alloc_) { + alloc_.value_ptr()->~value_allocator(); + } } - template <class K, class T, class H, class P, class A> - std::pair< - typename unordered_multimap<K,T,H,P,A>::const_iterator, - typename unordered_multimap<K,T,H,P,A>::const_iterator> - unordered_multimap<K,T,H,P,A>::equal_range(const key_type& k) const + node_handle_map(BOOST_RV_REF(node_handle_map) n) BOOST_NOEXCEPT + : ptr_(n.ptr_), + has_alloc_(false) { - return table_.equal_range(k); + if (n.has_alloc_) { + new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value())); + has_alloc_ = true; + n.ptr_ = node_pointer(); + n.alloc_.value_ptr()->~value_allocator(); + n.has_alloc_ = false; + } } - template <class K, class T, class H, class P, class A> - typename unordered_multimap<K,T,H,P,A>::size_type - unordered_multimap<K,T,H,P,A>::bucket_size(size_type n) const + node_handle_map& operator=(BOOST_RV_REF(node_handle_map) n) { - return table_.bucket_size(n); - } + BOOST_ASSERT(!has_alloc_ || + value_allocator_traits:: + propagate_on_container_move_assignment::value || + (n.has_alloc_ && alloc_.value() == n.alloc_.value())); - // hash policy + if (ptr_) { + node_allocator node_alloc(alloc_.value()); + boost::unordered::detail::node_tmp<node_allocator> tmp( + ptr_, node_alloc); + ptr_ = node_pointer(); + } - template <class K, class T, class H, class P, class A> - float unordered_multimap<K,T,H,P,A>::load_factor() const BOOST_NOEXCEPT - { - return table_.load_factor(); - } + if (has_alloc_) { + alloc_.value_ptr()->~value_allocator(); + has_alloc_ = false; + } - template <class K, class T, class H, class P, class A> - void unordered_multimap<K,T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT - { - table_.max_load_factor(m); + if (!has_alloc_ && n.has_alloc_) { + move_allocator(n); + } + + ptr_ = n.ptr_; + n.ptr_ = node_pointer(); + + return *this; } - template <class K, class T, class H, class P, class A> - void unordered_multimap<K,T,H,P,A>::rehash(size_type n) + key_type& key() const { return const_cast<key_type&>(ptr_->value().first); } + + mapped_type& mapped() const { return ptr_->value().second; } + + allocator_type get_allocator() const { return alloc_.value(); } + + BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() + + bool operator!() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; } + + bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; } + + void swap(node_handle_map& n) BOOST_NOEXCEPT_IF( + value_allocator_traits::propagate_on_container_swap::value + /* || value_allocator_traits::is_always_equal::value */) { - table_.rehash(n); + if (!has_alloc_) { + if (n.has_alloc_) { + move_allocator(n); + } + } else if (!n.has_alloc_) { + n.move_allocator(*this); + } else { + swap_impl(n, boost::unordered::detail::integral_constant<bool, + value_allocator_traits:: + propagate_on_container_swap::value>()); + } + boost::swap(ptr_, n.ptr_); } - template <class K, class T, class H, class P, class A> - void unordered_multimap<K,T,H,P,A>::reserve(size_type n) + private: + void move_allocator(node_handle_map& n) { - table_.reserve(n); + new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value())); + n.alloc_.value_ptr()->~value_allocator(); + has_alloc_ = true; + n.has_alloc_ = false; } - template <class K, class T, class H, class P, class A> - inline bool operator==( - unordered_multimap<K,T,H,P,A> const& m1, - unordered_multimap<K,T,H,P,A> const& m2) + void swap_impl(node_handle_map&, boost::unordered::detail::false_type) {} + + void swap_impl(node_handle_map& n, boost::unordered::detail::true_type) { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_multimap<K,T,H,P,A> x; }; -#endif - return m1.table_.equals(m2.table_); + boost::swap(alloc_, n.alloc_); } +}; - template <class K, class T, class H, class P, class A> - inline bool operator!=( - unordered_multimap<K,T,H,P,A> const& m1, - unordered_multimap<K,T,H,P,A> const& m2) +template <class N, class K, class T, class A> +void swap(node_handle_map<N, K, T, A>& x, node_handle_map<N, K, T, A>& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(x.swap(y))) +{ + x.swap(y); +} + +template <class N, class K, class T, class A> struct insert_return_type_map +{ + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_map) + + typedef typename boost::unordered::detail::rebind_wrap<A, + std::pair<K const, T> >::type value_allocator; + typedef N node_; + + public: + bool inserted; + boost::unordered::iterator_detail::iterator<node_> position; + boost::unordered::node_handle_map<N, K, T, A> node; + + insert_return_type_map() : inserted(false), position(), node() {} + + insert_return_type_map(BOOST_RV_REF(insert_return_type_map) + x) BOOST_NOEXCEPT : inserted(x.inserted), + position(x.position), + node(boost::move(x.node)) { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_multimap<K,T,H,P,A> x; }; -#endif - return !m1.table_.equals(m2.table_); } - template <class K, class T, class H, class P, class A> - inline void swap( - unordered_multimap<K,T,H,P,A> &m1, - unordered_multimap<K,T,H,P,A> &m2) + insert_return_type_map& operator=(BOOST_RV_REF(insert_return_type_map) x) { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_multimap<K,T,H,P,A> x; }; -#endif - m1.swap(m2); + inserted = x.inserted; + position = x.position; + node = boost::move(x.node); + return *this; } +}; +template <class N, class K, class T, class A> +void swap(insert_return_type_map<N, K, T, A>& x, + insert_return_type_map<N, K, T, A>& y) +{ + boost::swap(x.node, y.node); + boost::swap(x.inserted, y.inserted); + boost::swap(x.position, y.position); +} } // namespace unordered } // namespace boost diff --git a/boost/unordered/unordered_map_fwd.hpp b/boost/unordered/unordered_map_fwd.hpp index 1eb26ce951..12855e92ad 100644 --- a/boost/unordered/unordered_map_fwd.hpp +++ b/boost/unordered/unordered_map_fwd.hpp @@ -11,55 +11,51 @@ #pragma once #endif -#include <memory> -#include <functional> #include <boost/functional/hash_fwd.hpp> #include <boost/unordered/detail/fwd.hpp> +#include <functional> +#include <memory> -namespace boost -{ - namespace unordered - { - template <class K, - class T, - class H = boost::hash<K>, - class P = std::equal_to<K>, - class A = std::allocator<std::pair<const K, T> > > - class unordered_map; - - template <class K, class T, class H, class P, class A> - inline bool operator==(unordered_map<K, T, H, P, A> const&, - unordered_map<K, T, H, P, A> const&); - template <class K, class T, class H, class P, class A> - inline bool operator!=(unordered_map<K, T, H, P, A> const&, - unordered_map<K, T, H, P, A> const&); - template <class K, class T, class H, class P, class A> - inline void swap(unordered_map<K, T, H, P, A>&, - unordered_map<K, T, H, P, A>&); - - template <class K, - class T, - class H = boost::hash<K>, - class P = std::equal_to<K>, - class A = std::allocator<std::pair<const K, T> > > - class unordered_multimap; - - template <class K, class T, class H, class P, class A> - inline bool operator==(unordered_multimap<K, T, H, P, A> const&, - unordered_multimap<K, T, H, P, A> const&); - template <class K, class T, class H, class P, class A> - inline bool operator!=(unordered_multimap<K, T, H, P, A> const&, - unordered_multimap<K, T, H, P, A> const&); - template <class K, class T, class H, class P, class A> - inline void swap(unordered_multimap<K, T, H, P, A>&, - unordered_multimap<K, T, H, P, A>&); - } +namespace boost { +namespace unordered { +template <class K, class T, class H = boost::hash<K>, + class P = std::equal_to<K>, + class A = std::allocator<std::pair<const K, T> > > +class unordered_map; + +template <class K, class T, class H, class P, class A> +inline bool operator==( + unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&); +template <class K, class T, class H, class P, class A> +inline bool operator!=( + unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&); +template <class K, class T, class H, class P, class A> +inline void swap(unordered_map<K, T, H, P, A>&, unordered_map<K, T, H, P, A>&); + +template <class K, class T, class H = boost::hash<K>, + class P = std::equal_to<K>, + class A = std::allocator<std::pair<const K, T> > > +class unordered_multimap; + +template <class K, class T, class H, class P, class A> +inline bool operator==(unordered_multimap<K, T, H, P, A> const&, + unordered_multimap<K, T, H, P, A> const&); +template <class K, class T, class H, class P, class A> +inline bool operator!=(unordered_multimap<K, T, H, P, A> const&, + unordered_multimap<K, T, H, P, A> const&); +template <class K, class T, class H, class P, class A> +inline void swap( + unordered_multimap<K, T, H, P, A>&, unordered_multimap<K, T, H, P, A>&); + +template <class N, class K, class T, class A> class node_handle_map; +template <class N, class K, class T, class A> struct insert_return_type_map; +} - using boost::unordered::unordered_map; - using boost::unordered::unordered_multimap; - using boost::unordered::swap; - using boost::unordered::operator==; - using boost::unordered::operator!=; +using boost::unordered::unordered_map; +using boost::unordered::unordered_multimap; +using boost::unordered::swap; +using boost::unordered::operator==; +using boost::unordered::operator!=; } #endif diff --git a/boost/unordered/unordered_set.hpp b/boost/unordered/unordered_set.hpp index 77cd87e0fd..40d566c254 100644 --- a/boost/unordered/unordered_set.hpp +++ b/boost/unordered/unordered_set.hpp @@ -14,9 +14,10 @@ #pragma once #endif -#include <boost/unordered/detail/set.hpp> +#include <boost/core/explicit_operator_bool.hpp> #include <boost/functional/hash.hpp> #include <boost/move/move.hpp> +#include <boost/unordered/detail/set.hpp> #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) #include <initializer_list> @@ -25,1714 +26,1861 @@ #if defined(BOOST_MSVC) #pragma warning(push) #if BOOST_MSVC >= 1400 -#pragma warning(disable:4396) //the inline specifier cannot be used when a - // friend declaration refers to a specialization - // of a function template +#pragma warning(disable : 4396) // the inline specifier cannot be used when a +// friend declaration refers to a specialization +// of a function template #endif #endif -namespace boost -{ -namespace unordered +namespace boost { +namespace unordered { +template <class T, class H, class P, class A> class unordered_set { - template <class T, class H, class P, class A> - class unordered_set - { #if defined(BOOST_UNORDERED_USE_MOVE) - BOOST_COPYABLE_AND_MOVABLE(unordered_set) + BOOST_COPYABLE_AND_MOVABLE(unordered_set) #endif - public: - - typedef T key_type; - typedef T value_type; - typedef H hasher; - typedef P key_equal; - typedef A allocator_type; + template <typename, typename, typename, typename> + friend class unordered_multiset; - private: + public: + typedef T key_type; + typedef T value_type; + typedef H hasher; + typedef P key_equal; + typedef A allocator_type; - typedef boost::unordered::detail::set<A, T, H, P> types; - typedef typename types::traits allocator_traits; - typedef typename types::table table; + private: + typedef boost::unordered::detail::set<A, T, H, P> types; + typedef typename types::value_allocator_traits value_allocator_traits; + typedef typename types::table table; - public: + public: + typedef typename value_allocator_traits::pointer pointer; + typedef typename value_allocator_traits::const_pointer const_pointer; - typedef typename allocator_traits::pointer pointer; - typedef typename allocator_traits::const_pointer const_pointer; + typedef value_type& reference; + typedef value_type const& const_reference; - typedef value_type& reference; - typedef value_type const& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + typedef typename table::cl_iterator const_local_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::iterator iterator; + typedef typename types::node_type node_type; + typedef typename types::insert_return_type insert_return_type; - typedef typename table::cl_iterator const_local_iterator; - typedef typename table::l_iterator local_iterator; - typedef typename table::c_iterator const_iterator; - typedef typename table::iterator iterator; + private: + table table_; - private: + public: + // constructors - table table_; + unordered_set(); - public: + explicit unordered_set(size_type, const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - // constructors + explicit unordered_set(size_type, const allocator_type&); - unordered_set(); + explicit unordered_set(size_type, const hasher&, const allocator_type&); - explicit unordered_set( - size_type, - const hasher& = hasher(), - const key_equal& = key_equal(), - const allocator_type& = allocator_type()); + explicit unordered_set(allocator_type const&); - explicit unordered_set( - size_type, - const allocator_type&); + template <class InputIt> unordered_set(InputIt, InputIt); - explicit unordered_set( - size_type, - const hasher&, - const allocator_type&); - - explicit unordered_set(allocator_type const&); - - template <class InputIt> - unordered_set(InputIt, InputIt); - - template <class InputIt> - unordered_set( - InputIt, InputIt, - size_type, - const hasher& = hasher(), - const key_equal& = key_equal()); + template <class InputIt> + unordered_set(InputIt, InputIt, size_type, const hasher& = hasher(), + const key_equal& = key_equal()); - template <class InputIt> - unordered_set( - InputIt, InputIt, - size_type, - const hasher&, - const key_equal&, - const allocator_type&); + template <class InputIt> + unordered_set(InputIt, InputIt, size_type, const hasher&, const key_equal&, + const allocator_type&); - template <class InputIt> - unordered_set( - InputIt, InputIt, - size_type, - const hasher&, - const allocator_type&); + template <class InputIt> + unordered_set( + InputIt, InputIt, size_type, const hasher&, const allocator_type&); - template <class InputIt> - unordered_set( - InputIt, InputIt, - size_type, - const allocator_type&); + template <class InputIt> + unordered_set(InputIt, InputIt, size_type, const allocator_type&); - // copy/move constructors + // copy/move constructors - unordered_set(unordered_set const&); + unordered_set(unordered_set const&); - unordered_set(unordered_set const&, allocator_type const&); - unordered_set(BOOST_RV_REF(unordered_set), allocator_type const&); + unordered_set(unordered_set const&, allocator_type const&); + unordered_set(BOOST_RV_REF(unordered_set), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) - unordered_set(BOOST_RV_REF(unordered_set) other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } + unordered_set(BOOST_RV_REF(unordered_set) other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) + : table_(other.table_, boost::unordered::detail::move_tag()) + { + } #elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_set(unordered_set&& other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } + unordered_set(unordered_set&& other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) + : table_(other.table_, boost::unordered::detail::move_tag()) + { + } #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - unordered_set( - std::initializer_list<value_type>, - size_type = boost::unordered::detail::default_bucket_count, - const hasher& = hasher(), - const key_equal&l = key_equal(), - const allocator_type& = allocator_type()); - unordered_set( - std::initializer_list<value_type>, - size_type, - const hasher&, - const allocator_type&); - unordered_set( - std::initializer_list<value_type>, - size_type, - const allocator_type&); + unordered_set(std::initializer_list<value_type>, + size_type = boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), const key_equal& l = key_equal(), + const allocator_type& = allocator_type()); + unordered_set(std::initializer_list<value_type>, size_type, const hasher&, + const allocator_type&); + unordered_set( + std::initializer_list<value_type>, size_type, const allocator_type&); #endif - // Destructor + // Destructor - ~unordered_set() BOOST_NOEXCEPT; + ~unordered_set() BOOST_NOEXCEPT; - // Assign +// Assign #if defined(BOOST_UNORDERED_USE_MOVE) - unordered_set& operator=(BOOST_COPY_ASSIGN_REF(unordered_set) x) - { - table_.assign(x.table_); - return *this; - } + unordered_set& operator=(BOOST_COPY_ASSIGN_REF(unordered_set) x) + { + table_.assign(x.table_); + return *this; + } - unordered_set& operator=(BOOST_RV_REF(unordered_set) x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_set& operator=(BOOST_RV_REF(unordered_set) x) + { + table_.move_assign(x.table_); + return *this; + } #else - unordered_set& operator=(unordered_set const& x) - { - table_.assign(x.table_); - return *this; - } + unordered_set& operator=(unordered_set const& x) + { + table_.assign(x.table_); + return *this; + } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_set& operator=(unordered_set&& x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_set& operator=(unordered_set&& x) + { + table_.move_assign(x.table_); + return *this; + } #endif #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - unordered_set& operator=(std::initializer_list<value_type>); + unordered_set& operator=(std::initializer_list<value_type>); #endif - allocator_type get_allocator() const BOOST_NOEXCEPT - { - return table_.node_alloc(); - } + allocator_type get_allocator() const BOOST_NOEXCEPT + { + return table_.node_alloc(); + } - // size and capacity + // size and capacity - bool empty() const BOOST_NOEXCEPT - { - return table_.size_ == 0; - } + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - size_type size() const BOOST_NOEXCEPT - { - return table_.size_; - } + size_type size() const BOOST_NOEXCEPT { return table_.size_; } - size_type max_size() const BOOST_NOEXCEPT; + size_type max_size() const BOOST_NOEXCEPT; - // iterators + // iterators - iterator begin() BOOST_NOEXCEPT - { - return iterator(table_.begin()); - } + iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } - const_iterator begin() const BOOST_NOEXCEPT - { - return const_iterator(table_.begin()); - } + const_iterator begin() const BOOST_NOEXCEPT + { + return const_iterator(table_.begin()); + } - iterator end() BOOST_NOEXCEPT - { - return iterator(); - } + iterator end() BOOST_NOEXCEPT { return iterator(); } - const_iterator end() const BOOST_NOEXCEPT - { - return const_iterator(); - } + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(); } - const_iterator cbegin() const BOOST_NOEXCEPT - { - return const_iterator(table_.begin()); - } + const_iterator cbegin() const BOOST_NOEXCEPT + { + return const_iterator(table_.begin()); + } - const_iterator cend() const BOOST_NOEXCEPT - { - return const_iterator(); - } + const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } + + // extract + + node_type extract(const_iterator position) + { + return node_type( + table_.extract_by_iterator(position), table_.node_alloc()); + } + + node_type extract(const key_type& k) + { + return node_type(table_.extract_by_key(k), table_.node_alloc()); + } - // emplace +// emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <class... Args> - std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args) - { - return table_.emplace(boost::forward<Args>(args)...); - } + template <class... Args> + std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args) + { + return table_.emplace(boost::forward<Args>(args)...); + } - template <class... Args> - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) - { - return table_.emplace_hint(hint, boost::forward<Args>(args)...); - } + template <class... Args> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return table_.emplace_hint(hint, boost::forward<Args>(args)...); + } #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - // 0 argument emplace requires special treatment in case - // the container is instantiated with a value type that - // doesn't have a default constructor. + // 0 argument emplace requires special treatment in case + // the container is instantiated with a value type that + // doesn't have a default constructor. - std::pair<iterator, bool> emplace( - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type()) - { - return this->emplace(boost::move(v)); - } + std::pair<iterator, bool> emplace( + boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace(boost::move(v)); + } - iterator emplace_hint(const_iterator hint, - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ) - { - return this->emplace_hint(hint, boost::move(v)); - } + iterator emplace_hint(const_iterator hint, + boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace_hint(hint, boost::move(v)); + } #endif - template <typename A0> - std::pair<iterator, bool> emplace(BOOST_FWD_REF(A0) a0) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0)) - ); - } + template <typename A0> + std::pair<iterator, bool> emplace(BOOST_FWD_REF(A0) a0) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0> - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0)) - ); - } + template <typename A0> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0, typename A1> - std::pair<iterator, bool> emplace( - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1)) - ); - } + template <typename A0, typename A1> + std::pair<iterator, bool> emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } - template <typename A0, typename A1> - iterator emplace_hint(const_iterator hint, - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1)) - ); - } + template <typename A0, typename A1> + iterator emplace_hint( + const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } - template <typename A0, typename A1, typename A2> - std::pair<iterator, bool> emplace( - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1, - BOOST_FWD_REF(A2) a2) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1), - boost::forward<A2>(a2)) - ); - } + template <typename A0, typename A1, typename A2> + std::pair<iterator, bool> emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } - template <typename A0, typename A1, typename A2> - iterator emplace_hint(const_iterator hint, - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1, - BOOST_FWD_REF(A2) a2) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1), - boost::forward<A2>(a2)) - ); - } + template <typename A0, typename A1, typename A2> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, + BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ - > \ - std::pair<iterator, bool> emplace( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ - ) \ - { \ - return table_.emplace( \ - boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ - a) \ - )); \ - } \ - \ - template < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ - > \ - iterator emplace_hint( \ - const_iterator hint, \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ - ) \ - { \ - return table_.emplace_hint(hint, \ - boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ - a) \ - )); \ - } +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + std::pair<iterator, bool> emplace( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.emplace(boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + iterator emplace_hint(const_iterator hint, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.emplace_hint( \ + hint, boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_EMPLACE, _) + BOOST_PP_REPEAT_FROM_TO( + 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE #endif - std::pair<iterator, bool> insert(value_type const& x) - { - return this->emplace(x); - } + std::pair<iterator, bool> insert(value_type const& x) + { + return this->emplace(x); + } - std::pair<iterator, bool> insert(BOOST_UNORDERED_RV_REF(value_type) x) - { - return this->emplace(boost::move(x)); - } + std::pair<iterator, bool> insert(BOOST_UNORDERED_RV_REF(value_type) x) + { + return this->emplace(boost::move(x)); + } - iterator insert(const_iterator hint, value_type const& x) - { - return this->emplace_hint(hint, x); - } + iterator insert(const_iterator hint, value_type const& x) + { + return this->emplace_hint(hint, x); + } - iterator insert(const_iterator hint, - BOOST_UNORDERED_RV_REF(value_type) x) - { - return this->emplace_hint(hint, boost::move(x)); - } + iterator insert(const_iterator hint, BOOST_UNORDERED_RV_REF(value_type) x) + { + return this->emplace_hint(hint, boost::move(x)); + } - template <class InputIt> void insert(InputIt, InputIt); + template <class InputIt> void insert(InputIt, InputIt); #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - void insert(std::initializer_list<value_type>); + void insert(std::initializer_list<value_type>); #endif - iterator erase(const_iterator); - size_type erase(const key_type&); - iterator erase(const_iterator, const_iterator); - void quick_erase(const_iterator it) { erase(it); } - void erase_return_void(const_iterator it) { erase(it); } + insert_return_type insert(BOOST_RV_REF(node_type) np) + { + insert_return_type result; + table_.move_insert_node_type(np, result); + return boost::move(result); + } - void clear(); - void swap(unordered_set&); + iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) + { + return table_.move_insert_node_type_with_hint(hint, np); + } - // observers +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + private: + // Note: Use r-value node_type to insert. + insert_return_type insert(node_type&); + iterator insert(const_iterator, node_type& np); - hasher hash_function() const; - key_equal key_eq() const; + public: +#endif - // lookup + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } - const_iterator find(const key_type&) const; + void clear(); + void swap(unordered_set&); - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - const_iterator find( - CompatibleKey const&, - CompatibleHash const&, - CompatiblePredicate const&) const; + template <typename H2, typename P2> + void merge(boost::unordered_set<T, H2, P2, A>& source); - size_type count(const key_type&) const; +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename H2, typename P2> + void merge(boost::unordered_set<T, H2, P2, A>&& source); +#endif - std::pair<const_iterator, const_iterator> - equal_range(const key_type&) const; +#if BOOST_UNORDERED_INTEROPERABLE_NODES + template <typename H2, typename P2> + void merge(boost::unordered_multiset<T, H2, P2, A>& source); - // bucket interface +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename H2, typename P2> + void merge(boost::unordered_multiset<T, H2, P2, A>&& source); +#endif +#endif - size_type bucket_count() const BOOST_NOEXCEPT - { - return table_.bucket_count_; - } + // observers - size_type max_bucket_count() const BOOST_NOEXCEPT - { - return table_.max_bucket_count(); - } + hasher hash_function() const; + key_equal key_eq() const; - size_type bucket_size(size_type) const; + // lookup - size_type bucket(const key_type& k) const - { - return table_.hash_to_bucket(table_.hash(k)); - } + const_iterator find(const key_type&) const; - local_iterator begin(size_type n) - { - return local_iterator( - table_.begin(n), n, table_.bucket_count_); - } + template <class CompatibleKey, class CompatibleHash, + class CompatiblePredicate> + const_iterator find(CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&) const; - const_local_iterator begin(size_type n) const - { - return const_local_iterator( - table_.begin(n), n, table_.bucket_count_); - } + size_type count(const key_type&) const; - local_iterator end(size_type) - { - return local_iterator(); - } + std::pair<const_iterator, const_iterator> equal_range( + const key_type&) const; - const_local_iterator end(size_type) const - { - return const_local_iterator(); - } + // bucket interface - const_local_iterator cbegin(size_type n) const - { - return const_local_iterator( - table_.begin(n), n, table_.bucket_count_); - } + size_type bucket_count() const BOOST_NOEXCEPT + { + return table_.bucket_count_; + } - const_local_iterator cend(size_type) const - { - return const_local_iterator(); - } + size_type max_bucket_count() const BOOST_NOEXCEPT + { + return table_.max_bucket_count(); + } - // hash policy + size_type bucket_size(size_type) const; - float max_load_factor() const BOOST_NOEXCEPT - { - return table_.mlf_; - } + size_type bucket(const key_type& k) const + { + return table_.hash_to_bucket(table_.hash(k)); + } - float load_factor() const BOOST_NOEXCEPT; - void max_load_factor(float) BOOST_NOEXCEPT; - void rehash(size_type); - void reserve(size_type); + local_iterator begin(size_type n) + { + return local_iterator(table_.begin(n), n, table_.bucket_count_); + } -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==<T,H,P,A>( - unordered_set const&, unordered_set const&); - friend bool operator!=<T,H,P,A>( - unordered_set const&, unordered_set const&); -#endif - }; // class template unordered_set + const_local_iterator begin(size_type n) const + { + return const_local_iterator(table_.begin(n), n, table_.bucket_count_); + } + + local_iterator end(size_type) { return local_iterator(); } - template <class T, class H, class P, class A> - class unordered_multiset + const_local_iterator end(size_type) const { return const_local_iterator(); } + + const_local_iterator cbegin(size_type n) const { -#if defined(BOOST_UNORDERED_USE_MOVE) - BOOST_COPYABLE_AND_MOVABLE(unordered_multiset) -#endif - public: + return const_local_iterator(table_.begin(n), n, table_.bucket_count_); + } - typedef T key_type; - typedef T value_type; - typedef H hasher; - typedef P key_equal; - typedef A allocator_type; + const_local_iterator cend(size_type) const + { + return const_local_iterator(); + } - private: + // hash policy - typedef boost::unordered::detail::multiset<A, T, H, P> types; - typedef typename types::traits allocator_traits; - typedef typename types::table table; + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - public: + float load_factor() const BOOST_NOEXCEPT; + void max_load_factor(float) BOOST_NOEXCEPT; + void rehash(size_type); + void reserve(size_type); - typedef typename allocator_traits::pointer pointer; - typedef typename allocator_traits::const_pointer const_pointer; +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + friend bool operator== + <T, H, P, A>(unordered_set const&, unordered_set const&); + friend bool operator!= + <T, H, P, A>(unordered_set const&, unordered_set const&); +#endif +}; // class template unordered_set - typedef value_type& reference; - typedef value_type const& const_reference; +template <class T, class H, class P, class A> class unordered_multiset +{ +#if defined(BOOST_UNORDERED_USE_MOVE) + BOOST_COPYABLE_AND_MOVABLE(unordered_multiset) +#endif + template <typename, typename, typename, typename> + friend class unordered_set; + + public: + typedef T key_type; + typedef T value_type; + typedef H hasher; + typedef P key_equal; + typedef A allocator_type; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + private: + typedef boost::unordered::detail::multiset<A, T, H, P> types; + typedef typename types::value_allocator_traits value_allocator_traits; + typedef typename types::table table; - typedef typename table::cl_iterator const_local_iterator; - typedef typename table::l_iterator local_iterator; - typedef typename table::c_iterator const_iterator; - typedef typename table::iterator iterator; + public: + typedef typename value_allocator_traits::pointer pointer; + typedef typename value_allocator_traits::const_pointer const_pointer; - private: + typedef value_type& reference; + typedef value_type const& const_reference; - table table_; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; - public: + typedef typename table::cl_iterator const_local_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::iterator iterator; + typedef typename types::node_type node_type; - // constructors + private: + table table_; - unordered_multiset(); + public: + // constructors - explicit unordered_multiset( - size_type, - const hasher& = hasher(), - const key_equal& = key_equal(), - const allocator_type& = allocator_type()); + unordered_multiset(); - explicit unordered_multiset( - size_type, - const allocator_type&); + explicit unordered_multiset(size_type, const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_multiset( - size_type, - const hasher&, - const allocator_type&); + explicit unordered_multiset(size_type, const allocator_type&); - explicit unordered_multiset(allocator_type const&); + explicit unordered_multiset( + size_type, const hasher&, const allocator_type&); - template <class InputIt> - unordered_multiset(InputIt, InputIt); + explicit unordered_multiset(allocator_type const&); - template <class InputIt> - unordered_multiset( - InputIt, InputIt, - size_type, - const hasher& = hasher(), - const key_equal& = key_equal()); + template <class InputIt> unordered_multiset(InputIt, InputIt); - template <class InputIt> - unordered_multiset( - InputIt, InputIt, - size_type, - const hasher&, - const key_equal&, - const allocator_type&); + template <class InputIt> + unordered_multiset(InputIt, InputIt, size_type, const hasher& = hasher(), + const key_equal& = key_equal()); + + template <class InputIt> + unordered_multiset(InputIt, InputIt, size_type, const hasher&, + const key_equal&, const allocator_type&); - template <class InputIt> - unordered_multiset( - InputIt, InputIt, - size_type, - const hasher&, - const allocator_type&); + template <class InputIt> + unordered_multiset( + InputIt, InputIt, size_type, const hasher&, const allocator_type&); - template <class InputIt> - unordered_multiset( - InputIt, InputIt, - size_type, - const allocator_type&); + template <class InputIt> + unordered_multiset(InputIt, InputIt, size_type, const allocator_type&); - // copy/move constructors + // copy/move constructors - unordered_multiset(unordered_multiset const&); + unordered_multiset(unordered_multiset const&); - unordered_multiset(unordered_multiset const&, allocator_type const&); - unordered_multiset(BOOST_RV_REF(unordered_multiset), allocator_type const&); + unordered_multiset(unordered_multiset const&, allocator_type const&); + unordered_multiset(BOOST_RV_REF(unordered_multiset), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) - unordered_multiset(BOOST_RV_REF(unordered_multiset) other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } + unordered_multiset(BOOST_RV_REF(unordered_multiset) other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) + : table_(other.table_, boost::unordered::detail::move_tag()) + { + } #elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multiset(unordered_multiset&& other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } + unordered_multiset(unordered_multiset&& other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) + : table_(other.table_, boost::unordered::detail::move_tag()) + { + } #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - unordered_multiset( - std::initializer_list<value_type>, - size_type = boost::unordered::detail::default_bucket_count, - const hasher& = hasher(), - const key_equal&l = key_equal(), - const allocator_type& = allocator_type()); - unordered_multiset( - std::initializer_list<value_type>, - size_type, - const hasher&, - const allocator_type&); - unordered_multiset( - std::initializer_list<value_type>, - size_type, - const allocator_type&); + unordered_multiset(std::initializer_list<value_type>, + size_type = boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), const key_equal& l = key_equal(), + const allocator_type& = allocator_type()); + unordered_multiset(std::initializer_list<value_type>, size_type, + const hasher&, const allocator_type&); + unordered_multiset( + std::initializer_list<value_type>, size_type, const allocator_type&); #endif - // Destructor + // Destructor - ~unordered_multiset() BOOST_NOEXCEPT; + ~unordered_multiset() BOOST_NOEXCEPT; - // Assign +// Assign #if defined(BOOST_UNORDERED_USE_MOVE) - unordered_multiset& operator=( - BOOST_COPY_ASSIGN_REF(unordered_multiset) x) - { - table_.assign(x.table_); - return *this; - } + unordered_multiset& operator=(BOOST_COPY_ASSIGN_REF(unordered_multiset) x) + { + table_.assign(x.table_); + return *this; + } - unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x) + { + table_.move_assign(x.table_); + return *this; + } #else - unordered_multiset& operator=(unordered_multiset const& x) - { - table_.assign(x.table_); - return *this; - } + unordered_multiset& operator=(unordered_multiset const& x) + { + table_.assign(x.table_); + return *this; + } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multiset& operator=(unordered_multiset&& x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_multiset& operator=(unordered_multiset&& x) + { + table_.move_assign(x.table_); + return *this; + } #endif #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - unordered_multiset& operator=(std::initializer_list<value_type>); + unordered_multiset& operator=(std::initializer_list<value_type>); #endif - allocator_type get_allocator() const BOOST_NOEXCEPT - { - return table_.node_alloc(); - } + allocator_type get_allocator() const BOOST_NOEXCEPT + { + return table_.node_alloc(); + } - // size and capacity + // size and capacity - bool empty() const BOOST_NOEXCEPT - { - return table_.size_ == 0; - } + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - size_type size() const BOOST_NOEXCEPT - { - return table_.size_; - } + size_type size() const BOOST_NOEXCEPT { return table_.size_; } - size_type max_size() const BOOST_NOEXCEPT; + size_type max_size() const BOOST_NOEXCEPT; - // iterators + // iterators - iterator begin() BOOST_NOEXCEPT - { - return iterator(table_.begin()); - } + iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } - const_iterator begin() const BOOST_NOEXCEPT - { - return const_iterator(table_.begin()); - } + const_iterator begin() const BOOST_NOEXCEPT + { + return const_iterator(table_.begin()); + } - iterator end() BOOST_NOEXCEPT - { - return iterator(); - } + iterator end() BOOST_NOEXCEPT { return iterator(); } - const_iterator end() const BOOST_NOEXCEPT - { - return const_iterator(); - } + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(); } - const_iterator cbegin() const BOOST_NOEXCEPT - { - return const_iterator(table_.begin()); - } + const_iterator cbegin() const BOOST_NOEXCEPT + { + return const_iterator(table_.begin()); + } - const_iterator cend() const BOOST_NOEXCEPT - { - return const_iterator(); - } + const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } - // emplace + // extract + + node_type extract(const_iterator position) + { + return node_type( + table_.extract_by_iterator(position), table_.node_alloc()); + } + + node_type extract(const key_type& k) + { + return node_type(table_.extract_by_key(k), table_.node_alloc()); + } + +// emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <class... Args> - iterator emplace(BOOST_FWD_REF(Args)... args) - { - return table_.emplace(boost::forward<Args>(args)...); - } + template <class... Args> iterator emplace(BOOST_FWD_REF(Args)... args) + { + return table_.emplace(boost::forward<Args>(args)...); + } - template <class... Args> - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) - { - return table_.emplace_hint(hint, boost::forward<Args>(args)...); - } + template <class... Args> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return table_.emplace_hint(hint, boost::forward<Args>(args)...); + } #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - // 0 argument emplace requires special treatment in case - // the container is instantiated with a value type that - // doesn't have a default constructor. + // 0 argument emplace requires special treatment in case + // the container is instantiated with a value type that + // doesn't have a default constructor. - iterator emplace( - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type()) - { - return this->emplace(boost::move(v)); - } + iterator emplace(boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace(boost::move(v)); + } - iterator emplace_hint(const_iterator hint, - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ) - { - return this->emplace_hint(hint, boost::move(v)); - } + iterator emplace_hint(const_iterator hint, + boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace_hint(hint, boost::move(v)); + } #endif - template <typename A0> - iterator emplace(BOOST_FWD_REF(A0) a0) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0)) - ); - } + template <typename A0> iterator emplace(BOOST_FWD_REF(A0) a0) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0> - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0)) - ); - } + template <typename A0> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0))); + } - template <typename A0, typename A1> - iterator emplace( - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1)) - ); - } + template <typename A0, typename A1> + iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } - template <typename A0, typename A1> - iterator emplace_hint(const_iterator hint, - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1)) - ); - } + template <typename A0, typename A1> + iterator emplace_hint( + const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1))); + } - template <typename A0, typename A1, typename A2> - iterator emplace( - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1, - BOOST_FWD_REF(A2) a2) - { - return table_.emplace( - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1), - boost::forward<A2>(a2)) - ); - } + template <typename A0, typename A1, typename A2> + iterator emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } - template <typename A0, typename A1, typename A2> - iterator emplace_hint(const_iterator hint, - BOOST_FWD_REF(A0) a0, - BOOST_FWD_REF(A1) a1, - BOOST_FWD_REF(A2) a2) - { - return table_.emplace_hint(hint, - boost::unordered::detail::create_emplace_args( - boost::forward<A0>(a0), - boost::forward<A1>(a1), - boost::forward<A2>(a2)) - ); - } + template <typename A0, typename A1, typename A2> + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, + BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward<A0>(a0), boost::forward<A1>(a1), + boost::forward<A2>(a2))); + } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ - > \ - iterator emplace( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ - ) \ - { \ - return table_.emplace( \ - boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ - a) \ - )); \ - } \ - \ - template < \ - BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ - > \ - iterator emplace_hint( \ - const_iterator hint, \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ - ) \ - { \ - return table_.emplace_hint(hint, \ - boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ - a) \ - )); \ - } +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.emplace(boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + iterator emplace_hint(const_iterator hint, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.emplace_hint( \ + hint, boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_EMPLACE, _) + BOOST_PP_REPEAT_FROM_TO( + 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE #endif - iterator insert(value_type const& x) - { - return this->emplace(x); - } + iterator insert(value_type const& x) { return this->emplace(x); } - iterator insert(BOOST_UNORDERED_RV_REF(value_type) x) - { - return this->emplace(boost::move(x)); - } + iterator insert(BOOST_UNORDERED_RV_REF(value_type) x) + { + return this->emplace(boost::move(x)); + } - iterator insert(const_iterator hint, value_type const& x) - { - return this->emplace_hint(hint, x); - } + iterator insert(const_iterator hint, value_type const& x) + { + return this->emplace_hint(hint, x); + } - iterator insert(const_iterator hint, - BOOST_UNORDERED_RV_REF(value_type) x) - { - return this->emplace_hint(hint, boost::move(x)); - } + iterator insert(const_iterator hint, BOOST_UNORDERED_RV_REF(value_type) x) + { + return this->emplace_hint(hint, boost::move(x)); + } - template <class InputIt> void insert(InputIt, InputIt); + template <class InputIt> void insert(InputIt, InputIt); #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - void insert(std::initializer_list<value_type>); + void insert(std::initializer_list<value_type>); #endif - iterator erase(const_iterator); - size_type erase(const key_type&); - iterator erase(const_iterator, const_iterator); - void quick_erase(const_iterator it) { erase(it); } - void erase_return_void(const_iterator it) { erase(it); } - - void clear(); - void swap(unordered_multiset&); - - // observers - - hasher hash_function() const; - key_equal key_eq() const; - - // lookup - - const_iterator find(const key_type&) const; - - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - const_iterator find( - CompatibleKey const&, - CompatibleHash const&, - CompatiblePredicate const&) const; - - size_type count(const key_type&) const; + iterator insert(BOOST_RV_REF(node_type) np) + { + return table_.move_insert_node_type(np); + } - std::pair<const_iterator, const_iterator> - equal_range(const key_type&) const; + iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) + { + return table_.move_insert_node_type_with_hint(hint, np); + } - // bucket interface +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + private: + // Note: Use r-value node_type to insert. + iterator insert(node_type&); + iterator insert(const_iterator, node_type& np); - size_type bucket_count() const BOOST_NOEXCEPT - { - return table_.bucket_count_; - } + public: +#endif - size_type max_bucket_count() const BOOST_NOEXCEPT - { - return table_.max_bucket_count(); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } - size_type bucket_size(size_type) const; + void clear(); + void swap(unordered_multiset&); - size_type bucket(const key_type& k) const - { - return table_.hash_to_bucket(table_.hash(k)); - } + template <typename H2, typename P2> + void merge(boost::unordered_multiset<T, H2, P2, A>& source); - local_iterator begin(size_type n) - { - return local_iterator( - table_.begin(n), n, table_.bucket_count_); - } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename H2, typename P2> + void merge(boost::unordered_multiset<T, H2, P2, A>&& source); +#endif - const_local_iterator begin(size_type n) const - { - return const_local_iterator( - table_.begin(n), n, table_.bucket_count_); - } +#if BOOST_UNORDERED_INTEROPERABLE_NODES + template <typename H2, typename P2> + void merge(boost::unordered_set<T, H2, P2, A>& source); - local_iterator end(size_type) - { - return local_iterator(); - } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename H2, typename P2> + void merge(boost::unordered_set<T, H2, P2, A>&& source); +#endif +#endif - const_local_iterator end(size_type) const - { - return const_local_iterator(); - } + // observers - const_local_iterator cbegin(size_type n) const - { - return const_local_iterator( - table_.begin(n), n, table_.bucket_count_); - } + hasher hash_function() const; + key_equal key_eq() const; - const_local_iterator cend(size_type) const - { - return const_local_iterator(); - } + // lookup - // hash policy + const_iterator find(const key_type&) const; - float max_load_factor() const BOOST_NOEXCEPT - { - return table_.mlf_; - } + template <class CompatibleKey, class CompatibleHash, + class CompatiblePredicate> + const_iterator find(CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&) const; - float load_factor() const BOOST_NOEXCEPT; - void max_load_factor(float) BOOST_NOEXCEPT; - void rehash(size_type); - void reserve(size_type); + size_type count(const key_type&) const; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==<T,H,P,A>( - unordered_multiset const&, unordered_multiset const&); - friend bool operator!=<T,H,P,A>( - unordered_multiset const&, unordered_multiset const&); -#endif - }; // class template unordered_multiset + std::pair<const_iterator, const_iterator> equal_range( + const key_type&) const; -//////////////////////////////////////////////////////////////////////////////// + // bucket interface - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set() - : table_(boost::unordered::detail::default_bucket_count, hasher(), - key_equal(), allocator_type()) + size_type bucket_count() const BOOST_NOEXCEPT { + return table_.bucket_count_; } - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - size_type n, const hasher &hf, const key_equal &eql, - const allocator_type &a) - : table_(n, hf, eql, a) + size_type max_bucket_count() const BOOST_NOEXCEPT { + return table_.max_bucket_count(); } - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - size_type n, const allocator_type &a) - : table_(n, hasher(), key_equal(), a) - { - } + size_type bucket_size(size_type) const; - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - size_type n, const hasher &hf, const allocator_type &a) - : table_(n, hf, key_equal(), a) + size_type bucket(const key_type& k) const { + return table_.hash_to_bucket(table_.hash(k)); } - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set(allocator_type const& a) - : table_(boost::unordered::detail::default_bucket_count, - hasher(), key_equal(), a) + local_iterator begin(size_type n) { + return local_iterator(table_.begin(n), n, table_.bucket_count_); } - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - unordered_set const& other, allocator_type const& a) - : table_(other.table_, a) + const_local_iterator begin(size_type n) const { + return const_local_iterator(table_.begin(n), n, table_.bucket_count_); } - template <class T, class H, class P, class A> - template <class InputIt> - unordered_set<T,H,P,A>::unordered_set(InputIt f, InputIt l) - : table_(boost::unordered::detail::initial_size(f, l), - hasher(), key_equal(), allocator_type()) - { - table_.insert_range(f, l); - } + local_iterator end(size_type) { return local_iterator(); } - template <class T, class H, class P, class A> - template <class InputIt> - unordered_set<T,H,P,A>::unordered_set( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, eql, allocator_type()) - { - table_.insert_range(f, l); - } - - template <class T, class H, class P, class A> - template <class InputIt> - unordered_set<T,H,P,A>::unordered_set( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) - { - table_.insert_range(f, l); - } - - template <class T, class H, class P, class A> - template <class InputIt> - unordered_set<T,H,P,A>::unordered_set( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, key_equal(), a) + const_local_iterator end(size_type) const { return const_local_iterator(); } + + const_local_iterator cbegin(size_type n) const { - table_.insert_range(f, l); + return const_local_iterator(table_.begin(n), n, table_.bucket_count_); } - template <class T, class H, class P, class A> - template <class InputIt> - unordered_set<T,H,P,A>::unordered_set( - InputIt f, InputIt l, - size_type n, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hasher(), key_equal(), a) + const_local_iterator cend(size_type) const { - table_.insert_range(f, l); + return const_local_iterator(); } - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::~unordered_set() BOOST_NOEXCEPT {} + // hash policy - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - unordered_set const& other) - : table_(other.table_) - { - } + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - BOOST_RV_REF(unordered_set) other, allocator_type const& a) - : table_(other.table_, a, boost::unordered::detail::move_tag()) - { - } + float load_factor() const BOOST_NOEXCEPT; + void max_load_factor(float) BOOST_NOEXCEPT; + void rehash(size_type); + void reserve(size_type); -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + friend bool operator== + <T, H, P, A>(unordered_multiset const&, unordered_multiset const&); + friend bool operator!= + <T, H, P, A>(unordered_multiset const&, unordered_multiset const&); +#endif +}; // class template unordered_multiset - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - std::initializer_list<value_type> list, size_type n, - const hasher &hf, const key_equal &eql, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, eql, a) - { - table_.insert_range(list.begin(), list.end()); - } +//////////////////////////////////////////////////////////////////////////////// - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - std::initializer_list<value_type> list, size_type n, - const hasher &hf, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set() + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), allocator_type()) +{ +} - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::unordered_set( - std::initializer_list<value_type> list, size_type n, - const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hasher(), key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set(size_type n, const hasher& hf, + const key_equal& eql, const allocator_type& a) + : table_(n, hf, eql, a) +{ +} - template <class T, class H, class P, class A> - unordered_set<T,H,P,A>& unordered_set<T,H,P,A>::operator=( - std::initializer_list<value_type> list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set(size_type n, const allocator_type& a) + : table_(n, hasher(), key_equal(), a) +{ +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set( + size_type n, const hasher& hf, const allocator_type& a) + : table_(n, hf, key_equal(), a) +{ +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set(allocator_type const& a) + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), a) +{ +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set( + unordered_set const& other, allocator_type const& a) + : table_(other.table_, a) +{ +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_set<T, H, P, A>::unordered_set(InputIt f, InputIt l) + : table_(boost::unordered::detail::initial_size(f, l), hasher(), + key_equal(), allocator_type()) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_set<T, H, P, A>::unordered_set( + InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, + allocator_type()) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_set<T, H, P, A>::unordered_set(InputIt f, InputIt l, size_type n, + const hasher& hf, const key_equal& eql, const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_set<T, H, P, A>::unordered_set(InputIt f, InputIt l, size_type n, + const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(f, l, n), hf, key_equal(), a) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_set<T, H, P, A>::unordered_set( + InputIt f, InputIt l, size_type n, const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hasher(), + key_equal(), a) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::~unordered_set() BOOST_NOEXCEPT +{ +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set(unordered_set const& other) + : table_(other.table_) +{ +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set( + BOOST_RV_REF(unordered_set) other, allocator_type const& a) + : table_(other.table_, a, boost::unordered::detail::move_tag()) +{ +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set(std::initializer_list<value_type> list, + size_type n, const hasher& hf, const key_equal& eql, + const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hf, eql, a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set(std::initializer_list<value_type> list, + size_type n, const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hf, key_equal(), a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>::unordered_set(std::initializer_list<value_type> list, + size_type n, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hasher(), key_equal(), a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class T, class H, class P, class A> +unordered_set<T, H, P, A>& unordered_set<T, H, P, A>::operator=( + std::initializer_list<value_type> list) +{ + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; +} #endif - // size and capacity +// size and capacity - template <class T, class H, class P, class A> - std::size_t unordered_set<T,H,P,A>::max_size() const BOOST_NOEXCEPT - { - return table_.max_size(); - } +template <class T, class H, class P, class A> +std::size_t unordered_set<T, H, P, A>::max_size() const BOOST_NOEXCEPT +{ + return table_.max_size(); +} - // modifiers +// modifiers - template <class T, class H, class P, class A> - template <class InputIt> - void unordered_set<T,H,P,A>::insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } +template <class T, class H, class P, class A> +template <class InputIt> +void unordered_set<T, H, P, A>::insert(InputIt first, InputIt last) +{ + table_.insert_range(first, last); +} #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - template <class T, class H, class P, class A> - void unordered_set<T,H,P,A>::insert( - std::initializer_list<value_type> list) - { - table_.insert_range(list.begin(), list.end()); - } +template <class T, class H, class P, class A> +void unordered_set<T, H, P, A>::insert(std::initializer_list<value_type> list) +{ + table_.insert_range(list.begin(), list.end()); +} #endif - template <class T, class H, class P, class A> - typename unordered_set<T,H,P,A>::iterator - unordered_set<T,H,P,A>::erase(const_iterator position) - { - return table_.erase(position); - } +template <class T, class H, class P, class A> +typename unordered_set<T, H, P, A>::iterator unordered_set<T, H, P, A>::erase( + const_iterator position) +{ + return table_.erase(position); +} - template <class T, class H, class P, class A> - typename unordered_set<T,H,P,A>::size_type - unordered_set<T,H,P,A>::erase(const key_type& k) - { - return table_.erase_key(k); - } +template <class T, class H, class P, class A> +typename unordered_set<T, H, P, A>::size_type unordered_set<T, H, P, A>::erase( + const key_type& k) +{ + return table_.erase_key(k); +} - template <class T, class H, class P, class A> - typename unordered_set<T,H,P,A>::iterator - unordered_set<T,H,P,A>::erase( - const_iterator first, const_iterator last) - { - return table_.erase_range(first, last); - } +template <class T, class H, class P, class A> +typename unordered_set<T, H, P, A>::iterator unordered_set<T, H, P, A>::erase( + const_iterator first, const_iterator last) +{ + return table_.erase_range(first, last); +} - template <class T, class H, class P, class A> - void unordered_set<T,H,P,A>::clear() - { - table_.clear(); - } +template <class T, class H, class P, class A> +void unordered_set<T, H, P, A>::clear() +{ + table_.clear(); +} - template <class T, class H, class P, class A> - void unordered_set<T,H,P,A>::swap(unordered_set& other) - { - table_.swap(other.table_); - } +template <class T, class H, class P, class A> +void unordered_set<T, H, P, A>::swap(unordered_set& other) +{ + table_.swap(other.table_); +} - // observers +// observers - template <class T, class H, class P, class A> - typename unordered_set<T,H,P,A>::hasher - unordered_set<T,H,P,A>::hash_function() const - { - return table_.hash_function(); - } +template <class T, class H, class P, class A> +typename unordered_set<T, H, P, A>::hasher +unordered_set<T, H, P, A>::hash_function() const +{ + return table_.hash_function(); +} - template <class T, class H, class P, class A> - typename unordered_set<T,H,P,A>::key_equal - unordered_set<T,H,P,A>::key_eq() const - { - return table_.key_eq(); - } +template <class T, class H, class P, class A> +typename unordered_set<T, H, P, A>::key_equal +unordered_set<T, H, P, A>::key_eq() const +{ + return table_.key_eq(); +} - // lookup +template <class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_set<T, H, P, A>::merge( + boost::unordered_set<T, H2, P2, A>& source) +{ + table_.merge_impl(source.table_); +} - template <class T, class H, class P, class A> - typename unordered_set<T,H,P,A>::const_iterator - unordered_set<T,H,P,A>::find(const key_type& k) const - { - return const_iterator(table_.find_node(k)); - } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template <class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_set<T, H, P, A>::merge( + boost::unordered_set<T, H2, P2, A>&& source) +{ + table_.merge_impl(source.table_); +} +#endif - template <class T, class H, class P, class A> - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - typename unordered_set<T,H,P,A>::const_iterator - unordered_set<T,H,P,A>::find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const - { - return const_iterator(table_.generic_find_node(k, hash, eq)); - } +#if BOOST_UNORDERED_INTEROPERABLE_NODES +template <class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_set<T, H, P, A>::merge( + boost::unordered_multiset<T, H2, P2, A>& source) +{ + table_.merge_impl(source.table_); +} - template <class T, class H, class P, class A> - typename unordered_set<T,H,P,A>::size_type - unordered_set<T,H,P,A>::count(const key_type& k) const - { - return table_.count(k); - } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template <class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_set<T, H, P, A>::merge( + boost::unordered_multiset<T, H2, P2, A>&& source) +{ + table_.merge_impl(source.table_); +} +#endif +#endif - template <class T, class H, class P, class A> - std::pair< - typename unordered_set<T,H,P,A>::const_iterator, - typename unordered_set<T,H,P,A>::const_iterator> - unordered_set<T,H,P,A>::equal_range(const key_type& k) const - { - return table_.equal_range(k); - } +// lookup - template <class T, class H, class P, class A> - typename unordered_set<T,H,P,A>::size_type - unordered_set<T,H,P,A>::bucket_size(size_type n) const - { - return table_.bucket_size(n); - } +template <class T, class H, class P, class A> +typename unordered_set<T, H, P, A>::const_iterator +unordered_set<T, H, P, A>::find(const key_type& k) const +{ + return const_iterator(table_.find_node(k)); +} + +template <class T, class H, class P, class A> +template <class CompatibleKey, class CompatibleHash, class CompatiblePredicate> +typename unordered_set<T, H, P, A>::const_iterator +unordered_set<T, H, P, A>::find(CompatibleKey const& k, + CompatibleHash const& hash, CompatiblePredicate const& eq) const +{ + return const_iterator(table_.generic_find_node(k, hash, eq)); +} - // hash policy +template <class T, class H, class P, class A> +typename unordered_set<T, H, P, A>::size_type unordered_set<T, H, P, A>::count( + const key_type& k) const +{ + return table_.count(k); +} - template <class T, class H, class P, class A> - float unordered_set<T,H,P,A>::load_factor() const BOOST_NOEXCEPT - { - return table_.load_factor(); - } +template <class T, class H, class P, class A> +std::pair<typename unordered_set<T, H, P, A>::const_iterator, + typename unordered_set<T, H, P, A>::const_iterator> +unordered_set<T, H, P, A>::equal_range(const key_type& k) const +{ + return table_.equal_range(k); +} - template <class T, class H, class P, class A> - void unordered_set<T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT - { - table_.max_load_factor(m); - } +template <class T, class H, class P, class A> +typename unordered_set<T, H, P, A>::size_type +unordered_set<T, H, P, A>::bucket_size(size_type n) const +{ + return table_.bucket_size(n); +} - template <class T, class H, class P, class A> - void unordered_set<T,H,P,A>::rehash(size_type n) - { - table_.rehash(n); - } +// hash policy - template <class T, class H, class P, class A> - void unordered_set<T,H,P,A>::reserve(size_type n) - { - table_.reserve(n); - } +template <class T, class H, class P, class A> +float unordered_set<T, H, P, A>::load_factor() const BOOST_NOEXCEPT +{ + return table_.load_factor(); +} - template <class T, class H, class P, class A> - inline bool operator==( - unordered_set<T,H,P,A> const& m1, - unordered_set<T,H,P,A> const& m2) - { +template <class T, class H, class P, class A> +void unordered_set<T, H, P, A>::max_load_factor(float m) BOOST_NOEXCEPT +{ + table_.max_load_factor(m); +} + +template <class T, class H, class P, class A> +void unordered_set<T, H, P, A>::rehash(size_type n) +{ + table_.rehash(n); +} + +template <class T, class H, class P, class A> +void unordered_set<T, H, P, A>::reserve(size_type n) +{ + table_.reserve(n); +} + +template <class T, class H, class P, class A> +inline bool operator==( + unordered_set<T, H, P, A> const& m1, unordered_set<T, H, P, A> const& m2) +{ #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_set<T,H,P,A> x; }; + struct dummy + { + unordered_set<T, H, P, A> x; + }; #endif - return m1.table_.equals(m2.table_); - } + return m1.table_.equals(m2.table_); +} - template <class T, class H, class P, class A> - inline bool operator!=( - unordered_set<T,H,P,A> const& m1, - unordered_set<T,H,P,A> const& m2) - { +template <class T, class H, class P, class A> +inline bool operator!=( + unordered_set<T, H, P, A> const& m1, unordered_set<T, H, P, A> const& m2) +{ #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_set<T,H,P,A> x; }; + struct dummy + { + unordered_set<T, H, P, A> x; + }; #endif - return !m1.table_.equals(m2.table_); - } + return !m1.table_.equals(m2.table_); +} - template <class T, class H, class P, class A> - inline void swap( - unordered_set<T,H,P,A> &m1, - unordered_set<T,H,P,A> &m2) - { +template <class T, class H, class P, class A> +inline void swap(unordered_set<T, H, P, A>& m1, unordered_set<T, H, P, A>& m2) +{ #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_set<T,H,P,A> x; }; + struct dummy + { + unordered_set<T, H, P, A> x; + }; #endif - m1.swap(m2); - } + m1.swap(m2); +} //////////////////////////////////////////////////////////////////////////////// - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset() - : table_(boost::unordered::detail::default_bucket_count, hasher(), - key_equal(), allocator_type()) - { - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset() + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), allocator_type()) +{ +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - size_type n, const hasher &hf, const key_equal &eql, - const allocator_type &a) - : table_(n, hf, eql, a) - { - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset(size_type n, + const hasher& hf, const key_equal& eql, const allocator_type& a) + : table_(n, hf, eql, a) +{ +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - size_type n, const allocator_type &a) - : table_(n, hasher(), key_equal(), a) - { - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset( + size_type n, const allocator_type& a) + : table_(n, hasher(), key_equal(), a) +{ +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - size_type n, const hasher &hf, const allocator_type &a) - : table_(n, hf, key_equal(), a) - { - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset( + size_type n, const hasher& hf, const allocator_type& a) + : table_(n, hf, key_equal(), a) +{ +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset(allocator_type const& a) - : table_(boost::unordered::detail::default_bucket_count, - hasher(), key_equal(), a) - { - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset(allocator_type const& a) + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), a) +{ +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - unordered_multiset const& other, allocator_type const& a) - : table_(other.table_, a) - { - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset( + unordered_multiset const& other, allocator_type const& a) + : table_(other.table_, a) +{ +} - template <class T, class H, class P, class A> - template <class InputIt> - unordered_multiset<T,H,P,A>::unordered_multiset(InputIt f, InputIt l) - : table_(boost::unordered::detail::initial_size(f, l), - hasher(), key_equal(), allocator_type()) - { - table_.insert_range(f, l); - } +template <class T, class H, class P, class A> +template <class InputIt> +unordered_multiset<T, H, P, A>::unordered_multiset(InputIt f, InputIt l) + : table_(boost::unordered::detail::initial_size(f, l), hasher(), + key_equal(), allocator_type()) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_multiset<T, H, P, A>::unordered_multiset( + InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, + allocator_type()) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_multiset<T, H, P, A>::unordered_multiset(InputIt f, InputIt l, + size_type n, const hasher& hf, const key_equal& eql, + const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_multiset<T, H, P, A>::unordered_multiset(InputIt f, InputIt l, + size_type n, const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(f, l, n), hf, key_equal(), a) +{ + table_.insert_range(f, l); +} + +template <class T, class H, class P, class A> +template <class InputIt> +unordered_multiset<T, H, P, A>::unordered_multiset( + InputIt f, InputIt l, size_type n, const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hasher(), + key_equal(), a) +{ + table_.insert_range(f, l); +} - template <class T, class H, class P, class A> - template <class InputIt> - unordered_multiset<T,H,P,A>::unordered_multiset( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, eql, allocator_type()) - { - table_.insert_range(f, l); - } - - template <class T, class H, class P, class A> - template <class InputIt> - unordered_multiset<T,H,P,A>::unordered_multiset( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) - { - table_.insert_range(f, l); - } - - template <class T, class H, class P, class A> - template <class InputIt> - unordered_multiset<T,H,P,A>::unordered_multiset( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, key_equal(), a) - { - table_.insert_range(f, l); - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::~unordered_multiset() BOOST_NOEXCEPT +{ +} - template <class T, class H, class P, class A> - template <class InputIt> - unordered_multiset<T,H,P,A>::unordered_multiset( - InputIt f, InputIt l, - size_type n, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hasher(), key_equal(), a) - { - table_.insert_range(f, l); - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset( + unordered_multiset const& other) + : table_(other.table_) +{ +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::~unordered_multiset() BOOST_NOEXCEPT {} +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset( + BOOST_RV_REF(unordered_multiset) other, allocator_type const& a) + : table_(other.table_, a, boost::unordered::detail::move_tag()) +{ +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - unordered_multiset const& other) - : table_(other.table_) - { - } +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - BOOST_RV_REF(unordered_multiset) other, allocator_type const& a) - : table_(other.table_, a, boost::unordered::detail::move_tag()) - { - } +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset( + std::initializer_list<value_type> list, size_type n, const hasher& hf, + const key_equal& eql, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hf, eql, a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset( + std::initializer_list<value_type> list, size_type n, const hasher& hf, + const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hf, key_equal(), a) +{ + table_.insert_range(list.begin(), list.end()); +} + +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>::unordered_multiset( + std::initializer_list<value_type> list, size_type n, + const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(list.begin(), list.end(), n), + hasher(), key_equal(), a) +{ + table_.insert_range(list.begin(), list.end()); +} -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +template <class T, class H, class P, class A> +unordered_multiset<T, H, P, A>& unordered_multiset<T, H, P, A>::operator=( + std::initializer_list<value_type> list) +{ + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - std::initializer_list<value_type> list, size_type n, - const hasher &hf, const key_equal &eql, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, eql, a) - { - table_.insert_range(list.begin(), list.end()); - } +#endif - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - std::initializer_list<value_type> list, size_type n, - const hasher &hf, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } +// size and capacity - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::unordered_multiset( - std::initializer_list<value_type> list, size_type n, - const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hasher(), key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } +template <class T, class H, class P, class A> +std::size_t unordered_multiset<T, H, P, A>::max_size() const BOOST_NOEXCEPT +{ + return table_.max_size(); +} - template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>& unordered_multiset<T,H,P,A>::operator=( - std::initializer_list<value_type> list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } +// modifiers + +template <class T, class H, class P, class A> +template <class InputIt> +void unordered_multiset<T, H, P, A>::insert(InputIt first, InputIt last) +{ + table_.insert_range(first, last); +} +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +template <class T, class H, class P, class A> +void unordered_multiset<T, H, P, A>::insert( + std::initializer_list<value_type> list) +{ + table_.insert_range(list.begin(), list.end()); +} #endif - // size and capacity +template <class T, class H, class P, class A> +typename unordered_multiset<T, H, P, A>::iterator +unordered_multiset<T, H, P, A>::erase(const_iterator position) +{ + return table_.erase(position); +} - template <class T, class H, class P, class A> - std::size_t unordered_multiset<T,H,P,A>::max_size() const BOOST_NOEXCEPT - { - return table_.max_size(); - } +template <class T, class H, class P, class A> +typename unordered_multiset<T, H, P, A>::size_type +unordered_multiset<T, H, P, A>::erase(const key_type& k) +{ + return table_.erase_key(k); +} - // modifiers +template <class T, class H, class P, class A> +typename unordered_multiset<T, H, P, A>::iterator +unordered_multiset<T, H, P, A>::erase(const_iterator first, const_iterator last) +{ + return table_.erase_range(first, last); +} - template <class T, class H, class P, class A> - template <class InputIt> - void unordered_multiset<T,H,P,A>::insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); +template <class T, class H, class P, class A> +void unordered_multiset<T, H, P, A>::clear() +{ + table_.clear(); +} + +template <class T, class H, class P, class A> +void unordered_multiset<T, H, P, A>::swap(unordered_multiset& other) +{ + table_.swap(other.table_); +} + +// observers + +template <class T, class H, class P, class A> +typename unordered_multiset<T, H, P, A>::hasher +unordered_multiset<T, H, P, A>::hash_function() const +{ + return table_.hash_function(); +} + +template <class T, class H, class P, class A> +typename unordered_multiset<T, H, P, A>::key_equal +unordered_multiset<T, H, P, A>::key_eq() const +{ + return table_.key_eq(); +} + +template <class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_multiset<T, H, P, A>::merge( + boost::unordered_multiset<T, H2, P2, A>& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); } +} -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - template <class T, class H, class P, class A> - void unordered_multiset<T,H,P,A>::insert( - std::initializer_list<value_type> list) - { - table_.insert_range(list.begin(), list.end()); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template <class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_multiset<T, H, P, A>::merge( + boost::unordered_multiset<T, H2, P2, A>&& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); } +} #endif - template <class T, class H, class P, class A> - typename unordered_multiset<T,H,P,A>::iterator - unordered_multiset<T,H,P,A>::erase(const_iterator position) - { - return table_.erase(position); +#if BOOST_UNORDERED_INTEROPERABLE_NODES +template <class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_multiset<T, H, P, A>::merge( + boost::unordered_set<T, H2, P2, A>& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); } +} - template <class T, class H, class P, class A> - typename unordered_multiset<T,H,P,A>::size_type - unordered_multiset<T,H,P,A>::erase(const key_type& k) - { - return table_.erase_key(k); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template <class T, class H, class P, class A> +template <typename H2, typename P2> +void unordered_multiset<T, H, P, A>::merge( + boost::unordered_set<T, H2, P2, A>&& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); } +} +#endif +#endif + +// lookup + +template <class T, class H, class P, class A> +typename unordered_multiset<T, H, P, A>::const_iterator +unordered_multiset<T, H, P, A>::find(const key_type& k) const +{ + return const_iterator(table_.find_node(k)); +} + +template <class T, class H, class P, class A> +template <class CompatibleKey, class CompatibleHash, class CompatiblePredicate> +typename unordered_multiset<T, H, P, A>::const_iterator +unordered_multiset<T, H, P, A>::find(CompatibleKey const& k, + CompatibleHash const& hash, CompatiblePredicate const& eq) const +{ + return const_iterator(table_.generic_find_node(k, hash, eq)); +} + +template <class T, class H, class P, class A> +typename unordered_multiset<T, H, P, A>::size_type +unordered_multiset<T, H, P, A>::count(const key_type& k) const +{ + return table_.count(k); +} - template <class T, class H, class P, class A> - typename unordered_multiset<T,H,P,A>::iterator - unordered_multiset<T,H,P,A>::erase( - const_iterator first, const_iterator last) +template <class T, class H, class P, class A> +std::pair<typename unordered_multiset<T, H, P, A>::const_iterator, + typename unordered_multiset<T, H, P, A>::const_iterator> +unordered_multiset<T, H, P, A>::equal_range(const key_type& k) const +{ + return table_.equal_range(k); +} + +template <class T, class H, class P, class A> +typename unordered_multiset<T, H, P, A>::size_type +unordered_multiset<T, H, P, A>::bucket_size(size_type n) const +{ + return table_.bucket_size(n); +} + +// hash policy + +template <class T, class H, class P, class A> +float unordered_multiset<T, H, P, A>::load_factor() const BOOST_NOEXCEPT +{ + return table_.load_factor(); +} + +template <class T, class H, class P, class A> +void unordered_multiset<T, H, P, A>::max_load_factor(float m) BOOST_NOEXCEPT +{ + table_.max_load_factor(m); +} + +template <class T, class H, class P, class A> +void unordered_multiset<T, H, P, A>::rehash(size_type n) +{ + table_.rehash(n); +} + +template <class T, class H, class P, class A> +void unordered_multiset<T, H, P, A>::reserve(size_type n) +{ + table_.reserve(n); +} + +template <class T, class H, class P, class A> +inline bool operator==(unordered_multiset<T, H, P, A> const& m1, + unordered_multiset<T, H, P, A> const& m2) +{ +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { - return table_.erase_range(first, last); - } + unordered_multiset<T, H, P, A> x; + }; +#endif + return m1.table_.equals(m2.table_); +} - template <class T, class H, class P, class A> - void unordered_multiset<T,H,P,A>::clear() +template <class T, class H, class P, class A> +inline bool operator!=(unordered_multiset<T, H, P, A> const& m1, + unordered_multiset<T, H, P, A> const& m2) +{ +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { - table_.clear(); - } + unordered_multiset<T, H, P, A> x; + }; +#endif + return !m1.table_.equals(m2.table_); +} - template <class T, class H, class P, class A> - void unordered_multiset<T,H,P,A>::swap(unordered_multiset& other) +template <class T, class H, class P, class A> +inline void swap( + unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2) +{ +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { - table_.swap(other.table_); - } + unordered_multiset<T, H, P, A> x; + }; +#endif + m1.swap(m2); +} - // observers +template <typename N, typename T, typename A> class node_handle_set +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_set) - template <class T, class H, class P, class A> - typename unordered_multiset<T,H,P,A>::hasher - unordered_multiset<T,H,P,A>::hash_function() const - { - return table_.hash_function(); - } + template <typename Types> + friend struct ::boost::unordered::detail::table_impl; + template <typename Types> + friend struct ::boost::unordered::detail::grouped_table_impl; - template <class T, class H, class P, class A> - typename unordered_multiset<T,H,P,A>::key_equal - unordered_multiset<T,H,P,A>::key_eq() const - { - return table_.key_eq(); - } + typedef typename boost::unordered::detail::rebind_wrap<A, T>::type + value_allocator; + typedef boost::unordered::detail::allocator_traits<value_allocator> + value_allocator_traits; + typedef N node; + typedef typename boost::unordered::detail::rebind_wrap<A, node>::type + node_allocator; + typedef boost::unordered::detail::allocator_traits<node_allocator> + node_allocator_traits; + typedef typename node_allocator_traits::pointer node_pointer; - // lookup + public: + typedef T value_type; + typedef A allocator_type; + + private: + node_pointer ptr_; + bool has_alloc_; + boost::unordered::detail::value_base<value_allocator> alloc_; - template <class T, class H, class P, class A> - typename unordered_multiset<T,H,P,A>::const_iterator - unordered_multiset<T,H,P,A>::find(const key_type& k) const + public: + BOOST_CONSTEXPR node_handle_set() BOOST_NOEXCEPT : ptr_(), has_alloc_(false) { - return const_iterator(table_.find_node(k)); } - template <class T, class H, class P, class A> - template <class CompatibleKey, class CompatibleHash, - class CompatiblePredicate> - typename unordered_multiset<T,H,P,A>::const_iterator - unordered_multiset<T,H,P,A>::find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const + /*BOOST_CONSTEXPR */ node_handle_set( + node_pointer ptr, allocator_type const& a) + : ptr_(ptr), has_alloc_(false) { - return const_iterator(table_.generic_find_node(k, hash, eq)); + if (ptr_) { + new ((void*)&alloc_) value_allocator(a); + has_alloc_ = true; + } } - template <class T, class H, class P, class A> - typename unordered_multiset<T,H,P,A>::size_type - unordered_multiset<T,H,P,A>::count(const key_type& k) const + ~node_handle_set() { - return table_.count(k); + if (has_alloc_ && ptr_) { + node_allocator node_alloc(alloc_.value()); + boost::unordered::detail::node_tmp<node_allocator> tmp( + ptr_, node_alloc); + } + if (has_alloc_) { + alloc_.value_ptr()->~value_allocator(); + } } - template <class T, class H, class P, class A> - std::pair< - typename unordered_multiset<T,H,P,A>::const_iterator, - typename unordered_multiset<T,H,P,A>::const_iterator> - unordered_multiset<T,H,P,A>::equal_range(const key_type& k) const + node_handle_set(BOOST_RV_REF(node_handle_set) n) BOOST_NOEXCEPT + : ptr_(n.ptr_), + has_alloc_(false) { - return table_.equal_range(k); + if (n.has_alloc_) { + new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value())); + has_alloc_ = true; + n.ptr_ = node_pointer(); + n.alloc_.value_ptr()->~value_allocator(); + n.has_alloc_ = false; + } } - template <class T, class H, class P, class A> - typename unordered_multiset<T,H,P,A>::size_type - unordered_multiset<T,H,P,A>::bucket_size(size_type n) const + node_handle_set& operator=(BOOST_RV_REF(node_handle_set) n) { - return table_.bucket_size(n); - } + BOOST_ASSERT(!has_alloc_ || + value_allocator_traits:: + propagate_on_container_move_assignment::value || + (n.has_alloc_ && alloc_.value() == n.alloc_.value())); - // hash policy + if (ptr_) { + node_allocator node_alloc(alloc_.value()); + boost::unordered::detail::node_tmp<node_allocator> tmp( + ptr_, node_alloc); + ptr_ = node_pointer(); + } - template <class T, class H, class P, class A> - float unordered_multiset<T,H,P,A>::load_factor() const BOOST_NOEXCEPT - { - return table_.load_factor(); - } + if (has_alloc_) { + alloc_.value_ptr()->~value_allocator(); + has_alloc_ = false; + } - template <class T, class H, class P, class A> - void unordered_multiset<T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT - { - table_.max_load_factor(m); + if (!has_alloc_ && n.has_alloc_) { + move_allocator(n); + } + + ptr_ = n.ptr_; + n.ptr_ = node_pointer(); + + return *this; } - template <class T, class H, class P, class A> - void unordered_multiset<T,H,P,A>::rehash(size_type n) + value_type& value() const { return ptr_->value(); } + + allocator_type get_allocator() const { return alloc_.value(); } + + BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() + + bool operator!() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; } + + bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; } + + void swap(node_handle_set& n) BOOST_NOEXCEPT_IF( + value_allocator_traits::propagate_on_container_swap::value + /* || value_allocator_traits::is_always_equal::value */) { - table_.rehash(n); + if (!has_alloc_) { + if (n.has_alloc_) { + move_allocator(n); + } + } else if (!n.has_alloc_) { + n.move_allocator(*this); + } else { + swap_impl(n, boost::unordered::detail::integral_constant<bool, + value_allocator_traits:: + propagate_on_container_swap::value>()); + } + boost::swap(ptr_, n.ptr_); } - template <class T, class H, class P, class A> - void unordered_multiset<T,H,P,A>::reserve(size_type n) + private: + void move_allocator(node_handle_set& n) { - table_.reserve(n); + new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value())); + n.alloc_.value_ptr()->~value_allocator(); + has_alloc_ = true; + n.has_alloc_ = false; } - template <class T, class H, class P, class A> - inline bool operator==( - unordered_multiset<T,H,P,A> const& m1, - unordered_multiset<T,H,P,A> const& m2) + void swap_impl(node_handle_set&, boost::unordered::detail::false_type) {} + + void swap_impl(node_handle_set& n, boost::unordered::detail::true_type) { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_multiset<T,H,P,A> x; }; -#endif - return m1.table_.equals(m2.table_); + boost::swap(alloc_, n.alloc_); } +}; + +template <typename N, typename T, typename A> +void swap(node_handle_set<N, T, A>& x, node_handle_set<N, T, A>& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(x.swap(y))) +{ + x.swap(y); +} + +template <typename N, typename T, typename A> struct insert_return_type_set +{ + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_set) + + typedef typename boost::unordered::detail::rebind_wrap<A, T>::type + value_allocator; + typedef N node_; - template <class T, class H, class P, class A> - inline bool operator!=( - unordered_multiset<T,H,P,A> const& m1, - unordered_multiset<T,H,P,A> const& m2) + public: + bool inserted; + boost::unordered::iterator_detail::c_iterator<node_> position; + boost::unordered::node_handle_set<N, T, A> node; + + insert_return_type_set() : inserted(false), position(), node() {} + + insert_return_type_set(BOOST_RV_REF(insert_return_type_set) + x) BOOST_NOEXCEPT : inserted(x.inserted), + position(x.position), + node(boost::move(x.node)) { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_multiset<T,H,P,A> x; }; -#endif - return !m1.table_.equals(m2.table_); } - template <class T, class H, class P, class A> - inline void swap( - unordered_multiset<T,H,P,A> &m1, - unordered_multiset<T,H,P,A> &m2) + insert_return_type_set& operator=(BOOST_RV_REF(insert_return_type_set) x) { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_multiset<T,H,P,A> x; }; -#endif - m1.swap(m2); + inserted = x.inserted; + position = x.position; + node = boost::move(x.node); + return *this; } +}; + +template <typename N, typename T, typename A> +void swap( + insert_return_type_set<N, T, A>& x, insert_return_type_set<N, T, A>& y) +{ + boost::swap(x.node, y.node); + boost::swap(x.inserted, y.inserted); + boost::swap(x.position, y.position); +} } // namespace unordered } // namespace boost diff --git a/boost/unordered/unordered_set_fwd.hpp b/boost/unordered/unordered_set_fwd.hpp index 52b9e822f2..d3a3b51e74 100644 --- a/boost/unordered/unordered_set_fwd.hpp +++ b/boost/unordered/unordered_set_fwd.hpp @@ -11,53 +11,49 @@ #pragma once #endif -#include <memory> -#include <functional> #include <boost/functional/hash_fwd.hpp> #include <boost/unordered/detail/fwd.hpp> +#include <functional> +#include <memory> + +namespace boost { +namespace unordered { +template <class T, class H = boost::hash<T>, class P = std::equal_to<T>, + class A = std::allocator<T> > +class unordered_set; + +template <class T, class H, class P, class A> +inline bool operator==( + unordered_set<T, H, P, A> const&, unordered_set<T, H, P, A> const&); +template <class T, class H, class P, class A> +inline bool operator!=( + unordered_set<T, H, P, A> const&, unordered_set<T, H, P, A> const&); +template <class T, class H, class P, class A> +inline void swap(unordered_set<T, H, P, A>& m1, unordered_set<T, H, P, A>& m2); + +template <class T, class H = boost::hash<T>, class P = std::equal_to<T>, + class A = std::allocator<T> > +class unordered_multiset; + +template <class T, class H, class P, class A> +inline bool operator==(unordered_multiset<T, H, P, A> const&, + unordered_multiset<T, H, P, A> const&); +template <class T, class H, class P, class A> +inline bool operator!=(unordered_multiset<T, H, P, A> const&, + unordered_multiset<T, H, P, A> const&); +template <class T, class H, class P, class A> +inline void swap( + unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2); + +template <class N, class T, class A> class node_handle_set; +template <class N, class T, class A> struct insert_return_type_set; +} -namespace boost -{ - namespace unordered - { - template <class T, - class H = boost::hash<T>, - class P = std::equal_to<T>, - class A = std::allocator<T> > - class unordered_set; - - template <class T, class H, class P, class A> - inline bool operator==(unordered_set<T, H, P, A> const&, - unordered_set<T, H, P, A> const&); - template <class T, class H, class P, class A> - inline bool operator!=(unordered_set<T, H, P, A> const&, - unordered_set<T, H, P, A> const&); - template <class T, class H, class P, class A> - inline void swap(unordered_set<T, H, P, A> &m1, - unordered_set<T, H, P, A> &m2); - - template <class T, - class H = boost::hash<T>, - class P = std::equal_to<T>, - class A = std::allocator<T> > - class unordered_multiset; - - template <class T, class H, class P, class A> - inline bool operator==(unordered_multiset<T, H, P, A> const&, - unordered_multiset<T, H, P, A> const&); - template <class T, class H, class P, class A> - inline bool operator!=(unordered_multiset<T, H, P, A> const&, - unordered_multiset<T, H, P, A> const&); - template <class T, class H, class P, class A> - inline void swap(unordered_multiset<T, H, P, A> &m1, - unordered_multiset<T, H, P, A> &m2); - } - - using boost::unordered::unordered_set; - using boost::unordered::unordered_multiset; - using boost::unordered::swap; - using boost::unordered::operator==; - using boost::unordered::operator!=; +using boost::unordered::unordered_set; +using boost::unordered::unordered_multiset; +using boost::unordered::swap; +using boost::unordered::operator==; +using boost::unordered::operator!=; } #endif |