diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-12-11 18:55:56 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-12-11 18:55:56 +0900 |
commit | 08c1e93fa36a49f49325a07fe91ff92c964c2b6c (patch) | |
tree | 7a7053ceb8874b28ec4b868d4c49b500008a102e /boost/unordered | |
parent | bb4dd8289b351fae6b55e303f189127a394a1edd (diff) | |
download | boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.gz boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.bz2 boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.zip |
Imported Upstream version 1.57.0upstream/1.57.0
Diffstat (limited to 'boost/unordered')
-rw-r--r-- | boost/unordered/detail/allocate.hpp | 698 | ||||
-rw-r--r-- | boost/unordered/detail/buckets.hpp | 1124 | ||||
-rw-r--r-- | boost/unordered/detail/equivalent.hpp | 479 | ||||
-rw-r--r-- | boost/unordered/detail/extract_key.hpp | 80 | ||||
-rw-r--r-- | boost/unordered/detail/fwd.hpp | 6 | ||||
-rw-r--r-- | boost/unordered/detail/table.hpp | 731 | ||||
-rw-r--r-- | boost/unordered/detail/unique.hpp | 326 | ||||
-rw-r--r-- | boost/unordered/detail/util.hpp | 10 | ||||
-rw-r--r-- | boost/unordered/unordered_map.hpp | 147 | ||||
-rw-r--r-- | boost/unordered/unordered_map_fwd.hpp | 6 | ||||
-rw-r--r-- | boost/unordered/unordered_set.hpp | 147 | ||||
-rw-r--r-- | boost/unordered/unordered_set_fwd.hpp | 6 |
12 files changed, 1779 insertions, 1981 deletions
diff --git a/boost/unordered/detail/allocate.hpp b/boost/unordered/detail/allocate.hpp index 5574c15855..4c20b168ab 100644 --- a/boost/unordered/detail/allocate.hpp +++ b/boost/unordered/detail/allocate.hpp @@ -9,8 +9,9 @@ #ifndef BOOST_UNORDERED_ALLOCATE_HPP #define BOOST_UNORDERED_ALLOCATE_HPP -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif #include <boost/unordered/detail/fwd.hpp> @@ -85,7 +86,7 @@ namespace boost { namespace unordered { namespace detail { // Either forwarding variadic arguments, or storing the arguments in // emplace_args##n -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args #define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args @@ -136,7 +137,7 @@ namespace boost { namespace unordered { namespace detail { #define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args #define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args -#if defined(BOOST_NO_RVALUE_REFERENCES) +#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); \ @@ -167,347 +168,6 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, #endif - //////////////////////////////////////////////////////////////////////////// - // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter - // e.g. for int - -#if !defined(BOOST_NO_RVALUE_REFERENCES) -# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) -#else - struct please_ignore_this_overload { - typedef please_ignore_this_overload type; - }; - - template <typename T> - struct rv_ref_impl { - typedef BOOST_RV_REF(T) type; - }; - - template <typename T> - struct rv_ref : - boost::detail::if_true< - boost::is_class<T>::value - >::BOOST_NESTED_TEMPLATE then < - boost::unordered::detail::rv_ref_impl<T>, - please_ignore_this_overload - >::type - {}; - -# define BOOST_UNORDERED_RV_REF(T) \ - typename boost::unordered::detail::rv_ref<T>::type -#endif - - //////////////////////////////////////////////////////////////////////////// - // Construct from tuple - // - // Used for piecewise construction. - -#if !defined(__SUNPRO_CC) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template<typename T> \ - void construct_from_tuple(T* ptr, namespace_ tuple<>) \ - { \ - new ((void*) ptr) T(); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO(1, n, \ - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ - template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ - void construct_from_tuple(T* ptr, \ - namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ - { \ - new ((void*) ptr) T( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ - ); \ - } - -# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ - namespace_ get<n>(x) - -#else - - template <int N> struct length {}; - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template<typename T> \ - void construct_from_tuple_impl( \ - boost::unordered::detail::length<0>, T* ptr, \ - namespace_ tuple<>) \ - { \ - new ((void*) ptr) T(); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO(1, n, \ - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ - template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ - void construct_from_tuple_impl( \ - boost::unordered::detail::length<n>, T* ptr, \ - namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ - { \ - new ((void*) ptr) T( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ - ); \ - } - -# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ - namespace_ get<n>(x) - -#endif - -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) - -#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE) - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) -#endif - -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL -#undef BOOST_UNORDERED_GET_TUPLE_ARG - -#if defined(__SUNPRO_CC) - - template <typename T, typename Tuple> - void construct_from_tuple(T* ptr, Tuple const& x) - { - construct_from_tuple_impl( - boost::unordered::detail::length< - boost::tuples::length<Tuple>::value>(), - ptr, x); - } - -#endif - - //////////////////////////////////////////////////////////////////////////// - // SFINAE traits for construction. - - // Decide which construction method to use for a three argument - // call. Note that this is difficult to do using overloads because - // the arguments are packed into 'emplace_args3'. - // - // The decision is made on the first argument. - - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - template <typename A, typename B, typename A0> - struct emulation1 { - static choice1::type test(choice1, std::pair<A, B> const&); - static choice2::type test(choice2, A const&); - static choice3::type test(choice3, convert_from_anything const&); - - enum { value = - sizeof(test(choose(), boost::unordered::detail::make<A0>())) == - sizeof(choice2::type) }; - }; -#endif - - template <typename A, typename B, typename A0> - struct check3_base { - static choice1::type test(choice1, - boost::unordered::piecewise_construct_t); - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - static choice2::type test(choice2, A const&); -#endif - - static choice3::type test(choice3, ...); - - enum { value = - sizeof(test(choose(), boost::unordered::detail::make<A0>())) }; - }; - - template <typename A, typename B, typename A0> - struct piecewise3 { - enum { value = check3_base<A,B,A0>::value == sizeof(choice1::type) }; - }; - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - template <typename A, typename B, typename A0> - struct emulation3 { - enum { value = check3_base<A,B,A0>::value == sizeof(choice2::type) }; - }; - -#endif - -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) - - //////////////////////////////////////////////////////////////////////////// - // Construct from variadic parameters - - template <typename T, typename... Args> - inline void construct_impl(T* address, BOOST_FWD_REF(Args)... args) - { - new((void*) address) T(boost::forward<Args>(args)...); - } - - template <typename A, typename B, typename A0, typename A1, typename A2> - inline typename enable_if<piecewise3<A, B, A0>, void>::type - construct_impl(std::pair<A, B>* address, - BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - boost::unordered::detail::construct_from_tuple( - boost::addressof(address->first), boost::forward<A1>(a1)); - boost::unordered::detail::construct_from_tuple( - boost::addressof(address->second), boost::forward<A2>(a2)); - } - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - - template <typename A, typename B, typename A0> - inline typename enable_if<emulation1<A, B, A0>, void>::type - construct_impl(std::pair<A, B>* address, BOOST_FWD_REF(A0) a0) - { - new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0)); - new((void*) boost::addressof(address->second)) B(); - } - - template <typename A, typename B, typename A0, typename A1, typename A2> - inline typename enable_if<emulation3<A, B, A0>, void>::type - construct_impl(std::pair<A, B>* address, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0)); - new((void*) boost::addressof(address->second)) B( - boost::forward<A1>(a1), - boost::forward<A2>(a2)); - } - - template <typename A, typename B, - typename A0, typename A1, typename A2, typename A3, - typename... Args> - inline void construct_impl(std::pair<A, B>* address, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, - BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(Args)... args) - { - new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0)); - - new((void*) boost::addressof(address->second)) B( - boost::forward<A1>(a1), - boost::forward<A2>(a2), - boost::forward<A3>(a3), - boost::forward<Args>(args)...); - } - -#endif // BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT - -#else // BOOST_NO_VARIADIC_TEMPLATES - -//////////////////////////////////////////////////////////////////////////////// -// Construct from emplace_args - -#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ - template < \ - typename T, \ - BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \ - > \ - inline void construct_impl(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)); \ - } - - template <typename T, typename A0> - inline void construct_impl(T* address, emplace_args1<A0> const& args) - { - new((void*) address) T(boost::forward<A0>(args.a0)); - } - - template <typename T, typename A0, typename A1> - inline void construct_impl(T* address, emplace_args2<A0, A1> const& args) - { - new((void*) address) T( - boost::forward<A0>(args.a0), - boost::forward<A1>(args.a1) - ); - } - - template <typename T, typename A0, typename A1, typename A2> - inline void construct_impl(T* address, emplace_args3<A0, A1, A2> const& args) - { - new((void*) address) T( - boost::forward<A0>(args.a0), - boost::forward<A1>(args.a1), - boost::forward<A2>(args.a2) - ); - } - - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_CONSTRUCT_IMPL, _) - -#undef BOOST_UNORDERED_CONSTRUCT_IMPL - - template <typename A, typename B, typename A0, typename A1, typename A2> - inline void construct_impl(std::pair<A, B>* address, - boost::unordered::detail::emplace_args3<A0, A1, A2> const& args, - typename enable_if<piecewise3<A, B, A0>, void*>::type = 0) - { - boost::unordered::detail::construct_from_tuple( - boost::addressof(address->first), args.a1); - boost::unordered::detail::construct_from_tuple( - boost::addressof(address->second), args.a2); - } - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - - template <typename A, typename B, typename A0> - inline void construct_impl(std::pair<A, B>* address, - boost::unordered::detail::emplace_args1<A0> const& args, - typename enable_if<emulation1<A, B, A0>, void*>::type = 0) - { - new((void*) boost::addressof(address->first)) A( - boost::forward<A0>(args.a0)); - new((void*) boost::addressof(address->second)) B(); - } - - template <typename A, typename B, typename A0, typename A1, typename A2> - inline void construct_impl(std::pair<A, B>* address, - boost::unordered::detail::emplace_args3<A0, A1, A2> const& args, - typename enable_if<emulation3<A, B, A0>, void*>::type = 0) - { - new((void*) boost::addressof(address->first)) A( - boost::forward<A0>(args.a0)); - new((void*) boost::addressof(address->second)) B( - boost::forward<A1>(args.a1), - boost::forward<A2>(args.a2)); - } - -#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \ - template <typename A, typename B, \ - BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \ - > \ - inline void construct_impl(std::pair<A, B>* address, \ - boost::unordered::detail::BOOST_PP_CAT(emplace_args, num_params) < \ - BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \ - > const& args) \ - { \ - new((void*) boost::addressof(address->first)) A( \ - boost::forward<A0>(args.a0)); \ - new((void*) boost::addressof(address->second)) B( \ - BOOST_PP_ENUM_##z(BOOST_PP_DEC(num_params), \ - BOOST_UNORDERED_CALL_FORWARD2, args.a)); \ - } - -#define BOOST_UNORDERED_CALL_FORWARD2(z, i, a) \ - BOOST_UNORDERED_CALL_FORWARD(z, BOOST_PP_INC(i), a) - - BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(1, 2, _) - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _) - -#undef BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL -#undef BOOST_UNORDERED_CALL_FORWARD2 - -#endif // BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT -#endif // BOOST_NO_VARIADIC_TEMPLATES - }}} //////////////////////////////////////////////////////////////////////////////// @@ -575,9 +235,11 @@ namespace boost { namespace unordered { namespace detail { #pragma warning(disable:4100) // unreferenced formal parameter #endif - template <class T> - inline void destroy(T* x) { - x->~T(); + namespace func { + template <class T> + inline void destroy(T* x) { + x->~T(); + } } #if defined(BOOST_MSVC) @@ -598,13 +260,12 @@ namespace boost { namespace unordered { namespace detail { template <typename T, unsigned int> struct expr_test; template <typename T> struct expr_test<T, sizeof(char)> : T {}; - template <typename U> static char for_expr_test(U const&); # define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ template <typename U> \ static typename boost::unordered::detail::expr_test< \ BOOST_PP_CAT(choice, result), \ - sizeof(boost::unordered::detail::for_expr_test(( \ + sizeof(for_expr_test(( \ (expression), \ 0)))>::type test( \ BOOST_PP_CAT(choice, count)) @@ -617,6 +278,7 @@ namespace boost { namespace unordered { namespace detail { # define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \ struct BOOST_PP_CAT(has_, name) \ { \ + template <typename U> static char for_expr_test(U const&); \ BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, \ boost::unordered::detail::make< thing >().name args); \ BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \ @@ -683,7 +345,7 @@ namespace boost { namespace unordered { namespace detail { # include <boost/type_traits/is_same.hpp> # endif -# if !defined(BOOST_NO_VARIADIC_TEMPLATES) && \ +# if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ !defined(BOOST_NO_SFINAE_EXPR) # define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 # else @@ -773,7 +435,7 @@ namespace boost { namespace unordered { namespace detail { max_size, U const, (), 0 ); -# if !defined(BOOST_NO_VARIADIC_TEMPLATES) +# if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template <typename T, typename ValueType, typename... Args> BOOST_UNORDERED_HAS_FUNCTION( @@ -814,6 +476,9 @@ namespace boost { namespace unordered { namespace detail { # endif + namespace func + { + template <typename Alloc> inline Alloc call_select_on_container_copy_construction(const Alloc& rhs, typename boost::enable_if_c< @@ -851,6 +516,8 @@ namespace boost { namespace unordered { namespace detail { return (std::numeric_limits<SizeType>::max)(); } + } // namespace func. + template <typename Alloc> struct allocator_traits { @@ -930,7 +597,7 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::has_destroy<Alloc, T>::value>::type destroy(Alloc&, T* p) { - boost::unordered::detail::destroy(p); + boost::unordered::detail::func::destroy(p); } # elif !defined(BOOST_NO_SFINAE_EXPR) @@ -964,7 +631,7 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::has_destroy<Alloc, T>::value>::type destroy(Alloc&, T* p) { - boost::unordered::detail::destroy(p); + boost::unordered::detail::func::destroy(p); } # else @@ -1010,21 +677,22 @@ namespace boost { namespace unordered { namespace detail { boost::is_same<T, value_type>::value, void*>::type = 0) { - boost::unordered::detail::destroy(p); + boost::unordered::detail::func::destroy(p); } # endif static size_type max_size(const Alloc& a) { - return boost::unordered::detail::call_max_size<size_type>(a); + return boost::unordered::detail::func:: + call_max_size<size_type>(a); } // Allocator propagation on construction static Alloc select_on_container_copy_construction(Alloc const& rhs) { - return boost::unordered::detail:: + return boost::unordered::detail::func:: call_select_on_container_copy_construction(rhs); } @@ -1098,81 +766,292 @@ namespace boost { namespace unordered { namespace detail { #endif -//////////////////////////////////////////////////////////////////////////////// -// -// Some helper functions for allocating & constructing -namespace boost { namespace unordered { namespace detail { +namespace boost { namespace unordered { namespace detail { namespace func { //////////////////////////////////////////////////////////////////////////// - // - // construct_node/destroy_node - // - // Construct a node using the best available method. + // call_construct -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <typename Alloc, typename T, BOOST_UNORDERED_EMPLACE_TEMPLATE> - inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS) +# if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + + template <typename Alloc, typename T, typename... Args> + inline void call_construct(Alloc& alloc, T* address, + BOOST_FWD_REF(Args)... args) { - boost::unordered::detail::allocator_traits<Alloc>::construct( - a, p, BOOST_UNORDERED_EMPLACE_FORWARD); + boost::unordered::detail::allocator_traits<Alloc>::construct(alloc, + address, boost::forward<Args>(args)...); } template <typename Alloc, typename T> - inline void destroy_node(Alloc& a, T* p) + inline void destroy_value_impl(Alloc& alloc, T* x) { + boost::unordered::detail::allocator_traits<Alloc>::destroy(alloc, x); + } + + +# else + + template <typename Alloc, typename T, typename... Args> + inline void call_construct(Alloc&, T* address, + BOOST_FWD_REF(Args)... args) { - boost::unordered::detail::allocator_traits<Alloc>::destroy(a, p); + new((void*) address) T(boost::forward<Args>(args)...); + } + + template <typename Alloc, typename T> + inline void destroy_value_impl(Alloc&, T* x) { + boost::unordered::detail::func::destroy(x); + } + + +# endif + +#else + + template <typename Alloc, typename T> + inline void destroy_value_impl(Alloc&, T* x) { + boost::unordered::detail::func::destroy(x); + } + +#endif + + //////////////////////////////////////////////////////////////////////////// + // Construct from tuple + // + // Used for piecewise construction. + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template<typename Alloc, typename T> \ + void construct_from_tuple(Alloc& alloc, T* ptr, namespace_ tuple<>) \ + { \ + boost::unordered::detail::func::call_construct(alloc, ptr); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template<typename Alloc, typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + void construct_from_tuple(Alloc& alloc, T* ptr, \ + namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ + { \ + boost::unordered::detail::func::call_construct(alloc, ptr, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ + ); \ } +# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_ get<n>(x) + +#elif !defined(__SUNPRO_CC) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template<typename Alloc, typename T> \ + void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \ + { \ + new ((void*) ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template<typename Alloc, typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + void construct_from_tuple(Alloc&, T* ptr, \ + namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ + { \ + new ((void*) ptr) T( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ + ); \ + } + +# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_ get<n>(x) + #else - template <typename AllocTraits, typename T> - struct value_construct + template <int N> struct length {}; + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template<typename Alloc, typename T> \ + void construct_from_tuple_impl( \ + boost::unordered::detail::func::length<0>, Alloc&, T* ptr, \ + namespace_ tuple<>) \ + { \ + new ((void*) ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template<typename Alloc, typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ + void construct_from_tuple_impl( \ + boost::unordered::detail::func::length<n>, Alloc&, T* ptr, \ + namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \ + { \ + new ((void*) ptr) T( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ + ); \ + } + +# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_ get<n>(x) + +#endif + +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) + +#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) +#endif + +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL +#undef BOOST_UNORDERED_GET_TUPLE_ARG + +#if defined(__SUNPRO_CC) + + template <typename Alloc, typename T, typename Tuple> + void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x) { - typedef BOOST_DEDUCED_TYPENAME AllocTraits::allocator_type allocator; + construct_from_tuple_impl( + boost::unordered::detail::func::length< + boost::tuples::length<Tuple>::value>(), + alloc, ptr, x); + } - allocator& alloc; - T* ptr; +#endif - value_construct(allocator& a, T* p) : alloc(a), ptr(p) - { - AllocTraits::construct(alloc, ptr, T()); - } + //////////////////////////////////////////////////////////////////////////// + // Trait to check for piecewise construction. - void release() - { - ptr = 0; - } + template <typename A0> + struct use_piecewise { + static choice1::type test(choice1, + boost::unordered::piecewise_construct_t); - ~value_construct() - { - if (ptr) AllocTraits::destroy(alloc, ptr); - } + static choice2::type test(choice2, ...); - private: - value_construct(value_construct const&); - value_construct& operator=(value_construct const&); + enum { value = sizeof(choice1::type) == + sizeof(test(choose(), boost::unordered::detail::make<A0>())) }; }; - template <typename Alloc, typename T, BOOST_UNORDERED_EMPLACE_TEMPLATE> - inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //////////////////////////////////////////////////////////////////////////// + // Construct from variadic parameters + + // For the standard pair constructor. + + template <typename Alloc, typename T, typename... Args> + inline void construct_value_impl(Alloc& alloc, T* address, + BOOST_FWD_REF(Args)... args) { - value_construct<boost::unordered::detail::allocator_traits<Alloc>, T> - construct_guard(a, p); - boost::unordered::detail::construct_impl( - p->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - construct_guard.release(); + boost::unordered::detail::func::call_construct(alloc, + address, boost::forward<Args>(args)...); } - template <typename Alloc, typename T> - inline void destroy_node(Alloc& a, T* p) + // Special case for piece_construct + // + // TODO: When possible, it might be better to use std::pair's + // constructor for std::piece_construct with std::tuple. + + template <typename Alloc, typename A, typename B, + typename A0, typename A1, typename A2> + inline typename enable_if<use_piecewise<A0>, void>::type + construct_value_impl(Alloc& alloc, std::pair<A, B>* address, + BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - boost::unordered::detail::destroy(p->value_ptr()); - boost::unordered::detail::allocator_traits<Alloc>::destroy(a, p); + boost::unordered::detail::func::construct_from_tuple(alloc, + boost::addressof(address->first), boost::forward<A1>(a1)); + boost::unordered::detail::func::construct_from_tuple(alloc, + boost::addressof(address->second), boost::forward<A2>(a2)); } -#endif +#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +//////////////////////////////////////////////////////////////////////////////// +// Construct from emplace_args + + // Explicitly write out first three overloads for the sake of sane + // error messages. + + template <typename Alloc, typename T, typename A0> + inline void construct_value_impl(Alloc&, T* address, + emplace_args1<A0> const& args) + { + new((void*) address) T(boost::forward<A0>(args.a0)); + } + + template <typename Alloc, typename T, typename A0, typename A1> + inline void construct_value_impl(Alloc&, T* address, + emplace_args2<A0, A1> const& args) + { + new((void*) address) T( + boost::forward<A0>(args.a0), + boost::forward<A1>(args.a1) + ); + } + + template <typename Alloc, typename T, typename A0, typename A1, typename A2> + inline void construct_value_impl(Alloc&, T* address, + emplace_args3<A0, A1, A2> const& args) + { + new((void*) address) T( + boost::forward<A0>(args.a0), + boost::forward<A1>(args.a1), + boost::forward<A2>(args.a2) + ); + } + + // Use a macro for the rest. + +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ + template < \ + typename Alloc, typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \ + > \ + inline void construct_value_impl(Alloc&, T* address, \ + boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \ + > const& args) \ + { \ + new((void*) address) T( \ + BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_FORWARD, \ + args.a)); \ + } + + BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_IMPL, _) + +#undef BOOST_UNORDERED_CONSTRUCT_IMPL + + // Construct with piece_construct + + template <typename Alloc, typename A, typename B, + typename A0, typename A1, typename A2> + inline void construct_value_impl(Alloc& alloc, std::pair<A, B>* address, + boost::unordered::detail::emplace_args3<A0, A1, A2> const& args, + typename enable_if<use_piecewise<A0>, void*>::type = 0) + { + boost::unordered::detail::func::construct_from_tuple(alloc, + boost::addressof(address->first), args.a1); + boost::unordered::detail::func::construct_from_tuple(alloc, + boost::addressof(address->second), args.a2); + } + +#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +}}}} + +namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// // @@ -1202,8 +1081,10 @@ namespace boost { namespace unordered { namespace detail { ~array_constructor() { if (ptr_) { - for(pointer p = ptr_; p != constructed_; ++p) - traits::destroy(alloc_, boost::addressof(*p)); + for(pointer p = ptr_; p != constructed_; ++p) { + boost::unordered::detail::func::destroy( + boost::addressof(*p)); + } traits::deallocate(alloc_, ptr_, length_); } @@ -1216,8 +1097,9 @@ namespace boost { namespace unordered { namespace detail { length_ = l; ptr_ = traits::allocate(alloc_, length_); pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_); - for(constructed_ = ptr_; constructed_ != end; ++constructed_) - traits::construct(alloc_, boost::addressof(*constructed_), v); + for(constructed_ = ptr_; constructed_ != end; ++constructed_) { + new ((void*) boost::addressof(*constructed_)) V(v); + } } pointer get() const diff --git a/boost/unordered/detail/buckets.hpp b/boost/unordered/detail/buckets.hpp index 85681a685c..7de4317b5a 100644 --- a/boost/unordered/detail/buckets.hpp +++ b/boost/unordered/detail/buckets.hpp @@ -7,186 +7,36 @@ #ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif #include <boost/unordered/detail/util.hpp> #include <boost/unordered/detail/allocate.hpp> #include <boost/type_traits/aligned_storage.hpp> #include <boost/type_traits/alignment_of.hpp> +#include <boost/type_traits/is_nothrow_move_constructible.hpp> +#include <boost/type_traits/is_nothrow_move_assignable.hpp> #include <boost/swap.hpp> #include <boost/assert.hpp> #include <boost/limits.hpp> #include <boost/iterator.hpp> -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant -#endif - namespace boost { namespace unordered { namespace detail { template <typename Types> struct table; template <typename NodePointer> struct bucket; struct ptr_bucket; - template <typename A, typename Bucket, typename Node, typename Policy> - struct buckets; template <typename Types> struct table_impl; template <typename Types> struct grouped_table_impl; - /////////////////////////////////////////////////////////////////// - // - // Node construction - - template <typename NodeAlloc> - struct node_constructor - { - private: - - typedef NodeAlloc node_allocator; - typedef boost::unordered::detail::allocator_traits<NodeAlloc> - node_allocator_traits; - typedef typename node_allocator_traits::value_type node; - typedef typename node_allocator_traits::pointer node_pointer; - typedef typename node::value_type value_type; - - node_allocator& alloc_; - node_pointer node_; - bool constructed_; - - public: - - node_constructor(node_allocator& n) : - alloc_(n), - node_(), - constructed_(false) - { - } - - ~node_constructor(); - - void construct_node(); - - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - void construct_value(BOOST_UNORDERED_EMPLACE_ARGS) - { - BOOST_ASSERT(node_ && !constructed_); - boost::unordered::detail::construct_node(alloc_, - boost::addressof(*node_), BOOST_UNORDERED_EMPLACE_FORWARD); - node_->init(static_cast<typename node::link_pointer>(node_)); - constructed_ = true; - } - - template <typename A0> - void construct_value2(BOOST_FWD_REF(A0) a0) - { - BOOST_ASSERT(node_ && !constructed_); - - boost::unordered::detail::construct_node(alloc_, - boost::addressof(*node_), - BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward<A0>(a0))); - - constructed_ = true; - node_->init(static_cast<typename node::link_pointer>(node_)); - } - - value_type const& value() const { - BOOST_ASSERT(node_ && constructed_); - return node_->value(); - } - - node_pointer get() - { - return node_; - } - - // no throw - node_pointer release() - { - node_pointer p = node_; - node_ = node_pointer(); - return p; - } - - private: - node_constructor(node_constructor const&); - node_constructor& operator=(node_constructor const&); - }; - - template <typename Alloc> - node_constructor<Alloc>::~node_constructor() - { - if (node_) { - if (constructed_) { - boost::unordered::detail::destroy_node(alloc_, - boost::addressof(*node_)); - } - - node_allocator_traits::deallocate(alloc_, node_, 1); - } - } - - template <typename Alloc> - void node_constructor<Alloc>::construct_node() - { - if(!node_) { - constructed_ = false; - node_ = node_allocator_traits::allocate(alloc_, 1); - } - else if (constructed_) { - boost::unordered::detail::destroy_node(alloc_, - boost::addressof(*node_)); - constructed_ = false; - } - } - - /////////////////////////////////////////////////////////////////// - // - // Bucket - - template <typename NodePointer> - struct bucket - { - typedef NodePointer previous_pointer; - previous_pointer next_; - - bucket() : next_() {} - - previous_pointer first_from_start() - { - return next_; - } - - enum { extra_node = true }; - }; - - struct ptr_bucket - { - typedef ptr_bucket* previous_pointer; - previous_pointer next_; - - ptr_bucket() : next_(0) {} - - previous_pointer first_from_start() - { - return this; - } - - enum { extra_node = false }; - }; - - template <typename LinkPointer> - struct node_base - { - typedef LinkPointer link_pointer; - link_pointer next_; - - node_base() : next_() {} - }; - }}} +// 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 { //////////////////////////////////////////////////////////////////////////// @@ -194,49 +44,50 @@ namespace boost { namespace unordered { namespace iterator_detail { // // all no throw - template <typename NodePointer, typename Value> struct iterator; - template <typename ConstNodePointer, typename NodePointer, - typename Value> struct c_iterator; - template <typename NodePointer, typename Value, typename Policy> - struct l_iterator; - template <typename ConstNodePointer, typename NodePointer, - typename Value, typename Policy> struct cl_iterator; + template <typename Node> struct iterator; + template <typename Node, typename ConstNodePointer> struct c_iterator; + template <typename Node, typename Policy> struct l_iterator; + template <typename Node, typename ConstNodePointer, typename Policy> + struct cl_iterator; // Local Iterators // // all no throw - template <typename NodePointer, typename Value, typename Policy> + template <typename Node, typename Policy> struct l_iterator : public boost::iterator< - std::forward_iterator_tag, Value, std::ptrdiff_t, - NodePointer, Value&> + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + typename Node::value_type*, + typename Node::value_type&> { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template <typename ConstNodePointer, typename NodePointer2, - typename Value2, typename Policy2> + template <typename Node2, typename ConstNodePointer, typename Policy2> friend struct boost::unordered::iterator_detail::cl_iterator; private: #endif - typedef NodePointer node_pointer; - typedef boost::unordered::iterator_detail::iterator<NodePointer, Value> - iterator; + typedef typename Node::node_pointer node_pointer; + typedef boost::unordered::iterator_detail::iterator<Node> iterator; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; public: - l_iterator() : ptr_() {} + typedef typename Node::value_type value_type; + + l_iterator() BOOST_NOEXCEPT : ptr_() {} - l_iterator(iterator x, std::size_t b, std::size_t c) + l_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : ptr_(x.node_), bucket_(b), bucket_count_(c) {} - Value& operator*() const { + value_type& operator*() const { return ptr_->value(); } - Value* operator->() const { + value_type* operator->() const { return ptr_->value_ptr(); } @@ -254,51 +105,53 @@ namespace boost { namespace unordered { namespace iterator_detail { return tmp; } - bool operator==(l_iterator x) const { + bool operator==(l_iterator x) const BOOST_NOEXCEPT { return ptr_ == x.ptr_; } - bool operator!=(l_iterator x) const { + bool operator!=(l_iterator x) const BOOST_NOEXCEPT { return ptr_ != x.ptr_; } }; - template <typename ConstNodePointer, typename NodePointer, typename Value, - typename Policy> + template <typename Node, typename ConstNodePointer, typename Policy> struct cl_iterator : public boost::iterator< - std::forward_iterator_tag, Value, std::ptrdiff_t, - ConstNodePointer, Value const&> + 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 - <NodePointer, Value, Policy>; + <Node, Policy>; private: - typedef NodePointer node_pointer; - typedef boost::unordered::iterator_detail::iterator<NodePointer, Value> - iterator; + typedef typename Node::node_pointer node_pointer; + typedef boost::unordered::iterator_detail::iterator<Node> iterator; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; public: - cl_iterator() : ptr_() {} + typedef typename Node::value_type value_type; + + cl_iterator() BOOST_NOEXCEPT : ptr_() {} - cl_iterator(iterator x, std::size_t b, std::size_t c) : + cl_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : ptr_(x.node_), bucket_(b), bucket_count_(c) {} cl_iterator(boost::unordered::iterator_detail::l_iterator< - NodePointer, Value, Policy> const& x) : + Node, Policy> const& x) BOOST_NOEXCEPT : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) {} - Value const& - operator*() const { + value_type const& operator*() const { return ptr_->value(); } - Value const* operator->() const { + value_type const* operator->() const { return ptr_->value_ptr(); } @@ -316,52 +169,60 @@ namespace boost { namespace unordered { namespace iterator_detail { return tmp; } - friend bool operator==(cl_iterator const& x, cl_iterator const& y) { + 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) { + friend bool operator!=(cl_iterator const& x, cl_iterator const& y) + BOOST_NOEXCEPT + { return x.ptr_ != y.ptr_; } }; - template <typename NodePointer, typename Value> + template <typename Node> struct iterator : public boost::iterator< - std::forward_iterator_tag, Value, std::ptrdiff_t, - NodePointer, Value&> + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + typename Node::value_type*, + typename Node::value_type&> { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template <typename, typename, typename> + template <typename, typename> friend struct boost::unordered::iterator_detail::c_iterator; - template <typename, typename, typename> + template <typename, typename> friend struct boost::unordered::iterator_detail::l_iterator; - template <typename, typename, typename, typename> + template <typename, typename, typename> friend struct boost::unordered::iterator_detail::cl_iterator; template <typename> friend struct boost::unordered::detail::table; - template <typename, typename, typename, typename> - friend struct boost::unordered::detail::buckets; template <typename> friend struct boost::unordered::detail::table_impl; template <typename> friend struct boost::unordered::detail::grouped_table_impl; private: #endif - typedef NodePointer node_pointer; + typedef typename Node::node_pointer node_pointer; node_pointer node_; public: - iterator() : node_() {} + typedef typename Node::value_type value_type; + + iterator() BOOST_NOEXCEPT : node_() {} - explicit iterator(node_pointer const& x) : node_(x) {} + explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT : + node_(static_cast<node_pointer>(x)) {} - Value& operator*() const { + value_type& operator*() const { return node_->value(); } - Value* operator->() const { + value_type* operator->() const { return &node_->value(); } @@ -376,29 +237,29 @@ namespace boost { namespace unordered { namespace iterator_detail { return tmp; } - bool operator==(iterator const& x) const { + bool operator==(iterator const& x) const BOOST_NOEXCEPT { return node_ == x.node_; } - bool operator!=(iterator const& x) const { + bool operator!=(iterator const& x) const BOOST_NOEXCEPT { return node_ != x.node_; } }; - template <typename ConstNodePointer, typename NodePointer, typename Value> + template <typename Node, typename ConstNodePointer> struct c_iterator : public boost::iterator< - std::forward_iterator_tag, Value, std::ptrdiff_t, - ConstNodePointer, Value const&> + 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< - NodePointer, Value>; + friend struct boost::unordered::iterator_detail::iterator<Node>; #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template <typename> friend struct boost::unordered::detail::table; - template <typename, typename, typename, typename> - friend struct boost::unordered::detail::buckets; template <typename> friend struct boost::unordered::detail::table_impl; template <typename> @@ -406,26 +267,26 @@ namespace boost { namespace unordered { namespace iterator_detail { private: #endif - - typedef NodePointer node_pointer; - typedef boost::unordered::iterator_detail::iterator<NodePointer, Value> - iterator; + typedef typename Node::node_pointer node_pointer; + typedef boost::unordered::iterator_detail::iterator<Node> iterator; node_pointer node_; public: - c_iterator() : node_() {} + typedef typename Node::value_type value_type; + + c_iterator() BOOST_NOEXCEPT : node_() {} - explicit c_iterator(node_pointer const& x) : node_(x) {} + explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT : + node_(static_cast<node_pointer>(x)) {} - c_iterator(boost::unordered::iterator_detail::iterator< - NodePointer, Value> const& x) : node_(x.node_) {} + c_iterator(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} - Value const& operator*() const { + value_type const& operator*() const { return node_->value(); } - Value const* operator->() const { + value_type const* operator->() const { return &node_->value(); } @@ -440,11 +301,15 @@ namespace boost { namespace unordered { namespace iterator_detail { return tmp; } - friend bool operator==(c_iterator const& x, c_iterator const& y) { + 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) { + friend bool operator!=(c_iterator const& x, c_iterator const& y) + BOOST_NOEXCEPT + { return x.node_ != y.node_; } }; @@ -454,479 +319,397 @@ namespace boost { namespace unordered { namespace detail { /////////////////////////////////////////////////////////////////// // - // Hash Policy - // - // Don't really want buckets to derive from this, but will for now. + // Node construction - template <typename SizeT> - struct prime_policy + template <typename NodeAlloc> + struct node_constructor { - template <typename Hash, typename T> - static inline SizeT apply_hash(Hash const& hf, T const& x) { - return hf(x); + private: + + typedef NodeAlloc node_allocator; + typedef boost::unordered::detail::allocator_traits<NodeAlloc> + node_allocator_traits; + typedef typename node_allocator_traits::value_type node; + typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node::value_type value_type; + + protected: + + node_allocator& alloc_; + node_pointer node_; + bool node_constructed_; + bool value_constructed_; + + public: + + node_constructor(node_allocator& n) : + alloc_(n), + node_(), + node_constructed_(false), + value_constructed_(false) + { } - static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { - return hash % bucket_count; + ~node_constructor(); + + void construct(); + + template <BOOST_UNORDERED_EMPLACE_TEMPLATE> + void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS) + { + construct(); + boost::unordered::detail::func::construct_value_impl( + alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + value_constructed_ = true; } - static inline SizeT new_bucket_count(SizeT min) { - return boost::unordered::detail::next_prime(min); + template <typename A0> + void construct_with_value2(BOOST_FWD_REF(A0) a0) + { + construct(); + boost::unordered::detail::func::construct_value_impl( + alloc_, node_->value_ptr(), + BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward<A0>(a0))); + value_constructed_ = true; } - static inline SizeT prev_bucket_count(SizeT max) { - return boost::unordered::detail::prev_prime(max); + value_type const& value() const { + BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); + return node_->value(); + } + + // no throw + node_pointer release() + { + BOOST_ASSERT(node_ && node_constructed_); + node_pointer p = node_; + node_ = node_pointer(); + return p; } + + private: + node_constructor(node_constructor const&); + node_constructor& operator=(node_constructor const&); }; - template <typename SizeT> - struct mix64_policy + template <typename Alloc> + node_constructor<Alloc>::~node_constructor() { - template <typename Hash, typename T> - static inline SizeT apply_hash(Hash const& hf, T const& x) { - SizeT key = hf(x); - key = (~key) + (key << 21); // key = (key << 21) - key - 1; - key = key ^ (key >> 24); - key = (key + (key << 3)) + (key << 8); // key * 265 - key = key ^ (key >> 14); - key = (key + (key << 2)) + (key << 4); // key * 21 - key = key ^ (key >> 28); - key = key + (key << 31); - return key; - } + if (node_) { + if (value_constructed_) { + boost::unordered::detail::func::destroy_value_impl(alloc_, + node_->value_ptr()); + } - static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { - return hash & (bucket_count - 1); - } + if (node_constructed_) { + boost::unordered::detail::func::destroy( + boost::addressof(*node_)); + } - 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; + node_allocator_traits::deallocate(alloc_, node_, 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 <typename Alloc> + void node_constructor<Alloc>::construct() + { + if(!node_) { + node_constructed_ = false; + value_constructed_ = false; - template <int digits, int radix> - struct pick_policy_impl { - typedef prime_policy<std::size_t> type; - }; + node_ = node_allocator_traits::allocate(alloc_, 1); - template <> - struct pick_policy_impl<64, 2> { - typedef mix64_policy<std::size_t> type; - }; + new ((void*) boost::addressof(*node_)) node(); + node_->init(node_); + node_constructed_ = true; + } + else { + BOOST_ASSERT(node_constructed_); - struct pick_policy : - pick_policy_impl< - std::numeric_limits<std::size_t>::digits, - std::numeric_limits<std::size_t>::radix> {}; + if (value_constructed_) + { + boost::unordered::detail::func::destroy_value_impl(alloc_, + node_->value_ptr()); + value_constructed_ = false; + } + } + } /////////////////////////////////////////////////////////////////// // - // Buckets + // Node Holder + // + // Temporary store for nodes. Deletes any that aren't used. - template <typename A, typename Bucket, typename Node, typename Policy> - struct buckets : Policy + template <typename NodeAlloc> + struct node_holder : private node_constructor<NodeAlloc> { private: - buckets(buckets const&); - buckets& operator=(buckets const&); - public: - typedef boost::unordered::detail::allocator_traits<A> traits; - typedef typename traits::value_type value_type; - - typedef Policy policy; - typedef Node node; - typedef Bucket bucket; - typedef typename boost::unordered::detail::rebind_wrap<A, node>::type - node_allocator; - typedef typename boost::unordered::detail::rebind_wrap<A, bucket>::type - bucket_allocator; - typedef boost::unordered::detail::allocator_traits<node_allocator> + typedef node_constructor<NodeAlloc> base; + + typedef NodeAlloc node_allocator; + typedef boost::unordered::detail::allocator_traits<NodeAlloc> node_allocator_traits; - typedef boost::unordered::detail::allocator_traits<bucket_allocator> - bucket_allocator_traits; - typedef typename node_allocator_traits::pointer - node_pointer; - typedef typename node_allocator_traits::const_pointer - const_node_pointer; - typedef typename bucket_allocator_traits::pointer - bucket_pointer; - typedef typename bucket::previous_pointer - previous_pointer; - typedef boost::unordered::detail::node_constructor<node_allocator> - node_constructor; - - typedef boost::unordered::iterator_detail:: - iterator<node_pointer, value_type> iterator; - typedef boost::unordered::iterator_detail:: - c_iterator<const_node_pointer, node_pointer, value_type> c_iterator; - typedef boost::unordered::iterator_detail:: - l_iterator<node_pointer, value_type, policy> l_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator<const_node_pointer, node_pointer, value_type, policy> - cl_iterator; - - // Members - - bucket_pointer buckets_; - std::size_t bucket_count_; - std::size_t size_; - boost::unordered::detail::compressed<bucket_allocator, node_allocator> - allocators_; + typedef typename node_allocator_traits::value_type node; + typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node::value_type value_type; + typedef typename node::link_pointer link_pointer; + typedef boost::unordered::iterator_detail::iterator<node> iterator; - // Data access + node_pointer nodes_; - bucket_allocator const& bucket_alloc() const - { - return allocators_.first(); - } + public: - node_allocator const& node_alloc() const + template <typename Table> + explicit node_holder(Table& b) : + base(b.node_alloc()), + nodes_() { - return allocators_.second(); + if (b.size_) { + typename Table::link_pointer prev = b.get_previous_start(); + nodes_ = static_cast<node_pointer>(prev->next_); + prev->next_ = link_pointer(); + b.size_ = 0; + } } - bucket_allocator& bucket_alloc() - { - return allocators_.first(); - } + ~node_holder(); - node_allocator& node_alloc() + void node_for_assignment() { - return allocators_.second(); - } + if (!this->node_ && nodes_) { + this->node_ = nodes_; + nodes_ = static_cast<node_pointer>(nodes_->next_); + this->node_->init(this->node_); + this->node_->next_ = link_pointer(); - 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); + this->node_constructed_ = true; + this->value_constructed_ = true; + } } - bucket_pointer get_bucket(std::size_t bucket_index) const - { - return buckets_ + static_cast<std::ptrdiff_t>(bucket_index); + template <typename T> + inline void assign_impl(T const& v) { + if (this->node_ && this->value_constructed_) { + this->node_->value() = v; + } + else { + this->construct_with_value2(v); + } } - previous_pointer get_previous_start() const - { - return this->get_bucket(this->bucket_count_)->first_from_start(); + template <typename T1, typename T2> + inline void assign_impl(std::pair<T1 const, T2> const& v) { + this->construct_with_value2(v); } - previous_pointer get_previous_start(std::size_t bucket_index) const - { - return this->get_bucket(bucket_index)->next_; + template <typename T> + inline void move_assign_impl(T& v) { + if (this->node_ && this->value_constructed_) { + this->node_->value() = boost::move(v); + } + else { + this->construct_with_value2(boost::move(v)); + } } - iterator get_start() const - { - return iterator(static_cast<node_pointer>( - this->get_previous_start()->next_)); + template <typename T1, typename T2> + inline void move_assign_impl(std::pair<T1 const, T2>& v) { + this->construct_with_value2(boost::move(v)); } - iterator get_start(std::size_t bucket_index) const + node_pointer copy_of(value_type const& v) { - previous_pointer prev = this->get_previous_start(bucket_index); - return prev ? iterator(static_cast<node_pointer>(prev->next_)) : - iterator(); + node_for_assignment(); + assign_impl(v); + return base::release(); } - float load_factor() const + node_pointer move_copy_of(value_type& v) { - BOOST_ASSERT(this->bucket_count_ != 0); - return static_cast<float>(this->size_) - / static_cast<float>(this->bucket_count_); + node_for_assignment(); + move_assign_impl(v); + return base::release(); } - std::size_t bucket_size(std::size_t index) const + iterator begin() const { - if (!this->size_) return 0; - iterator it = this->get_start(index); - if (!it.node_) return 0; + return iterator(nodes_); + } + }; - std::size_t count = 0; - while(it.node_ && policy::to_bucket( - this->bucket_count_, it.node_->hash_) == index) - { - ++count; - ++it; - } + template <typename Alloc> + node_holder<Alloc>::~node_holder() + { + while (nodes_) { + node_pointer p = nodes_; + nodes_ = static_cast<node_pointer>(p->next_); - return count; + boost::unordered::detail::func::destroy_value_impl(this->alloc_, + p->value_ptr()); + boost::unordered::detail::func::destroy(boost::addressof(*p)); + node_allocator_traits::deallocate(this->alloc_, p, 1); } + } - //////////////////////////////////////////////////////////////////////// - // Constructors + /////////////////////////////////////////////////////////////////// + // + // Bucket - buckets(node_allocator const& a, std::size_t bucket_count) : - buckets_(), - bucket_count_(bucket_count), - size_(), - allocators_(a,a) - { - } + template <typename NodePointer> + struct bucket + { + typedef NodePointer link_pointer; + link_pointer next_; - buckets(buckets& b, boost::unordered::detail::move_tag m) : - buckets_(), - bucket_count_(b.bucket_count_), - size_(), - allocators_(b.allocators_, m) - { - swap(b); - } + bucket() : next_() {} - template <typename Types> - buckets(boost::unordered::detail::table<Types>& x, - boost::unordered::detail::move_tag m) : - buckets_(), - bucket_count_(x.bucket_count_), - size_(), - allocators_(x.allocators_, m) + link_pointer first_from_start() { - swap(x); + return next_; } - //////////////////////////////////////////////////////////////////////// - // Create buckets - // (never called in constructor to avoid exception issues) - - void create_buckets() - { - boost::unordered::detail::array_constructor<bucket_allocator> - constructor(bucket_alloc()); - - // Creates an extra bucket to act as the start node. - constructor.construct(bucket(), this->bucket_count_ + 1); - - if (bucket::extra_node) - { - node_constructor a(this->node_alloc()); - a.construct_node(); - - // Since this node is just to mark the beginning it doesn't - // contain a value, so just construct node::node_base - // which containers the pointer to the next element. - node_allocator_traits::construct(node_alloc(), - static_cast<typename node::node_base*>( - boost::addressof(*a.get())), - typename node::node_base()); - - (constructor.get() + - static_cast<std::ptrdiff_t>(this->bucket_count_))->next_ = - a.release(); - } + enum { extra_node = true }; + }; - this->buckets_ = constructor.release(); - } + struct ptr_bucket + { + typedef ptr_bucket* link_pointer; + link_pointer next_; - //////////////////////////////////////////////////////////////////////// - // Swap and Move + ptr_bucket() : next_(0) {} - void swap(buckets& other, false_type = false_type()) + link_pointer first_from_start() { - BOOST_ASSERT(node_alloc() == other.node_alloc()); - boost::swap(buckets_, other.buckets_); - boost::swap(bucket_count_, other.bucket_count_); - boost::swap(size_, other.size_); + return this; } - void swap(buckets& other, true_type) - { - allocators_.swap(other.allocators_); - boost::swap(buckets_, other.buckets_); - boost::swap(bucket_count_, other.bucket_count_); - boost::swap(size_, other.size_); - } + enum { extra_node = false }; + }; - void move_buckets_from(buckets& other) - { - BOOST_ASSERT(node_alloc() == other.node_alloc()); - BOOST_ASSERT(!this->buckets_); - this->buckets_ = other.buckets_; - this->bucket_count_ = other.bucket_count_; - this->size_ = other.size_; - other.buckets_ = bucket_pointer(); - other.bucket_count_ = 0; - other.size_ = 0; - } + /////////////////////////////////////////////////////////////////// + // + // Hash Policy - //////////////////////////////////////////////////////////////////////// - // Delete/destruct + template <typename SizeT> + struct prime_policy + { + template <typename Hash, typename T> + static inline SizeT apply_hash(Hash const& hf, T const& x) { + return hf(x); + } - inline void delete_node(c_iterator n) - { - boost::unordered::detail::destroy_node( - node_alloc(), boost::addressof(*n.node_)); - node_allocator_traits::deallocate(node_alloc(), n.node_, 1); - --size_; + static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { + return hash % bucket_count; } - std::size_t delete_nodes(c_iterator begin, c_iterator end) - { - std::size_t count = 0; + static inline SizeT new_bucket_count(SizeT min) { + return boost::unordered::detail::next_prime(min); + } - while(begin != end) { - c_iterator n = begin; - ++begin; - delete_node(n); - ++count; - } + static inline SizeT prev_bucket_count(SizeT max) { + return boost::unordered::detail::prev_prime(max); + } + }; - return count; + template <typename SizeT> + struct mix64_policy + { + template <typename Hash, typename T> + static inline SizeT apply_hash(Hash const& hf, T const& x) { + SizeT key = hf(x); + key = (~key) + (key << 21); // key = (key << 21) - key - 1; + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); // key * 265 + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); // key * 21 + key = key ^ (key >> 28); + key = key + (key << 31); + return key; } - inline void delete_extra_node(bucket_pointer) {} + static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { + return hash & (bucket_count - 1); + } - inline void delete_extra_node(node_pointer n) { - node_allocator_traits::destroy(node_alloc(), - static_cast<typename node::node_base*>(boost::addressof(*n))); - node_allocator_traits::deallocate(node_alloc(), n, 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; } - inline ~buckets() - { - this->delete_buckets(); + 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; } + }; - void delete_buckets() - { - if(this->buckets_) { - previous_pointer prev = this->get_previous_start(); - - while(prev->next_) { - node_pointer n = static_cast<node_pointer>(prev->next_); - prev->next_ = n->next_; - delete_node(iterator(n)); - } - - delete_extra_node(prev); - - bucket_pointer end = this->get_bucket(this->bucket_count_ + 1); - for(bucket_pointer it = this->buckets_; it != end; ++it) - { - bucket_allocator_traits::destroy(bucket_alloc(), - boost::addressof(*it)); - } - - bucket_allocator_traits::deallocate(bucket_alloc(), - this->buckets_, this->bucket_count_ + 1); - - this->buckets_ = bucket_pointer(); - } + template <int digits, int radix> + struct pick_policy_impl { + typedef prime_policy<std::size_t> type; + }; - BOOST_ASSERT(!this->size_); - } + template <> + struct pick_policy_impl<64, 2> { + typedef mix64_policy<std::size_t> type; + }; - void clear() - { - if(!this->size_) return; + template <typename T> + struct pick_policy : + pick_policy_impl< + std::numeric_limits<std::size_t>::digits, + std::numeric_limits<std::size_t>::radix> {}; - previous_pointer prev = this->get_previous_start(); + // 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. - while(prev->next_) { - node_pointer n = static_cast<node_pointer>(prev->next_); - prev->next_ = n->next_; - delete_node(iterator(n)); - } + template <> + struct pick_policy<int> { + typedef prime_policy<std::size_t> type; + }; - bucket_pointer end = this->get_bucket(this->bucket_count_); - for(bucket_pointer it = this->buckets_; it != end; ++it) - { - it->next_ = node_pointer(); - } + template <> + struct pick_policy<unsigned int> { + typedef prime_policy<std::size_t> type; + }; - BOOST_ASSERT(!this->size_); - } + template <> + struct pick_policy<long> { + typedef prime_policy<std::size_t> type; + }; - // This is called after erasing a node or group of nodes to fix up - // the bucket pointers. - void fix_buckets(bucket_pointer this_bucket, - previous_pointer prev, node_pointer next) - { - if (!next) - { - if (this_bucket->next_ == prev) - this_bucket->next_ = node_pointer(); - } - else - { - bucket_pointer next_bucket = this->get_bucket( - policy::to_bucket(this->bucket_count_, next->hash_)); - - if (next_bucket != this_bucket) - { - next_bucket->next_ = prev; - if (this_bucket->next_ == prev) - this_bucket->next_ = node_pointer(); - } - } - } + template <> + struct pick_policy<unsigned long> { + typedef prime_policy<std::size_t> type; + }; - // This is called after erasing a range of nodes to fix any bucket - // pointers into that range. - void fix_buckets_range(std::size_t bucket_index, - previous_pointer prev, node_pointer begin, node_pointer end) - { - node_pointer n = begin; - - // If we're not at the start of the current bucket, then - // go to the start of the next bucket. - if (this->get_bucket(bucket_index)->next_ != prev) - { - for(;;) { - n = static_cast<node_pointer>(n->next_); - if (n == end) return; - - std::size_t new_bucket_index = - policy::to_bucket(this->bucket_count_, n->hash_); - if (bucket_index != new_bucket_index) { - bucket_index = new_bucket_index; - break; - } - } - } - - // Iterate through the remaining nodes, clearing out the bucket - // pointers. - this->get_bucket(bucket_index)->next_ = previous_pointer(); - for(;;) { - n = static_cast<node_pointer>(n->next_); - if (n == end) break; - - std::size_t new_bucket_index = - policy::to_bucket(this->bucket_count_, n->hash_); - if (bucket_index != new_bucket_index) { - bucket_index = new_bucket_index; - this->get_bucket(bucket_index)->next_ = previous_pointer(); - } - }; - - // Finally fix the bucket containing the trailing node. - if (n) { - this->get_bucket( - policy::to_bucket(this->bucket_count_, n->hash_))->next_ - = prev; - } - } + // TODO: Maybe not if std::size_t is smaller than long long. +#if !defined(BOOST_NO_LONG_LONG) + template <> + struct pick_policy<long long> { + typedef prime_policy<std::size_t> type; }; + template <> + struct pick_policy<unsigned long long> { + typedef prime_policy<std::size_t> type; + }; +#endif + //////////////////////////////////////////////////////////////////////////// // Functions @@ -941,12 +724,23 @@ namespace boost { namespace unordered { namespace detail { // atomically assigns the new function objects in a strongly // exception safe manner. - template <class H, class P> class set_hash_functions; + template <class H, class P, bool NoThrowMoveAssign> + class set_hash_functions; template <class H, class P> class functions { - friend class boost::unordered::detail::set_hash_functions<H, P>; + public: + static const bool nothrow_move_assignable = + boost::is_nothrow_move_assignable<H>::value && + boost::is_nothrow_move_assignable<P>::value; + static const bool nothrow_move_constructible = + boost::is_nothrow_move_constructible<H>::value && + boost::is_nothrow_move_constructible<P>::value; + + private: + friend class boost::unordered::detail::set_hash_functions<H, P, + nothrow_move_assignable>; functions& operator=(functions const&); typedef compressed<H, P> function_pair; @@ -963,23 +757,40 @@ namespace boost { namespace unordered { namespace detail { static_cast<void const*>(&funcs_[current_])); } + function_pair& current() { + return *static_cast<function_pair*>( + static_cast<void*>(&funcs_[current_])); + } + void construct(bool which, H const& hf, P const& eq) { new((void*) &funcs_[which]) function_pair(hf, eq); } - void construct(bool which, function_pair const& f) + 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::destroy((function_pair*)(&funcs_[which])); + boost::unordered::detail::func::destroy((function_pair*)(&funcs_[which])); } public: + typedef boost::unordered::detail::set_hash_functions<H, P, + nothrow_move_assignable> set_hash_functions; + functions(H const& hf, P const& eq) : current_(false) { @@ -992,6 +803,14 @@ namespace boost { namespace unordered { namespace detail { construct(current_, bf.current()); } + functions(functions& bf, boost::unordered::detail::move_tag) + : current_(false) + { + construct(current_, bf.current(), + boost::unordered::detail::integral_constant<bool, + nothrow_move_constructible>()); + } + ~functions() { this->destroy(current_); } @@ -1004,26 +823,28 @@ namespace boost { namespace unordered { namespace detail { return current().second(); } }; - + template <class H, class P> - class set_hash_functions + class set_hash_functions<H, P, false> { set_hash_functions(set_hash_functions const&); set_hash_functions& operator=(set_hash_functions const&); + + typedef functions<H, P> functions_type; - functions<H,P>& functions_; + functions_type& functions_; bool tmp_functions_; public: - set_hash_functions(functions<H,P>& f, H const& h, P const& p) + 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<H,P>& f, functions<H,P> const& other) + set_hash_functions(functions_type& f, functions_type const& other) : functions_(f), tmp_functions_(!f.current_) { @@ -1041,10 +862,67 @@ namespace boost { namespace unordered { namespace detail { tmp_functions_ = !tmp_functions_; } }; -}}} -#if defined(BOOST_MSVC) -#pragma warning(pop) + template <class H, class P> + class set_hash_functions<H, P, true> + { + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef functions<H, P> functions_type; + + functions_type& functions_; + H hash_; + P pred_; + + public: + + set_hash_functions(functions_type& f, H const& h, P const& p) : + functions_(f), + hash_(h), + pred_(p) {} + + set_hash_functions(functions_type& f, functions_type const& other) : + functions_(f), + hash_(other.hash_function()), + pred_(other.key_eq()) {} + + void commit() + { + functions_.current().first() = boost::move(hash_); + functions_.current().second() = boost::move(pred_); + } + }; + + //////////////////////////////////////////////////////////////////////////// + // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter + // e.g. for int + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) +#else + struct please_ignore_this_overload { + typedef please_ignore_this_overload type; + }; + + template <typename T> + struct rv_ref_impl { + typedef BOOST_RV_REF(T) type; + }; + + template <typename T> + struct rv_ref : + boost::detail::if_true< + boost::is_class<T>::value + >::BOOST_NESTED_TEMPLATE then < + boost::unordered::detail::rv_ref_impl<T>, + please_ignore_this_overload + >::type + {}; + +# define BOOST_UNORDERED_RV_REF(T) \ + typename boost::unordered::detail::rv_ref<T>::type #endif +}}} #endif diff --git a/boost/unordered/detail/equivalent.hpp b/boost/unordered/detail/equivalent.hpp index 5cbf6a7cea..58478f99b6 100644 --- a/boost/unordered/detail/equivalent.hpp +++ b/boost/unordered/detail/equivalent.hpp @@ -7,8 +7,9 @@ #ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif #include <boost/unordered/detail/table.hpp> @@ -22,46 +23,25 @@ namespace boost { namespace unordered { namespace detail { template <typename A, typename T> struct grouped_node : - boost::unordered::detail::node_base< - typename ::boost::unordered::detail::rebind_wrap< - A, grouped_node<A, T> >::type::pointer - >, boost::unordered::detail::value_base<T> { typedef typename ::boost::unordered::detail::rebind_wrap< - A, grouped_node<A, T> >::type::pointer link_pointer; - typedef boost::unordered::detail::node_base<link_pointer> node_base; + A, grouped_node<A, T> >::type allocator; + typedef typename ::boost::unordered::detail:: + allocator_traits<allocator>::pointer node_pointer; + typedef node_pointer link_pointer; - link_pointer group_prev_; + link_pointer next_; + node_pointer group_prev_; std::size_t hash_; -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - explicit grouped_node(BOOST_UNORDERED_EMPLACE_ARGS) : - node_base(), - group_prev_(), - hash_(0) - { - boost::unordered::detail::construct_impl( - this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - } - - ~grouped_node() { - boost::unordered::detail::destroy(this->value_ptr()); - } - - grouped_node(grouped_node const&) { - assert(false); - } -#else grouped_node() : - node_base(), + next_(), group_prev_(), hash_(0) {} -#endif - void init(link_pointer self) + void init(node_pointer self) { group_prev_ = self; } @@ -72,47 +52,32 @@ namespace boost { namespace unordered { namespace detail { template <typename T> struct grouped_ptr_node : - boost::unordered::detail::value_base<T>, boost::unordered::detail::ptr_bucket { + typedef T value_type; typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef bucket_base node_base; + typedef grouped_ptr_node<T>* node_pointer; typedef ptr_bucket* link_pointer; - link_pointer group_prev_; + node_pointer group_prev_; std::size_t hash_; + boost::unordered::detail::value_base<T> value_base_; -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - explicit grouped_ptr_node(BOOST_UNORDERED_EMPLACE_ARGS) : - bucket_base(), - group_prev_(0), - hash_(0) - { - boost::unordered::detail::construct_impl( - this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - } - - ~grouped_ptr_node() { - boost::unordered::detail::destroy(this->value_ptr()); - } - - grouped_ptr_node(grouped_ptr_node const&) { - assert(false); - } -#else grouped_ptr_node() : bucket_base(), group_prev_(0), hash_(0) {} -#endif - void init(link_pointer self) + 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&); }; @@ -170,16 +135,15 @@ namespace boost { namespace unordered { namespace detail { { typedef boost::unordered::detail::multiset<A, T, H, P> types; + typedef A allocator; typedef T value_type; typedef H hasher; typedef P key_equal; typedef T key_type; - typedef typename boost::unordered::detail::rebind_wrap< - A, value_type>::type allocator; - typedef boost::unordered::detail::allocator_traits<allocator> traits; - typedef boost::unordered::detail::pick_grouped_node<allocator, value_type> pick; + typedef boost::unordered::detail::pick_grouped_node<allocator, + value_type> pick; typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; @@ -187,7 +151,7 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::grouped_table_impl<types> table; typedef boost::unordered::detail::set_extractor<value_type> extractor; - typedef boost::unordered::detail::pick_policy::type policy; + typedef typename boost::unordered::detail::pick_policy<T>::type policy; }; template <typename A, typename K, typename M, typename H, typename P> @@ -195,16 +159,15 @@ namespace boost { namespace unordered { namespace detail { { typedef boost::unordered::detail::multimap<A, K, M, H, P> types; + typedef A allocator; typedef std::pair<K const, M> value_type; typedef H hasher; typedef P key_equal; typedef K key_type; - typedef typename boost::unordered::detail::rebind_wrap< - A, value_type>::type allocator; - typedef boost::unordered::detail::allocator_traits<allocator> traits; - typedef boost::unordered::detail::pick_grouped_node<allocator, value_type> pick; + typedef boost::unordered::detail::pick_grouped_node<allocator, + value_type> pick; typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; @@ -213,7 +176,7 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::map_extractor<key_type, value_type> extractor; - typedef boost::unordered::detail::pick_policy::type policy; + typedef typename boost::unordered::detail::pick_policy<K>::type policy; }; template <typename Types> @@ -222,14 +185,12 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::table<Types> table; typedef typename table::value_type value_type; typedef typename table::bucket bucket; - typedef typename table::buckets buckets; 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::previous_pointer previous_pointer; typedef typename table::hasher hasher; typedef typename table::key_equal key_equal; typedef typename table::key_type key_type; @@ -249,12 +210,17 @@ namespace boost { namespace unordered { namespace detail { grouped_table_impl(grouped_table_impl const& x) : table(x, node_allocator_traits:: - select_on_container_copy_construction(x.node_alloc())) {} + 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) @@ -265,7 +231,9 @@ namespace boost { namespace unordered { namespace detail { node_allocator const& a, boost::unordered::detail::move_tag m) : table(x, a, m) - {} + { + this->move_init(x); + } // Accessors @@ -275,9 +243,8 @@ namespace boost { namespace unordered { namespace detail { Key const& k, Pred const& eq) const { - std::size_t bucket_index = - policy::to_bucket(this->bucket_count_, key_hash); - iterator n = this->get_start(bucket_index); + std::size_t bucket_index = this->hash_to_bucket(key_hash); + iterator n = this->begin(bucket_index); for (;;) { @@ -291,13 +258,11 @@ namespace boost { namespace unordered { namespace detail { } else { - if (policy::to_bucket(this->bucket_count_, node_hash) - != bucket_index) + if (this->hash_to_bucket(node_hash) != bucket_index) return iterator(); } - n = iterator(static_cast<node_pointer>( - static_cast<node_pointer>(n.node_->group_prev_)->next_)); + n = iterator(n.node_->group_prev_->next_); } } @@ -309,7 +274,7 @@ namespace boost { namespace unordered { namespace detail { std::size_t x = 0; node_pointer it = n.node_; do { - it = static_cast<node_pointer>(it->group_prev_); + it = it->group_prev_; ++x; } while(it != n.node_); @@ -321,10 +286,7 @@ namespace boost { namespace unordered { namespace detail { { iterator n = this->find_node(k); return std::make_pair( - n, n.node_ ? iterator( - static_cast<node_pointer>( - static_cast<node_pointer>(n.node_->group_prev_)->next_ - )) : n); + n, n.node_ ? iterator(n.node_->group_prev_->next_) : n); } // Equality @@ -332,16 +294,13 @@ namespace boost { namespace unordered { namespace detail { bool equals(grouped_table_impl const& other) const { if(this->size_ != other.size_) return false; - if(!this->size_) return true; - for(iterator n1 = this->get_start(); n1.node_;) + for(iterator n1 = this->begin(); n1.node_;) { iterator n2 = other.find_matching_node(n1); if (!n2.node_) return false; - iterator end1(static_cast<node_pointer>( - static_cast<node_pointer>(n1.node_->group_prev_)->next_)); - iterator end2(static_cast<node_pointer>( - static_cast<node_pointer>(n2.node_->group_prev_)->next_)); + iterator end1(n1.node_->group_prev_->next_); + iterator end2(n2.node_->group_prev_->next_); if (!group_equals(n1, end1, n2, end2)) return false; n1 = end1; } @@ -349,8 +308,6 @@ namespace boost { namespace unordered { namespace detail { return true; } -#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) - static bool group_equals(iterator n1, iterator end1, iterator n2, iterator end2) { @@ -411,37 +368,16 @@ namespace boost { namespace unordered { namespace detail { return count; } -#else - - static bool group_equals(iterator n1, iterator end1, - iterator n2, iterator end2) - { - for(;;) - { - if(!extractor::compare_mapped(*n1, *n2)) - return false; - - ++n1; - ++n2; - - if (n1 == end1) return n2 == end2; - if (n2 == end2) return false; - } - } - -#endif - // Emplace/Insert static inline void add_after_node( node_pointer n, node_pointer pos) { - n->next_ = static_cast<node_pointer>(pos->group_prev_)->next_; + n->next_ = pos->group_prev_->next_; n->group_prev_ = pos->group_prev_; - static_cast<node_pointer>(pos->group_prev_)->next_ = - static_cast<link_pointer>(n); - pos->group_prev_ = static_cast<link_pointer>(n); + pos->group_prev_->next_ = n; + pos->group_prev_ = n; } inline iterator add_node( @@ -454,37 +390,35 @@ namespace boost { namespace unordered { namespace detail { if (pos.node_) { this->add_after_node(n, pos.node_); if (n->next_) { - std::size_t next_bucket = policy::to_bucket( - this->bucket_count_, + std::size_t next_bucket = this->hash_to_bucket( static_cast<node_pointer>(n->next_)->hash_); - if (next_bucket != - policy::to_bucket(this->bucket_count_, key_hash)) { + if (next_bucket != this->hash_to_bucket(key_hash)) { this->get_bucket(next_bucket)->next_ = n; } } } else { bucket_pointer b = this->get_bucket( - policy::to_bucket(this->bucket_count_, key_hash)); + this->hash_to_bucket(key_hash)); if (!b->next_) { - previous_pointer start_node = this->get_previous_start(); + link_pointer start_node = this->get_previous_start(); if (start_node->next_) { - this->get_bucket(policy::to_bucket(this->bucket_count_, + this->get_bucket(this->hash_to_bucket( static_cast<node_pointer>(start_node->next_)->hash_ ))->next_ = n; } b->next_ = start_node; n->next_ = start_node->next_; - start_node->next_ = static_cast<link_pointer>(n); + start_node->next_ = n; } else { n->next_ = b->next_->next_; - b->next_->next_ = static_cast<link_pointer>(n); + b->next_->next_ = n; } } ++this->size_; @@ -510,8 +444,8 @@ namespace boost { namespace unordered { namespace detail { this->add_node(a, key_hash, this->find_node(key_hash, k)); } -#if defined(BOOST_NO_RVALUE_REFERENCES) -# if defined(BOOST_NO_VARIADIC_TEMPLATES) +#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&) { @@ -532,8 +466,7 @@ namespace boost { namespace unordered { namespace detail { iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) { node_constructor a(this->node_alloc()); - a.construct_node(); - a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD); + a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD); return iterator(emplace_impl(a)); } @@ -552,8 +485,7 @@ namespace boost { namespace unordered { namespace detail { std::size_t distance = boost::unordered::detail::distance(i, j); if(distance == 1) { node_constructor a(this->node_alloc()); - a.construct_node(); - a.construct_value2(*i); + a.construct_with_value2(*i); emplace_impl(a); } else { @@ -562,8 +494,7 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(this->node_alloc()); for (; i != j; ++i) { - a.construct_node(); - a.construct_value2(*i); + a.construct_with_value2(*i); emplace_impl_no_rehash(a); } } @@ -575,8 +506,7 @@ namespace boost { namespace unordered { namespace detail { { node_constructor a(this->node_alloc()); for (; i != j; ++i) { - a.construct_node(); - a.construct_value2(*i); + a.construct_with_value2(*i); emplace_impl(a); } } @@ -591,11 +521,8 @@ namespace boost { namespace unordered { namespace detail { if(!this->size_) return 0; std::size_t key_hash = this->hash(k); - std::size_t bucket_index = - policy::to_bucket(this->bucket_count_, key_hash); - bucket_pointer this_bucket = this->get_bucket(bucket_index); - - previous_pointer prev = this_bucket->next_; + 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 (;;) @@ -603,24 +530,21 @@ namespace boost { namespace unordered { namespace detail { if (!prev->next_) return 0; std::size_t node_hash = static_cast<node_pointer>(prev->next_)->hash_; - if (policy::to_bucket(this->bucket_count_, node_hash) - != bucket_index) + if (this->hash_to_bucket(node_hash) != bucket_index) return 0; if (node_hash == key_hash && this->key_eq()(k, this->get_key( static_cast<node_pointer>(prev->next_)->value()))) break; - prev = static_cast<previous_pointer>( - static_cast<node_pointer>(prev->next_)->group_prev_); + prev = static_cast<node_pointer>(prev->next_)->group_prev_; } - node_pointer pos = static_cast<node_pointer>(prev->next_); - link_pointer end1 = - static_cast<node_pointer>(pos->group_prev_)->next_; - node_pointer end = static_cast<node_pointer>(end1); - prev->next_ = end1; - this->fix_buckets(this_bucket, prev, end); - return this->delete_nodes(c_iterator(pos), c_iterator(end)); + node_pointer first_node = static_cast<node_pointer>(prev->next_); + 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) @@ -628,217 +552,94 @@ namespace boost { namespace unordered { namespace detail { BOOST_ASSERT(r.node_); iterator next(r.node_); ++next; - - bucket_pointer this_bucket = this->get_bucket( - policy::to_bucket(this->bucket_count_, r.node_->hash_)); - previous_pointer prev = unlink_node(*this_bucket, r.node_); - - this->fix_buckets(this_bucket, prev, next.node_); - - this->delete_node(r); - + erase_nodes(r.node_, next.node_); return next; } iterator erase_range(c_iterator r1, c_iterator r2) { if (r1 == r2) return iterator(r2.node_); - - std::size_t bucket_index = - policy::to_bucket(this->bucket_count_, r1.node_->hash_); - previous_pointer prev = unlink_nodes( - *this->get_bucket(bucket_index), r1.node_, r2.node_); - this->fix_buckets_range(bucket_index, prev, r1.node_, r2.node_); - this->delete_nodes(r1, r2); - + erase_nodes(r1.node_, r2.node_); return iterator(r2.node_); } - static previous_pointer unlink_node(bucket& b, node_pointer n) + link_pointer erase_nodes(node_pointer i, node_pointer j) { - node_pointer next = static_cast<node_pointer>(n->next_); - previous_pointer prev = - static_cast<previous_pointer>(n->group_prev_); - - if(prev->next_ != n) { - // The node is at the beginning of a group. - - // Find the previous node pointer: - prev = b.next_; - while(prev->next_ != n) { - prev = static_cast<previous_pointer>( - static_cast<node_pointer>(prev->next_)->group_prev_); - } - - // Remove from group - if (next && next->group_prev_ == static_cast<link_pointer>(n)) - { - next->group_prev_ = n->group_prev_; - } - } - else if (next && next->group_prev_ == static_cast<link_pointer>(n)) - { - // The deleted node is not at the end of the group, so - // change the link from the next node. - next->group_prev_ = n->group_prev_; - } - else { - // The deleted node is at the end of the group, so the - // first node in the group is pointing to it. - // Find that to change its pointer. - node_pointer x = static_cast<node_pointer>(n->group_prev_); - while(x->group_prev_ != static_cast<link_pointer>(n)) { - x = static_cast<node_pointer>(x->group_prev_); - } - x->group_prev_ = n->group_prev_; + 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 = static_cast<node_pointer>(prev->next_)->group_prev_; } - prev->next_ = static_cast<link_pointer>(next); + // Delete the nodes. + do { + link_pointer group_end = + static_cast<node_pointer>(prev->next_)->group_prev_->next_; + this->delete_nodes(prev, group_end); + bucket_index = this->fix_bucket(bucket_index, prev); + } while(prev->next_ != j); + return prev; } - static previous_pointer unlink_nodes(bucket& b, - node_pointer begin, node_pointer end) + static link_pointer split_groups(node_pointer i, node_pointer j) { - previous_pointer prev = static_cast<previous_pointer>( - begin->group_prev_); + node_pointer prev = i->group_prev_; + if (prev->next_ != i) prev = node_pointer(); - if(prev->next_ != static_cast<link_pointer>(begin)) { - // The node is at the beginning of a group. - - // Find the previous node pointer: - prev = b.next_; - while(prev->next_ != static_cast<link_pointer>(begin)) - prev = static_cast<previous_pointer>( - static_cast<node_pointer>(prev->next_)->group_prev_); + if (j) { + node_pointer first = j; + while (first != i && first->group_prev_->next_ == first) { + first = first->group_prev_; + } - if (end) split_group(end); + boost::swap(first->group_prev_, j->group_prev_); + if (first == i) return prev; } - else { - node_pointer group1 = split_group(begin); - if (end) { - node_pointer group2 = split_group(end); - - if(begin == group2) { - link_pointer end1 = group1->group_prev_; - link_pointer end2 = group2->group_prev_; - group1->group_prev_ = end2; - group2->group_prev_ = end1; - } + if (prev) { + node_pointer first = prev; + while (first->group_prev_->next_ == first) { + first = first->group_prev_; } + boost::swap(first->group_prev_, i->group_prev_); } - prev->next_ = static_cast<link_pointer>(end); - return prev; } - // Break a ciruclar list into two, with split as the beginning - // of the second group (if split is at the beginning then don't - // split). - static node_pointer split_group(node_pointer split) - { - // Find first node in group. - node_pointer first = split; - while (static_cast<node_pointer>(first->group_prev_)->next_ == - static_cast<link_pointer>(first)) - first = static_cast<node_pointer>(first->group_prev_); - - if(first == split) return split; - - link_pointer last = first->group_prev_; - first->group_prev_ = split->group_prev_; - split->group_prev_ = last; - - return first; - } - //////////////////////////////////////////////////////////////////////// - // copy_buckets_to - // - // Basic exception safety. If an exception is thrown this will - // leave dst partially filled and the buckets unset. + // fill_buckets - static void copy_buckets_to(buckets const& src, buckets& dst) + template <class NodeCreator> + static void fill_buckets(iterator n, table& dst, + NodeCreator& creator) { - BOOST_ASSERT(!dst.buckets_); - - dst.create_buckets(); - - node_constructor a(dst.node_alloc()); - - iterator n = src.get_start(); - previous_pointer prev = dst.get_previous_start(); + link_pointer prev = dst.get_previous_start(); while (n.node_) { std::size_t key_hash = n.node_->hash_; - iterator group_end( - static_cast<node_pointer>( - static_cast<node_pointer>(n.node_->group_prev_)->next_ - )); - - a.construct_node(); - a.construct_value2(*n); + iterator group_end(n.node_->group_prev_->next_); - node_pointer first_node = a.release(); + node_pointer first_node = creator.create(*n); node_pointer end = first_node; first_node->hash_ = key_hash; - prev->next_ = static_cast<link_pointer>(first_node); + prev->next_ = first_node; ++dst.size_; for (++n; n != group_end; ++n) { - a.construct_node(); - a.construct_value2(*n); - end = a.release(); - end->hash_ = key_hash; - add_after_node(end, first_node); - ++dst.size_; - } - - prev = place_in_bucket(dst, prev, end); - } - } - - //////////////////////////////////////////////////////////////////////// - // move_buckets_to - // - // Basic exception safety. The source nodes are left in an unusable - // state if an exception throws. - - static void move_buckets_to(buckets& src, buckets& dst) - { - BOOST_ASSERT(!dst.buckets_); - - dst.create_buckets(); - - node_constructor a(dst.node_alloc()); - - iterator n = src.get_start(); - previous_pointer prev = dst.get_previous_start(); - - while (n.node_) { - std::size_t key_hash = n.node_->hash_; - iterator group_end( - static_cast<node_pointer>( - static_cast<node_pointer>(n.node_->group_prev_)->next_ - )); - - a.construct_node(); - a.construct_value2(boost::move(*n)); - - node_pointer first_node = a.release(); - node_pointer end = first_node; - first_node->hash_ = key_hash; - prev->next_ = static_cast<link_pointer>(first_node); - ++dst.size_; - - for(++n; n != group_end; ++n) - { - a.construct_node(); - a.construct_value2(boost::move(*n)); - end = a.release(); + end = creator.create(*n); end->hash_ = key_hash; add_after_node(end, first_node); ++dst.size_; @@ -851,41 +652,25 @@ namespace boost { namespace unordered { namespace detail { // strong otherwise exception safety void rehash_impl(std::size_t num_buckets) { - BOOST_ASSERT(this->size_); - - buckets dst(this->node_alloc(), num_buckets); - dst.create_buckets(); - - previous_pointer src_start = this->get_previous_start(); - previous_pointer dst_start = dst.get_previous_start(); + BOOST_ASSERT(this->buckets_); - dst_start->next_ = src_start->next_; - src_start->next_ = link_pointer(); - dst.size_ = this->size_; - this->size_ = 0; - - previous_pointer prev = dst_start; + this->create_buckets(num_buckets); + link_pointer prev = this->get_previous_start(); while (prev->next_) - prev = place_in_bucket(dst, prev, - static_cast<node_pointer>( - static_cast<node_pointer>(prev->next_)->group_prev_)); - - // Swap the new nodes back into the container and setup the - // variables. - dst.swap(*this); // no throw + prev = place_in_bucket(*this, prev, + static_cast<node_pointer>(prev->next_)->group_prev_); } // Iterate through the nodes placing them in the correct buckets. // pre: prev->next_ is not null. - static previous_pointer place_in_bucket(buckets& dst, - previous_pointer prev, node_pointer end) + static link_pointer place_in_bucket(table& dst, + link_pointer prev, node_pointer end) { - bucket_pointer b = dst.get_bucket(policy::to_bucket( - dst.bucket_count_, end->hash_)); + bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_)); if (!b->next_) { - b->next_ = static_cast<node_pointer>(prev); - return static_cast<previous_pointer>(end); + b->next_ = prev; + return end; } else { link_pointer next = end->next_; diff --git a/boost/unordered/detail/extract_key.hpp b/boost/unordered/detail/extract_key.hpp index 56a85324ba..d68a4a77ef 100644 --- a/boost/unordered/detail/extract_key.hpp +++ b/boost/unordered/detail/extract_key.hpp @@ -6,6 +6,11 @@ #ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + #include <boost/unordered/detail/table.hpp> namespace boost { @@ -56,30 +61,25 @@ namespace detail { return no_key(); } -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) - template <class... Args> - static no_key extract(Args const&...) - { - return no_key(); - } -#else template <class Arg> static no_key extract(Arg const&) { return no_key(); } +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class Arg1, class Arg2, class... Args> + static no_key extract(Arg1 const&, Arg2 const&, Args const&...) + { + return no_key(); + } +#else template <class Arg1, class Arg2> static no_key extract(Arg1 const&, Arg2 const&) { return no_key(); } #endif - - static bool compare_mapped(value_type const&, value_type const&) - { - return true; - } }; template <class Key, class ValueType> @@ -93,11 +93,6 @@ namespace detail { return v.first; } - static key_type const& extract(key_type const& v) - { - return v; - } - template <class Second> static key_type const& extract(std::pair<key_type, Second> const& v) { @@ -111,21 +106,6 @@ namespace detail { return v.first; } -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) - template <class Arg1, class... Args> - static key_type const& extract(key_type const& k, - Arg1 const&, Args const&...) - { - return k; - } - - template <class... Args> - static no_key extract(Args const&...) - { - return no_key(); - } -#else - template <class Arg1> static key_type const& extract(key_type const& k, Arg1 const&) { @@ -143,19 +123,27 @@ namespace detail { return no_key(); } - template <class Arg, class Arg1> - static no_key extract(Arg const&, Arg1 const&) + template <class Arg1, class Arg2> + static no_key extract(Arg1 const&, Arg2 const&) + { + return no_key(); + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class Arg1, class Arg2, class Arg3, class... Args> + static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&, + Args const&...) { return no_key(); } #endif -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ template <typename T2> \ static no_key extract(boost::unordered::piecewise_construct_t, \ - namespace_::tuple<> const&, BOOST_FWD_REF(T2)) \ + namespace_ tuple<> const&, T2 const&) \ { \ return no_key(); \ } \ @@ -163,17 +151,17 @@ namespace detail { template <typename T, typename T2> \ static typename is_key<key_type, T>::type \ extract(boost::unordered::piecewise_construct_t, \ - namespace_::tuple<T> const& k, BOOST_FWD_REF(T2)) \ + namespace_ tuple<T> const& k, T2 const&) \ { \ return typename is_key<key_type, T>::type( \ - namespace_::get<0>(k)); \ + namespace_ get<0>(k)); \ } #else #define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ static no_key extract(boost::unordered::piecewise_construct_t, \ - namespace_::tuple<> const&) \ + namespace_ tuple<> const&) \ { \ return no_key(); \ } \ @@ -181,25 +169,19 @@ namespace detail { template <typename T> \ static typename is_key<key_type, T>::type \ extract(boost::unordered::piecewise_construct_t, \ - namespace_::tuple<T> const& k) \ + namespace_ tuple<T> const& k) \ { \ return typename is_key<key_type, T>::type( \ - namespace_::get<0>(k)); \ + namespace_ get<0>(k)); \ } #endif -BOOST_UNORDERED_KEY_FROM_TUPLE(boost) +BOOST_UNORDERED_KEY_FROM_TUPLE(boost::) #if !defined(BOOST_NO_CXX11_HDR_TUPLE) -BOOST_UNORDERED_KEY_FROM_TUPLE(std) +BOOST_UNORDERED_KEY_FROM_TUPLE(std::) #endif - - - static bool compare_mapped(value_type const& x, value_type const& y) - { - return x.second == y.second; - } }; }}} diff --git a/boost/unordered/detail/fwd.hpp b/boost/unordered/detail/fwd.hpp index ee8966b755..87c2c23b04 100644 --- a/boost/unordered/detail/fwd.hpp +++ b/boost/unordered/detail/fwd.hpp @@ -6,11 +6,11 @@ #ifndef BOOST_UNORDERED_FWD_HPP_INCLUDED #define BOOST_UNORDERED_FWD_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif - namespace boost { namespace unordered diff --git a/boost/unordered/detail/table.hpp b/boost/unordered/detail/table.hpp index cbf6219554..2bb5d45003 100644 --- a/boost/unordered/detail/table.hpp +++ b/boost/unordered/detail/table.hpp @@ -7,12 +7,34 @@ #ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + #include <boost/unordered/detail/buckets.hpp> #include <boost/unordered/detail/util.hpp> #include <boost/type_traits/aligned_storage.hpp> #include <boost/type_traits/alignment_of.hpp> #include <cmath> +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + +#if defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) + +#if defined(__EDG__) +#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) +#pragma message("Warning: BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.") +#elif defined(__GNUC__) || defined(__HP_aCC) || \ + defined(__SUNPRO_CC) || defined(__IBMCPP__) +#warning "BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported." +#endif + +#endif + namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// @@ -37,6 +59,10 @@ namespace boost { namespace unordered { namespace detail { sizeof(value_type), boost::alignment_of<value_type>::value>::type data_; + value_base() : + data_() + {} + void* address() { return this; } @@ -54,13 +80,72 @@ namespace boost { namespace unordered { namespace detail { value_base& operator=(value_base const&); }; + template <typename NodeAlloc> + struct copy_nodes + { + typedef boost::unordered::detail::allocator_traits<NodeAlloc> + node_allocator_traits; + + node_constructor<NodeAlloc> constructor; + + explicit copy_nodes(NodeAlloc& a) : constructor(a) {} + + typename node_allocator_traits::pointer create( + typename node_allocator_traits::value_type::value_type const& v) + { + constructor.construct_with_value2(v); + return constructor.release(); + } + }; + + template <typename NodeAlloc> + struct move_nodes + { + typedef boost::unordered::detail::allocator_traits<NodeAlloc> + node_allocator_traits; + + node_constructor<NodeAlloc> constructor; + + explicit move_nodes(NodeAlloc& a) : constructor(a) {} + + typename node_allocator_traits::pointer create( + typename node_allocator_traits::value_type::value_type& v) + { + constructor.construct_with_value2(boost::move(v)); + return constructor.release(); + } + }; + + template <typename Buckets> + struct assign_nodes + { + node_holder<typename Buckets::node_allocator> holder; + + explicit assign_nodes(Buckets& b) : holder(b) {} + + typename Buckets::node_pointer create( + typename Buckets::value_type const& v) + { + return holder.copy_of(v); + } + }; + + template <typename Buckets> + struct move_assign_nodes + { + node_holder<typename Buckets::node_allocator> holder; + + explicit move_assign_nodes(Buckets& b) : holder(b) {} + + typename Buckets::node_pointer create( + typename Buckets::value_type& v) + { + return holder.move_copy_of(v); + } + }; + template <typename Types> struct table : - boost::unordered::detail::buckets< - typename Types::allocator, - typename Types::bucket, - typename Types::node, - typename Types::policy>, boost::unordered::detail::functions< typename Types::hasher, typename Types::key_equal> @@ -69,6 +154,8 @@ namespace boost { namespace unordered { namespace detail { 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; @@ -81,24 +168,130 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::functions< typename Types::hasher, typename Types::key_equal> functions; + typedef typename functions::set_hash_functions set_hash_functions; + + typedef typename Types::allocator allocator; + typedef typename boost::unordered::detail:: + rebind_wrap<allocator, node>::type node_allocator; + typedef typename boost::unordered::detail:: + rebind_wrap<allocator, bucket>::type bucket_allocator; + typedef boost::unordered::detail::allocator_traits<node_allocator> + node_allocator_traits; + typedef boost::unordered::detail::allocator_traits<bucket_allocator> + bucket_allocator_traits; + typedef typename node_allocator_traits::pointer + node_pointer; + typedef typename node_allocator_traits::const_pointer + const_node_pointer; + typedef typename bucket_allocator_traits::pointer + bucket_pointer; + typedef boost::unordered::detail::node_constructor<node_allocator> + node_constructor; + + typedef boost::unordered::iterator_detail:: + iterator<node> iterator; + typedef boost::unordered::iterator_detail:: + c_iterator<node, const_node_pointer> c_iterator; + typedef boost::unordered::iterator_detail:: + l_iterator<node, policy> l_iterator; + typedef boost::unordered::iterator_detail:: + cl_iterator<node, const_node_pointer, policy> cl_iterator; - typedef boost::unordered::detail::buckets< - typename Types::allocator, - typename Types::bucket, - typename Types::node, - typename Types::policy> buckets; + //////////////////////////////////////////////////////////////////////// + // Members - typedef typename buckets::node_allocator node_allocator; - typedef typename buckets::node_allocator_traits node_allocator_traits; - typedef typename buckets::node_pointer node_pointer; - typedef typename buckets::const_node_pointer const_node_pointer; + boost::unordered::detail::compressed<bucket_allocator, node_allocator> + allocators_; + std::size_t bucket_count_; + std::size_t size_; + float mlf_; + std::size_t max_load_; + bucket_pointer buckets_; - typedef typename table::iterator iterator; + //////////////////////////////////////////////////////////////////////// + // Data access - // Members + bucket_allocator const& bucket_alloc() const + { + return allocators_.first(); + } - float mlf_; - std::size_t max_load_; // Only use if this->buckets_. + node_allocator const& node_alloc() const + { + return allocators_.second(); + } + + bucket_allocator& bucket_alloc() + { + return allocators_.first(); + } + + node_allocator& node_alloc() + { + return allocators_.second(); + } + + std::size_t max_bucket_count() const + { + // -1 to account for the start bucket. + return policy::prev_bucket_count( + bucket_allocator_traits::max_size(bucket_alloc()) - 1); + } + + bucket_pointer get_bucket(std::size_t bucket_index) const + { + BOOST_ASSERT(buckets_); + return buckets_ + static_cast<std::ptrdiff_t>(bucket_index); + } + + link_pointer get_previous_start() const + { + return get_bucket(bucket_count_)->first_from_start(); + } + + link_pointer get_previous_start(std::size_t bucket_index) const + { + return get_bucket(bucket_index)->next_; + } + + iterator begin() const + { + return size_ ? iterator(get_previous_start()->next_) : iterator(); + } + + iterator begin(std::size_t bucket_index) const + { + if (!size_) return iterator(); + link_pointer prev = get_previous_start(bucket_index); + return prev ? iterator(prev->next_) : iterator(); + } + + std::size_t hash_to_bucket(std::size_t hash_value) const + { + return policy::to_bucket(bucket_count_, hash_value); + } + + float load_factor() const + { + BOOST_ASSERT(bucket_count_ != 0); + return static_cast<float>(size_) + / static_cast<float>(bucket_count_); + } + + std::size_t bucket_size(std::size_t index) const + { + iterator it = begin(index); + if (!it.node_) return 0; + + std::size_t count = 0; + while(it.node_ && hash_to_bucket(it.node_->hash_) == index) + { + ++count; + ++it; + } + + return count; + } //////////////////////////////////////////////////////////////////////// // Load methods @@ -109,34 +302,34 @@ namespace boost { namespace unordered { namespace detail { // size < mlf_ * count return boost::unordered::detail::double_to_size(ceil( - static_cast<double>(this->mlf_) * - static_cast<double>(this->max_bucket_count()) + static_cast<double>(mlf_) * + static_cast<double>(max_bucket_count()) )) - 1; } - std::size_t calculate_max_load() + void recalculate_max_load() { using namespace std; // From 6.3.1/13: // Only resize when size >= mlf_ * count - return boost::unordered::detail::double_to_size(ceil( - static_cast<double>(this->mlf_) * - static_cast<double>(this->bucket_count_) - )); + max_load_ = buckets_ ? boost::unordered::detail::double_to_size(ceil( + static_cast<double>(mlf_) * + static_cast<double>(bucket_count_) + )) : 0; } + void max_load_factor(float z) { BOOST_ASSERT(z > 0); mlf_ = (std::max)(z, minimum_max_load_factor); - if (this->buckets_) - this->max_load_ = this->calculate_max_load(); + recalculate_max_load(); } std::size_t min_buckets_for_size(std::size_t size) const { - BOOST_ASSERT(this->mlf_ >= minimum_max_load_factor); + BOOST_ASSERT(mlf_ >= minimum_max_load_factor); using namespace std; @@ -160,177 +353,407 @@ namespace boost { namespace unordered { namespace detail { hasher const& hf, key_equal const& eq, node_allocator const& a) : - buckets(a, policy::new_bucket_count(num_buckets)), functions(hf, eq), + allocators_(a,a), + bucket_count_(policy::new_bucket_count(num_buckets)), + size_(0), mlf_(1.0f), - max_load_(0) + max_load_(0), + buckets_() {} table(table const& x, node_allocator const& a) : - buckets(a, x.min_buckets_for_size(x.size_)), functions(x), + allocators_(a,a), + bucket_count_(x.min_buckets_for_size(x.size_)), + size_(0), mlf_(x.mlf_), - max_load_(0) - { - if(x.size_) { - table_impl::copy_buckets_to(x, *this); - this->max_load_ = calculate_max_load(); - } - } + max_load_(0), + buckets_() + {} - // TODO: Why calculate_max_load? table(table& x, boost::unordered::detail::move_tag m) : - buckets(x, m), - functions(x), + functions(x, m), + allocators_(x.allocators_, m), + bucket_count_(x.bucket_count_), + size_(x.size_), mlf_(x.mlf_), - max_load_(calculate_max_load()) - {} + max_load_(x.max_load_), + buckets_(x.buckets_) + { + x.buckets_ = bucket_pointer(); + x.size_ = 0; + x.max_load_ = 0; + } - // TODO: Why not calculate_max_load? - // TODO: Why do I use x's bucket count? table(table& x, node_allocator const& a, boost::unordered::detail::move_tag m) : - buckets(a, x.bucket_count_), - functions(x), + functions(x, m), + allocators_(a, a), + bucket_count_(x.bucket_count_), + size_(0), mlf_(x.mlf_), - max_load_(x.max_load_) + max_load_(x.max_load_), + buckets_() + {} + + //////////////////////////////////////////////////////////////////////// + // Initialisation. + + void init(table const& x) { - if(a == x.node_alloc()) { - this->buckets::swap(x, false_type()); + if (x.size_) { + create_buckets(bucket_count_); + copy_nodes<node_allocator> node_creator(node_alloc()); + table_impl::fill_buckets(x.begin(), *this, node_creator); + } + } + + void move_init(table& x) + { + if(node_alloc() == x.node_alloc()) { + move_buckets_from(x); } else if(x.size_) { - // Use a temporary table because move_buckets_to leaves the - // source container in a complete mess. + // TODO: Could pick new bucket size? + create_buckets(bucket_count_); - buckets tmp(x, m); - table_impl::move_buckets_to(tmp, *this); - this->max_load_ = calculate_max_load(); + move_nodes<node_allocator> node_creator(node_alloc()); + node_holder<node_allocator> nodes(x); + table_impl::fill_buckets(nodes.begin(), *this, node_creator); } } - // Iterators + //////////////////////////////////////////////////////////////////////// + // Create buckets + + void create_buckets(std::size_t new_count) + { + boost::unordered::detail::array_constructor<bucket_allocator> + constructor(bucket_alloc()); + + // Creates an extra bucket to act as the start node. + constructor.construct(bucket(), new_count + 1); + + if (buckets_) + { + // Copy the nodes to the new buckets, including the dummy + // node if there is one. + (constructor.get() + + static_cast<std::ptrdiff_t>(new_count))->next_ = + (buckets_ + static_cast<std::ptrdiff_t>( + bucket_count_))->next_; + destroy_buckets(); + } + else if (bucket::extra_node) + { + node_constructor a(node_alloc()); + a.construct(); + + (constructor.get() + + static_cast<std::ptrdiff_t>(new_count))->next_ = + a.release(); + } - iterator begin() const { - return !this->buckets_ ? - iterator() : this->get_start(); + bucket_count_ = new_count; + buckets_ = constructor.release(); + recalculate_max_load(); } - // Assignment + //////////////////////////////////////////////////////////////////////// + // Swap and Move - void assign(table const& x) + 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) { - assign(x, + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); + + // I think swap can throw if Propagate::value, + // since the allocators' swap can throw. Not sure though. + swap_allocators(x, boost::unordered::detail::integral_constant<bool, allocator_traits<node_allocator>:: - propagate_on_container_copy_assignment::value>()); + 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(); + } + + void move_buckets_from(table& other) + { + BOOST_ASSERT(node_alloc() == other.node_alloc()); + BOOST_ASSERT(!buckets_); + buckets_ = other.buckets_; + bucket_count_ = other.bucket_count_; + size_ = other.size_; + other.buckets_ = bucket_pointer(); + other.size_ = 0; + other.max_load_ = 0; + } + + //////////////////////////////////////////////////////////////////////// + // Delete/destruct + + ~table() + { + delete_buckets(); + } + + void delete_node(link_pointer prev) + { + node_pointer n = static_cast<node_pointer>(prev->next_); + prev->next_ = n->next_; + + boost::unordered::detail::func::destroy_value_impl(node_alloc(), + n->value_ptr()); + boost::unordered::detail::func::destroy(boost::addressof(*n)); + node_allocator_traits::deallocate(node_alloc(), n, 1); + --size_; + } + + std::size_t delete_nodes(link_pointer prev, link_pointer end) + { + BOOST_ASSERT(prev->next_ != end); + + std::size_t count = 0; + + do { + delete_node(prev); + ++count; + } while (prev->next_ != end); + + return count; + } + + void delete_buckets() + { + if(buckets_) { + if (size_) delete_nodes(get_previous_start(), link_pointer()); + + if (bucket::extra_node) { + node_pointer n = static_cast<node_pointer>( + get_bucket(bucket_count_)->next_); + boost::unordered::detail::func::destroy( + boost::addressof(*n)); + node_allocator_traits::deallocate(node_alloc(), n, 1); + } + + destroy_buckets(); + buckets_ = bucket_pointer(); + max_load_ = 0; + } + + BOOST_ASSERT(!size_); + } + + void clear() + { + if (!size_) return; + + delete_nodes(get_previous_start(), link_pointer()); + clear_buckets(); + + BOOST_ASSERT(!size_); + } + + void clear_buckets() + { + bucket_pointer end = get_bucket(bucket_count_); + for(bucket_pointer it = buckets_; it != end; ++it) + { + it->next_ = node_pointer(); + } + } + + void destroy_buckets() + { + bucket_pointer end = get_bucket(bucket_count_ + 1); + for(bucket_pointer it = buckets_; it != end; ++it) + { + boost::unordered::detail::func::destroy( + boost::addressof(*it)); + } + + bucket_allocator_traits::deallocate(bucket_alloc(), + buckets_, bucket_count_ + 1); + } + + //////////////////////////////////////////////////////////////////////// + // Fix buckets after delete + // + + std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev) + { + link_pointer end = prev->next_; + std::size_t bucket_index2 = bucket_index; + + if (end) + { + bucket_index2 = hash_to_bucket( + static_cast<node_pointer>(end)->hash_); + + // If begin and end are in the same bucket, then + // there's nothing to do. + if (bucket_index == bucket_index2) return bucket_index2; + + // Update the bucket containing end. + get_bucket(bucket_index2)->next_ = prev; + } + + // Check if this bucket is now empty. + bucket_pointer this_bucket = get_bucket(bucket_index); + if (this_bucket->next_ == prev) + this_bucket->next_ = link_pointer(); + + return bucket_index2; + } + + //////////////////////////////////////////////////////////////////////// + // Assignment + + void assign(table const& x) + { + if (this != boost::addressof(x)) + { + assign(x, + boost::unordered::detail::integral_constant<bool, + allocator_traits<node_allocator>:: + propagate_on_container_copy_assignment::value>()); + } } void assign(table const& x, false_type) { - table tmp(x, this->node_alloc()); - this->swap(tmp, false_type()); + // Strong exception safety. + set_hash_functions new_func_this(*this, x); + new_func_this.commit(); + mlf_ = x.mlf_; + recalculate_max_load(); + + if (!size_ && !x.size_) return; + + if (x.size_ >= max_load_) { + create_buckets(min_buckets_for_size(x.size_)); + } + else { + clear_buckets(); + } + + // assign_nodes takes ownership of the container's elements, + // assigning to them if possible, and deleting any that are + // left over. + assign_nodes<table> node_creator(*this); + table_impl::fill_buckets(x.begin(), *this, node_creator); } void assign(table const& x, true_type) { - table tmp(x, x.node_alloc()); - // Need to delete before setting the allocator so that buckets - // aren't deleted with the wrong allocator. - if(this->buckets_) this->delete_buckets(); - // TODO: Can allocator assignment throw? - this->allocators_.assign(x.allocators_); - this->swap(tmp, false_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_) { + create_buckets(bucket_count_); + copy_nodes<node_allocator> node_creator(node_alloc()); + table_impl::fill_buckets(x.begin(), *this, node_creator); + } + } } void move_assign(table& x) { - move_assign(x, - boost::unordered::detail::integral_constant<bool, - allocator_traits<node_allocator>:: - propagate_on_container_move_assignment::value>()); + if (this != boost::addressof(x)) + { + move_assign(x, + boost::unordered::detail::integral_constant<bool, + allocator_traits<node_allocator>:: + propagate_on_container_move_assignment::value>()); + } } void move_assign(table& x, true_type) { - if(this->buckets_) this->delete_buckets(); - this->allocators_.move_assign(x.allocators_); + delete_buckets(); + allocators_.move_assign(x.allocators_); move_assign_no_alloc(x); } void move_assign(table& x, false_type) { - if(this->node_alloc() == x.node_alloc()) { - if(this->buckets_) this->delete_buckets(); + if (node_alloc() == x.node_alloc()) { + delete_buckets(); move_assign_no_alloc(x); } else { - boost::unordered::detail::set_hash_functions<hasher, key_equal> - new_func_this(*this, x); + set_hash_functions new_func_this(*this, x); + new_func_this.commit(); + mlf_ = x.mlf_; + recalculate_max_load(); - if (x.size_) { - buckets b(this->node_alloc(), - x.min_buckets_for_size(x.size_)); - buckets tmp(x, move_tag()); - table_impl::move_buckets_to(tmp, b); - b.swap(*this); + if (!size_ && !x.size_) return; + + if (x.size_ >= max_load_) { + create_buckets(min_buckets_for_size(x.size_)); } else { - this->clear(); + clear_buckets(); } - - this->mlf_ = x.mlf_; - if (this->buckets_) this->max_load_ = calculate_max_load(); - new_func_this.commit(); + + // move_assign_nodes takes ownership of the container's + // elements, assigning to them if possible, and deleting + // any that are left over. + move_assign_nodes<table> node_creator(*this); + node_holder<node_allocator> nodes(x); + table_impl::fill_buckets(nodes.begin(), *this, node_creator); } } void move_assign_no_alloc(table& x) { - boost::unordered::detail::set_hash_functions<hasher, key_equal> - new_func_this(*this, x); + set_hash_functions new_func_this(*this, x); // No throw from here. - this->move_buckets_from(x); - this->mlf_ = x.mlf_; - this->max_load_ = x.max_load_; + mlf_ = x.mlf_; + max_load_ = x.max_load_; + move_buckets_from(x); new_func_this.commit(); } - //////////////////////////////////////////////////////////////////////// - // Swap & Move - - void swap(table& x) - { - swap(x, - boost::unordered::detail::integral_constant<bool, - allocator_traits<node_allocator>:: - propagate_on_container_swap::value>()); - } - - // Only swaps the allocators if Propagate::value - template <typename Propagate> - void swap(table& x, Propagate p) - { - boost::unordered::detail::set_hash_functions<hasher, key_equal> - op1(*this, x); - boost::unordered::detail::set_hash_functions<hasher, key_equal> - op2(x, *this); - // I think swap can throw if Propagate::value, - // since the allocators' swap can throw. Not sure though. - this->buckets::swap(x, p); - std::swap(this->mlf_, x.mlf_); - std::swap(this->max_load_, x.max_load_); - op1.commit(); - op2.commit(); - } - - // Swap everything but the allocators, and the functions objects. - void swap_contents(table& x) - { - this->buckets::swap(x, false_type()); - std::swap(this->mlf_, x.mlf_); - std::swap(this->max_load_, x.max_load_); - } - // Accessors key_type const& get_key(value_type const& x) const @@ -351,7 +774,6 @@ namespace boost { namespace unordered { namespace detail { Hash const& hf, Pred const& eq) const { - if (!this->size_) return iterator(); return static_cast<table_impl const*>(this)-> find_node_impl(policy::apply_hash(hf, k), k, eq); } @@ -360,16 +782,14 @@ namespace boost { namespace unordered { namespace detail { std::size_t key_hash, key_type const& k) const { - if (!this->size_) return iterator(); return static_cast<table_impl const*>(this)-> find_node_impl(key_hash, k, this->key_eq()); } iterator find_node(key_type const& k) const { - if (!this->size_) return iterator(); return static_cast<table_impl const*>(this)-> - find_node_impl(this->hash(k), k, this->key_eq()); + find_node_impl(hash(k), k, this->key_eq()); } iterator find_matching_node(iterator n) const @@ -397,22 +817,19 @@ namespace boost { namespace unordered { namespace detail { template <typename Types> inline void table<Types>::reserve_for_insert(std::size_t size) { - if (!this->buckets_) { - this->bucket_count_ = (std::max)(this->bucket_count_, - this->min_buckets_for_size(size)); - this->create_buckets(); - this->max_load_ = this->calculate_max_load(); + 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 - = this->min_buckets_for_size((std::max)(size, - this->size_ + (this->size_ >> 1))); - if (num_buckets != this->bucket_count_) { + = min_buckets_for_size((std::max)(size, + size_ + (size_ >> 1))); + + if (num_buckets != bucket_count_) static_cast<table_impl*>(this)->rehash_impl(num_buckets); - this->max_load_ = this->calculate_max_load(); - } } } @@ -424,20 +841,18 @@ namespace boost { namespace unordered { namespace detail { { using namespace std; - if(!this->size_) { - if(this->buckets_) this->delete_buckets(); - this->bucket_count_ = policy::new_bucket_count(min_buckets); + if(!size_) { + delete_buckets(); + bucket_count_ = policy::new_bucket_count(min_buckets); } else { min_buckets = policy::new_bucket_count((std::max)(min_buckets, boost::unordered::detail::double_to_size(floor( - static_cast<double>(this->size_) / + static_cast<double>(size_) / static_cast<double>(mlf_))) + 1)); - if(min_buckets != this->bucket_count_) { + if(min_buckets != bucket_count_) static_cast<table_impl*>(this)->rehash_impl(min_buckets); - this->max_load_ = this->calculate_max_load(); - } } } @@ -445,8 +860,12 @@ namespace boost { namespace unordered { namespace detail { inline void table<Types>::reserve(std::size_t num_elements) { rehash(static_cast<std::size_t>( - std::ceil(static_cast<double>(num_elements) / this->mlf_))); + std::ceil(static_cast<double>(num_elements) / mlf_))); } }}} +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + #endif diff --git a/boost/unordered/detail/unique.hpp b/boost/unordered/detail/unique.hpp index 10db58fa75..f76ca5a6a5 100644 --- a/boost/unordered/detail/unique.hpp +++ b/boost/unordered/detail/unique.hpp @@ -7,8 +7,9 @@ #ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif #include <boost/unordered/detail/table.hpp> @@ -24,43 +25,23 @@ namespace boost { namespace unordered { namespace detail { template <typename A, typename T> struct unique_node : - boost::unordered::detail::node_base< - typename ::boost::unordered::detail::rebind_wrap< - A, unique_node<A, T> >::type::pointer - >, boost::unordered::detail::value_base<T> { typedef typename ::boost::unordered::detail::rebind_wrap< - A, unique_node<A, T> >::type::pointer link_pointer; - typedef boost::unordered::detail::node_base<link_pointer> node_base; + A, unique_node<A, T> >::type allocator; + typedef typename ::boost::unordered::detail:: + allocator_traits<allocator>::pointer node_pointer; + typedef node_pointer link_pointer; + link_pointer next_; std::size_t hash_; -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - explicit unique_node(BOOST_UNORDERED_EMPLACE_ARGS) : - node_base(), - hash_(0) - { - boost::unordered::detail::construct_impl( - this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - } - - ~unique_node() { - boost::unordered::detail::destroy(this->value_ptr()); - } - - unique_node(unique_node const&) { - BOOST_ASSERT(false); - } -#else unique_node() : - node_base(), + next_(), hash_(0) {} -#endif - void init(link_pointer) + void init(node_pointer) { } @@ -70,43 +51,29 @@ namespace boost { namespace unordered { namespace detail { template <typename T> struct ptr_node : - boost::unordered::detail::value_base<T>, boost::unordered::detail::ptr_bucket { + typedef T value_type; typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef bucket_base node_base; + typedef ptr_node<T>* node_pointer; typedef ptr_bucket* link_pointer; std::size_t hash_; + boost::unordered::detail::value_base<T> value_base_; -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - template <BOOST_UNORDERED_EMPLACE_TEMPLATE> - explicit ptr_node(BOOST_UNORDERED_EMPLACE_ARGS) : - bucket_base(), - hash_(0) - { - boost::unordered::detail::construct_impl( - this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - } - - ~ptr_node() { - boost::unordered::detail::destroy(this->value_ptr()); - } - - ptr_node(ptr_node const&) { - BOOST_ASSERT(false); - } -#else ptr_node() : bucket_base(), hash_(0) {} -#endif - void init(link_pointer) + 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&); }; @@ -164,14 +131,12 @@ namespace boost { namespace unordered { namespace detail { { typedef boost::unordered::detail::set<A, T, H, P> types; + typedef A allocator; typedef T value_type; typedef H hasher; typedef P key_equal; typedef T key_type; - typedef typename boost::unordered::detail::rebind_wrap< - A, value_type>::type allocator; - typedef boost::unordered::detail::allocator_traits<allocator> traits; typedef boost::unordered::detail::pick_node<allocator, value_type> pick; typedef typename pick::node node; @@ -181,7 +146,7 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::table_impl<types> table; typedef boost::unordered::detail::set_extractor<value_type> extractor; - typedef boost::unordered::detail::pick_policy::type policy; + typedef typename boost::unordered::detail::pick_policy<T>::type policy; }; template <typename A, typename K, typename M, typename H, typename P> @@ -189,15 +154,14 @@ namespace boost { namespace unordered { namespace detail { { typedef boost::unordered::detail::map<A, K, M, H, P> types; + typedef A allocator; typedef std::pair<K const, M> value_type; typedef H hasher; typedef P key_equal; typedef K key_type; - typedef typename boost::unordered::detail::rebind_wrap< - A, value_type>::type allocator; - - typedef boost::unordered::detail::allocator_traits<allocator> traits; + typedef boost::unordered::detail::allocator_traits<allocator> + traits; typedef boost::unordered::detail::pick_node<allocator, value_type> pick; typedef typename pick::node node; typedef typename pick::bucket bucket; @@ -207,7 +171,7 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::map_extractor<key_type, value_type> extractor; - typedef boost::unordered::detail::pick_policy::type policy; + typedef typename boost::unordered::detail::pick_policy<K>::type policy; }; template <typename Types> @@ -216,14 +180,12 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::table<Types> table; typedef typename table::value_type value_type; typedef typename table::bucket bucket; - typedef typename table::buckets buckets; 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::previous_pointer previous_pointer; typedef typename table::hasher hasher; typedef typename table::key_equal key_equal; typedef typename table::key_type key_type; @@ -245,12 +207,17 @@ namespace boost { namespace unordered { namespace detail { table_impl(table_impl const& x) : table(x, node_allocator_traits:: - select_on_container_copy_construction(x.node_alloc())) {} + 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) @@ -261,7 +228,9 @@ namespace boost { namespace unordered { namespace detail { node_allocator const& a, boost::unordered::detail::move_tag m) : table(x, a, m) - {} + { + this->move_init(x); + } // Accessors @@ -271,9 +240,8 @@ namespace boost { namespace unordered { namespace detail { Key const& k, Pred const& eq) const { - std::size_t bucket_index = - policy::to_bucket(this->bucket_count_, key_hash); - iterator n = this->get_start(bucket_index); + std::size_t bucket_index = this->hash_to_bucket(key_hash); + iterator n = this->begin(bucket_index); for (;;) { @@ -287,8 +255,7 @@ namespace boost { namespace unordered { namespace detail { } else { - if (policy::to_bucket(this->bucket_count_, node_hash) - != bucket_index) + if (this->hash_to_bucket(node_hash) != bucket_index) return iterator(); } @@ -326,19 +293,13 @@ namespace boost { namespace unordered { namespace detail { bool equals(table_impl const& other) const { if(this->size_ != other.size_) return false; - if(!this->size_) return true; - for(iterator n1 = this->get_start(); n1.node_; ++n1) + for(iterator n1 = this->begin(); n1.node_; ++n1) { iterator n2 = other.find_matching_node(n1); -#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) if (!n2.node_ || *n1 != *n2) return false; -#else - if (!n2.node_ || !extractor::compare_mapped(*n1, *n2)) - return false; -#endif } return true; @@ -353,27 +314,26 @@ namespace boost { namespace unordered { namespace detail { node_pointer n = a.release(); n->hash_ = key_hash; - bucket_pointer b = this->get_bucket( - policy::to_bucket(this->bucket_count_, key_hash)); + bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); if (!b->next_) { - previous_pointer start_node = this->get_previous_start(); + link_pointer start_node = this->get_previous_start(); if (start_node->next_) { - this->get_bucket(policy::to_bucket(this->bucket_count_, + this->get_bucket(this->hash_to_bucket( static_cast<node_pointer>(start_node->next_)->hash_) )->next_ = n; } b->next_ = start_node; n->next_ = start_node->next_; - start_node->next_ = static_cast<link_pointer>(n); + start_node->next_ = n; } else { n->next_ = b->next_->next_; - b->next_->next_ = static_cast<link_pointer>(n); + b->next_->next_ = n; } ++this->size_; @@ -382,8 +342,6 @@ namespace boost { namespace unordered { namespace detail { value_type& operator[](key_type const& k) { - typedef typename value_type::second_type mapped_type; - std::size_t key_hash = this->hash(k); iterator pos = this->find_node(key_hash, k); @@ -392,9 +350,7 @@ namespace boost { namespace unordered { namespace detail { // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). node_constructor a(this->node_alloc()); - a.construct_node(); - - a.construct_value(BOOST_UNORDERED_EMPLACE_ARGS3( + a.construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS3( boost::unordered::piecewise_construct, boost::make_tuple(k), boost::make_tuple())); @@ -403,8 +359,8 @@ namespace boost { namespace unordered { namespace detail { return *add_node(a, key_hash); } -#if defined(BOOST_NO_RVALUE_REFERENCES) -# if defined(BOOST_NO_VARIADIC_TEMPLATES) +#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&) { @@ -424,7 +380,7 @@ namespace boost { namespace unordered { namespace detail { template <BOOST_UNORDERED_EMPLACE_TEMPLATE> emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS) { -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) return emplace_impl( extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), BOOST_UNORDERED_EMPLACE_FORWARD); @@ -435,7 +391,7 @@ namespace boost { namespace unordered { namespace detail { #endif } -#if defined(BOOST_NO_VARIADIC_TEMPLATES) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template <typename A0> emplace_return emplace( boost::unordered::detail::emplace_args1<A0> const& args) @@ -456,8 +412,7 @@ namespace boost { namespace unordered { namespace detail { // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). node_constructor a(this->node_alloc()); - a.construct_node(); - a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD); + a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD); // reserve has basic exception safety if the hash function // throws, strong otherwise. @@ -485,8 +440,7 @@ namespace boost { namespace unordered { namespace detail { // Don't have a key, so construct the node first in order // to be able to lookup the position. node_constructor a(this->node_alloc()); - a.construct_node(); - a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD); + a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD); return emplace_impl_with_node(a); } @@ -508,14 +462,9 @@ namespace boost { namespace unordered { namespace detail { { node_constructor a(this->node_alloc()); - // Special case for empty buckets so that we can use - // max_load_ (which isn't valid when buckets_ is null). - if (!this->buckets_) { - insert_range_empty(a, k, i, j); - if (++i == j) return; - } + insert_range_impl2(a, k, i, j); - do { + 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. @@ -525,19 +474,7 @@ namespace boost { namespace unordered { namespace detail { // be less efficient if copying the full value_type is // expensive. insert_range_impl2(a, extractor::extract(*i), i, j); - } while(++i != j); - } - - template <class InputIt> - void insert_range_empty(node_constructor& a, key_type const& k, - InputIt i, InputIt j) - { - std::size_t key_hash = this->hash(k); - a.construct_node(); - a.construct_value2(*i); - this->reserve_for_insert(this->size_ + - boost::unordered::detail::insert_size(i, j)); - this->add_node(a, key_hash); + } } template <class InputIt> @@ -549,9 +486,7 @@ namespace boost { namespace unordered { namespace detail { iterator pos = this->find_node(key_hash, k); if (!pos.node_) { - a.construct_node(); - a.construct_value2(*i); - + a.construct_with_value2(*i); if(this->size_ + 1 > this->max_load_) this->reserve_for_insert(this->size_ + boost::unordered::detail::insert_size(i, j)); @@ -567,8 +502,7 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(this->node_alloc()); do { - a.construct_node(); - a.construct_value2(*i); + a.construct_with_value2(*i); emplace_impl_with_node(a); } while(++i != j); } @@ -583,11 +517,8 @@ namespace boost { namespace unordered { namespace detail { if(!this->size_) return 0; std::size_t key_hash = this->hash(k); - std::size_t bucket_index = - policy::to_bucket(this->bucket_count_, key_hash); - bucket_pointer this_bucket = this->get_bucket(bucket_index); - - previous_pointer prev = this_bucket->next_; + 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 (;;) @@ -595,21 +526,20 @@ namespace boost { namespace unordered { namespace detail { if (!prev->next_) return 0; std::size_t node_hash = static_cast<node_pointer>(prev->next_)->hash_; - if (policy::to_bucket(this->bucket_count_, node_hash) - != bucket_index) + if (this->hash_to_bucket(node_hash) != bucket_index) return 0; if (node_hash == key_hash && this->key_eq()(k, this->get_key( static_cast<node_pointer>(prev->next_)->value()))) break; - prev = static_cast<previous_pointer>(prev->next_); + prev = prev->next_; } - node_pointer pos = static_cast<node_pointer>(prev->next_); - node_pointer end = static_cast<node_pointer>(pos->next_); - prev->next_ = pos->next_; - this->fix_buckets(this_bucket, prev, end); - return this->delete_nodes(c_iterator(pos), c_iterator(end)); + link_pointer end = static_cast<node_pointer>(prev->next_)->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) @@ -617,103 +547,45 @@ namespace boost { namespace unordered { namespace detail { BOOST_ASSERT(r.node_); iterator next(r.node_); ++next; - - bucket_pointer this_bucket = this->get_bucket( - policy::to_bucket(this->bucket_count_, r.node_->hash_)); - previous_pointer prev = unlink_node(*this_bucket, r.node_); - - this->fix_buckets(this_bucket, prev, next.node_); - - this->delete_node(r); - + erase_nodes(r.node_, next.node_); return next; } iterator erase_range(c_iterator r1, c_iterator r2) { if (r1 == r2) return iterator(r2.node_); - - std::size_t bucket_index = - policy::to_bucket(this->bucket_count_, r1.node_->hash_); - previous_pointer prev = unlink_nodes( - *this->get_bucket(bucket_index), r1.node_, r2.node_); - this->fix_buckets_range(bucket_index, prev, r1.node_, r2.node_); - this->delete_nodes(r1, r2); - + erase_nodes(r1.node_, r2.node_); return iterator(r2.node_); } - static previous_pointer unlink_node(bucket& b, node_pointer n) + void erase_nodes(node_pointer i, node_pointer j) { - return unlink_nodes(b, n, static_cast<node_pointer>(n->next_)); - } + std::size_t bucket_index = this->hash_to_bucket(i->hash_); - static previous_pointer unlink_nodes(bucket& b, - node_pointer begin, node_pointer end) - { - previous_pointer prev = b.next_; - link_pointer begin_void = static_cast<link_pointer>(begin); - while(prev->next_ != begin_void) - prev = static_cast<previous_pointer>(prev->next_); - prev->next_ = static_cast<link_pointer>(end); - return prev; - } + // Find the node before i. + link_pointer prev = this->get_previous_start(bucket_index); + while(prev->next_ != i) prev = prev->next_; - //////////////////////////////////////////////////////////////////////// - // copy_buckets_to - // - // Basic exception safety. If an exception is thrown this will - // leave dst partially filled and the buckets unset. - - static void copy_buckets_to(buckets const& src, buckets& dst) - { - BOOST_ASSERT(!dst.buckets_); - - dst.create_buckets(); - - node_constructor a(dst.node_alloc()); - - iterator n = src.get_start(); - previous_pointer prev = dst.get_previous_start(); - - while(n.node_) { - a.construct_node(); - a.construct_value2(*n); - - node_pointer node = a.release(); - node->hash_ = n.node_->hash_; - prev->next_ = static_cast<link_pointer>(node); - ++dst.size_; - ++n; - - prev = place_in_bucket(dst, prev); - } + // Delete the nodes. + do { + this->delete_node(prev); + bucket_index = this->fix_bucket(bucket_index, prev); + } while (prev->next_ != j); } //////////////////////////////////////////////////////////////////////// - // move_buckets_to - // - // Basic exception safety. The source nodes are left in an unusable - // state if an exception throws. + // fill_buckets - static void move_buckets_to(buckets& src, buckets& dst) + template <class NodeCreator> + static void fill_buckets(iterator n, table& dst, + NodeCreator& creator) { - BOOST_ASSERT(!dst.buckets_); - - dst.create_buckets(); - - node_constructor a(dst.node_alloc()); - - iterator n = src.get_start(); - previous_pointer prev = dst.get_previous_start(); + link_pointer prev = dst.get_previous_start(); while (n.node_) { - a.construct_node(); - a.construct_value2(boost::move(*n)); - - node_pointer node = a.release(); + node_pointer node = creator.create(*n); node->hash_ = n.node_->hash_; - prev->next_ = static_cast<link_pointer>(node); + prev->next_ = node; ++dst.size_; ++n; @@ -724,45 +596,29 @@ namespace boost { namespace unordered { namespace detail { // strong otherwise exception safety void rehash_impl(std::size_t num_buckets) { - BOOST_ASSERT(this->size_); + BOOST_ASSERT(this->buckets_); - buckets dst(this->node_alloc(), num_buckets); - dst.create_buckets(); - - previous_pointer src_start = this->get_previous_start(); - previous_pointer dst_start = dst.get_previous_start(); - - dst_start->next_ = src_start->next_; - src_start->next_ = link_pointer(); - dst.size_ = this->size_; - this->size_ = 0; - - previous_pointer prev = dst.get_previous_start(); + this->create_buckets(num_buckets); + link_pointer prev = this->get_previous_start(); while (prev->next_) - prev = place_in_bucket(dst, prev); - - // Swap the new nodes back into the container and setup the - // variables. - dst.swap(*this); // no throw + prev = place_in_bucket(*this, prev); } // Iterate through the nodes placing them in the correct buckets. // pre: prev->next_ is not null. - static previous_pointer place_in_bucket(buckets& dst, - previous_pointer prev) + static link_pointer place_in_bucket(table& dst, link_pointer prev) { node_pointer n = static_cast<node_pointer>(prev->next_); - bucket_pointer b = dst.get_bucket( - buckets::to_bucket(dst.bucket_count_, n->hash_)); + bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_)); if (!b->next_) { b->next_ = prev; - return static_cast<previous_pointer>(n); + return n; } else { prev->next_ = n->next_; n->next_ = b->next_->next_; - b->next_->next_ = static_cast<link_pointer>(n); + b->next_->next_ = n; return prev; } } diff --git a/boost/unordered/detail/util.hpp b/boost/unordered/detail/util.hpp index a901477d19..3428ed7ae2 100644 --- a/boost/unordered/detail/util.hpp +++ b/boost/unordered/detail/util.hpp @@ -7,8 +7,9 @@ #ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif #include <boost/type_traits/is_convertible.hpp> @@ -28,6 +29,11 @@ namespace boost { namespace unordered { namespace detail { struct move_tag {}; struct empty_emplace {}; + namespace func { + template <class T> + inline void ignore_unused_variable_warning(T const&) {} + } + //////////////////////////////////////////////////////////////////////////// // iterator SFINAE diff --git a/boost/unordered/unordered_map.hpp b/boost/unordered/unordered_map.hpp index ce52e5becf..9b180796d1 100644 --- a/boost/unordered/unordered_map.hpp +++ b/boost/unordered/unordered_map.hpp @@ -9,8 +9,9 @@ #ifndef BOOST_UNORDERED_UNORDERED_MAP_HPP_INCLUDED #define BOOST_UNORDERED_UNORDERED_MAP_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif #include <boost/unordered/unordered_map_fwd.hpp> @@ -56,7 +57,6 @@ namespace unordered private: typedef boost::unordered::detail::map<A, K, T, H, P> types; - typedef typename types::allocator value_allocator; typedef typename types::traits allocator_traits; typedef typename types::table table; @@ -118,17 +118,19 @@ namespace unordered #if defined(BOOST_UNORDERED_USE_MOVE) unordered_map(BOOST_RV_REF(unordered_map) other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } -#elif !defined(BOOST_NO_RVALUE_REFERENCES) +#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_map(unordered_map&& other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } #endif -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_map(unordered_map&&, allocator_type const&); #endif @@ -143,7 +145,7 @@ namespace unordered // Destructor - ~unordered_map(); + ~unordered_map() BOOST_NOEXCEPT; // Assign @@ -166,7 +168,7 @@ namespace unordered return *this; } -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_map& operator=(unordered_map&& x) { table_.move_assign(x.table_); @@ -179,60 +181,60 @@ namespace unordered unordered_map& operator=(std::initializer_list<value_type>); #endif - allocator_type get_allocator() const + allocator_type get_allocator() const BOOST_NOEXCEPT { return table_.node_alloc(); } // size and capacity - bool empty() const + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - size_type size() const + size_type size() const BOOST_NOEXCEPT { return table_.size_; } - size_type max_size() const; + size_type max_size() const BOOST_NOEXCEPT; // iterators - iterator begin() + iterator begin() BOOST_NOEXCEPT { return table_.begin(); } - const_iterator begin() const + const_iterator begin() const BOOST_NOEXCEPT { return table_.begin(); } - iterator end() + iterator end() BOOST_NOEXCEPT { return iterator(); } - const_iterator end() const + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(); } - const_iterator cbegin() const + const_iterator cbegin() const BOOST_NOEXCEPT { return table_.begin(); } - const_iterator cend() const + const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } // emplace -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template <class... Args> std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args) { @@ -450,12 +452,12 @@ namespace unordered // bucket interface - size_type bucket_count() const + size_type bucket_count() const BOOST_NOEXCEPT { return table_.bucket_count_; } - size_type max_bucket_count() const + size_type max_bucket_count() const BOOST_NOEXCEPT { return table_.max_bucket_count(); } @@ -464,22 +466,19 @@ namespace unordered size_type bucket(const key_type& k) const { - return table::to_bucket(table_.bucket_count_, - table_.hash(k)); + return table_.hash_to_bucket(table_.hash(k)); } local_iterator begin(size_type n) { - return table_.size_ ? local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - local_iterator(); + return local_iterator( + table_.begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return table_.size_ ? const_local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - const_local_iterator(); + return const_local_iterator( + table_.begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -494,9 +493,8 @@ namespace unordered const_local_iterator cbegin(size_type n) const { - return table_.size_ ? const_local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - const_local_iterator(); + return const_local_iterator( + table_.begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -506,13 +504,13 @@ namespace unordered // hash policy - float max_load_factor() const + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - float load_factor() const; - void max_load_factor(float); + float load_factor() const BOOST_NOEXCEPT; + void max_load_factor(float) BOOST_NOEXCEPT; void rehash(size_type); void reserve(size_type); @@ -542,7 +540,6 @@ namespace unordered private: typedef boost::unordered::detail::multimap<A, K, T, H, P> types; - typedef typename types::allocator value_allocator; typedef typename types::traits allocator_traits; typedef typename types::table table; @@ -604,17 +601,19 @@ namespace unordered #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multimap(BOOST_RV_REF(unordered_multimap) other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } -#elif !defined(BOOST_NO_RVALUE_REFERENCES) +#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multimap(unordered_multimap&& other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } #endif -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multimap(unordered_multimap&&, allocator_type const&); #endif @@ -629,7 +628,7 @@ namespace unordered // Destructor - ~unordered_multimap(); + ~unordered_multimap() BOOST_NOEXCEPT; // Assign @@ -653,7 +652,7 @@ namespace unordered return *this; } -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multimap& operator=(unordered_multimap&& x) { table_.move_assign(x.table_); @@ -666,60 +665,60 @@ namespace unordered unordered_multimap& operator=(std::initializer_list<value_type>); #endif - allocator_type get_allocator() const + allocator_type get_allocator() const BOOST_NOEXCEPT { return table_.node_alloc(); } // size and capacity - bool empty() const + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - size_type size() const + size_type size() const BOOST_NOEXCEPT { return table_.size_; } - size_type max_size() const; + size_type max_size() const BOOST_NOEXCEPT; // iterators - iterator begin() + iterator begin() BOOST_NOEXCEPT { return table_.begin(); } - const_iterator begin() const + const_iterator begin() const BOOST_NOEXCEPT { return table_.begin(); } - iterator end() + iterator end() BOOST_NOEXCEPT { return iterator(); } - const_iterator end() const + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(); } - const_iterator cbegin() const + const_iterator cbegin() const BOOST_NOEXCEPT { return table_.begin(); } - const_iterator cend() const + const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } // emplace -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template <class... Args> iterator emplace(BOOST_FWD_REF(Args)... args) { @@ -933,12 +932,12 @@ namespace unordered // bucket interface - size_type bucket_count() const + size_type bucket_count() const BOOST_NOEXCEPT { return table_.bucket_count_; } - size_type max_bucket_count() const + size_type max_bucket_count() const BOOST_NOEXCEPT { return table_.max_bucket_count(); } @@ -947,22 +946,19 @@ namespace unordered size_type bucket(const key_type& k) const { - return table::to_bucket(table_.bucket_count_, - table_.hash(k)); + return table_.hash_to_bucket(table_.hash(k)); } local_iterator begin(size_type n) { - return table_.size_ ? local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - local_iterator(); + return local_iterator( + table_.begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return table_.size_ ? const_local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - const_local_iterator(); + return const_local_iterator( + table_.begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -977,9 +973,8 @@ namespace unordered const_local_iterator cbegin(size_type n) const { - return table_.size_ ? const_local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - const_local_iterator(); + return const_local_iterator( + table_.begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -989,13 +984,13 @@ namespace unordered // hash policy - float max_load_factor() const + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - float load_factor() const; - void max_load_factor(float); + float load_factor() const BOOST_NOEXCEPT; + void max_load_factor(float) BOOST_NOEXCEPT; void rehash(size_type); void reserve(size_type); @@ -1067,7 +1062,7 @@ namespace unordered } template <class K, class T, class H, class P, class A> - unordered_map<K,T,H,P,A>::~unordered_map() {} + unordered_map<K,T,H,P,A>::~unordered_map() BOOST_NOEXCEPT {} template <class K, class T, class H, class P, class A> unordered_map<K,T,H,P,A>::unordered_map( @@ -1076,7 +1071,7 @@ namespace unordered { } -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template <class K, class T, class H, class P, class A> unordered_map<K,T,H,P,A>::unordered_map( @@ -1115,7 +1110,7 @@ namespace unordered // size and capacity template <class K, class T, class H, class P, class A> - std::size_t unordered_map<K,T,H,P,A>::max_size() const + std::size_t unordered_map<K,T,H,P,A>::max_size() const BOOST_NOEXCEPT { return table_.max_size(); } @@ -1284,13 +1279,13 @@ namespace unordered // hash policy template <class K, class T, class H, class P, class A> - float unordered_map<K,T,H,P,A>::load_factor() const + float unordered_map<K,T,H,P,A>::load_factor() const BOOST_NOEXCEPT { return table_.load_factor(); } template <class K, class T, class H, class P, class A> - void unordered_map<K,T,H,P,A>::max_load_factor(float m) + void unordered_map<K,T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT { table_.max_load_factor(m); } @@ -1400,7 +1395,7 @@ namespace unordered } template <class K, class T, class H, class P, class A> - unordered_multimap<K,T,H,P,A>::~unordered_multimap() {} + unordered_multimap<K,T,H,P,A>::~unordered_multimap() BOOST_NOEXCEPT {} template <class K, class T, class H, class P, class A> unordered_multimap<K,T,H,P,A>::unordered_multimap( @@ -1409,7 +1404,7 @@ namespace unordered { } -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template <class K, class T, class H, class P, class A> unordered_multimap<K,T,H,P,A>::unordered_multimap( @@ -1448,7 +1443,7 @@ namespace unordered // size and capacity template <class K, class T, class H, class P, class A> - std::size_t unordered_multimap<K,T,H,P,A>::max_size() const + std::size_t unordered_multimap<K,T,H,P,A>::max_size() const BOOST_NOEXCEPT { return table_.max_size(); } @@ -1596,13 +1591,13 @@ namespace unordered // hash policy template <class K, class T, class H, class P, class A> - float unordered_multimap<K,T,H,P,A>::load_factor() const + float unordered_multimap<K,T,H,P,A>::load_factor() const BOOST_NOEXCEPT { return table_.load_factor(); } template <class K, class T, class H, class P, class A> - void unordered_multimap<K,T,H,P,A>::max_load_factor(float m) + void unordered_multimap<K,T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT { table_.max_load_factor(m); } diff --git a/boost/unordered/unordered_map_fwd.hpp b/boost/unordered/unordered_map_fwd.hpp index 980bb3ee77..1eb26ce951 100644 --- a/boost/unordered/unordered_map_fwd.hpp +++ b/boost/unordered/unordered_map_fwd.hpp @@ -6,11 +6,11 @@ #ifndef BOOST_UNORDERED_MAP_FWD_HPP_INCLUDED #define BOOST_UNORDERED_MAP_FWD_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif -#include <boost/config.hpp> #include <memory> #include <functional> #include <boost/functional/hash_fwd.hpp> diff --git a/boost/unordered/unordered_set.hpp b/boost/unordered/unordered_set.hpp index 5d9a0b8e8d..853b5d7317 100644 --- a/boost/unordered/unordered_set.hpp +++ b/boost/unordered/unordered_set.hpp @@ -9,8 +9,9 @@ #ifndef BOOST_UNORDERED_UNORDERED_SET_HPP_INCLUDED #define BOOST_UNORDERED_UNORDERED_SET_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif #include <boost/unordered/unordered_set_fwd.hpp> @@ -54,7 +55,6 @@ namespace unordered private: typedef boost::unordered::detail::set<A, T, H, P> types; - typedef typename types::allocator value_allocator; typedef typename types::traits allocator_traits; typedef typename types::table table; @@ -116,17 +116,19 @@ namespace unordered #if defined(BOOST_UNORDERED_USE_MOVE) unordered_set(BOOST_RV_REF(unordered_set) other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } -#elif !defined(BOOST_NO_RVALUE_REFERENCES) +#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_set(unordered_set&& other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } #endif -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_set(unordered_set&&, allocator_type const&); #endif @@ -141,7 +143,7 @@ namespace unordered // Destructor - ~unordered_set(); + ~unordered_set() BOOST_NOEXCEPT; // Assign @@ -164,7 +166,7 @@ namespace unordered return *this; } -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_set& operator=(unordered_set&& x) { table_.move_assign(x.table_); @@ -177,60 +179,60 @@ namespace unordered unordered_set& operator=(std::initializer_list<value_type>); #endif - allocator_type get_allocator() const + allocator_type get_allocator() const BOOST_NOEXCEPT { return table_.node_alloc(); } // size and capacity - bool empty() const + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - size_type size() const + size_type size() const BOOST_NOEXCEPT { return table_.size_; } - size_type max_size() const; + size_type max_size() const BOOST_NOEXCEPT; // iterators - iterator begin() + iterator begin() BOOST_NOEXCEPT { return table_.begin(); } - const_iterator begin() const + const_iterator begin() const BOOST_NOEXCEPT { return table_.begin(); } - iterator end() + iterator end() BOOST_NOEXCEPT { return iterator(); } - const_iterator end() const + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(); } - const_iterator cbegin() const + const_iterator cbegin() const BOOST_NOEXCEPT { return table_.begin(); } - const_iterator cend() const + const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } // emplace -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template <class... Args> std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args) { @@ -435,12 +437,12 @@ namespace unordered // bucket interface - size_type bucket_count() const + size_type bucket_count() const BOOST_NOEXCEPT { return table_.bucket_count_; } - size_type max_bucket_count() const + size_type max_bucket_count() const BOOST_NOEXCEPT { return table_.max_bucket_count(); } @@ -449,22 +451,19 @@ namespace unordered size_type bucket(const key_type& k) const { - return table::to_bucket(table_.bucket_count_, - table_.hash(k)); + return table_.hash_to_bucket(table_.hash(k)); } local_iterator begin(size_type n) { - return table_.size_ ? local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - local_iterator(); + return local_iterator( + table_.begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return table_.size_ ? const_local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - const_local_iterator(); + return const_local_iterator( + table_.begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -479,9 +478,8 @@ namespace unordered const_local_iterator cbegin(size_type n) const { - return table_.size_ ? const_local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - const_local_iterator(); + return const_local_iterator( + table_.begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -491,13 +489,13 @@ namespace unordered // hash policy - float max_load_factor() const + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - float load_factor() const; - void max_load_factor(float); + float load_factor() const BOOST_NOEXCEPT; + void max_load_factor(float) BOOST_NOEXCEPT; void rehash(size_type); void reserve(size_type); @@ -526,7 +524,6 @@ namespace unordered private: typedef boost::unordered::detail::multiset<A, T, H, P> types; - typedef typename types::allocator value_allocator; typedef typename types::traits allocator_traits; typedef typename types::table table; @@ -588,17 +585,19 @@ namespace unordered #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multiset(BOOST_RV_REF(unordered_multiset) other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } -#elif !defined(BOOST_NO_RVALUE_REFERENCES) +#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multiset(unordered_multiset&& other) + BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } #endif -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multiset(unordered_multiset&&, allocator_type const&); #endif @@ -613,7 +612,7 @@ namespace unordered // Destructor - ~unordered_multiset(); + ~unordered_multiset() BOOST_NOEXCEPT; // Assign @@ -637,7 +636,7 @@ namespace unordered return *this; } -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multiset& operator=(unordered_multiset&& x) { table_.move_assign(x.table_); @@ -650,60 +649,60 @@ namespace unordered unordered_multiset& operator=(std::initializer_list<value_type>); #endif - allocator_type get_allocator() const + allocator_type get_allocator() const BOOST_NOEXCEPT { return table_.node_alloc(); } // size and capacity - bool empty() const + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - size_type size() const + size_type size() const BOOST_NOEXCEPT { return table_.size_; } - size_type max_size() const; + size_type max_size() const BOOST_NOEXCEPT; // iterators - iterator begin() + iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } - const_iterator begin() const + const_iterator begin() const BOOST_NOEXCEPT { return const_iterator(table_.begin()); } - iterator end() + iterator end() BOOST_NOEXCEPT { return iterator(); } - const_iterator end() const + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(); } - const_iterator cbegin() const + const_iterator cbegin() const BOOST_NOEXCEPT { return const_iterator(table_.begin()); } - const_iterator cend() const + const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } // emplace -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template <class... Args> iterator emplace(BOOST_FWD_REF(Args)... args) { @@ -908,12 +907,12 @@ namespace unordered // bucket interface - size_type bucket_count() const + size_type bucket_count() const BOOST_NOEXCEPT { return table_.bucket_count_; } - size_type max_bucket_count() const + size_type max_bucket_count() const BOOST_NOEXCEPT { return table_.max_bucket_count(); } @@ -922,22 +921,19 @@ namespace unordered size_type bucket(const key_type& k) const { - return table::to_bucket(table_.bucket_count_, - table_.hash(k)); + return table_.hash_to_bucket(table_.hash(k)); } local_iterator begin(size_type n) { - return table_.size_ ? local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - local_iterator(); + return local_iterator( + table_.begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return table_.size_ ? const_local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - const_local_iterator(); + return const_local_iterator( + table_.begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -952,9 +948,8 @@ namespace unordered const_local_iterator cbegin(size_type n) const { - return table_.size_ ? const_local_iterator( - table_.get_start(n), n, table_.bucket_count_) : - const_local_iterator(); + return const_local_iterator( + table_.begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -964,13 +959,13 @@ namespace unordered // hash policy - float max_load_factor() const + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - float load_factor() const; - void max_load_factor(float); + float load_factor() const BOOST_NOEXCEPT; + void max_load_factor(float) BOOST_NOEXCEPT; void rehash(size_type); void reserve(size_type); @@ -1042,7 +1037,7 @@ namespace unordered } template <class T, class H, class P, class A> - unordered_set<T,H,P,A>::~unordered_set() {} + unordered_set<T,H,P,A>::~unordered_set() BOOST_NOEXCEPT {} template <class T, class H, class P, class A> unordered_set<T,H,P,A>::unordered_set( @@ -1051,7 +1046,7 @@ namespace unordered { } -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template <class T, class H, class P, class A> unordered_set<T,H,P,A>::unordered_set( @@ -1090,7 +1085,7 @@ namespace unordered // size and capacity template <class T, class H, class P, class A> - std::size_t unordered_set<T,H,P,A>::max_size() const + std::size_t unordered_set<T,H,P,A>::max_size() const BOOST_NOEXCEPT { return table_.max_size(); } @@ -1210,13 +1205,13 @@ namespace unordered // hash policy template <class T, class H, class P, class A> - float unordered_set<T,H,P,A>::load_factor() const + float unordered_set<T,H,P,A>::load_factor() const BOOST_NOEXCEPT { return table_.load_factor(); } template <class T, class H, class P, class A> - void unordered_set<T,H,P,A>::max_load_factor(float m) + void unordered_set<T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT { table_.max_load_factor(m); } @@ -1326,7 +1321,7 @@ namespace unordered } template <class T, class H, class P, class A> - unordered_multiset<T,H,P,A>::~unordered_multiset() {} + unordered_multiset<T,H,P,A>::~unordered_multiset() BOOST_NOEXCEPT {} template <class T, class H, class P, class A> unordered_multiset<T,H,P,A>::unordered_multiset( @@ -1335,7 +1330,7 @@ namespace unordered { } -#if !defined(BOOST_NO_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template <class T, class H, class P, class A> unordered_multiset<T,H,P,A>::unordered_multiset( @@ -1374,7 +1369,7 @@ namespace unordered // size and capacity template <class T, class H, class P, class A> - std::size_t unordered_multiset<T,H,P,A>::max_size() const + std::size_t unordered_multiset<T,H,P,A>::max_size() const BOOST_NOEXCEPT { return table_.max_size(); } @@ -1494,13 +1489,13 @@ namespace unordered // hash policy template <class T, class H, class P, class A> - float unordered_multiset<T,H,P,A>::load_factor() const + float unordered_multiset<T,H,P,A>::load_factor() const BOOST_NOEXCEPT { return table_.load_factor(); } template <class T, class H, class P, class A> - void unordered_multiset<T,H,P,A>::max_load_factor(float m) + void unordered_multiset<T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT { table_.max_load_factor(m); } diff --git a/boost/unordered/unordered_set_fwd.hpp b/boost/unordered/unordered_set_fwd.hpp index 0c8b6d8d63..52b9e822f2 100644 --- a/boost/unordered/unordered_set_fwd.hpp +++ b/boost/unordered/unordered_set_fwd.hpp @@ -6,11 +6,11 @@ #ifndef BOOST_UNORDERED_SET_FWD_HPP_INCLUDED #define BOOST_UNORDERED_SET_FWD_HPP_INCLUDED -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once +#include <boost/config.hpp> +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once #endif -#include <boost/config.hpp> #include <memory> #include <functional> #include <boost/functional/hash_fwd.hpp> |