From 67ab88b064e479e5e07f0ecd64fda447988ab258 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 19 Feb 2017 13:05:17 +0000 Subject: [PATCH] Combine most of the detail headers into a single header --- include/boost/unordered/detail/allocate.hpp | 1396 ----- include/boost/unordered/detail/buckets.hpp | 768 --- include/boost/unordered/detail/equivalent.hpp | 730 --- .../boost/unordered/detail/extract_key.hpp | 183 - .../boost/unordered/detail/implementation.hpp | 4746 +++++++++++++++++ include/boost/unordered/detail/map.hpp | 2 +- include/boost/unordered/detail/set.hpp | 2 +- include/boost/unordered/detail/table.hpp | 789 --- include/boost/unordered/detail/unique.hpp | 676 --- include/boost/unordered/detail/util.hpp | 279 - test/helpers/memory.hpp | 2 +- test/unordered/allocator_traits.cpp | 2 +- test/unordered/minimal_allocator.cpp | 2 +- 13 files changed, 4751 insertions(+), 4826 deletions(-) delete mode 100644 include/boost/unordered/detail/allocate.hpp delete mode 100644 include/boost/unordered/detail/buckets.hpp delete mode 100644 include/boost/unordered/detail/equivalent.hpp delete mode 100644 include/boost/unordered/detail/extract_key.hpp create mode 100644 include/boost/unordered/detail/implementation.hpp delete mode 100644 include/boost/unordered/detail/table.hpp delete mode 100644 include/boost/unordered/detail/unique.hpp delete mode 100644 include/boost/unordered/detail/util.hpp diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp deleted file mode 100644 index 39a6c3f6..00000000 --- a/include/boost/unordered/detail/allocate.hpp +++ /dev/null @@ -1,1396 +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 - -#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 boost::add_lvalue_reference::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 - no_type is_private_type(T const&); - yes_type is_private_type(private_type const&); - - struct convert_from_anything { - template - 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 T* const_cast_pointer(T* x) { return x; } - template T* const_cast_pointer(T const* x) { - return const_cast(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)... - -#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::type \ - BOOST_PP_CAT(Arg, n); \ - BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); - -#endif - -template -struct emplace_args1 -{ - BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) - - emplace_args1(Arg0 b0) : a0(b0) {} -}; - -template -inline emplace_args1 create_emplace_args( - BOOST_FWD_REF(A0) b0) -{ - emplace_args1 e(b0); - return e; -} - -template -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 -inline emplace_args2 create_emplace_args( - BOOST_FWD_REF(A0) b0, - BOOST_FWD_REF(A1) b1) -{ - emplace_args2 e(b0, b1); - return e; -} - -template -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 -inline emplace_args3 create_emplace_args( - BOOST_FWD_REF(A0) b0, - BOOST_FWD_REF(A1) b1, - BOOST_FWD_REF(A2) b2) -{ - emplace_args3 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)) - -#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ -BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n)) - -#define BOOST_UNORDERED_EARGS(z, n, _) \ - template \ - 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 \ - 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 -#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 - struct integral_constant { enum { value = Value }; }; - - typedef boost::unordered::detail::integral_constant true_type; - typedef boost::unordered::detail::integral_constant 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 - 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 struct expr_test; - template struct expr_test : T {}; - -# define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ - template \ - 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 \ - 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 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(choose())) == sizeof(choice1::type) };\ - } - -#else - - template struct identity { typedef T type; }; - -# define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ - \ - typedef typename boost::unordered::detail::identity::type \ - BOOST_PP_CAT(check, count); \ - \ - template \ - struct BOOST_PP_CAT(test, count) { \ - typedef BOOST_PP_CAT(choice, result) type; \ - }; \ - \ - template static typename \ - BOOST_PP_CAT(test, count)<&U::name>::type \ - test(BOOST_PP_CAT(choice, count)) - -# define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ - template 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(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 -# include -# include -# if defined(BOOST_NO_SFINAE_EXPR) -# include -# 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 - struct rebind_alloc; - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - template class Alloc, - typename U, typename T, typename... Args> - struct rebind_alloc, T> - { - typedef Alloc type; - }; - -#else - - template < - template class Alloc, - typename U, typename T> - struct rebind_alloc, T> - { - typedef Alloc type; - }; - - template < - template class Alloc, - typename U, typename T, - typename A0> - struct rebind_alloc, T> - { - typedef Alloc type; - }; - - template < - template class Alloc, - typename U, typename T, - typename A0, typename A1> - struct rebind_alloc, T> - { - typedef Alloc type; - }; - -#endif - - template - struct rebind_wrap - { - template - static choice1::type test(choice1, - typename X::BOOST_NESTED_TEMPLATE rebind::other* = 0); - template - static choice2::type test(choice2, void* = 0); - - enum { value = (1 == sizeof(test(choose()))) }; - - struct fallback { - template - struct rebind { - typedef typename rebind_alloc::type other; - }; - }; - - typedef typename boost::detail::if_true:: - BOOST_NESTED_TEMPLATE then - ::type::BOOST_NESTED_TEMPLATE rebind::other type; - }; - -# if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 - -# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ - template \ - struct default_type_ ## tname { \ - \ - template \ - static choice1::type test(choice1, typename X::tname* = 0); \ - \ - template \ - static choice2::type test(choice2, void* = 0); \ - \ - struct DefaultWrap { typedef Default tname; }; \ - \ - enum { value = (1 == sizeof(test(choose()))) }; \ - \ - typedef typename boost::detail::if_true:: \ - BOOST_NESTED_TEMPLATE then \ - ::type::tname type; \ - } - -# else - - template - struct sfinae : T2 {}; - -# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ - template \ - struct default_type_ ## tname { \ - \ - template \ - static typename boost::unordered::detail::sfinae< \ - typename X::tname, choice1>::type \ - test(choice1); \ - \ - template \ - static choice2::type test(choice2); \ - \ - struct DefaultWrap { typedef Default tname; }; \ - \ - enum { value = (1 == sizeof(test(choose()))) }; \ - \ - typedef typename boost::detail::if_true:: \ - BOOST_NESTED_TEMPLATE then \ - ::type::tname type; \ - } - -# endif - -# define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \ - typename default_type_ ## tname::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 - BOOST_UNORDERED_HAS_FUNCTION( - select_on_container_copy_construction, U const, (), 0 - ); - - template - BOOST_UNORDERED_HAS_FUNCTION( - max_size, U const, (), 0 - ); - -# if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - template - BOOST_UNORDERED_HAS_FUNCTION( - construct, U, ( - boost::unordered::detail::make(), - boost::unordered::detail::make()...), 2 - ); - -# else - - template - BOOST_UNORDERED_HAS_FUNCTION( - construct, U, ( - boost::unordered::detail::make(), - boost::unordered::detail::make()), 2 - ); - -# endif - - template - BOOST_UNORDERED_HAS_FUNCTION( - destroy, U, (boost::unordered::detail::make()), 1 - ); - -# else - - template - BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction); - - template - BOOST_UNORDERED_HAS_MEMBER(max_size); - - template - BOOST_UNORDERED_HAS_MEMBER(construct); - - template - BOOST_UNORDERED_HAS_MEMBER(destroy); - -# endif - - namespace func - { - - template - 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::value, void* - >::type = 0) - { - return rhs.select_on_container_copy_construction(); - } - - template - 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::value, void* - >::type = 0) - { - return rhs; - } - - template - inline SizeType call_max_size(const Alloc& a, - typename boost::enable_if_c< - boost::unordered::detail::has_max_size::value, void* - >::type = 0) - { - return a.max_size(); - } - - template - inline SizeType call_max_size(const Alloc&, typename boost::disable_if_c< - boost::unordered::detail::has_max_size::value, void* - >::type = 0) - { - return (std::numeric_limits::max)(); - } - - } // namespace func. - - template - 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 - struct pointer_to_other : boost::pointer_to_other {}; - - typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, - typename pointer_to_other::type) - const_pointer; - - //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer, - // typename pointer_to_other::type) - // void_pointer; - // - //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer, - // typename pointer_to_other::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 - using rebind_alloc = typename rebind_wrap::type; - - template - using rebind_traits = - boost::unordered::detail::allocator_traits >; -#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 - static typename boost::enable_if_c< - boost::unordered::detail::has_construct - ::value>::type - construct(Alloc& a, T* p, BOOST_FWD_REF(Args)... x) - { - a.construct(p, boost::forward(x)...); - } - - template - static typename boost::disable_if_c< - boost::unordered::detail::has_construct - ::value>::type - construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x) - { - new (static_cast(p)) T(boost::forward(x)...); - } - - template - static typename boost::enable_if_c< - boost::unordered::detail::has_destroy::value>::type - destroy(Alloc& a, T* p) - { - a.destroy(p); - } - - template - static typename boost::disable_if_c< - boost::unordered::detail::has_destroy::value>::type - destroy(Alloc&, T* p) - { - boost::unordered::detail::func::destroy(p); - } - -# elif !defined(BOOST_NO_SFINAE_EXPR) - - template - static typename boost::enable_if_c< - boost::unordered::detail::has_construct::value>::type - construct(Alloc& a, T* p, T const& x) - { - a.construct(p, x); - } - - template - static typename boost::disable_if_c< - boost::unordered::detail::has_construct::value>::type - construct(Alloc&, T* p, T const& x) - { - new (static_cast(p)) T(x); - } - - template - static typename boost::enable_if_c< - boost::unordered::detail::has_destroy::value>::type - destroy(Alloc& a, T* p) - { - a.destroy(p); - } - - template - static typename boost::disable_if_c< - boost::unordered::detail::has_destroy::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 - static void construct(Alloc& a, T* p, T const& x, - typename boost::enable_if_c< - boost::unordered::detail::has_construct::value && - boost::is_same::value, - void*>::type = 0) - { - a.construct(p, x); - } - - template - static void construct(Alloc&, T* p, T const& x, - typename boost::disable_if_c< - boost::unordered::detail::has_construct::value && - boost::is_same::value, - void*>::type = 0) - { - new (static_cast(p)) T(x); - } - - template - static void destroy(Alloc& a, T* p, - typename boost::enable_if_c< - boost::unordered::detail::has_destroy::value && - boost::is_same::value, - void*>::type = 0) - { - a.destroy(p); - } - - template - static void destroy(Alloc&, T* p, - typename boost::disable_if_c< - boost::unordered::detail::has_destroy::value && - boost::is_same::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(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 - -# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 - -namespace boost { namespace unordered { namespace detail { - - template - struct allocator_traits : std::allocator_traits {}; - - template - struct rebind_wrap - { - typedef typename std::allocator_traits:: - template rebind_alloc type; - }; -}}} - -//////////////////////////////////////////////////////////////////////////////// -// -// boost::container::allocator_traits - -#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 - -# include - -# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 - -namespace boost { namespace unordered { namespace detail { - - template - struct allocator_traits : - boost::container::allocator_traits {}; - - template - struct rebind_wrap : - boost::container::allocator_traits:: - template portable_rebind_alloc - {}; - -}}} - -#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 - inline void call_construct(Alloc& alloc, T* address, - BOOST_FWD_REF(Args)... args) - { - boost::unordered::detail::allocator_traits::construct(alloc, - address, boost::forward(args)...); - } - - template - inline void call_destroy(Alloc& alloc, T* x) { - boost::unordered::detail::allocator_traits::destroy(alloc, x); - } - - -# else - - template - inline void call_construct(Alloc&, T* address, - BOOST_FWD_REF(Args)... args) - { - new((void*) address) T(boost::forward(args)...); - } - - template - inline void call_destroy(Alloc&, T* x) { - boost::unordered::detail::func::destroy(x); - } - - -# endif - -#else - template - inline void call_construct(Alloc&, T* address) - { - new ((void*) address) T(); - } - - template - inline void call_construct(Alloc&, T* address, - BOOST_FWD_REF(A0) a0) - { - new ((void*) address) T(boost::forward(a0)); - } - - template - 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 \ - 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 \ - void construct_from_tuple(Alloc& alloc, T* ptr, \ - namespace_ tuple 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(x) - -#elif !defined(__SUNPRO_CC) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template \ - 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 \ - void construct_from_tuple(Alloc&, T* ptr, \ - namespace_ tuple 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(x) - -#else - - template struct length {}; - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template \ - 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 \ - void construct_from_tuple_impl( \ - boost::unordered::detail::func::length, Alloc&, T* ptr, \ - namespace_ tuple 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(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 - void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x) - { - construct_from_tuple_impl( - boost::unordered::detail::func::length< - boost::tuples::length::value>(), - alloc, ptr, x); - } - -#endif - - //////////////////////////////////////////////////////////////////////////// - // Trait to check for piecewise construction. - - template - 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())) }; - }; - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - //////////////////////////////////////////////////////////////////////////// - // Construct from variadic parameters - - // For the standard pair constructor. - - template - 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)...); - } - - // 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 - inline typename enable_if, void>::type - construct_from_args(Alloc& alloc, std::pair* 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)); - BOOST_TRY { - boost::unordered::detail::func::construct_from_tuple(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->second)), - boost::forward(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 - inline void construct_from_args(Alloc&, T* address, - emplace_args1 const& args) - { - new((void*) address) T(boost::forward(args.a0)); - } - - template - inline void construct_from_args(Alloc&, T* address, - emplace_args2 const& args) - { - new((void*) address) T( - boost::forward(args.a0), - boost::forward(args.a1) - ); - } - - template - inline void construct_from_args(Alloc&, T* address, - emplace_args3 const& args) - { - new((void*) address) T( - boost::forward(args.a0), - boost::forward(args.a1), - boost::forward(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 - inline void construct_from_args(Alloc& alloc, std::pair* address, - boost::unordered::detail::emplace_args3 const& args, - typename enable_if, 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 - struct node_constructor - { - typedef NodeAlloc node_allocator; - typedef boost::unordered::detail::allocator_traits - 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 - node_constructor::~node_constructor() - { - if (node_) { - if (node_constructed_) { - boost::unordered::detail::func::destroy( - boost::addressof(*node_)); - } - - node_allocator_traits::deallocate(alloc_, node_, 1); - } - } - - template - void node_constructor::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 - struct node_tmp - { - typedef boost::unordered::detail::allocator_traits - 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 - node_tmp::~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 - inline typename boost::unordered::detail::allocator_traits::pointer - construct_node_from_args(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS) - { - node_constructor a(alloc); - a.create_node(); - construct_from_args(alloc, a.node_->value_ptr(), - BOOST_UNORDERED_EMPLACE_FORWARD); - return a.release(); - } - - template - inline typename boost::unordered::detail::allocator_traits::pointer - construct_node(Alloc& alloc, BOOST_FWD_REF(U) x) - { - node_constructor a(alloc); - a.create_node(); - boost::unordered::detail::func::call_construct( - alloc, a.node_->value_ptr(), boost::forward(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 - inline typename boost::unordered::detail::allocator_traits::pointer - construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) - { - node_constructor 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(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 - inline typename boost::unordered::detail::allocator_traits::pointer - construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) - { - node_constructor 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(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(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(); - } -}}}} - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - -#endif diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp deleted file mode 100644 index e4adb83d..00000000 --- a/include/boost/unordered/detail/buckets.hpp +++ /dev/null @@ -1,768 +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 - -namespace boost { namespace unordered { namespace detail { - - template struct table; - template struct bucket; - struct ptr_bucket; - template struct table_impl; - template 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 struct iterator; - template struct c_iterator; - template struct l_iterator; - template - struct cl_iterator; - - // Local Iterators - // - // all no throw - - template - 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 - 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(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 - 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 - ; - 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(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 - 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 - friend struct boost::unordered::iterator_detail::c_iterator; - template - friend struct boost::unordered::detail::table; - template - friend struct boost::unordered::detail::table_impl; - template - 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(x)) {} - - value_type& operator*() const { - return node_->value(); - } - - value_type* operator->() const { - return node_->value_ptr(); - } - - iterator& operator++() { - node_ = static_cast(node_->next_); - return *this; - } - - iterator operator++(int) { - iterator tmp(node_); - node_ = static_cast(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 - 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; - -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template - friend struct boost::unordered::detail::table; - template - friend struct boost::unordered::detail::table_impl; - template - friend struct boost::unordered::detail::grouped_table_impl; - - private: -#endif - typedef typename Node::node_pointer node_pointer; - typedef boost::unordered::iterator_detail::iterator 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(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_->next_); - return *this; - } - - c_iterator operator++(int) { - c_iterator tmp(node_); - node_ = static_cast(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 - struct node_holder - { - private: - typedef NodeAlloc node_allocator; - typedef boost::unordered::detail::allocator_traits - 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 iterator; - - node_constructor constructor_; - node_pointer nodes_; - - public: - - template - 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(prev->next_); - prev->next_ = link_pointer(); - b.size_ = 0; - } - } - - ~node_holder(); - - node_pointer pop_node() - { - node_pointer n = nodes_; - nodes_ = static_cast(nodes_->next_); - n->init(n); - n->next_ = link_pointer(); - return n; - } - - template - 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 - 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 - node_holder::~node_holder() - { - while (nodes_) { - node_pointer p = nodes_; - nodes_ = static_cast(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 - 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 - struct prime_policy - { - template - 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 - struct mix64_policy - { - template - 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 - struct pick_policy_impl { - typedef prime_policy type; - }; - - template <> - struct pick_policy_impl<64, 2> { - typedef mix64_policy type; - }; - - template - struct pick_policy : - pick_policy_impl< - std::numeric_limits::digits, - std::numeric_limits::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 { - typedef prime_policy type; - }; - - template <> - struct pick_policy { - typedef prime_policy type; - }; - - template <> - struct pick_policy { - typedef prime_policy type; - }; - - template <> - struct pick_policy { - typedef prime_policy type; - }; - - // TODO: Maybe not if std::size_t is smaller than long long. -#if !defined(BOOST_NO_LONG_LONG) - template <> - struct pick_policy { - typedef prime_policy type; - }; - - template <> - struct pick_policy { - typedef prime_policy 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 set_hash_functions; - - template - class functions - { - public: - static const bool nothrow_move_assignable = - boost::is_nothrow_move_assignable::value && - boost::is_nothrow_move_assignable

::value; - static const bool nothrow_move_constructible = - boost::is_nothrow_move_constructible::value && - boost::is_nothrow_move_constructible

::value; - - private: - friend class boost::unordered::detail::set_hash_functions; - functions& operator=(functions const&); - - typedef compressed function_pair; - - typedef typename boost::aligned_storage< - sizeof(function_pair), - boost::alignment_of::value>::type aligned_function; - - bool current_; // The currently active functions. - aligned_function funcs_[2]; - - function_pair const& current() const { - return *static_cast( - static_cast(&funcs_[current_])); - } - - function_pair& current() { - return *static_cast( - static_cast(&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 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()); - } - - ~functions() { - this->destroy(current_); - } - - H const& hash_function() const { - return current().first(); - } - - P const& key_eq() const { - return current().second(); - } - }; - - template - class set_hash_functions - { - set_hash_functions(set_hash_functions const&); - set_hash_functions& operator=(set_hash_functions const&); - - typedef functions 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 set_hash_functions - { - set_hash_functions(set_hash_functions const&); - set_hash_functions& operator=(set_hash_functions const&); - - typedef functions 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 - struct rv_ref_impl { - typedef BOOST_RV_REF(T) type; - }; - - template - struct rv_ref : - boost::detail::if_true< - boost::is_class::value - >::BOOST_NESTED_TEMPLATE then < - boost::unordered::detail::rv_ref_impl, - please_ignore_this_overload - >::type - {}; - -# define BOOST_UNORDERED_RV_REF(T) \ - typename boost::unordered::detail::rv_ref::type -#endif -}}} - -#endif diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp deleted file mode 100644 index 3a648086..00000000 --- a/include/boost/unordered/detail/equivalent.hpp +++ /dev/null @@ -1,730 +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 - -namespace boost { namespace unordered { namespace detail { - - template struct grouped_node; - template struct grouped_ptr_node; - template struct grouped_table_impl; - - template - struct grouped_node : - boost::unordered::detail::value_base - { - typedef typename ::boost::unordered::detail::rebind_wrap< - A, grouped_node >::type allocator; - typedef typename ::boost::unordered::detail:: - allocator_traits::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 - 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* node_pointer; - typedef ptr_bucket* link_pointer; - - node_pointer group_prev_; - std::size_t hash_; - boost::unordered::detail::value_base 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 - struct pick_grouped_node2 - { - typedef boost::unordered::detail::grouped_node node; - - typedef typename boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type - >::pointer node_pointer; - - typedef boost::unordered::detail::bucket bucket; - typedef node_pointer link_pointer; - }; - - template - struct pick_grouped_node2*, - boost::unordered::detail::ptr_bucket*> - { - typedef boost::unordered::detail::grouped_ptr_node node; - typedef boost::unordered::detail::ptr_bucket bucket; - typedef bucket* link_pointer; - }; - - template - struct pick_grouped_node - { - typedef typename boost::remove_const::type nonconst; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap >::type - > tentative_node_traits; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type - > tentative_bucket_traits; - - typedef pick_grouped_node2 pick; - - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - }; - - template - struct grouped_table_impl : boost::unordered::detail::table - { - typedef boost::unordered::detail::table 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(n->next_); - } - - static inline node_pointer next_group(node_pointer n) { - return static_cast(n->group_prev_->next_); - } - - // Accessors - - template - 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 - 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 - 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 - 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 - void insert_range(I i, I j, typename - boost::unordered::detail::enable_if_forward::type = 0) - { - if(i == j) return; - - std::size_t distance = static_cast(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 - void insert_range(I i, I j, typename - boost::unordered::detail::disable_if_forward::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 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 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/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp deleted file mode 100644 index 95f2dbf4..00000000 --- a/include/boost/unordered/detail/extract_key.hpp +++ /dev/null @@ -1,183 +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 - -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 no_key(T const&) {} - }; - - template - struct is_key { - template - static choice1::type test(T2 const&); - static choice2::type test(Key const&); - - enum { value = sizeof(test(boost::unordered::detail::make())) == - sizeof(choice2::type) }; - - typedef typename boost::detail::if_true:: - BOOST_NESTED_TEMPLATE then::type type; - }; - - template - 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 - static no_key extract(Arg const&) - { - return no_key(); - } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template - static no_key extract(Arg1 const&, Arg2 const&, Args const&...) - { - return no_key(); - } -#else - template - static no_key extract(Arg1 const&, Arg2 const&) - { - return no_key(); - } -#endif - }; - - template - struct map_extractor - { - typedef ValueType value_type; - typedef typename boost::remove_const::type key_type; - - static key_type const& extract(value_type const& v) - { - return v.first; - } - - template - static key_type const& extract(std::pair const& v) - { - return v.first; - } - - template - static key_type const& extract( - std::pair const& v) - { - return v.first; - } - - template - static key_type const& extract(key_type const& k, Arg1 const&) - { - return k; - } - - static no_key extract() - { - return no_key(); - } - - template - static no_key extract(Arg const&) - { - return no_key(); - } - - template - static no_key extract(Arg1 const&, Arg2 const&) - { - return no_key(); - } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template - 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 \ - static no_key extract(boost::unordered::piecewise_construct_t, \ - namespace_ tuple<> const&, T2 const&) \ - { \ - return no_key(); \ - } \ - \ - template \ - static typename is_key::type \ - extract(boost::unordered::piecewise_construct_t, \ - namespace_ tuple const& k, T2 const&) \ - { \ - return typename is_key::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 \ - static typename is_key::type \ - extract(boost::unordered::piecewise_construct_t, \ - namespace_ tuple const& k) \ - { \ - return typename is_key::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/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp new file mode 100644 index 00000000..4adbfaa5 --- /dev/null +++ b/include/boost/unordered/detail/implementation.hpp @@ -0,0 +1,4746 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2016 Daniel James + +#ifndef BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP +#define BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) +#include +#endif + +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 + inline void ignore_unused_variable_warning(T const&) {} + } + + //////////////////////////////////////////////////////////////////////////// + // iterator SFINAE + + template + struct is_forward : + boost::is_convertible< + typename boost::iterator_traversal::type, + boost::forward_traversal_tag> + {}; + + template + struct enable_if_forward : + boost::enable_if_c< + boost::unordered::detail::is_forward::value, + ReturnType> + {}; + + template + struct disable_if_forward : + boost::disable_if_c< + boost::unordered::detail::is_forward::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 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 + std::size_t const prime_list_template::value[] = { + BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) + }; + +#if !defined(SUNPRO_CC) + template + std::ptrdiff_t const prime_list_template::length + = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); +#endif + +#undef BOOST_UNORDERED_PRIMES + + typedef prime_list_template 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 + inline std::size_t insert_size(I i, I j, typename + boost::unordered::detail::enable_if_forward::type = 0) + { + return static_cast(std::distance(i, j)); + } + + template + inline std::size_t insert_size(I, I, typename + boost::unordered::detail::disable_if_forward::type = 0) + { + return 1; + } + + template + 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 + 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 + 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 + struct generate_base + : boost::detail::if_true< + boost::is_empty::value + >:: BOOST_NESTED_TEMPLATE then< + boost::unordered::detail::compressed_base, + boost::unordered::detail::uncompressed_base + > + {}; + + template + struct compressed + : private boost::unordered::detail::generate_base::type, + private boost::unordered::detail::generate_base::type + { + typedef typename generate_base::type base1; + typedef typename generate_base::type base2; + + typedef T1 first_type; + typedef T2 second_type; + + first_type& first() { + return static_cast(this)->get(); + } + + first_type const& first() const { + return static_cast(this)->get(); + } + + second_type& second() { + return static_cast(this)->get(); + } + + second_type const& second() const { + return static_cast(this)->get(); + } + + template + 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&); + }; +}}} + +#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 boost::add_lvalue_reference::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 + no_type is_private_type(T const&); + yes_type is_private_type(private_type const&); + + struct convert_from_anything { + template + 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 T* const_cast_pointer(T* x) { return x; } + template T* const_cast_pointer(T const* x) { + return const_cast(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)... + +#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::type \ + BOOST_PP_CAT(Arg, n); \ + BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); + +#endif + +template +struct emplace_args1 +{ + BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) + + emplace_args1(Arg0 b0) : a0(b0) {} +}; + +template +inline emplace_args1 create_emplace_args( + BOOST_FWD_REF(A0) b0) +{ + emplace_args1 e(b0); + return e; +} + +template +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 +inline emplace_args2 create_emplace_args( + BOOST_FWD_REF(A0) b0, + BOOST_FWD_REF(A1) b1) +{ + emplace_args2 e(b0, b1); + return e; +} + +template +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 +inline emplace_args3 create_emplace_args( + BOOST_FWD_REF(A0) b0, + BOOST_FWD_REF(A1) b1, + BOOST_FWD_REF(A2) b2) +{ + emplace_args3 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)) + +#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ +BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n)) + +#define BOOST_UNORDERED_EARGS(z, n, _) \ + template \ + 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 \ + 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 +#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 + struct integral_constant { enum { value = Value }; }; + + typedef boost::unordered::detail::integral_constant true_type; + typedef boost::unordered::detail::integral_constant 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 + 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 struct expr_test; + template struct expr_test : T {}; + +# define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ + template \ + 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 \ + 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 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(choose())) == sizeof(choice1::type) };\ + } + +#else + + template struct identity { typedef T type; }; + +# define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ + \ + typedef typename boost::unordered::detail::identity::type \ + BOOST_PP_CAT(check, count); \ + \ + template \ + struct BOOST_PP_CAT(test, count) { \ + typedef BOOST_PP_CAT(choice, result) type; \ + }; \ + \ + template static typename \ + BOOST_PP_CAT(test, count)<&U::name>::type \ + test(BOOST_PP_CAT(choice, count)) + +# define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ + template 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(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 +# include +# include +# if defined(BOOST_NO_SFINAE_EXPR) +# include +# 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 + struct rebind_alloc; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template class Alloc, + typename U, typename T, typename... Args> + struct rebind_alloc, T> + { + typedef Alloc type; + }; + +#else + + template < + template class Alloc, + typename U, typename T> + struct rebind_alloc, T> + { + typedef Alloc type; + }; + + template < + template class Alloc, + typename U, typename T, + typename A0> + struct rebind_alloc, T> + { + typedef Alloc type; + }; + + template < + template class Alloc, + typename U, typename T, + typename A0, typename A1> + struct rebind_alloc, T> + { + typedef Alloc type; + }; + +#endif + + template + struct rebind_wrap + { + template + static choice1::type test(choice1, + typename X::BOOST_NESTED_TEMPLATE rebind::other* = 0); + template + static choice2::type test(choice2, void* = 0); + + enum { value = (1 == sizeof(test(choose()))) }; + + struct fallback { + template + struct rebind { + typedef typename rebind_alloc::type other; + }; + }; + + typedef typename boost::detail::if_true:: + BOOST_NESTED_TEMPLATE then + ::type::BOOST_NESTED_TEMPLATE rebind::other type; + }; + +# if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 + +# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ + template \ + struct default_type_ ## tname { \ + \ + template \ + static choice1::type test(choice1, typename X::tname* = 0); \ + \ + template \ + static choice2::type test(choice2, void* = 0); \ + \ + struct DefaultWrap { typedef Default tname; }; \ + \ + enum { value = (1 == sizeof(test(choose()))) }; \ + \ + typedef typename boost::detail::if_true:: \ + BOOST_NESTED_TEMPLATE then \ + ::type::tname type; \ + } + +# else + + template + struct sfinae : T2 {}; + +# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ + template \ + struct default_type_ ## tname { \ + \ + template \ + static typename boost::unordered::detail::sfinae< \ + typename X::tname, choice1>::type \ + test(choice1); \ + \ + template \ + static choice2::type test(choice2); \ + \ + struct DefaultWrap { typedef Default tname; }; \ + \ + enum { value = (1 == sizeof(test(choose()))) }; \ + \ + typedef typename boost::detail::if_true:: \ + BOOST_NESTED_TEMPLATE then \ + ::type::tname type; \ + } + +# endif + +# define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \ + typename default_type_ ## tname::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 + BOOST_UNORDERED_HAS_FUNCTION( + select_on_container_copy_construction, U const, (), 0 + ); + + template + BOOST_UNORDERED_HAS_FUNCTION( + max_size, U const, (), 0 + ); + +# if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + BOOST_UNORDERED_HAS_FUNCTION( + construct, U, ( + boost::unordered::detail::make(), + boost::unordered::detail::make()...), 2 + ); + +# else + + template + BOOST_UNORDERED_HAS_FUNCTION( + construct, U, ( + boost::unordered::detail::make(), + boost::unordered::detail::make()), 2 + ); + +# endif + + template + BOOST_UNORDERED_HAS_FUNCTION( + destroy, U, (boost::unordered::detail::make()), 1 + ); + +# else + + template + BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction); + + template + BOOST_UNORDERED_HAS_MEMBER(max_size); + + template + BOOST_UNORDERED_HAS_MEMBER(construct); + + template + BOOST_UNORDERED_HAS_MEMBER(destroy); + +# endif + + namespace func + { + + template + 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::value, void* + >::type = 0) + { + return rhs.select_on_container_copy_construction(); + } + + template + 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::value, void* + >::type = 0) + { + return rhs; + } + + template + inline SizeType call_max_size(const Alloc& a, + typename boost::enable_if_c< + boost::unordered::detail::has_max_size::value, void* + >::type = 0) + { + return a.max_size(); + } + + template + inline SizeType call_max_size(const Alloc&, typename boost::disable_if_c< + boost::unordered::detail::has_max_size::value, void* + >::type = 0) + { + return (std::numeric_limits::max)(); + } + + } // namespace func. + + template + 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 + struct pointer_to_other : boost::pointer_to_other {}; + + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, + typename pointer_to_other::type) + const_pointer; + + //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer, + // typename pointer_to_other::type) + // void_pointer; + // + //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer, + // typename pointer_to_other::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 + using rebind_alloc = typename rebind_wrap::type; + + template + using rebind_traits = + boost::unordered::detail::allocator_traits >; +#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 + static typename boost::enable_if_c< + boost::unordered::detail::has_construct + ::value>::type + construct(Alloc& a, T* p, BOOST_FWD_REF(Args)... x) + { + a.construct(p, boost::forward(x)...); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_construct + ::value>::type + construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x) + { + new (static_cast(p)) T(boost::forward(x)...); + } + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_destroy::value>::type + destroy(Alloc& a, T* p) + { + a.destroy(p); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_destroy::value>::type + destroy(Alloc&, T* p) + { + boost::unordered::detail::func::destroy(p); + } + +# elif !defined(BOOST_NO_SFINAE_EXPR) + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_construct::value>::type + construct(Alloc& a, T* p, T const& x) + { + a.construct(p, x); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_construct::value>::type + construct(Alloc&, T* p, T const& x) + { + new (static_cast(p)) T(x); + } + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_destroy::value>::type + destroy(Alloc& a, T* p) + { + a.destroy(p); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_destroy::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 + static void construct(Alloc& a, T* p, T const& x, + typename boost::enable_if_c< + boost::unordered::detail::has_construct::value && + boost::is_same::value, + void*>::type = 0) + { + a.construct(p, x); + } + + template + static void construct(Alloc&, T* p, T const& x, + typename boost::disable_if_c< + boost::unordered::detail::has_construct::value && + boost::is_same::value, + void*>::type = 0) + { + new (static_cast(p)) T(x); + } + + template + static void destroy(Alloc& a, T* p, + typename boost::enable_if_c< + boost::unordered::detail::has_destroy::value && + boost::is_same::value, + void*>::type = 0) + { + a.destroy(p); + } + + template + static void destroy(Alloc&, T* p, + typename boost::disable_if_c< + boost::unordered::detail::has_destroy::value && + boost::is_same::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(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 + +# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 + +namespace boost { namespace unordered { namespace detail { + + template + struct allocator_traits : std::allocator_traits {}; + + template + struct rebind_wrap + { + typedef typename std::allocator_traits:: + template rebind_alloc type; + }; +}}} + +//////////////////////////////////////////////////////////////////////////////// +// +// boost::container::allocator_traits + +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 + +# include + +# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 + +namespace boost { namespace unordered { namespace detail { + + template + struct allocator_traits : + boost::container::allocator_traits {}; + + template + struct rebind_wrap : + boost::container::allocator_traits:: + template portable_rebind_alloc + {}; + +}}} + +#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 + inline void call_construct(Alloc& alloc, T* address, + BOOST_FWD_REF(Args)... args) + { + boost::unordered::detail::allocator_traits::construct(alloc, + address, boost::forward(args)...); + } + + template + inline void call_destroy(Alloc& alloc, T* x) { + boost::unordered::detail::allocator_traits::destroy(alloc, x); + } + + +# else + + template + inline void call_construct(Alloc&, T* address, + BOOST_FWD_REF(Args)... args) + { + new((void*) address) T(boost::forward(args)...); + } + + template + inline void call_destroy(Alloc&, T* x) { + boost::unordered::detail::func::destroy(x); + } + + +# endif + +#else + template + inline void call_construct(Alloc&, T* address) + { + new ((void*) address) T(); + } + + template + inline void call_construct(Alloc&, T* address, + BOOST_FWD_REF(A0) a0) + { + new ((void*) address) T(boost::forward(a0)); + } + + template + 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 \ + 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 \ + void construct_from_tuple(Alloc& alloc, T* ptr, \ + namespace_ tuple 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(x) + +#elif !defined(__SUNPRO_CC) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + 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 \ + void construct_from_tuple(Alloc&, T* ptr, \ + namespace_ tuple 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(x) + +#else + + template struct length {}; + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + 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 \ + void construct_from_tuple_impl( \ + boost::unordered::detail::func::length, Alloc&, T* ptr, \ + namespace_ tuple 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(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 + void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x) + { + construct_from_tuple_impl( + boost::unordered::detail::func::length< + boost::tuples::length::value>(), + alloc, ptr, x); + } + +#endif + + //////////////////////////////////////////////////////////////////////////// + // Trait to check for piecewise construction. + + template + 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())) }; + }; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //////////////////////////////////////////////////////////////////////////// + // Construct from variadic parameters + + // For the standard pair constructor. + + template + 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)...); + } + + // 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 + inline typename enable_if, void>::type + construct_from_args(Alloc& alloc, std::pair* 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)); + BOOST_TRY { + boost::unordered::detail::func::construct_from_tuple(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->second)), + boost::forward(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 + inline void construct_from_args(Alloc&, T* address, + emplace_args1 const& args) + { + new((void*) address) T(boost::forward(args.a0)); + } + + template + inline void construct_from_args(Alloc&, T* address, + emplace_args2 const& args) + { + new((void*) address) T( + boost::forward(args.a0), + boost::forward(args.a1) + ); + } + + template + inline void construct_from_args(Alloc&, T* address, + emplace_args3 const& args) + { + new((void*) address) T( + boost::forward(args.a0), + boost::forward(args.a1), + boost::forward(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 + inline void construct_from_args(Alloc& alloc, std::pair* address, + boost::unordered::detail::emplace_args3 const& args, + typename enable_if, 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 + struct node_constructor + { + typedef NodeAlloc node_allocator; + typedef boost::unordered::detail::allocator_traits + 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 + node_constructor::~node_constructor() + { + if (node_) { + if (node_constructed_) { + boost::unordered::detail::func::destroy( + boost::addressof(*node_)); + } + + node_allocator_traits::deallocate(alloc_, node_, 1); + } + } + + template + void node_constructor::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 + struct node_tmp + { + typedef boost::unordered::detail::allocator_traits + 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 + node_tmp::~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 + inline typename boost::unordered::detail::allocator_traits::pointer + construct_node_from_args(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS) + { + node_constructor a(alloc); + a.create_node(); + construct_from_args(alloc, a.node_->value_ptr(), + BOOST_UNORDERED_EMPLACE_FORWARD); + return a.release(); + } + + template + inline typename boost::unordered::detail::allocator_traits::pointer + construct_node(Alloc& alloc, BOOST_FWD_REF(U) x) + { + node_constructor a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct( + alloc, a.node_->value_ptr(), boost::forward(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 + inline typename boost::unordered::detail::allocator_traits::pointer + construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) + { + node_constructor 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(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 + inline typename boost::unordered::detail::allocator_traits::pointer + construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) + { + node_constructor 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(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(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(); + } +}}}} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +namespace boost { namespace unordered { namespace detail { + + template struct table; + template struct bucket; + struct ptr_bucket; + template struct table_impl; + template 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 struct iterator; + template struct c_iterator; + template struct l_iterator; + template + struct cl_iterator; + + // Local Iterators + // + // all no throw + + template + 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 + 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(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 + 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 + ; + 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(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 + 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 + friend struct boost::unordered::iterator_detail::c_iterator; + template + friend struct boost::unordered::detail::table; + template + friend struct boost::unordered::detail::table_impl; + template + 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(x)) {} + + value_type& operator*() const { + return node_->value(); + } + + value_type* operator->() const { + return node_->value_ptr(); + } + + iterator& operator++() { + node_ = static_cast(node_->next_); + return *this; + } + + iterator operator++(int) { + iterator tmp(node_); + node_ = static_cast(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 + 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; + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend struct boost::unordered::detail::table; + template + friend struct boost::unordered::detail::table_impl; + template + friend struct boost::unordered::detail::grouped_table_impl; + + private: +#endif + typedef typename Node::node_pointer node_pointer; + typedef boost::unordered::iterator_detail::iterator 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(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_->next_); + return *this; + } + + c_iterator operator++(int) { + c_iterator tmp(node_); + node_ = static_cast(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 + struct node_holder + { + private: + typedef NodeAlloc node_allocator; + typedef boost::unordered::detail::allocator_traits + 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 iterator; + + node_constructor constructor_; + node_pointer nodes_; + + public: + + template + 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(prev->next_); + prev->next_ = link_pointer(); + b.size_ = 0; + } + } + + ~node_holder(); + + node_pointer pop_node() + { + node_pointer n = nodes_; + nodes_ = static_cast(nodes_->next_); + n->init(n); + n->next_ = link_pointer(); + return n; + } + + template + 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 + 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 + node_holder::~node_holder() + { + while (nodes_) { + node_pointer p = nodes_; + nodes_ = static_cast(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 + 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 + struct prime_policy + { + template + 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 + struct mix64_policy + { + template + 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 + struct pick_policy_impl { + typedef prime_policy type; + }; + + template <> + struct pick_policy_impl<64, 2> { + typedef mix64_policy type; + }; + + template + struct pick_policy : + pick_policy_impl< + std::numeric_limits::digits, + std::numeric_limits::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 { + typedef prime_policy type; + }; + + template <> + struct pick_policy { + typedef prime_policy type; + }; + + template <> + struct pick_policy { + typedef prime_policy type; + }; + + template <> + struct pick_policy { + typedef prime_policy type; + }; + + // TODO: Maybe not if std::size_t is smaller than long long. +#if !defined(BOOST_NO_LONG_LONG) + template <> + struct pick_policy { + typedef prime_policy type; + }; + + template <> + struct pick_policy { + typedef prime_policy 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 set_hash_functions; + + template + class functions + { + public: + static const bool nothrow_move_assignable = + boost::is_nothrow_move_assignable::value && + boost::is_nothrow_move_assignable

::value; + static const bool nothrow_move_constructible = + boost::is_nothrow_move_constructible::value && + boost::is_nothrow_move_constructible

::value; + + private: + friend class boost::unordered::detail::set_hash_functions; + functions& operator=(functions const&); + + typedef compressed function_pair; + + typedef typename boost::aligned_storage< + sizeof(function_pair), + boost::alignment_of::value>::type aligned_function; + + bool current_; // The currently active functions. + aligned_function funcs_[2]; + + function_pair const& current() const { + return *static_cast( + static_cast(&funcs_[current_])); + } + + function_pair& current() { + return *static_cast( + static_cast(&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 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()); + } + + ~functions() { + this->destroy(current_); + } + + H const& hash_function() const { + return current().first(); + } + + P const& key_eq() const { + return current().second(); + } + }; + + template + class set_hash_functions + { + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef functions 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 set_hash_functions + { + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef functions 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 + struct rv_ref_impl { + typedef BOOST_RV_REF(T) type; + }; + + template + struct rv_ref : + boost::detail::if_true< + boost::is_class::value + >::BOOST_NESTED_TEMPLATE then < + boost::unordered::detail::rv_ref_impl, + please_ignore_this_overload + >::type + {}; + +# define BOOST_UNORDERED_RV_REF(T) \ + typename boost::unordered::detail::rv_ref::type +#endif +}}} + +#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( + (std::numeric_limits::max)()) ? + (std::numeric_limits::max)() : + static_cast(f); + } + + // The space used to store values in a node. + + template + struct value_base + { + typedef ValueType value_type; + + typename boost::aligned_storage< + sizeof(value_type), + boost::alignment_of::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 + 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::type node_allocator; + typedef typename boost::unordered::detail:: + rebind_wrap::type bucket_allocator; + typedef boost::unordered::detail::allocator_traits + node_allocator_traits; + typedef boost::unordered::detail::allocator_traits + 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_constructor; + typedef boost::unordered::detail::node_tmp + node_tmp; + + //////////////////////////////////////////////////////////////////////// + // Members + + boost::unordered::detail::compressed + 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(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(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(size_) + / static_cast(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(mlf_) * + static_cast(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(mlf_) * + static_cast(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(size) / + static_cast(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(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(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(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(new_count))->next_ = + (buckets_ + static_cast( + bucket_count_))->next_; + destroy_buckets(); + } + else if (bucket::extra_node) + { + node_constructor a(node_alloc()); + a.create_node(); + + (new_buckets + + static_cast(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:: + 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(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( + 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(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:: + 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(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(this)->copy_buckets(x); + } + } + } + + void move_assign(table& x) + { + if (this != boost::addressof(x)) + { + move_assign(x, + boost::unordered::detail::integral_constant:: + 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(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 + node_pointer generic_find_node( + Key const& k, + Hash const& hf, + Pred const& eq) const + { + return static_cast(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(this)-> + find_node_impl(key_hash, k, this->key_eq()); + } + + node_pointer find_node(key_type const& k) const + { + return static_cast(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 + inline void table::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(this)->rehash_impl(num_buckets); + } + } + + // if hash function throws, basic exception safety + // strong otherwise. + + template + inline void table::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(size_) / + static_cast(mlf_))) + 1)); + + if(min_buckets != bucket_count_) + static_cast(this)->rehash_impl(min_buckets); + } + } + + template + inline void table::reserve(std::size_t num_elements) + { + rehash(static_cast( + std::ceil(static_cast(num_elements) / mlf_))); + } +}}} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +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 no_key(T const&) {} + }; + + template + struct is_key { + template + static choice1::type test(T2 const&); + static choice2::type test(Key const&); + + enum { value = sizeof(test(boost::unordered::detail::make())) == + sizeof(choice2::type) }; + + typedef typename boost::detail::if_true:: + BOOST_NESTED_TEMPLATE then::type type; + }; + + template + 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 + static no_key extract(Arg const&) + { + return no_key(); + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + static no_key extract(Arg1 const&, Arg2 const&, Args const&...) + { + return no_key(); + } +#else + template + static no_key extract(Arg1 const&, Arg2 const&) + { + return no_key(); + } +#endif + }; + + template + struct map_extractor + { + typedef ValueType value_type; + typedef typename boost::remove_const::type key_type; + + static key_type const& extract(value_type const& v) + { + return v.first; + } + + template + static key_type const& extract(std::pair const& v) + { + return v.first; + } + + template + static key_type const& extract( + std::pair const& v) + { + return v.first; + } + + template + static key_type const& extract(key_type const& k, Arg1 const&) + { + return k; + } + + static no_key extract() + { + return no_key(); + } + + template + static no_key extract(Arg const&) + { + return no_key(); + } + + template + static no_key extract(Arg1 const&, Arg2 const&) + { + return no_key(); + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + 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 \ + static no_key extract(boost::unordered::piecewise_construct_t, \ + namespace_ tuple<> const&, T2 const&) \ + { \ + return no_key(); \ + } \ + \ + template \ + static typename is_key::type \ + extract(boost::unordered::piecewise_construct_t, \ + namespace_ tuple const& k, T2 const&) \ + { \ + return typename is_key::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 \ + static typename is_key::type \ + extract(boost::unordered::piecewise_construct_t, \ + namespace_ tuple const& k) \ + { \ + return typename is_key::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 + }; +}}} + +namespace boost { namespace unordered { namespace detail { + + template struct unique_node; + template struct ptr_node; + template struct table_impl; + + template + struct unique_node : + boost::unordered::detail::value_base + { + typedef typename ::boost::unordered::detail::rebind_wrap< + A, unique_node >::type allocator; + typedef typename ::boost::unordered::detail:: + allocator_traits::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 + struct ptr_node : + boost::unordered::detail::ptr_bucket + { + typedef T value_type; + typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef ptr_node* node_pointer; + typedef ptr_bucket* link_pointer; + + std::size_t hash_; + boost::unordered::detail::value_base 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 + struct pick_node2 + { + typedef boost::unordered::detail::unique_node node; + + typedef typename boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap::type + >::pointer node_pointer; + + typedef boost::unordered::detail::bucket bucket; + typedef node_pointer link_pointer; + }; + + template + struct pick_node2*, + boost::unordered::detail::ptr_bucket*> + { + typedef boost::unordered::detail::ptr_node node; + typedef boost::unordered::detail::ptr_bucket bucket; + typedef bucket* link_pointer; + }; + + template + struct pick_node + { + typedef typename boost::remove_const::type nonconst; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap >::type + > tentative_node_traits; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap::type + > tentative_bucket_traits; + + typedef pick_node2 pick; + + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + }; + + template + struct table_impl : boost::unordered::detail::table + { + typedef boost::unordered::detail::table 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 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(n->next_); + } + + // Accessors + + template + 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 + 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 + 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 + 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 + emplace_return emplace( + boost::unordered::detail::emplace_args1 const& args) + { + return emplace_impl(extractor::extract(args.a0), args); + } + + template + iterator emplace_hint(c_iterator hint, + boost::unordered::detail::emplace_args1 const& args) + { + return emplace_hint_impl(hint, extractor::extract(args.a0), args); + } +#endif + + 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 + 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 + 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 + 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 + void insert_range(InputIt i, InputIt j) + { + if(i != j) + return insert_range_impl(extractor::extract(*i), i, j); + } + + template + 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 + 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 + 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 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 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; + } + } + }; +}}} + +namespace boost { namespace unordered { namespace detail { + + template struct grouped_node; + template struct grouped_ptr_node; + template struct grouped_table_impl; + + template + struct grouped_node : + boost::unordered::detail::value_base + { + typedef typename ::boost::unordered::detail::rebind_wrap< + A, grouped_node >::type allocator; + typedef typename ::boost::unordered::detail:: + allocator_traits::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 + 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* node_pointer; + typedef ptr_bucket* link_pointer; + + node_pointer group_prev_; + std::size_t hash_; + boost::unordered::detail::value_base 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 + struct pick_grouped_node2 + { + typedef boost::unordered::detail::grouped_node node; + + typedef typename boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap::type + >::pointer node_pointer; + + typedef boost::unordered::detail::bucket bucket; + typedef node_pointer link_pointer; + }; + + template + struct pick_grouped_node2*, + boost::unordered::detail::ptr_bucket*> + { + typedef boost::unordered::detail::grouped_ptr_node node; + typedef boost::unordered::detail::ptr_bucket bucket; + typedef bucket* link_pointer; + }; + + template + struct pick_grouped_node + { + typedef typename boost::remove_const::type nonconst; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap >::type + > tentative_node_traits; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap::type + > tentative_bucket_traits; + + typedef pick_grouped_node2 pick; + + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + }; + + template + struct grouped_table_impl : boost::unordered::detail::table + { + typedef boost::unordered::detail::table 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(n->next_); + } + + static inline node_pointer next_group(node_pointer n) { + return static_cast(n->group_prev_->next_); + } + + // Accessors + + template + 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 + 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 + 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 + 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 + void insert_range(I i, I j, typename + boost::unordered::detail::enable_if_forward::type = 0) + { + if(i == j) return; + + std::size_t distance = static_cast(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 + void insert_range(I i, I j, typename + boost::unordered::detail::disable_if_forward::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 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 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/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 81e19e44..ef527a34 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -4,7 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include namespace boost { namespace unordered { namespace detail { template diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 58093131..c254742f 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -4,7 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include namespace boost { namespace unordered { namespace detail { template diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp deleted file mode 100644 index 182535a8..00000000 --- a/include/boost/unordered/detail/table.hpp +++ /dev/null @@ -1,789 +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 - -#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( - (std::numeric_limits::max)()) ? - (std::numeric_limits::max)() : - static_cast(f); - } - - // The space used to store values in a node. - - template - struct value_base - { - typedef ValueType value_type; - - typename boost::aligned_storage< - sizeof(value_type), - boost::alignment_of::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 - 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::type node_allocator; - typedef typename boost::unordered::detail:: - rebind_wrap::type bucket_allocator; - typedef boost::unordered::detail::allocator_traits - node_allocator_traits; - typedef boost::unordered::detail::allocator_traits - 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_constructor; - typedef boost::unordered::detail::node_tmp - node_tmp; - - //////////////////////////////////////////////////////////////////////// - // Members - - boost::unordered::detail::compressed - 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(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(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(size_) - / static_cast(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(mlf_) * - static_cast(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(mlf_) * - static_cast(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(size) / - static_cast(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(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(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(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(new_count))->next_ = - (buckets_ + static_cast( - bucket_count_))->next_; - destroy_buckets(); - } - else if (bucket::extra_node) - { - node_constructor a(node_alloc()); - a.create_node(); - - (new_buckets + - static_cast(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:: - 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(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( - 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(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:: - 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(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(this)->copy_buckets(x); - } - } - } - - void move_assign(table& x) - { - if (this != boost::addressof(x)) - { - move_assign(x, - boost::unordered::detail::integral_constant:: - 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(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 - node_pointer generic_find_node( - Key const& k, - Hash const& hf, - Pred const& eq) const - { - return static_cast(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(this)-> - find_node_impl(key_hash, k, this->key_eq()); - } - - node_pointer find_node(key_type const& k) const - { - return static_cast(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 - inline void table::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(this)->rehash_impl(num_buckets); - } - } - - // if hash function throws, basic exception safety - // strong otherwise. - - template - inline void table::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(size_) / - static_cast(mlf_))) + 1)); - - if(min_buckets != bucket_count_) - static_cast(this)->rehash_impl(min_buckets); - } - } - - template - inline void table::reserve(std::size_t num_elements) - { - rehash(static_cast( - std::ceil(static_cast(num_elements) / mlf_))); - } -}}} - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - -#endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp deleted file mode 100644 index 52020307..00000000 --- a/include/boost/unordered/detail/unique.hpp +++ /dev/null @@ -1,676 +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 - -namespace boost { namespace unordered { namespace detail { - - template struct unique_node; - template struct ptr_node; - template struct table_impl; - - template - struct unique_node : - boost::unordered::detail::value_base - { - typedef typename ::boost::unordered::detail::rebind_wrap< - A, unique_node >::type allocator; - typedef typename ::boost::unordered::detail:: - allocator_traits::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 - struct ptr_node : - boost::unordered::detail::ptr_bucket - { - typedef T value_type; - typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef ptr_node* node_pointer; - typedef ptr_bucket* link_pointer; - - std::size_t hash_; - boost::unordered::detail::value_base 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 - struct pick_node2 - { - typedef boost::unordered::detail::unique_node node; - - typedef typename boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type - >::pointer node_pointer; - - typedef boost::unordered::detail::bucket bucket; - typedef node_pointer link_pointer; - }; - - template - struct pick_node2*, - boost::unordered::detail::ptr_bucket*> - { - typedef boost::unordered::detail::ptr_node node; - typedef boost::unordered::detail::ptr_bucket bucket; - typedef bucket* link_pointer; - }; - - template - struct pick_node - { - typedef typename boost::remove_const::type nonconst; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap >::type - > tentative_node_traits; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type - > tentative_bucket_traits; - - typedef pick_node2 pick; - - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - }; - - template - struct table_impl : boost::unordered::detail::table - { - typedef boost::unordered::detail::table 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 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(n->next_); - } - - // Accessors - - template - 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 - 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 - 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 - 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 - emplace_return emplace( - boost::unordered::detail::emplace_args1 const& args) - { - return emplace_impl(extractor::extract(args.a0), args); - } - - template - iterator emplace_hint(c_iterator hint, - boost::unordered::detail::emplace_args1 const& args) - { - return emplace_hint_impl(hint, extractor::extract(args.a0), args); - } -#endif - - 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 - 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 - 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 - 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 - void insert_range(InputIt i, InputIt j) - { - if(i != j) - return insert_range_impl(extractor::extract(*i), i, j); - } - - template - 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 - 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 - 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 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 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/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp deleted file mode 100644 index ec44119f..00000000 --- a/include/boost/unordered/detail/util.hpp +++ /dev/null @@ -1,279 +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 -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(BOOST_NO_CXX11_HDR_TUPLE) -#include -#endif - -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 - inline void ignore_unused_variable_warning(T const&) {} - } - - //////////////////////////////////////////////////////////////////////////// - // iterator SFINAE - - template - struct is_forward : - boost::is_convertible< - typename boost::iterator_traversal::type, - boost::forward_traversal_tag> - {}; - - template - struct enable_if_forward : - boost::enable_if_c< - boost::unordered::detail::is_forward::value, - ReturnType> - {}; - - template - struct disable_if_forward : - boost::disable_if_c< - boost::unordered::detail::is_forward::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 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 - std::size_t const prime_list_template::value[] = { - BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) - }; - -#if !defined(SUNPRO_CC) - template - std::ptrdiff_t const prime_list_template::length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); -#endif - -#undef BOOST_UNORDERED_PRIMES - - typedef prime_list_template 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 - inline std::size_t insert_size(I i, I j, typename - boost::unordered::detail::enable_if_forward::type = 0) - { - return static_cast(std::distance(i, j)); - } - - template - inline std::size_t insert_size(I, I, typename - boost::unordered::detail::disable_if_forward::type = 0) - { - return 1; - } - - template - 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 - 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 - 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 - struct generate_base - : boost::detail::if_true< - boost::is_empty::value - >:: BOOST_NESTED_TEMPLATE then< - boost::unordered::detail::compressed_base, - boost::unordered::detail::uncompressed_base - > - {}; - - template - struct compressed - : private boost::unordered::detail::generate_base::type, - private boost::unordered::detail::generate_base::type - { - typedef typename generate_base::type base1; - typedef typename generate_base::type base2; - - typedef T1 first_type; - typedef T2 second_type; - - first_type& first() { - return static_cast(this)->get(); - } - - first_type const& first() const { - return static_cast(this)->get(); - } - - second_type& second() { - return static_cast(this)->get(); - } - - second_type const& second() const { - return static_cast(this)->get(); - } - - template - 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/test/helpers/memory.hpp b/test/helpers/memory.hpp index a30d7522..6c095e98 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include "../helpers/test.hpp" namespace test diff --git a/test/unordered/allocator_traits.cpp b/test/unordered/allocator_traits.cpp index 4f4fe797..d36d85b7 100644 --- a/test/unordered/allocator_traits.cpp +++ b/test/unordered/allocator_traits.cpp @@ -3,7 +3,7 @@ // 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 +#include #include #include #include diff --git a/test/unordered/minimal_allocator.cpp b/test/unordered/minimal_allocator.cpp index 85e99e61..7099d573 100644 --- a/test/unordered/minimal_allocator.cpp +++ b/test/unordered/minimal_allocator.cpp @@ -3,7 +3,7 @@ // 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 +#include #include #include #include