diff --git a/include/boost/container/allocator_traits.hpp b/include/boost/container/allocator_traits.hpp index c1d46c8..55e0771 100644 --- a/include/boost/container/allocator_traits.hpp +++ b/include/boost/container/allocator_traits.hpp @@ -44,6 +44,8 @@ #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #endif +// other boost +#include #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -106,6 +108,7 @@ BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assig BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_swap) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(is_always_equal) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(difference_type) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(is_partially_propagable) } //namespace container_detail { @@ -158,6 +161,11 @@ struct allocator_traits //! Allocator::is_always_equal if such a type exists, otherwise a type //! with an internal constant static boolean member value == is_empty::value typedef see_documentation is_always_equal; + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED //Still experimental + //! Allocator::is_partially_propagable if such a type exists, otherwise a type + //! with an internal constant static boolean member value == false + typedef see_documentation is_partially_propagable; + #endif //! Defines an allocator: Allocator::rebind::other if such a type exists; otherwise, Allocator //! if Allocator is a class template instantiation of the form Allocator, where Args is zero or //! more type arguments ; otherwise, the instantiation of rebind_alloc is ill-formed. @@ -228,6 +236,14 @@ struct allocator_traits typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Allocator, is_always_equal, container_detail::is_empty) is_always_equal; + //is_partially_propagable + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Allocator, + is_partially_propagable, container_detail::false_type) + is_partially_propagable; + //is_always_equal and is_partially_propagable are not compatible + BOOST_STATIC_ASSERT((!is_always_equal::value || !is_partially_propagable::value)); + + //rebind_alloc & rebind_traits #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) //C++11 template using rebind_alloc = typename boost::intrusive::pointer_rebind::type; @@ -256,6 +272,8 @@ struct allocator_traits : allocator_traits::type> {}; #endif // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + + //portable_rebind_alloc template struct portable_rebind_alloc { typedef typename boost::intrusive::pointer_rebind::type type; }; @@ -307,16 +325,10 @@ struct allocator_traits //! Returns: a.select_on_container_copy_construction() if that expression is well-formed; //! otherwise, a. - static - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - typename container_detail::if_c - < allocator_traits_detail::has_select_on_container_copy_construction::value - , Allocator - , const Allocator & - >::type - #else - Allocator - #endif + static BOOST_CONTAINER_DOC1ST(Allocator, + typename container_detail::if_c + < allocator_traits_detail::has_select_on_container_copy_construction::value + BOOST_MOVE_I Allocator BOOST_MOVE_I const Allocator & >::type) select_on_container_copy_construction(const Allocator &a) { const bool value = allocator_traits_detail::has_select_on_container_copy_construction @@ -335,116 +347,143 @@ struct allocator_traits allocator_traits::priv_construct(flag, a, p, ::boost::forward(args)...); } #endif - #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Returns: a.storage_can_be_propagated(p, to, propagate_a) if is_partially_propagable::value is true; otherwise, + //! a == to. + static bool storage_can_be_propagated(const Allocator &a, pointer p, const Allocator &to, bool propagate_a) BOOST_NOEXCEPT_OR_NOTHROW + { + container_detail::bool_ flag; + return allocator_traits::priv_storage_can_be_propagated(flag, a, p, to, propagate_a); + } + + //! Returns: true if is_always_equal::value == true, otherwise, + //! a == b. + static bool equal(const Allocator &a, const Allocator &b) BOOST_NOEXCEPT_OR_NOTHROW + { + container_detail::bool_ flag; + return allocator_traits::priv_equal(flag, a, b); + } + + private: + static pointer priv_allocate(container_detail::true_type, Allocator &a, size_type n, const_void_pointer p) + { return a.allocate(n, p); } + + static pointer priv_allocate(container_detail::false_type, Allocator &a, size_type n, const_void_pointer) + { return a.allocate(n); } + + template + static void priv_destroy(container_detail::true_type, Allocator &a, T* p) BOOST_NOEXCEPT_OR_NOTHROW + { a.destroy(p); } + + template + static void priv_destroy(container_detail::false_type, Allocator &, T* p) BOOST_NOEXCEPT_OR_NOTHROW + { p->~T(); (void)p; } + + static size_type priv_max_size(container_detail::true_type, const Allocator &a) BOOST_NOEXCEPT_OR_NOTHROW + { return a.max_size(); } + + static size_type priv_max_size(container_detail::false_type, const Allocator &) BOOST_NOEXCEPT_OR_NOTHROW + { return size_type(-1)/sizeof(value_type); } + + static Allocator priv_select_on_container_copy_construction(container_detail::true_type, const Allocator &a) + { return a.select_on_container_copy_construction(); } + + static const Allocator &priv_select_on_container_copy_construction(container_detail::false_type, const Allocator &a) BOOST_NOEXCEPT_OR_NOTHROW + { return a; } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + static void priv_construct(container_detail::false_type, Allocator &a, T *p, BOOST_FWD_REF(Args) ...args) + { + const bool value = boost::container::container_detail:: + has_member_function_callable_with_construct + < Allocator, T*, Args... >::value; + container_detail::bool_ flag; + (priv_construct_dispatch_next)(flag, a, p, ::boost::forward(args)...); + } + + template + static void priv_construct(container_detail::true_type, Allocator &a, T *p, BOOST_FWD_REF(Args) ...args) + { (priv_construct_dispatch_next)(container_detail::false_type(), a, p, ::boost::forward(args)...); } + + template + static void priv_construct_dispatch_next(container_detail::true_type, Allocator &a, T *p, BOOST_FWD_REF(Args) ...args) + { a.construct( p, ::boost::forward(args)...); } + + template + static void priv_construct_dispatch_next(container_detail::false_type, Allocator &, T *p, BOOST_FWD_REF(Args) ...args) + { ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); } + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + public: + + #define BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL(N) \ + template\ + static void construct(Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + container_detail::bool_::value> flag;\ + (priv_construct)(flag, a, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL) + #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL + private: - static pointer priv_allocate(container_detail::true_type, Allocator &a, size_type n, const_void_pointer p) - { return a.allocate(n, p); } - static pointer priv_allocate(container_detail::false_type, Allocator &a, size_type n, const_void_pointer) - { return a.allocate(n); } + ////////////////// + // priv_construct + ////////////////// + #define BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL(N) \ + template\ + static void priv_construct(container_detail::false_type, Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + const bool value = boost::container::container_detail::has_member_function_callable_with_construct\ + < Allocator, T* BOOST_MOVE_I##N BOOST_MOVE_FWD_T##N>::value;\ + container_detail::bool_ flag;\ + (priv_construct_dispatch_next)(flag, a, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + \ + template\ + static void priv_construct(container_detail::true_type, Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { (priv_construct_dispatch_next)(container_detail::false_type(), a, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ + // + BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL) + #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL - template - static void priv_destroy(container_detail::true_type, Allocator &a, T* p) BOOST_NOEXCEPT_OR_NOTHROW - { a.destroy(p); } + ///////////////////////////////// + // priv_construct_dispatch_next + ///////////////////////////////// + #define BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_DISPATCH_NEXT_IMPL(N) \ + template\ + static void priv_construct_dispatch_next(container_detail::true_type, Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { a.construct( p BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); }\ + \ + template\ + static void priv_construct_dispatch_next(container_detail::false_type, Allocator &, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { ::new((void*)p, boost_container_new_t()) T(BOOST_MOVE_FWD##N); }\ + // + BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_DISPATCH_NEXT_IMPL) + #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_DISPATCH_NEXT_IMPL - template - static void priv_destroy(container_detail::false_type, Allocator &, T* p) BOOST_NOEXCEPT_OR_NOTHROW - { p->~T(); (void)p; } + #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - static size_type priv_max_size(container_detail::true_type, const Allocator &a) BOOST_NOEXCEPT_OR_NOTHROW - { return a.max_size(); } + template + static void priv_construct_dispatch_next(container_detail::false_type, Allocator &, T *p, const ::boost::container::default_init_t&) + { ::new((void*)p) T; } - static size_type priv_max_size(container_detail::false_type, const Allocator &) BOOST_NOEXCEPT_OR_NOTHROW - { return size_type(-1)/sizeof(value_type); } + static bool priv_storage_can_be_propagated(container_detail::true_type, const Allocator &a, pointer p, const Allocator &to, const bool propagate_a) + { return a.storage_can_be_propagated(p, to, propagate_a); } - static Allocator priv_select_on_container_copy_construction(container_detail::true_type, const Allocator &a) - { return a.select_on_container_copy_construction(); } + static bool priv_storage_can_be_propagated(container_detail::false_type, const Allocator &a, pointer, const Allocator &to, const bool propagate_a) + { return allocator_traits::equal(a, to) || propagate_a; } - static const Allocator &priv_select_on_container_copy_construction(container_detail::false_type, const Allocator &a) BOOST_NOEXCEPT_OR_NOTHROW - { return a; } + static bool priv_equal(container_detail::true_type, const Allocator &, const Allocator &) + { return true; } - #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template - static void priv_construct(container_detail::false_type, Allocator &a, T *p, BOOST_FWD_REF(Args) ...args) - { - const bool value = boost::container::container_detail:: - has_member_function_callable_with_construct - < Allocator, T*, Args... >::value; - container_detail::bool_ flag; - (priv_construct_dispatch_next)(flag, a, p, ::boost::forward(args)...); - } + static bool priv_equal(container_detail::false_type, const Allocator &a, const Allocator &b) + { return a == b; } - template - static void priv_construct(container_detail::true_type, Allocator &a, T *p, BOOST_FWD_REF(Args) ...args) - { (priv_construct_dispatch_next)(container_detail::false_type(), a, p, ::boost::forward(args)...); } - - template - static void priv_construct_dispatch_next(container_detail::true_type, Allocator &a, T *p, BOOST_FWD_REF(Args) ...args) - { a.construct( p, ::boost::forward(args)...); } - - template - static void priv_construct_dispatch_next(container_detail::false_type, Allocator &, T *p, BOOST_FWD_REF(Args) ...args) - { ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); } - #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - public: - - #define BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL(N) \ - template\ - static void construct(Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ - {\ - container_detail::bool_::value> flag;\ - (priv_construct)(flag, a, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - }\ - // - BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL) - #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL - - private: - - ////////////////// - // priv_construct - ////////////////// - #define BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL(N) \ - template\ - static void priv_construct(container_detail::false_type, Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ - {\ - const bool value = boost::container::container_detail::has_member_function_callable_with_construct\ - < Allocator, T* BOOST_MOVE_I##N BOOST_MOVE_FWD_T##N>::value;\ - container_detail::bool_ flag;\ - (priv_construct_dispatch_next)(flag, a, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - }\ - \ - template\ - static void priv_construct(container_detail::true_type, Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ - { (priv_construct_dispatch_next)(container_detail::false_type(), a, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ - // - BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL) - #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL - - ///////////////////////////////// - // priv_construct_dispatch_next - ///////////////////////////////// - #define BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_DISPATCH_NEXT_IMPL(N) \ - template\ - static void priv_construct_dispatch_next(container_detail::true_type, Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ - { a.construct( p BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); }\ - \ - template\ - static void priv_construct_dispatch_next(container_detail::false_type, Allocator &, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ - { ::new((void*)p, boost_container_new_t()) T(BOOST_MOVE_FWD##N); }\ - // - BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_DISPATCH_NEXT_IMPL) - #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_DISPATCH_NEXT_IMPL - - #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - template - static void priv_construct_dispatch_next(container_detail::false_type, Allocator &, T *p, const ::boost::container::default_init_t&) - { ::new((void*)p) T; } #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - - #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; } //namespace container { diff --git a/test/allocator_traits_test.cpp b/test/allocator_traits_test.cpp index ac6988d..53dd273 100644 --- a/test/allocator_traits_test.cpp +++ b/test/allocator_traits_test.cpp @@ -27,6 +27,9 @@ class SimpleAllocator bool allocate_called_; bool deallocate_called_; + typedef boost::container::container_detail:: + true_type is_always_equal; + typedef T value_type; template @@ -51,15 +54,26 @@ class SimpleAllocator bool deallocate_called() const { return deallocate_called_; } + + friend bool operator==(const SimpleAllocator &, const SimpleAllocator &) + { return true; } + + friend bool operator!=(const SimpleAllocator &, const SimpleAllocator &) + { return false; } }; template class SimpleSmartPtr { + void unspecified_bool_type_func() const {} + typedef void (SimpleSmartPtr::*unspecified_bool_type)() const; + public: - SimpleSmartPtr() - : ptr_(0) + typedef T* pointer; + + explicit SimpleSmartPtr(pointer p = 0) + : ptr_(p) {} SimpleSmartPtr(const SimpleSmartPtr &c) @@ -68,7 +82,8 @@ class SimpleSmartPtr SimpleSmartPtr & operator=(const SimpleSmartPtr &c) { this->ptr_ = c.ptr_; } - typedef T* pointer; + operator unspecified_bool_type() const + { return ptr_? &SimpleSmartPtr::unspecified_bool_type_func : 0; } private: T *ptr_; @@ -85,6 +100,7 @@ class ComplexAllocator mutable bool max_size_called_; mutable bool select_on_container_copy_construction_called_; bool construct_called_; + mutable bool storage_can_be_propagated_; typedef T value_type; typedef SimpleSmartPtr pointer; @@ -104,7 +120,7 @@ class ComplexAllocator typedef boost::container::container_detail:: true_type propagate_on_container_swap; typedef boost::container::container_detail:: - true_type is_always_equal; + true_type is_partially_propagable; ComplexAllocator() : allocate_called_(false) @@ -158,6 +174,9 @@ class ComplexAllocator void construct(U *p, boost::container::default_init_t) { construct_called_ = true; ::new(p)U; } + bool storage_can_be_propagated(pointer p, const ComplexAllocator &, bool) const + { storage_can_be_propagated_ = true; return p ? true : false; } + //getters bool allocate_called() const { return allocate_called_; } @@ -179,6 +198,9 @@ class ComplexAllocator bool construct_called() const { return construct_called_; } + + bool storage_can_be_propagated_called() const + { return storage_can_be_propagated_; } }; class copymovable @@ -250,7 +272,9 @@ int main() BOOST_STATIC_ASSERT(( boost::container::allocator_traits < SimpleAllocator >::propagate_on_container_swap::value == false )); BOOST_STATIC_ASSERT(( boost::container::allocator_traits - < SimpleAllocator >::is_always_equal::value == false )); + < SimpleAllocator >::is_always_equal::value == true )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::is_partially_propagable::value == false )); BOOST_STATIC_ASSERT(( is_same >::rebind_traits::allocator_type , SimpleAllocator >::value )); @@ -280,7 +304,9 @@ int main() BOOST_STATIC_ASSERT(( boost::container::allocator_traits < ComplexAllocator >::propagate_on_container_swap::value == true )); BOOST_STATIC_ASSERT(( boost::container::allocator_traits - < ComplexAllocator >::is_always_equal::value == true )); + < ComplexAllocator >::is_always_equal::value == false )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::is_partially_propagable::value == true )); BOOST_STATIC_ASSERT(( is_same >::rebind_traits::allocator_type , ComplexAllocator >::value )); @@ -396,6 +422,25 @@ int main() SAllocTraits::construct(s_alloc, &c, 0, 1, 2); BOOST_TEST(!c.copymoveconstructed() && !c.moved()); } + //storage_can_be_propagated + { + SAlloc s_alloc2; + BOOST_TEST(SAllocTraits::storage_can_be_propagated(s_alloc, SAllocTraits::pointer(), s_alloc2, true)); + } + { + { + CAlloc c_alloc2; + CAlloc::value_type v; + BOOST_TEST( CAllocTraits::storage_can_be_propagated(c_alloc, CAllocTraits::pointer(&v), c_alloc2, true)); + BOOST_TEST(c_alloc.storage_can_be_propagated_called()); + } + { + CAlloc c_alloc2; + BOOST_TEST(!CAllocTraits::storage_can_be_propagated(c_alloc2, CAllocTraits::pointer(), c_alloc, true)); + BOOST_TEST(c_alloc2.storage_can_be_propagated_called()); + } + + } return ::boost::report_errors(); }