diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 3392ac03..5dc8491e 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS # include @@ -97,6 +99,22 @@ namespace boost { namespace unordered { namespace detail { struct choice1 : choice2 { typedef char (&type)[1]; }; choice1 choose(); + typedef choice1::type yes_type; + typedef choice2::type no_type; + + struct private_type + { + private_type const &operator,(int) const; + }; + + template + no_type is_private_type(T const&); + yes_type is_private_type(private_type const&); + + struct convert_from_anything { + convert_from_anything(...); + }; + #if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 #define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ @@ -176,44 +194,40 @@ namespace boost { namespace unordered { namespace detail { static BOOST_PP_CAT(choice, result)::type test( \ BOOST_PP_CAT(choice, count)) -#define BOOST_UNORDERED_HAS_EXPRESSION(name, expression) \ +#define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \ struct BOOST_PP_CAT(has_, name) \ { \ - BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, expression); \ + BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, make< thing >().name args); \ BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \ \ enum { value = sizeof(test(choose())) == sizeof(choice1::type) };\ } template - BOOST_UNORDERED_HAS_EXPRESSION( - select_on_container_copy_construction, - make().select_on_container_copy_construction() + BOOST_UNORDERED_HAS_FUNCTION( + select_on_container_copy_construction, U const, (), 0 ); // Only supporting the basic copy constructor for now. template - BOOST_UNORDERED_HAS_EXPRESSION( - construct, - make().construct(make(), make()) + BOOST_UNORDERED_HAS_FUNCTION( + construct, U, (make(), make()), 2 ); template - BOOST_UNORDERED_HAS_EXPRESSION( - destroy, - make().destroy(make()) + BOOST_UNORDERED_HAS_FUNCTION( + destroy, U, (make()), 1 ); template - BOOST_UNORDERED_HAS_EXPRESSION( - max_size, - make().max_size() + BOOST_UNORDERED_HAS_FUNCTION( + max_size, U const, (), 0 ); #else - template struct identity { typedef T type; }; + template struct identity { typedef T type; }; #define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ \ @@ -232,27 +246,73 @@ namespace boost { namespace unordered { namespace detail { template static BOOST_PP_CAT(choice, result)::type \ test(BOOST_PP_CAT(choice, count)) +#define BOOST_UNORDERED_WRAP_PARAMATERS(z, n, data) convert_from_anything + +#define BOOST_UNORDERED_HAS_MEMBER(name) \ + struct BOOST_PP_CAT(has_, name) \ + { \ + struct base_mixin { void name(); }; \ + struct base : public T, public base_mixin {}; \ + \ + BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, void (base_mixin::*)()); \ + BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \ + \ + enum { value = sizeof(choice2::type) == \ + sizeof(test(choose())) \ + }; \ + } + +#define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, arg_count) \ + struct BOOST_PP_CAT(has_, name) \ + { \ + struct base_mixin { void name(); }; \ + struct base : public T, public base_mixin {}; \ + \ + BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, void (base_mixin::*)()); \ + BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \ + \ + enum { has_member = sizeof(choice2::type) == \ + sizeof(test(choose())) \ + }; \ + \ + template \ + struct wrap : U \ + { \ + using U::name; \ + private_type name( \ + BOOST_PP_ENUM(arg_count, BOOST_UNORDERED_WRAP_PARAMATERS, _) \ + ); \ + }; \ + \ + template \ + struct impl \ + { \ + enum { value = sizeof(is_private_type(( \ + make >().name args \ + , 0))) == sizeof(yes_type) }; \ + }; \ + \ + enum { value = \ + boost::detail::if_true:: \ + BOOST_NESTED_TEMPLATE then, false_type>::type::value \ + }; \ + } template - struct has_select_on_container_copy_construction - { - BOOST_UNORDERED_CHECK_MEMBER(1, 1, - select_on_container_copy_construction, - T (T::*)() const); - BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); - - enum { value = sizeof(test(choose())) == sizeof(choice1::type) }; - }; + BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction); - // Detection isn't reliable enough, so just assume that we have these - // functions. - - template - struct has_construct : true_type {}; - template - struct has_destroy : true_type {}; - template - struct has_max_size : true_type {}; + template + BOOST_UNORDERED_HAS_FUNCTION( + construct, U, (make(), make()), 2 + ); + + template + BOOST_UNORDERED_HAS_FUNCTION( + destroy, U, (make()), 1 + ); + + template + BOOST_UNORDERED_HAS_MEMBER(max_size); #endif @@ -295,27 +355,20 @@ namespace boost { namespace unordered { namespace detail { typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*) pointer; - // For now always use the allocator's const_pointer. - - //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, - // typename pointer_traits:: - // BOOST_NESTED_TEMPLATE rebind::other) - // const_pointer; + template + struct pointer_to_other : boost::pointer_to_other {}; typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, - value_type const*) const_pointer; + typename pointer_to_other::type) + const_pointer; - // I'm not using void pointers for now. + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer, + typename pointer_to_other::type) + void_pointer; - //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer, - // BOOST_NESTED_TEMPLATE pointer_traits:: - // BOOST_NESTED_TEMPLATE rebind::other) - // void_pointer; - - //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer, - // typename pointer_traits:: - // BOOST_NESTED_TEMPLATE rebind::other) - // const_void_pointer; + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer, + typename pointer_to_other::type) + const_void_pointer; typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, difference_type, std::ptrdiff_t) difference_type; diff --git a/test/unordered/allocator_traits.cpp b/test/unordered/allocator_traits.cpp index c27176c4..ba8ac0d8 100644 --- a/test/unordered/allocator_traits.cpp +++ b/test/unordered/allocator_traits.cpp @@ -136,8 +136,17 @@ void test_allocator1() // allocator 2 +template +struct allocator2_base +{ + Alloc select_on_container_copy_construction() const { + ++selected; + return Alloc(); + } +}; + template -struct allocator2 +struct allocator2 : allocator2_base > { typedef T value_type; typedef T* pointer; @@ -149,12 +158,6 @@ struct allocator2 typedef no_type propagate_on_container_copy_assignment; typedef no_type propagate_on_container_move_assignment; typedef no_type propagate_on_container_swap; - - // Note: Not const - so it shouldn't be called. - allocator2 select_on_container_copy_construction() { - ++selected; - return allocator2(); - } }; void test_allocator2() @@ -169,7 +172,7 @@ void test_allocator2() BOOST_TEST(!traits::propagate_on_container_copy_assignment::value); BOOST_TEST(!traits::propagate_on_container_move_assignment::value); BOOST_TEST(!traits::propagate_on_container_swap::value); - BOOST_TEST(call_select() == 0); + BOOST_TEST(call_select() == 1); } // allocator 3