From d5971171da31cdeed7c06bd32e7fe9fc8f86cf51 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 1 Sep 2012 15:50:36 +0000 Subject: [PATCH] Unordered: Merge from trunk. - Some changes to the internals, including reverting some of the recent changes to constructing values which turned out to be more bother than it was worth. - On C++11 compilers, better use of `construct` and `destroy`. - Better testing. [SVN r80350] --- include/boost/unordered/detail/allocate.hpp | 817 +++++++++--------- include/boost/unordered/detail/buckets.hpp | 121 +-- include/boost/unordered/detail/equivalent.hpp | 49 +- include/boost/unordered/detail/table.hpp | 5 + include/boost/unordered/detail/unique.hpp | 47 +- test/exception/assign_exception_tests.cpp | 30 +- test/exception/containers.hpp | 4 +- test/exception/swap_exception_tests.cpp | 5 +- test/helpers/invariants.hpp | 25 +- test/objects/exception.hpp | 180 ++++ test/objects/minimal.hpp | 22 +- test/unordered/assign_tests.cpp | 71 ++ test/unordered/compile_map.cpp | 30 +- test/unordered/unnecessary_copy_tests.cpp | 23 +- 14 files changed, 833 insertions(+), 596 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 5574c158..b6f1c796 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -167,347 +167,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 - struct rv_ref_impl { - typedef BOOST_RV_REF(T) type; - }; - - template - struct rv_ref : - boost::detail::if_true< - boost::is_class::value - >::BOOST_NESTED_TEMPLATE then < - boost::unordered::detail::rv_ref_impl, - please_ignore_this_overload - >::type - {}; - -# define BOOST_UNORDERED_RV_REF(T) \ - typename boost::unordered::detail::rv_ref::type -#endif - - //////////////////////////////////////////////////////////////////////////// - // Construct from tuple - // - // Used for piecewise construction. - -#if !defined(__SUNPRO_CC) - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template \ - 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 \ - void construct_from_tuple(T* ptr, \ - namespace_ tuple const& x) \ - { \ - new ((void*) ptr) T( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ - ); \ - } - -# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ - namespace_ get(x) - -#else - - template struct length {}; - -# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template \ - void construct_from_tuple_impl( \ - boost::unordered::detail::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 \ - void construct_from_tuple_impl( \ - boost::unordered::detail::length, T* ptr, \ - namespace_ tuple const& x) \ - { \ - new ((void*) ptr) T( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ - ); \ - } - -# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ - namespace_ get(x) - -#endif - -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) - -#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE) - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) -#endif - -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL -#undef BOOST_UNORDERED_GET_TUPLE_ARG - -#if defined(__SUNPRO_CC) - - template - void construct_from_tuple(T* ptr, Tuple const& x) - { - construct_from_tuple_impl( - boost::unordered::detail::length< - boost::tuples::length::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 - struct emulation1 { - static choice1::type test(choice1, std::pair 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())) == - sizeof(choice2::type) }; - }; -#endif - - template - 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())) }; - }; - - template - struct piecewise3 { - enum { value = check3_base::value == sizeof(choice1::type) }; - }; - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - template - struct emulation3 { - enum { value = check3_base::value == sizeof(choice2::type) }; - }; - -#endif - -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) - - //////////////////////////////////////////////////////////////////////////// - // Construct from variadic parameters - - template - inline void construct_impl(T* address, BOOST_FWD_REF(Args)... args) - { - new((void*) address) T(boost::forward(args)...); - } - - template - inline typename enable_if, void>::type - construct_impl(std::pair* 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)); - boost::unordered::detail::construct_from_tuple( - boost::addressof(address->second), boost::forward(a2)); - } - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - - template - inline typename enable_if, void>::type - construct_impl(std::pair* address, BOOST_FWD_REF(A0) a0) - { - new((void*) boost::addressof(address->first)) A(boost::forward(a0)); - new((void*) boost::addressof(address->second)) B(); - } - - template - inline typename enable_if, void>::type - construct_impl(std::pair* 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)); - new((void*) boost::addressof(address->second)) B( - boost::forward(a1), - boost::forward(a2)); - } - - template - inline void construct_impl(std::pair* 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)); - - new((void*) boost::addressof(address->second)) B( - boost::forward(a1), - boost::forward(a2), - boost::forward(a3), - boost::forward(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 - inline void construct_impl(T* address, emplace_args1 const& args) - { - new((void*) address) T(boost::forward(args.a0)); - } - - template - inline void construct_impl(T* address, emplace_args2 const& args) - { - new((void*) address) T( - boost::forward(args.a0), - boost::forward(args.a1) - ); - } - - template - inline void construct_impl(T* address, emplace_args3 const& args) - { - new((void*) address) T( - boost::forward(args.a0), - boost::forward(args.a1), - boost::forward(args.a2) - ); - } - - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_CONSTRUCT_IMPL, _) - -#undef BOOST_UNORDERED_CONSTRUCT_IMPL - - template - inline void construct_impl(std::pair* address, - boost::unordered::detail::emplace_args3 const& args, - typename enable_if, 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 - inline void construct_impl(std::pair* address, - boost::unordered::detail::emplace_args1 const& args, - typename enable_if, void*>::type = 0) - { - new((void*) boost::addressof(address->first)) A( - boost::forward(args.a0)); - new((void*) boost::addressof(address->second)) B(); - } - - template - inline void construct_impl(std::pair* address, - boost::unordered::detail::emplace_args3 const& args, - typename enable_if, void*>::type = 0) - { - new((void*) boost::addressof(address->first)) A( - boost::forward(args.a0)); - new((void*) boost::addressof(address->second)) B( - boost::forward(args.a1), - boost::forward(args.a2)); - } - -#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \ - template \ - inline void construct_impl(std::pair* 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(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 - }}} //////////////////////////////////////////////////////////////////////////////// @@ -1098,82 +757,418 @@ namespace boost { namespace unordered { namespace detail { #endif + +namespace boost { namespace unordered { namespace detail { + + //////////////////////////////////////////////////////////////////////////// + // call_construct + +#if !defined(BOOST_NO_VARIADIC_TEMPLATES) + +# if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + + template + inline void call_construct(Alloc& alloc, T* address, + BOOST_FWD_REF(Args)... args) + { + boost::unordered::detail::allocator_traits::construct(alloc, + address, boost::forward(args)...); + } + + template + inline void destroy_value_impl(Alloc& alloc, T* x) { + boost::unordered::detail::allocator_traits::destroy(alloc, x); + } + + +# else + + template + inline void call_construct(Alloc&, T* address, + BOOST_FWD_REF(Args)... args) + { + new((void*) address) T(boost::forward(args)...); + } + + template + inline void destroy_value_impl(Alloc&, T* x) { + boost::unordered::detail::destroy(x); + } + + +# endif + +#else + + template + inline void destroy_value_impl(Alloc&, T* x) { + boost::unordered::detail::destroy(x); + } + +#endif + + //////////////////////////////////////////////////////////////////////////// + // Construct from tuple + // + // Used for piecewise construction. + +#if !defined(BOOST_NO_VARIADIC_TEMPLATES) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + void construct_from_tuple(Alloc& alloc, T* ptr, namespace_ tuple<>) \ + { \ + boost::unordered::detail::call_construct(alloc, ptr); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template \ + void construct_from_tuple(Alloc& alloc, T* ptr, \ + namespace_ tuple const& x) \ + { \ + boost::unordered::detail::call_construct(alloc, ptr, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ + ); \ + } + +# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_ get(x) + +#elif !defined(__SUNPRO_CC) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \ + { \ + new ((void*) ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template \ + void construct_from_tuple(Alloc&, T* ptr, \ + namespace_ tuple const& x) \ + { \ + new ((void*) ptr) T( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ + ); \ + } + +# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_ get(x) + +#else + + template struct length {}; + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + void construct_from_tuple_impl( \ + boost::unordered::detail::length<0>, Alloc&, T* ptr, \ + namespace_ tuple<>) \ + { \ + new ((void*) ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template \ + void construct_from_tuple_impl( \ + boost::unordered::detail::length, Alloc&, T* ptr, \ + namespace_ tuple const& x) \ + { \ + new ((void*) ptr) T( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ + ); \ + } + +# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_ get(x) + +#endif + +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) + +#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) +#endif + +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL +#undef BOOST_UNORDERED_GET_TUPLE_ARG + +#if defined(__SUNPRO_CC) + + template + void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x) + { + construct_from_tuple_impl( + boost::unordered::detail::length< + boost::tuples::length::value>(), + alloc, 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 + struct emulation1 { + static choice1::type test(choice1, std::pair 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())) == + sizeof(choice2::type) }; + }; +#endif + + template + 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())) }; + }; + + template + struct piecewise3 { + enum { value = check3_base::value == sizeof(choice1::type) }; + }; + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct emulation3 { + enum { value = check3_base::value == sizeof(choice2::type) }; + }; + +#endif + +// TODO: Full construct? +#if !defined(BOOST_NO_VARIADIC_TEMPLATES) + + //////////////////////////////////////////////////////////////////////////// + // Construct from variadic parameters + + template + inline void construct_value_impl(Alloc& alloc, T* address, + BOOST_FWD_REF(Args)... args) + { + boost::unordered::detail::call_construct(alloc, + address, boost::forward(args)...); + } + + template + inline typename enable_if, void>::type + construct_value_impl(Alloc& alloc, std::pair* address, + BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + boost::unordered::detail::construct_from_tuple(alloc, + boost::addressof(address->first), boost::forward(a1)); + boost::unordered::detail::construct_from_tuple(alloc, + boost::addressof(address->second), boost::forward(a2)); + } + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + + template + inline typename enable_if, void>::type + construct_value_impl(Alloc& alloc, std::pair* address, + BOOST_FWD_REF(A0) a0) + { + boost::unordered::detail::call_construct(alloc, + boost::addressof(address->first),boost::forward(a0)); + boost::unordered::detail::call_construct(alloc, + boost::addressof(address->second)); + } + + template + inline typename enable_if, void>::type + construct_value_impl(Alloc& alloc, std::pair* address, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + boost::unordered::detail::call_construct(alloc, + boost::addressof(address->first),boost::forward(a0)); + boost::unordered::detail::call_construct(alloc, + boost::addressof(address->second), + boost::forward(a1), + boost::forward(a2)); + } + + template + inline void construct_value_impl(Alloc& alloc, std::pair* 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) + { + boost::unordered::detail::call_construct(alloc, + boost::addressof(address->first),boost::forward(a0)); + boost::unordered::detail::call_construct(alloc, + boost::addressof(address->second), + boost::forward(a1), + boost::forward(a2), + boost::forward(a3), + boost::forward(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 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)); \ + } + + template + inline void construct_value_impl(Alloc&, T* address, + emplace_args1 const& args) + { + new((void*) address) T(boost::forward(args.a0)); + } + + template + inline void construct_value_impl(Alloc&, T* address, + emplace_args2 const& args) + { + new((void*) address) T( + boost::forward(args.a0), + boost::forward(args.a1) + ); + } + + template + inline void construct_value_impl(Alloc&, T* address, + emplace_args3 const& args) + { + new((void*) address) T( + boost::forward(args.a0), + boost::forward(args.a1), + boost::forward(args.a2) + ); + } + + BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_IMPL, _) + +#undef BOOST_UNORDERED_CONSTRUCT_IMPL + + template + inline void construct_value_impl(Alloc& alloc, std::pair* address, + boost::unordered::detail::emplace_args3 const& args, + typename enable_if, void*>::type = 0) + { + boost::unordered::detail::construct_from_tuple(alloc, + boost::addressof(address->first), args.a1); + boost::unordered::detail::construct_from_tuple(alloc, + boost::addressof(address->second), args.a2); + } + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + + template + inline void construct_value_impl(Alloc&, std::pair* address, + boost::unordered::detail::emplace_args1 const& args, + typename enable_if, void*>::type = 0) + { + new((void*) boost::addressof(address->first)) A( + boost::forward(args.a0)); + new((void*) boost::addressof(address->second)) B(); + } + + template + inline void construct_value_impl(Alloc&, std::pair* address, + boost::unordered::detail::emplace_args3 const& args, + typename enable_if, void*>::type = 0) + { + new((void*) boost::addressof(address->first)) A( + boost::forward(args.a0)); + new((void*) boost::addressof(address->second)) B( + boost::forward(args.a1), + boost::forward(args.a2)); + } + +#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \ + template \ + inline void construct_value_impl(Alloc&, std::pair* 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(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 + +}}} + //////////////////////////////////////////////////////////////////////////////// // // Some helper functions for allocating & constructing namespace boost { namespace unordered { namespace detail { - //////////////////////////////////////////////////////////////////////////// - // - // construct_node/destroy_node - // - // Construct a node using the best available method. - -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - - template - inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS) - { - boost::unordered::detail::allocator_traits::construct( - a, p, BOOST_UNORDERED_EMPLACE_FORWARD); - } - - template - inline void destroy_node(Alloc& a, T* p) - { - boost::unordered::detail::allocator_traits::destroy(a, p); - } - -#else - - template - struct value_construct - { - typedef BOOST_DEDUCED_TYPENAME AllocTraits::allocator_type allocator; - - allocator& alloc; - T* ptr; - - value_construct(allocator& a, T* p) : alloc(a), ptr(p) - { - AllocTraits::construct(alloc, ptr, T()); - } - - void release() - { - ptr = 0; - } - - ~value_construct() - { - if (ptr) AllocTraits::destroy(alloc, ptr); - } - - private: - value_construct(value_construct const&); - value_construct& operator=(value_construct const&); - }; - - template - inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS) - { - value_construct, T> - construct_guard(a, p); - boost::unordered::detail::construct_impl( - p->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - construct_guard.release(); - } - - template - inline void destroy_node(Alloc& a, T* p) - { - boost::unordered::detail::destroy(p->value_ptr()); - boost::unordered::detail::allocator_traits::destroy(a, p); - } - -#endif - //////////////////////////////////////////////////////////////////////////// // // array_constructor diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 85681a68..4dfe0445 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -53,14 +53,16 @@ namespace boost { namespace unordered { namespace detail { node_allocator& alloc_; node_pointer node_; - bool constructed_; + bool node_constructed_; + bool value_constructed_; public: node_constructor(node_allocator& n) : alloc_(n), node_(), - constructed_(false) + node_constructed_(false), + value_constructed_(false) { } @@ -71,36 +73,27 @@ namespace boost { namespace unordered { namespace detail { 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(node_)); - constructed_ = true; + BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); + boost::unordered::detail::construct_value_impl( + alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + value_constructed_ = true; } template void construct_value2(BOOST_FWD_REF(A0) a0) { - BOOST_ASSERT(node_ && !constructed_); - - boost::unordered::detail::construct_node(alloc_, - boost::addressof(*node_), + BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); + boost::unordered::detail::construct_value_impl( + alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward(a0))); - - constructed_ = true; - node_->init(static_cast(node_)); + value_constructed_ = true; } value_type const& value() const { - BOOST_ASSERT(node_ && constructed_); + BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); return node_->value(); } - node_pointer get() - { - return node_; - } - // no throw node_pointer release() { @@ -118,8 +111,13 @@ namespace boost { namespace unordered { namespace detail { node_constructor::~node_constructor() { if (node_) { - if (constructed_) { - boost::unordered::detail::destroy_node(alloc_, + if (value_constructed_) { + boost::unordered::detail::destroy_value_impl(alloc_, + node_->value_ptr()); + } + + if (node_constructed_) { + node_allocator_traits::destroy(alloc_, boost::addressof(*node_)); } @@ -131,13 +129,25 @@ namespace boost { namespace unordered { namespace detail { void node_constructor::construct_node() { if(!node_) { - constructed_ = false; + node_constructed_ = false; + value_constructed_ = false; + node_ = node_allocator_traits::allocate(alloc_, 1); + + node_allocator_traits::construct(alloc_, + boost::addressof(*node_), node()); + node_->init(static_cast(node_)); + node_constructed_ = true; } - else if (constructed_) { - boost::unordered::detail::destroy_node(alloc_, - boost::addressof(*node_)); - constructed_ = false; + else { + BOOST_ASSERT(node_constructed_); + + if (value_constructed_) + { + boost::unordered::detail::destroy_value_impl(alloc_, + node_->value_ptr()); + value_constructed_ = false; + } } } @@ -175,16 +185,6 @@ namespace boost { namespace unordered { namespace detail { enum { extra_node = false }; }; - - template - struct node_base - { - typedef LinkPointer link_pointer; - link_pointer next_; - - node_base() : next_() {} - }; - }}} namespace boost { namespace unordered { namespace iterator_detail { @@ -720,14 +720,6 @@ namespace boost { namespace unordered { namespace detail { 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( - boost::addressof(*a.get())), - typename node::node_base()); - (constructor.get() + static_cast(this->bucket_count_))->next_ = a.release(); @@ -772,8 +764,10 @@ namespace boost { namespace unordered { namespace detail { inline void delete_node(c_iterator n) { - boost::unordered::detail::destroy_node( - node_alloc(), boost::addressof(*n.node_)); + boost::unordered::detail::destroy_value_impl(node_alloc(), + n.node_->value_ptr()); + node_allocator_traits::destroy(node_alloc(), + boost::addressof(*n.node_)); node_allocator_traits::deallocate(node_alloc(), n.node_, 1); --size_; } @@ -795,8 +789,7 @@ namespace boost { namespace unordered { namespace detail { inline void delete_extra_node(bucket_pointer) {} inline void delete_extra_node(node_pointer n) { - node_allocator_traits::destroy(node_alloc(), - static_cast(boost::addressof(*n))); + node_allocator_traits::destroy(node_alloc(), boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); } @@ -1041,6 +1034,36 @@ namespace boost { namespace unordered { namespace detail { tmp_functions_ = !tmp_functions_; } }; + + //////////////////////////////////////////////////////////////////////////// + // 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 + struct rv_ref_impl { + typedef BOOST_RV_REF(T) type; + }; + + template + struct rv_ref : + boost::detail::if_true< + boost::is_class::value + >::BOOST_NESTED_TEMPLATE then < + boost::unordered::detail::rv_ref_impl, + please_ignore_this_overload + >::type + {}; + +# define BOOST_UNORDERED_RV_REF(T) \ + typename boost::unordered::detail::rv_ref::type +#endif }}} #if defined(BOOST_MSVC) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 5cbf6a7c..54ace45f 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -22,44 +22,20 @@ namespace boost { namespace unordered { namespace detail { template struct grouped_node : - boost::unordered::detail::node_base< - typename ::boost::unordered::detail::rebind_wrap< - A, grouped_node >::type::pointer - >, boost::unordered::detail::value_base { typedef typename ::boost::unordered::detail::rebind_wrap< A, grouped_node >::type::pointer link_pointer; - typedef boost::unordered::detail::node_base node_base; + link_pointer next_; link_pointer group_prev_; std::size_t hash_; -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - 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) { @@ -76,37 +52,16 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::ptr_bucket { typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef bucket_base node_base; typedef ptr_bucket* link_pointer; link_pointer group_prev_; std::size_t hash_; -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - 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) { diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index cbf62195..116c4e9c 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -310,6 +310,11 @@ namespace boost { namespace unordered { namespace detail { template void swap(table& x, Propagate p) { + // According to 23.2.1.8, if propagate_on_container_swap is + // false the behaviour is undefined unless the allocators + // are equal. + BOOST_ASSERT(p.value || this->node_alloc() == x.node_alloc()); + boost::unordered::detail::set_hash_functions op1(*this, x); boost::unordered::detail::set_hash_functions diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 10db58fa..34cfea25 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -24,41 +24,18 @@ namespace boost { namespace unordered { namespace detail { template struct unique_node : - boost::unordered::detail::node_base< - typename ::boost::unordered::detail::rebind_wrap< - A, unique_node >::type::pointer - >, boost::unordered::detail::value_base { typedef typename ::boost::unordered::detail::rebind_wrap< A, unique_node >::type::pointer link_pointer; - typedef boost::unordered::detail::node_base node_base; + link_pointer next_; std::size_t hash_; -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - 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) { @@ -74,34 +51,14 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::ptr_bucket { typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef bucket_base node_base; typedef ptr_bucket* link_pointer; std::size_t hash_; -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT - 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) { diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index 624d4779..515d8bb6 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -39,26 +39,40 @@ template struct assign_base : public test::exception_base { const test::random_values x_values, y_values; - const T x,y; + T x,y; typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type; - assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2) : + assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2, + float mlf1 = 1.0, float mlf2 = 1.0) : x_values(count1), y_values(count2), x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1), allocator_type(tag1)), y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2), allocator_type(tag2)) - {} + { + x.max_load_factor(mlf1); + y.max_load_factor(mlf2); + } typedef T data_type; T init() const { return T(x); } void run(T& x1) const { x1 = y; } void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const - { test::check_equivalent_keys(x1); } + { + test::check_equivalent_keys(x1); + + // If the container is empty at the point of the exception, the + // internal structure is hidden, this exposes it. + T& y = const_cast(x1); + if (x_values.size()) { + y.emplace(*x_values.begin()); + test::check_equivalent_keys(y); + } + } }; template @@ -85,7 +99,13 @@ struct assign_test4 : assign_base assign_test4() : assign_base(10, 10, 1, 2) {} }; +template +struct assign_test5 : assign_base +{ + assign_test5() : assign_base(5, 60, 0, 0, 1.0, 0.1) {} +}; + RUN_EXCEPTION_TESTS( (self_assign_test1)(self_assign_test2) - (assign_test1)(assign_test2)(assign_test3)(assign_test4), + (assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test5), CONTAINER_SEQ) diff --git a/test/exception/containers.hpp b/test/exception/containers.hpp index b3a326b8..1e379645 100644 --- a/test/exception/containers.hpp +++ b/test/exception/containers.hpp @@ -18,13 +18,13 @@ typedef boost::unordered_multiset< test::exception::object, test::exception::hash, test::exception::equal_to, - test::exception::allocator > test_multiset; + test::exception::allocator2 > test_multiset; typedef boost::unordered_map< test::exception::object, test::exception::object, test::exception::hash, test::exception::equal_to, - test::exception::allocator > test_map; + test::exception::allocator2 > test_map; typedef boost::unordered_multimap< test::exception::object, test::exception::object, diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 23f12476..39e59494 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -60,7 +60,9 @@ struct swap_base : public test::exception_base initial_x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1), allocator_type(tag1)), initial_y(y_values.begin(), y_values.end(), 0, hasher(tag2), - key_equal(tag2), allocator_type(tag2)) + key_equal(tag2), allocator_type( + T::allocator_type::propagate_on_container_swap::value ? + tag2 : tag1)) {} struct data_type { @@ -71,6 +73,7 @@ struct swap_base : public test::exception_base }; data_type init() const { return data_type(initial_x, initial_y); } + void run(data_type& d) const { try { d.x.swap(d.y); diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index abb8fb1e..fec7ee65 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -82,16 +82,39 @@ namespace test } }; - // Finally, check that size matches up. + // Check that size matches up. + if(x1.size() != size) { BOOST_ERROR("x1.size() doesn't match actual size."); std::cout<(size) / static_cast(x1.bucket_count()); using namespace std; if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64) BOOST_ERROR("x1.load_factor() doesn't match actual load_factor."); + + // Check that size in the buckets matches up. + + BOOST_DEDUCED_TYPENAME X::size_type bucket_size = 0; + + for (BOOST_DEDUCED_TYPENAME X::size_type + i = 0; i < x1.bucket_count(); ++i) + { + for (BOOST_DEDUCED_TYPENAME X::const_local_iterator + begin = x1.begin(i), end = x1.end(i); begin != end; ++begin) + { + ++bucket_size; + } + } + + if(x1.size() != bucket_size) { + BOOST_ERROR("x1.size() doesn't match bucket size."); + std::cout< + class allocator2 + { + public: + int tag_; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T const* const_pointer; + typedef T& reference; + typedef T const& const_reference; + typedef T value_type; + + template struct rebind { typedef allocator2 other; }; + + explicit allocator2(int t = 0) : tag_(t) + { + UNORDERED_SCOPE(allocator2::allocator2()) { + UNORDERED_EPOINT("Mock allocator2 default constructor."); + } + test::detail::tracker.allocator_ref(); + } + + allocator2(allocator const& x) : tag_(x.tag_) + { + UNORDERED_SCOPE(allocator2::allocator2()) { + UNORDERED_EPOINT("Mock allocator2 constructor from allocator."); + } + test::detail::tracker.allocator_ref(); + } + + template allocator2(allocator2 const& x) : tag_(x.tag_) + { + UNORDERED_SCOPE(allocator2::allocator2()) { + UNORDERED_EPOINT("Mock allocator2 template copy constructor."); + } + test::detail::tracker.allocator_ref(); + } + + allocator2(allocator2 const& x) : tag_(x.tag_) + { + UNORDERED_SCOPE(allocator2::allocator2()) { + UNORDERED_EPOINT("Mock allocator2 copy constructor."); + } + test::detail::tracker.allocator_ref(); + } + + ~allocator2() { + test::detail::tracker.allocator_unref(); + } + + allocator2& operator=(allocator2 const& x) { + UNORDERED_SCOPE(allocator2::allocator2()) { + UNORDERED_EPOINT("Mock allocator2 assignment operator."); + tag_ = x.tag_; + } + return *this; + } + + // If address throws, then it can't be used in erase or the + // destructor, which is very limiting. I need to check up on + // this. + + pointer address(reference r) { + //UNORDERED_SCOPE(allocator2::address(reference)) { + // UNORDERED_EPOINT("Mock allocator2 address function."); + //} + return pointer(&r); + } + + const_pointer address(const_reference r) { + //UNORDERED_SCOPE(allocator2::address(const_reference)) { + // UNORDERED_EPOINT("Mock allocator2 const address function."); + //} + return const_pointer(&r); + } + + pointer allocate(size_type n) { + T* ptr = 0; + UNORDERED_SCOPE(allocator2::allocate(size_type)) { + UNORDERED_EPOINT("Mock allocator2 allocate function."); + + using namespace std; + ptr = (T*) malloc(n * sizeof(T)); + if(!ptr) throw std::bad_alloc(); + } + test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_); + return pointer(ptr); + + //return pointer(static_cast(::operator new(n * sizeof(T)))); + } + + pointer allocate(size_type n, void const* u) + { + T* ptr = 0; + UNORDERED_SCOPE(allocator2::allocate(size_type, const_pointer)) { + UNORDERED_EPOINT("Mock allocator2 allocate function."); + + using namespace std; + ptr = (T*) malloc(n * sizeof(T)); + if(!ptr) throw std::bad_alloc(); + } + test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_); + return pointer(ptr); + + //return pointer(static_cast(::operator new(n * sizeof(T)))); + } + + void deallocate(pointer p, size_type n) + { + //::operator delete((void*) p); + if(p) { + test::detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_); + using namespace std; + free(p); + } + } + + void construct(pointer p, T const& t) { + UNORDERED_SCOPE(allocator2::construct(T*, T)) { + UNORDERED_EPOINT("Mock allocator2 construct function."); + new(p) T(t); + } + test::detail::tracker.track_construct((void*) p, sizeof(T), tag_); + } + +#if !defined(BOOST_NO_VARIADIC_TEMPLATES) + template void construct(T* p, BOOST_FWD_REF(Args)... args) { + UNORDERED_SCOPE(allocator2::construct(pointer, BOOST_FWD_REF(Args)...)) { + UNORDERED_EPOINT("Mock allocator2 construct function."); + new(p) T(boost::forward(args)...); + } + test::detail::tracker.track_construct((void*) p, sizeof(T), tag_); + } +#endif + + void destroy(T* p) { + test::detail::tracker.track_destroy((void*) p, sizeof(T), tag_); + p->~T(); + } + + size_type max_size() const { + UNORDERED_SCOPE(allocator2::construct(pointer, T)) { + UNORDERED_EPOINT("Mock allocator2 max_size function."); + } + return (std::numeric_limits::max)(); + } + + typedef false_type propagate_on_container_copy_assignment; + typedef false_type propagate_on_container_move_assignment; + typedef false_type propagate_on_container_swap; + }; + + template + void swap(allocator2& x, allocator2& y) + { + std::swap(x.tag_, y.tag_); + } + + // It's pretty much impossible to write a compliant swap when these + // two can throw. So they don't. + + template + inline bool operator==(allocator2 const& x, allocator2 const& y) + { + //UNORDERED_SCOPE(operator==(allocator2, allocator2)) { + // UNORDERED_EPOINT("Mock allocator2 equality operator."); + //} + return x.tag_ == y.tag_; + } + + template + inline bool operator!=(allocator2 const& x, allocator2 const& y) + { + //UNORDERED_SCOPE(operator!=(allocator2, allocator2)) { + // UNORDERED_EPOINT("Mock allocator2 inequality operator."); + //} + return x.tag_ != y.tag_; + } } } diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index 0d9ae8b2..ba32167a 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -26,7 +26,7 @@ namespace minimal class destructible; class copy_constructible; class copy_constructible_equality_comparable; - class default_copy_constructible; + class default_assignable; class assignable; struct ampersand_operator_used {}; @@ -99,26 +99,29 @@ namespace minimal return false; } - class default_copy_constructible + class default_assignable { public: - default_copy_constructible(constructor_param const&) {} + default_assignable(constructor_param const&) {} - default_copy_constructible() + default_assignable() { } - default_copy_constructible(default_copy_constructible const&) + default_assignable(default_assignable const&) { } - ~default_copy_constructible() + default_assignable& operator=(default_assignable const&) + { + return *this; + } + + ~default_assignable() { } private: - default_copy_constructible& operator=( - default_copy_constructible const&); ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; @@ -148,7 +151,7 @@ namespace minimal movable1() {} explicit movable1(movable_init) {} movable1(BOOST_RV_REF(movable1)) {} - movable1& operator=(BOOST_RV_REF(movable1)); + movable1& operator=(BOOST_RV_REF(movable1)) { return *this; } ~movable1() {} }; @@ -160,6 +163,7 @@ namespace minimal explicit movable2(movable_init) {} movable2(movable2&&) {} ~movable2() {} + movable2& operator=(movable2&&) { return *this; } private: movable2() {} movable2(movable2 const&); diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index c829e254..0c2aec04 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -63,6 +63,7 @@ void assign_tests1(T*, tracker.compare(y); BOOST_TEST(x.max_load_factor() == mlf); BOOST_TEST(y.max_load_factor() == mlf); + BOOST_TEST(y.load_factor() <= y.max_load_factor()); } } @@ -87,9 +88,31 @@ void assign_tests2(T*, T x1(v.begin(), v.end(), 0, hf1, eq1); T x2(0, hf2, eq2); x2 = x1; + BOOST_TEST(test::equivalent(x1.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x1.key_eq(), eq1)); BOOST_TEST(test::equivalent(x2.hash_function(), hf1)); BOOST_TEST(test::equivalent(x2.key_eq(), eq1)); + test::check_container(x1, v); test::check_container(x2, v); + BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); + } + + std::cerr<<"assign_tests2.1a\n"; + { + test::check_instances check_; + + test::random_values v1(0, generator); + test::random_values v2(1000, generator); + T x1(0, hf2, eq2); + T x2(v2.begin(), v2.end(), 0, hf1, eq1); + x2 = x1; + BOOST_TEST(test::equivalent(x1.hash_function(), hf2)); + BOOST_TEST(test::equivalent(x1.key_eq(), eq2)); + BOOST_TEST(test::equivalent(x2.hash_function(), hf2)); + BOOST_TEST(test::equivalent(x2.key_eq(), eq2)); + test::check_container(x1, v1); + test::check_container(x2, v1); + BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); } std::cerr<<"assign_tests2.2\n"; @@ -110,7 +133,55 @@ void assign_tests2(T*, BOOST_TEST(test::equivalent(x2.get_allocator(), al2)); BOOST_TEST(!test::equivalent(x2.get_allocator(), al1)); } + test::check_container(x1, v1); test::check_container(x2, v1); + BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); + } + + std::cerr<<"assign_tests2.3\n"; + { + test::check_instances check_; + + test::random_values v1(100, generator), v2(1000, generator); + T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1); + T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2); + x2 = x1; + BOOST_TEST(test::equivalent(x2.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x2.key_eq(), eq1)); + if (allocator_type::is_propagate_on_assign) { + BOOST_TEST(test::equivalent(x2.get_allocator(), al1)); + BOOST_TEST(!test::equivalent(x2.get_allocator(), al2)); + } + else { + BOOST_TEST(test::equivalent(x2.get_allocator(), al2)); + BOOST_TEST(!test::equivalent(x2.get_allocator(), al1)); + } + test::check_container(x1, v1); + test::check_container(x2, v1); + BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); + } + + std::cerr<<"assign_tests2.4\n"; + { + test::check_instances check_; + + test::random_values v1(1000, generator), v2(100, generator); + T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1); + T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2); + x2 = x1; + BOOST_TEST(test::equivalent(x2.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x2.key_eq(), eq1)); + if (allocator_type::is_propagate_on_assign) { + BOOST_TEST(test::equivalent(x2.get_allocator(), al1)); + BOOST_TEST(!test::equivalent(x2.get_allocator(), al2)); + } + else { + BOOST_TEST(test::equivalent(x2.get_allocator(), al2)); + BOOST_TEST(!test::equivalent(x2.get_allocator(), al1)); + } + test::check_container(x1, v1); + test::check_container(x2, v1); + BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); } } diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 6cd3c503..317607c7 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -32,13 +32,13 @@ template class boost::unordered_multimap< template class boost::unordered_map< test::minimal::assignable, - test::minimal::default_copy_constructible, + test::minimal::default_assignable, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator >; template class boost::unordered_multimap< test::minimal::assignable, - test::minimal::copy_constructible, + test::minimal::assignable, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator >; @@ -48,7 +48,7 @@ UNORDERED_AUTO_TEST(test0) test::minimal::constructor_param x; typedef std::pair value_type; + test::minimal::assignable> value_type; value_type value(x, x); std::cout<<"Test unordered_map.\n"; @@ -62,7 +62,7 @@ UNORDERED_AUTO_TEST(test0) boost::unordered_map< test::minimal::assignable, - test::minimal::copy_constructible, + test::minimal::assignable, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator > map; @@ -82,7 +82,7 @@ UNORDERED_AUTO_TEST(test0) boost::unordered_multimap< test::minimal::assignable, - test::minimal::copy_constructible, + test::minimal::assignable, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator > multimap; @@ -95,7 +95,7 @@ UNORDERED_AUTO_TEST(test0) UNORDERED_AUTO_TEST(equality_tests) { typedef std::pair< test::minimal::copy_constructible_equality_comparable const, - test::minimal::copy_constructible> value_type; + test::minimal::copy_constructible_equality_comparable> value_type; boost::unordered_map int_map; @@ -187,44 +187,44 @@ UNORDERED_AUTO_TEST(test2) test::minimal::equal_to equal_to(x); typedef std::pair map_value_type; - map_value_type map_value(assignable, copy_constructible); + test::minimal::assignable> map_value_type; + map_value_type map_value(assignable, assignable); std::cout<<"Test unordered_map.\n"; boost::unordered_map< test::minimal::assignable, - test::minimal::copy_constructible, + test::minimal::assignable, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator > map; unordered_unique_test(map, map_value); - unordered_map_test(map, assignable, copy_constructible); + unordered_map_test(map, assignable, assignable); unordered_copyable_test(map, assignable, map_value, hash, equal_to); boost::unordered_map< test::minimal::assignable, - test::minimal::default_copy_constructible, + test::minimal::default_assignable, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator > map2; - test::minimal::default_copy_constructible default_copy_constructible; + test::minimal::default_assignable default_assignable; - unordered_map_functions(map2, assignable, default_copy_constructible); + unordered_map_functions(map2, assignable, default_assignable); std::cout<<"Test unordered_multimap.\n"; boost::unordered_multimap< test::minimal::assignable, - test::minimal::copy_constructible, + test::minimal::assignable, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator > multimap; unordered_equivalent_test(multimap, map_value); - unordered_map_test(multimap, assignable, copy_constructible); + unordered_map_test(multimap, assignable, assignable); unordered_copyable_test(multimap, assignable, map_value, hash, equal_to); } diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 29ca4282..284dd56b 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -170,7 +170,6 @@ namespace unnecessary_copy_tests UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test, ((set)(multiset)(map)(multimap))) -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template void unnecessary_copy_emplace_move_test(T*) { @@ -178,13 +177,17 @@ namespace unnecessary_copy_tests T x; BOOST_DEDUCED_TYPENAME T::value_type a; COPY_COUNT(1); MOVE_COUNT(0); - x.emplace(std::move(a)); + x.emplace(boost::move(a)); +#if !defined(BOOST_NO_RVALUE_REFERENCES) COPY_COUNT(1); MOVE_COUNT(1); +#else + // Since std::pair isn't movable, move only works for sets. + COPY_COUNT_RANGE(1, 2); MOVE_COUNT_RANGE(0, 1); +#endif } UNORDERED_TEST(unnecessary_copy_emplace_move_test, ((set)(multiset)(map)(multimap))) -#endif template void unnecessary_copy_emplace_boost_move_set_test(T*) @@ -270,14 +273,16 @@ namespace unnecessary_copy_tests x.emplace(source()); COPY_COUNT(1); MOVE_COUNT(source_cost); -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) // No move should take place. reset(); - x.emplace(std::move(a)); + x.emplace(boost::move(a)); +#if !defined(BOOST_NO_RVALUE_REFERENCES) COPY_COUNT(0); MOVE_COUNT(0); +#else + COPY_COUNT(0); MOVE_COUNT(1); #endif - // Just in case a did get moved... + // Use a new value for cases where a did get moved... count_copies b; // The container will have to create a copy in order to compare with @@ -367,16 +372,12 @@ namespace unnecessary_copy_tests #endif -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - // No move should take place. // (since a is already in the container) reset(); - x.emplace(std::move(a)); + x.emplace(boost::move(a)); COPY_COUNT(0); MOVE_COUNT(0); -#endif - // // 2 arguments //