From 67f1f65174fc46d449277cd691d537a4ca5ab622 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 19 Feb 2017 13:05:17 +0000 Subject: [PATCH 1/7] Linearise the detail includes The current organisation of the headers has been making less and less sense over the years, so to simplify things, I'm just going to combine them into a single header. This change will make it easier to do that. --- include/boost/unordered/detail/allocate.hpp | 35 +------------------ include/boost/unordered/detail/buckets.hpp | 6 ---- include/boost/unordered/detail/equivalent.hpp | 7 +--- .../boost/unordered/detail/extract_key.hpp | 5 --- include/boost/unordered/detail/map.hpp | 1 - include/boost/unordered/detail/set.hpp | 1 - include/boost/unordered/detail/table.hpp | 5 --- include/boost/unordered/detail/unique.hpp | 7 ---- include/boost/unordered/detail/util.hpp | 30 ++++++++++++++++ 9 files changed, 32 insertions(+), 65 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 2da85be8..39a6c3f6 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -9,40 +9,7 @@ #ifndef BOOST_UNORDERED_ALLOCATE_HPP #define BOOST_UNORDERED_ALLOCATE_HPP -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -// Some of these includes are required for other detail headers. -#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 +#include #if defined(BOOST_MSVC) #pragma warning(push) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index bd9a5cbb..e4adb83d 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -7,12 +7,6 @@ #ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include #include namespace boost { namespace unordered { namespace detail { diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 618d3af9..3a648086 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -7,12 +7,7 @@ #ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include +#include namespace boost { namespace unordered { namespace detail { diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index 338e918c..95f2dbf4 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -6,11 +6,6 @@ #ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - #include namespace boost { diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 14253ef4..81e19e44 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -5,7 +5,6 @@ #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 ccbc4c99..58093131 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -5,7 +5,6 @@ #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 index 1092d31f..182535a8 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -7,11 +7,6 @@ #ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - #include #if defined(BOOST_MSVC) diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index e77b4c14..52020307 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -7,14 +7,7 @@ #ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - #include -#include -#include namespace boost { namespace unordered { namespace detail { diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index cd722e44..ec44119f 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -12,6 +12,7 @@ #pragma once #endif +#include #include #include #include @@ -21,6 +22,35 @@ #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 { From 67ab88b064e479e5e07f0ecd64fda447988ab258 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 19 Feb 2017 13:05:17 +0000 Subject: [PATCH 2/7] 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 From 3bf664ad31e124291db9aae9b341bc6f9d8081f5 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 19 Feb 2017 13:05:17 +0000 Subject: [PATCH 3/7] Add a missing header --- test/helpers/count.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/helpers/count.hpp b/test/helpers/count.hpp index dfb34e61..69004dcf 100644 --- a/test/helpers/count.hpp +++ b/test/helpers/count.hpp @@ -6,6 +6,7 @@ #if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD) #define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD +#include #include namespace test { From f2af10c74661382996e7a60f3cfda2a394c829e8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 19 Feb 2017 13:05:17 +0000 Subject: [PATCH 4/7] Protect preprocess sequence from clang format --- include/boost/unordered/detail/implementation.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 4adbfaa5..ec5d129e 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -89,6 +89,7 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// // primes +// clang-format off #define BOOST_UNORDERED_PRIMES \ (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ @@ -97,6 +98,7 @@ namespace boost { namespace unordered { namespace detail { (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ (1610612741ul)(3221225473ul)(4294967291ul) +// clang-format on template struct prime_list_template { From b2f2fdc2f385cf78c3b0aaed0a06a1b83d884be5 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 19 Feb 2017 13:05:17 +0000 Subject: [PATCH 5/7] Prevent clang-format sorting some test includes --- test/exception/assign_exception_tests.cpp | 1 + test/exception/constructor_exception_tests.cpp | 1 + test/exception/containers.hpp | 3 +++ test/exception/copy_exception_tests.cpp | 1 + test/exception/erase_exception_tests.cpp | 1 + test/exception/insert_exception_tests.cpp | 1 + test/exception/move_assign_exception_tests.cpp | 3 ++- test/exception/rehash_exception_tests.cpp | 1 + test/exception/swap_exception_tests.cpp | 1 + test/unordered/assign_tests.cpp | 3 +++ test/unordered/at_tests.cpp | 2 ++ test/unordered/bucket_tests.cpp | 2 ++ test/unordered/compile_map.cpp | 2 ++ test/unordered/compile_set.cpp | 2 ++ test/unordered/constructor_tests.cpp | 2 ++ test/unordered/copy_tests.cpp | 2 ++ test/unordered/emplace_tests.cpp | 2 ++ test/unordered/equality_tests.cpp | 2 ++ test/unordered/equivalent_keys_tests.cpp | 2 ++ test/unordered/erase_equiv_tests.cpp | 2 ++ test/unordered/erase_tests.cpp | 2 ++ test/unordered/find_tests.cpp | 2 ++ test/unordered/fwd_map_test.cpp | 2 ++ test/unordered/fwd_set_test.cpp | 2 ++ test/unordered/incomplete_test.cpp | 2 ++ test/unordered/insert_hint_tests.cpp | 2 ++ test/unordered/insert_stable_tests.cpp | 2 ++ test/unordered/insert_tests.cpp | 2 ++ test/unordered/link_test_1.cpp | 2 ++ test/unordered/link_test_2.cpp | 2 ++ test/unordered/load_factor_tests.cpp | 2 ++ test/unordered/move_tests.cpp | 2 ++ test/unordered/noexcept_tests.cpp | 2 ++ test/unordered/rehash_tests.cpp | 2 ++ test/unordered/simple_tests.cpp | 2 ++ test/unordered/swap_tests.cpp | 2 ++ test/unordered/unnecessary_copy_tests.cpp | 2 ++ 37 files changed, 69 insertions(+), 1 deletion(-) diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index e8304ee9..1831f808 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "./containers.hpp" + #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index abadd65a..eaa9ae58 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "./containers.hpp" + #include "../helpers/random_values.hpp" #include "../helpers/input_iterator.hpp" diff --git a/test/exception/containers.hpp b/test/exception/containers.hpp index ee938330..b1a873e4 100644 --- a/test/exception/containers.hpp +++ b/test/exception/containers.hpp @@ -3,10 +3,13 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on + #include "../objects/exception.hpp" typedef boost::unordered_set< diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 15c7364d..564db33c 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "./containers.hpp" + #include "../helpers/random_values.hpp" template inline void avoid_unused_warning(T const&) {} diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index 18f333a8..11b8c3d4 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "./containers.hpp" + #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" #include "../helpers/helpers.hpp" diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index d4c1e243..1b0cf6e3 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "./containers.hpp" + #include #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" diff --git a/test/exception/move_assign_exception_tests.cpp b/test/exception/move_assign_exception_tests.cpp index d09b1b82..2a2f70ee 100644 --- a/test/exception/move_assign_exception_tests.cpp +++ b/test/exception/move_assign_exception_tests.cpp @@ -3,8 +3,9 @@ // 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 "./containers.hpp" + +#include #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index 0163bfec..46c70504 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "./containers.hpp" + #include #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 0873093a..e6ec789e 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "./containers.hpp" + #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 0e2f6fdd..8dc6786e 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -3,10 +3,13 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on + #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../objects/cxx11_allocator.hpp" diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index 8899efcb..824b6e88 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -3,9 +3,11 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 4417f2d5..d879ad41 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index f42da0de..6b33d8ae 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -6,9 +6,11 @@ // This test creates the containers with members that meet their minimum // requirements. Makes sure everything compiles and is defined correctly. +// clang-format off #include "../helpers/prefix.hpp" #include #include "../helpers/postfix.hpp" +// clang-format on #include #include "../helpers/test.hpp" diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index a95ab007..ed5363d6 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -6,9 +6,11 @@ // This test creates the containers with members that meet their minimum // requirements. Makes sure everything compiles and is defined correctly. +// clang-format off #include "../helpers/prefix.hpp" #include #include "../helpers/postfix.hpp" +// clang-format on #include #include "../helpers/test.hpp" diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 84c63742..6ad3f273 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index db687e79..14502ff2 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/emplace_tests.cpp b/test/unordered/emplace_tests.cpp index c08adc0b..b6682939 100644 --- a/test/unordered/emplace_tests.cpp +++ b/test/unordered/emplace_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include #include "../helpers/test.hpp" diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index 4dc6bb1e..82b4ef27 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include #include diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp index 2d459a4b..cf3e792c 100644 --- a/test/unordered/equivalent_keys_tests.cpp +++ b/test/unordered/equivalent_keys_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index b55bc202..4a46ddf0 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -6,9 +6,11 @@ // The code for erasing elements from containers with equivalent keys is very // hairy with several tricky edge cases - so explicitly test each one. +// clang-format off #include "../helpers/prefix.hpp" #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../helpers/list.hpp" diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 34d7ec9e..7e6a98ed 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index 7073566a..38c7c09c 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/fwd_map_test.cpp b/test/unordered/fwd_map_test.cpp index 5a943657..1e656331 100644 --- a/test/unordered/fwd_map_test.cpp +++ b/test/unordered/fwd_map_test.cpp @@ -3,9 +3,11 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include "../helpers/postfix.hpp" +// clang-format on template void call_swap(boost::unordered_map& x, diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index 62067f52..44cd1436 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -3,9 +3,11 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include "../helpers/postfix.hpp" +// clang-format on struct true_type { char x[100]; }; struct false_type { char x; }; diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 4300a8e6..8c3d2a53 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include diff --git a/test/unordered/insert_hint_tests.cpp b/test/unordered/insert_hint_tests.cpp index add39024..90289f75 100644 --- a/test/unordered/insert_hint_tests.cpp +++ b/test/unordered/insert_hint_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../helpers/invariants.hpp" diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index b4482764..5a22e267 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index a3384652..73c44873 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/link_test_1.cpp b/test/unordered/link_test_1.cpp index 8df5337e..f44c1116 100644 --- a/test/unordered/link_test_1.cpp +++ b/test/unordered/link_test_1.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on void foo(boost::unordered_set&, boost::unordered_map&, diff --git a/test/unordered/link_test_2.cpp b/test/unordered/link_test_2.cpp index 40ac9ebd..b052be17 100644 --- a/test/unordered/link_test_2.cpp +++ b/test/unordered/link_test_2.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on void foo(boost::unordered_set& x1, boost::unordered_map& x2, diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 655cc883..dd4fbb1f 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index b04f33b0..ed5b4aa7 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -3,10 +3,12 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/noexcept_tests.cpp b/test/unordered/noexcept_tests.cpp index 9ccc846c..bf4421a1 100644 --- a/test/unordered/noexcept_tests.cpp +++ b/test/unordered/noexcept_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 01009b6d..0c3d5828 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include "../helpers/random_values.hpp" diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index e3d0ebe1..940b031e 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -5,10 +5,12 @@ // This test checks the runtime requirements of containers. +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include "../helpers/test.hpp" #include diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index 7814a26a..93a8f583 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include #include diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index cb1346ba..5978b1a2 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -3,10 +3,12 @@ // 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) +// clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" +// clang-format on #include #include "../helpers/test.hpp" From 01dcd36c41d8e4341117976cf2098e34d1fc27f9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 19 Feb 2017 13:05:17 +0000 Subject: [PATCH 6/7] Add _clang-format file --- _clang-format | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 _clang-format diff --git a/_clang-format b/_clang-format new file mode 100644 index 00000000..5ca4ced9 --- /dev/null +++ b/_clang-format @@ -0,0 +1,37 @@ + +# Copyright 2017 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) + +# Using clang format 3.8 +# http://llvm.org/releases/3.8.0/tools/clang/docs/ClangFormatStyleOptions.html + +# Becuase you have to start somewhere. +BasedOnStyle: LLVM + +# Basic settings +ColumnLimit: 80 +ContinuationIndentWidth: 4 +IndentWidth: 4 +UseTab: Never +Language: Cpp +Standard: Cpp03 + +# Code layout +AlignAfterOpenBracket: DontAlign +AlignTrailingComments: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterNamespace: false + AfterClass: true + AfterStruct: true + AfterUnion: true + AfterEnum: true + AfterFunction: true + AfterControlStatement: false + BeforeCatch: false + BeforeElse: false +PointerAlignment: Left + +# Boost specific stuff +ForEachMacros: [ BOOST_FOREACH ] From bf5ef9824da093186b05ad78032b160f7a6152b4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 19 Feb 2017 13:05:17 +0000 Subject: [PATCH 7/7] Reformat with clang-format --- include/boost/unordered/detail/fwd.hpp | 34 +- .../boost/unordered/detail/implementation.hpp | 7831 ++++++++--------- include/boost/unordered/detail/map.hpp | 117 +- include/boost/unordered/detail/set.hpp | 110 +- include/boost/unordered/unordered_map.hpp | 2765 +++--- include/boost/unordered/unordered_map_fwd.hpp | 77 +- include/boost/unordered/unordered_set.hpp | 2589 +++--- include/boost/unordered/unordered_set_fwd.hpp | 73 +- test/exception/assign_exception_tests.cpp | 73 +- .../exception/constructor_exception_tests.cpp | 116 +- test/exception/containers.hpp | 52 +- test/exception/copy_exception_tests.cpp | 27 +- test/exception/erase_exception_tests.cpp | 34 +- test/exception/insert_exception_tests.cpp | 214 +- .../exception/move_assign_exception_tests.cpp | 63 +- test/exception/rehash_exception_tests.cpp | 38 +- test/exception/swap_exception_tests.cpp | 94 +- test/helpers/check_return_type.hpp | 35 +- test/helpers/count.hpp | 136 +- test/helpers/equivalent.hpp | 133 +- test/helpers/exception_test.hpp | 451 +- test/helpers/fwd.hpp | 34 +- test/helpers/generators.hpp | 136 +- test/helpers/helpers.hpp | 78 +- test/helpers/input_iterator.hpp | 286 +- test/helpers/invariants.hpp | 178 +- test/helpers/list.hpp | 548 +- test/helpers/memory.hpp | 265 +- test/helpers/metafunctions.hpp | 34 +- test/helpers/prefix.hpp | 2 +- test/helpers/random_values.hpp | 155 +- test/helpers/strong.hpp | 53 +- test/helpers/test.hpp | 190 +- test/helpers/tracker.hpp | 256 +- test/objects/cxx11_allocator.hpp | 529 +- test/objects/exception.hpp | 1180 +-- test/objects/fwd.hpp | 13 +- test/objects/minimal.hpp | 797 +- test/objects/test.hpp | 1142 +-- test/unordered/allocator_traits.cpp | 207 +- test/unordered/assign_tests.cpp | 136 +- test/unordered/at_tests.cpp | 7 +- test/unordered/bucket_tests.cpp | 68 +- test/unordered/compile_map.cpp | 146 +- test/unordered/compile_set.cpp | 179 +- test/unordered/compile_tests.hpp | 280 +- test/unordered/constructor_tests.cpp | 141 +- test/unordered/copy_tests.cpp | 100 +- test/unordered/emplace_tests.cpp | 768 +- test/unordered/equality_tests.cpp | 272 +- test/unordered/equivalent_keys_tests.cpp | 26 +- test/unordered/erase_equiv_tests.cpp | 97 +- test/unordered/erase_tests.cpp | 129 +- test/unordered/find_tests.cpp | 91 +- test/unordered/fwd_map_test.cpp | 32 +- test/unordered/fwd_set_test.cpp | 65 +- test/unordered/incomplete_test.cpp | 261 +- test/unordered/insert_hint_tests.cpp | 33 +- test/unordered/insert_stable_tests.cpp | 101 +- test/unordered/insert_tests.cpp | 429 +- test/unordered/link_test_1.cpp | 8 +- test/unordered/link_test_2.cpp | 19 +- test/unordered/load_factor_tests.cpp | 45 +- test/unordered/minimal_allocator.cpp | 70 +- test/unordered/move_tests.cpp | 639 +- test/unordered/noexcept_tests.cpp | 274 +- test/unordered/rehash_tests.cpp | 113 +- test/unordered/simple_tests.cpp | 34 +- test/unordered/swap_tests.cpp | 120 +- test/unordered/unnecessary_copy_tests.cpp | 797 +- 70 files changed, 13000 insertions(+), 13625 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 74419062..6a842042 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -15,21 +15,21 @@ // Already defined. #elif defined(BOOST_LIBSTDCXX11) // https://github.com/gcc-mirror/gcc/blob/gcc-4_6-branch/libstdc++-v3/include/bits/stl_pair.h#L70 -# if BOOST_LIBSTDCXX_VERSION > 40600 -# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 -# endif +#if BOOST_LIBSTDCXX_VERSION > 40600 +#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +#endif #elif defined(_LIBCPP_VERSION) // https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206 -# if LIBCPP_VERSION >= 3000 -# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 -# endif +#if LIBCPP_VERSION >= 3000 +#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +#endif #elif defined(BOOST_MSVC) // Apparently C++11 standard supported in Visual Studio 2012 // https://msdn.microsoft.com/en-us/library/hh567368.aspx#stl // 2012 = VC+11 = BOOST_MSVC 1700 Hopefully! -# if BOOST_MSVC >= 1700 -# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 -# endif +#if BOOST_MSVC >= 1700 +#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +#endif #endif #if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT) @@ -40,16 +40,16 @@ #include #endif -namespace boost -{ -namespace unordered -{ +namespace boost { +namespace unordered { #if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT - using std::piecewise_construct_t; - using std::piecewise_construct; +using std::piecewise_construct_t; +using std::piecewise_construct; #else - struct piecewise_construct_t {}; - const piecewise_construct_t piecewise_construct = piecewise_construct_t(); +struct piecewise_construct_t +{ +}; +const piecewise_construct_t piecewise_construct = piecewise_construct_t(); #endif } } diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index ec5d129e..78850bba 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -10,84 +10,89 @@ #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 +#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 { +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 {}; +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&) {} - } +namespace func { +template inline void ignore_unused_variable_warning(T const&) {} +} - //////////////////////////////////////////////////////////////////////////// - // iterator SFINAE +//////////////////////////////////////////////////////////////////////////// +// iterator SFINAE - template - struct is_forward : - boost::is_convertible< - typename boost::iterator_traversal::type, - boost::forward_traversal_tag> - {}; +template +struct is_forward + : boost::is_convertible::type, + boost::forward_traversal_tag> +{ +}; - template - struct enable_if_forward : - boost::enable_if_c< - boost::unordered::detail::is_forward::value, - ReturnType> - {}; +template +struct enable_if_forward + : boost::enable_if_c::value, + ReturnType> +{ +}; - template - struct disable_if_forward : - boost::disable_if_c< - boost::unordered::detail::is_forward::value, - ReturnType> - {}; +template +struct disable_if_forward + : boost::disable_if_c::value, + ReturnType> +{ +}; - //////////////////////////////////////////////////////////////////////////// - // primes +//////////////////////////////////////////////////////////////////////////// +// primes // clang-format off #define BOOST_UNORDERED_PRIMES \ @@ -100,242 +105,268 @@ namespace boost { namespace unordered { namespace detail { (1610612741ul)(3221225473ul)(4294967291ul) // clang-format on - template struct prime_list_template - { - static std::size_t const value[]; +template struct prime_list_template +{ + static std::size_t const value[]; #if !defined(SUNPRO_CC) - static std::ptrdiff_t const length; + static std::ptrdiff_t const length; #else - static std::ptrdiff_t const length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); + 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) - }; +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); +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; +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 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::value>::BOOST_NESTED_TEMPLATE + then, + 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(); } - // 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; + second_type& second() { return static_cast(this)->get(); } + + second_type const& second() const + { + return static_cast(this)->get(); } - //////////////////////////////////////////////////////////////////////////// - // insert_size/initial_size - - template - inline std::size_t insert_size(I i, I j, typename - boost::unordered::detail::enable_if_forward::type = 0) + template + compressed(First const& x1, Second const& x2) : base1(x1), base2(x2) { - 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) + compressed(compressed const& x) : base1(x.first()), base2(x.second()) {} + + compressed(compressed& x, move_tag m) + : base1(x.first(), m), base2(x.second(), m) { - return 1; } - template - inline std::size_t initial_size(I i, I j, - std::size_t num_buckets = - boost::unordered::detail::default_bucket_count) + void assign(compressed const& x) { - // TODO: Why +1? - return (std::max)( - boost::unordered::detail::insert_size(i, j) + 1, - num_buckets); + first() = x.first(); + second() = x.second(); } - //////////////////////////////////////////////////////////////////////////// - // compressed - - template - struct compressed_base : private T + void move_assign(compressed& x) { - compressed_base(T const& x) : T(x) {} - compressed_base(T& x, move_tag) : T(boost::move(x)) {} + first() = boost::move(x.first()); + second() = boost::move(x.second()); + } - T& get() { return *this; } - T const& get() const { return *this; } - }; - - template - struct uncompressed_base + void swap(compressed& x) { - uncompressed_base(T const& x) : value_(x) {} - uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {} + boost::swap(first(), x.first()); + boost::swap(second(), x.second()); + } - 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&); - }; -}}} + 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. +#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 { +namespace boost { +namespace unordered { +namespace detail { - //////////////////////////////////////////////////////////////////////////// - // Bits and pieces for implementing traits +//////////////////////////////////////////////////////////////////////////// +// 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(); +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; +typedef choice1::type yes_type; +typedef choice2::type no_type; - struct private_type - { - private_type const &operator,(int) const; - }; +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&); +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&); - }; +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); - } - } +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 +//////////////////////////////////////////////////////////////////////////// +// emplace_args +// +// Either forwarding variadic arguments, or storing the arguments in +// emplace_args##n #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -359,21 +390,20 @@ namespace boost { namespace unordered { namespace detail { #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); \ +#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); \ +#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 +template struct emplace_args1 { BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) @@ -381,15 +411,13 @@ struct emplace_args1 }; template -inline emplace_args1 create_emplace_args( - BOOST_FWD_REF(A0) b0) +inline emplace_args1 create_emplace_args(BOOST_FWD_REF(A0) b0) { emplace_args1 e(b0); return e; } -template -struct emplace_args2 +template struct emplace_args2 { BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) @@ -399,15 +427,13 @@ struct emplace_args2 template inline emplace_args2 create_emplace_args( - BOOST_FWD_REF(A0) b0, - BOOST_FWD_REF(A1) b1) + BOOST_FWD_REF(A0) b0, BOOST_FWD_REF(A1) b1) { emplace_args2 e(b0, b1); return e; } -template -struct emplace_args3 +template struct emplace_args3 { BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) @@ -418,58 +444,53 @@ struct emplace_args3 template inline emplace_args3 create_emplace_args( - BOOST_FWD_REF(A0) b0, - BOOST_FWD_REF(A1) b1, - BOOST_FWD_REF(A2) b2) + 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) \ +#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_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_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; \ +#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) \ + create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, b)) \ + { \ + BOOST_PP_CAT(emplace_args, n) e( \ + BOOST_PP_ENUM_PARAMS_Z(z, n, b)); \ + return e; \ } -BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, - _) +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 - -}}} +} +} +} //////////////////////////////////////////////////////////////////////////////// // @@ -480,19 +501,19 @@ BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, // 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 +#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 +#define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 #endif //////////////////////////////////////////////////////////////////////////////// @@ -501,134 +522,156 @@ BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, // they're always defined. #if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) -# include +#include #endif -namespace boost { namespace unordered { namespace detail { +namespace boost { +namespace unordered { +namespace detail { - //////////////////////////////////////////////////////////////////////////// - // Integral_constrant, true_type, false_type - // - // Uses the standard versions if available. +//////////////////////////////////////////////////////////////////////////// +// 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; +using std::integral_constant; +using std::true_type; +using std::false_type; #else - template - struct integral_constant { enum { value = Value }; }; +template struct integral_constant +{ + enum + { + value = Value + }; +}; - typedef boost::unordered::detail::integral_constant true_type; - typedef boost::unordered::detail::integral_constant false_type; +typedef boost::unordered::detail::integral_constant true_type; +typedef boost::unordered::detail::integral_constant false_type; #endif - //////////////////////////////////////////////////////////////////////////// - // Explicitly call a destructor +//////////////////////////////////////////////////////////////////////////// +// Explicitly call a destructor #if defined(BOOST_MSVC) #pragma warning(push) -#pragma warning(disable:4100) // unreferenced formal parameter +#pragma warning(disable : 4100) // unreferenced formal parameter #endif - namespace func { - template - inline void destroy(T* x) { - x->~T(); - } - } +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. +//////////////////////////////////////////////////////////////////////////// +// 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 {}; +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_CHECK_EXPRESSION(count, result, expression) \ + template \ + static typename boost::unordered::detail::expr_test::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_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) };\ +#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().name args); \ + BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \ + \ + enum \ + { \ + value = sizeof(test(choose())) == sizeof(choice1::type) \ + }; \ } #else - template struct identity { typedef T type; }; +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_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_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 }; \ +#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 - -}}} +} +} +} //////////////////////////////////////////////////////////////////////////////// // @@ -638,445 +681,434 @@ namespace boost { namespace unordered { namespace detail { #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 -# include -# include -# include -# if defined(BOOST_NO_SFINAE_EXPR) -# include -# endif +#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 +#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 { +namespace boost { +namespace unordered { +namespace detail { - template - struct rebind_alloc; +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; - }; +template