diff --git a/doc/container.qbk b/doc/container.qbk index b78921e..f8c64ce 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -749,7 +749,8 @@ C++11 further improves stateful allocator support through an allocator writer can customize its behaviour (should the container propagate it in move constructor, swap, etc.?) following `allocator_traits` requirements. [*Boost.Container] not only supports this model with C++11 but also [*backports it to C++03] via -[classref boost::container::allocator_traits boost::container::allocator_traits]. This class +[classref boost::container::allocator_traits boost::container::allocator_traits] including some +C++17 changes. This class offers some workarounds for C++03 compilers to achieve the same allocator guarantees as `std::allocator_traits`. @@ -1084,6 +1085,7 @@ use [*Boost.Container]? There are several reasons for that: * Massive dependency reorganization. Now [*Boost.Container depends on very basic utilities like Boost.Core and [*Boost.Intrusive]. Preprocessed code size have decreased considerably and compilation times have improved. * Added `nth` and `index_of` functions to containers with random-access iterators (except `basic_string`). +* Added C++17's `allocator_traits::is_always_equal`. * Fixed bugs: * [@https://svn.boost.org/trac/boost/ticket/10790 Trac #10790 (['long long errors from container"])]. * [@https://svn.boost.org/trac/boost/ticket/10808 Trac #10808 (['compare equal operator of vector is broken"])]. diff --git a/include/boost/container/allocator_traits.hpp b/include/boost/container/allocator_traits.hpp index 01be0ef..f99d11d 100644 --- a/include/boost/container/allocator_traits.hpp +++ b/include/boost/container/allocator_traits.hpp @@ -26,6 +26,7 @@ // container #include #include +#include //is_empty #include #ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP #include @@ -94,6 +95,7 @@ BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(size_type) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment) 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) } //namespace container_detail { @@ -138,12 +140,15 @@ struct allocator_traits //! Allocator::propagate_on_container_copy_assignment if such a type exists, otherwise a type //! with an internal constant static boolean member value == false. typedef see_documentation propagate_on_container_copy_assignment; - //! Allocator::propagate_on_container_move_assignment if such a type exists, otherwise otherwise a type + //! Allocator::propagate_on_container_move_assignment if such a type exists, otherwise a type //! with an internal constant static boolean member value == false. typedef see_documentation propagate_on_container_move_assignment; - //! Allocator::propagate_on_container_swap if such a type exists, otherwise an otherwise a type + //! Allocator::propagate_on_container_swap if such a type exists, otherwise a type //! with an internal constant static boolean member value == false. typedef see_documentation propagate_on_container_swap; + //! 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; //! 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. @@ -210,7 +215,10 @@ struct allocator_traits typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Allocator, propagate_on_container_swap, container_detail::false_type) propagate_on_container_swap; - + //is_always_equal + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Allocator, + is_always_equal, container_detail::is_empty) + is_always_equal; #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) //C++11 template using rebind_alloc = typename boost::intrusive::pointer_rebind::type; diff --git a/include/boost/container/detail/type_traits.hpp b/include/boost/container/detail/type_traits.hpp index 81de6a7..86b640c 100644 --- a/include/boost/container/detail/type_traits.hpp +++ b/include/boost/container/detail/type_traits.hpp @@ -38,6 +38,7 @@ using ::boost::move_detail::is_floating_point; using ::boost::move_detail::is_integral; using ::boost::move_detail::is_enum; using ::boost::move_detail::is_pod; +using ::boost::move_detail::is_empty; using ::boost::move_detail::is_trivially_destructible; using ::boost::move_detail::is_trivially_default_constructible; using ::boost::move_detail::is_trivially_copy_constructible; diff --git a/include/boost/container/scoped_allocator.hpp b/include/boost/container/scoped_allocator.hpp index dee2b32..2f2470e 100644 --- a/include/boost/container/scoped_allocator.hpp +++ b/include/boost/container/scoped_allocator.hpp @@ -474,6 +474,10 @@ class scoped_allocator_adaptor_base outer_traits_type::propagate_on_container_swap::value || inner_allocator_type::propagate_on_container_swap::value > propagate_on_container_swap; + typedef container_detail::bool_< + outer_traits_type::is_always_equal::value && + inner_allocator_type::is_always_equal::value + > is_always_equal; scoped_allocator_adaptor_base() {} @@ -613,6 +617,11 @@ class scoped_allocator_adaptor_base\ inner_allocator_type::propagate_on_container_swap::value\ > propagate_on_container_swap;\ \ + typedef container_detail::bool_<\ + outer_traits_type::is_always_equal::value &&\ + inner_allocator_type::is_always_equal::value\ + > is_always_equal;\ + \ scoped_allocator_adaptor_base(){}\ \ template \ @@ -746,6 +755,8 @@ class scoped_allocator_adaptor_base< OuterAlloc BOOST_CONTAINER_SCOPEDALLOC_DUMM propagate_on_container_move_assignment propagate_on_container_move_assignment; typedef typename outer_traits_type:: propagate_on_container_swap propagate_on_container_swap; + typedef typename outer_traits_type:: + is_always_equal is_always_equal; scoped_allocator_adaptor_base() {} @@ -913,21 +924,27 @@ class scoped_allocator_adaptor typedef typename outer_traits_type::const_void_pointer const_void_pointer; //! Type: A type with a constant boolean value == true if //!allocator_traits::propagate_on_container_copy_assignment::value is - //! true for any Allocator in the set of OuterAlloc and InnerAllocs...; otherwise, false otherwise. + //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. typedef typename base_type:: propagate_on_container_copy_assignment propagate_on_container_copy_assignment; //! Type: A type with a constant boolean value == true if //!allocator_traits::propagate_on_container_move_assignment::value is - //! true for any Allocator in the set of OuterAlloc and InnerAllocs...; otherwise, false otherwise. + //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. typedef typename base_type:: propagate_on_container_move_assignment propagate_on_container_move_assignment; //! Type: A type with a constant boolean value == true if //!allocator_traits::propagate_on_container_swap::value is - //! true for any Allocator in the set of OuterAlloc and InnerAllocs...; otherwise, false otherwise. + //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. typedef typename base_type:: propagate_on_container_swap propagate_on_container_swap; + //! Type: A type with a constant boolean value == true if + //!allocator_traits::is_always_equal::value is + //! true for all Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. + typedef typename base_type:: + is_always_equal is_always_equal; + //! Type: Rebinds scoped allocator to //! typedef scoped_allocator_adaptor //! < typename outer_traits_type::template portable_rebind_alloc::type diff --git a/test/allocator_traits_test.cpp b/test/allocator_traits_test.cpp index 47a3764..ac6988d 100644 --- a/test/allocator_traits_test.cpp +++ b/test/allocator_traits_test.cpp @@ -103,6 +103,8 @@ class ComplexAllocator true_type propagate_on_container_move_assignment; typedef boost::container::container_detail:: true_type propagate_on_container_swap; + typedef boost::container::container_detail:: + true_type is_always_equal; ComplexAllocator() : allocate_called_(false) @@ -247,6 +249,8 @@ int main() < SimpleAllocator >::propagate_on_container_move_assignment::value == false )); 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 )); BOOST_STATIC_ASSERT(( is_same >::rebind_traits::allocator_type , SimpleAllocator >::value )); @@ -275,6 +279,8 @@ int main() < ComplexAllocator >::propagate_on_container_move_assignment::value == true )); 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 )); BOOST_STATIC_ASSERT(( is_same >::rebind_traits::allocator_type , ComplexAllocator >::value )); diff --git a/test/scoped_allocator_adaptor_test.cpp b/test/scoped_allocator_adaptor_test.cpp index 3d63ed5..04b7f81 100644 --- a/test/scoped_allocator_adaptor_test.cpp +++ b/test/scoped_allocator_adaptor_test.cpp @@ -21,7 +21,7 @@ using namespace boost::container; -template +template class test_allocator { BOOST_COPYABLE_AND_MOVABLE(test_allocator) @@ -30,12 +30,13 @@ class test_allocator template struct rebind { - typedef test_allocator other; + typedef test_allocator other; }; - typedef container_detail::bool_ propagate_on_container_copy_assignment; - typedef container_detail::bool_ propagate_on_container_move_assignment; - typedef container_detail::bool_ propagate_on_container_swap; + typedef container_detail::bool_ propagate_on_container_copy_assignment; + typedef container_detail::bool_ propagate_on_container_move_assignment; + typedef container_detail::bool_ propagate_on_container_swap; + typedef container_detail::bool_ is_always_equal; typedef T value_type; test_allocator() @@ -51,12 +52,12 @@ class test_allocator {} template - test_allocator(BOOST_RV_REF_BEG test_allocator BOOST_RV_REF_END) + test_allocator(BOOST_RV_REF_BEG test_allocator BOOST_RV_REF_END) : m_move_contructed(true), m_move_assigned(false) {} template - test_allocator(const test_allocator &) + test_allocator(const test_allocator &) {} test_allocator & operator=(BOOST_COPY_ASSIGN_REF(test_allocator)) @@ -83,14 +84,14 @@ class test_allocator bool m_move_assigned; }; -template -bool operator==( const test_allocator& - , const test_allocator&) +template +bool operator==( const test_allocator& + , const test_allocator&) { return true; } -template -bool operator!=( const test_allocator& - , const test_allocator&) +template +bool operator!=( const test_allocator& + , const test_allocator&) { return false; } @@ -269,12 +270,12 @@ int main() typedef test_allocator, 2> InnerAlloc2; typedef test_allocator, 11> Inner11IdAlloc1; - typedef test_allocator, 0, false> OuterAllocFalsePropagate; - typedef test_allocator, 0, true> OuterAllocTruePropagate; - typedef test_allocator, 1, false> InnerAlloc1FalsePropagate; - typedef test_allocator, 1, true> InnerAlloc1TruePropagate; - typedef test_allocator, 2, false> InnerAlloc2FalsePropagate; - typedef test_allocator, 2, true> InnerAlloc2TruePropagate; + typedef test_allocator, 0, false> OuterAllocFalseHasTrueTypes; + typedef test_allocator, 0, true> OuterAllocTrueHasTrueTypes; + typedef test_allocator, 1, false> InnerAlloc1FalseHasTrueTypes; + typedef test_allocator, 1, true> InnerAlloc1TrueHasTrueTypes; + typedef test_allocator, 2, false> InnerAlloc2FalseHasTrueTypes; + typedef test_allocator, 2, true> InnerAlloc2TrueHasTrueTypes; // typedef scoped_allocator_adaptor< OuterAlloc > Scoped0Inner; @@ -379,40 +380,40 @@ int main() { //Propagation test - typedef scoped_allocator_adaptor< OuterAllocFalsePropagate > Scoped0InnerF; - typedef scoped_allocator_adaptor< OuterAllocTruePropagate > Scoped0InnerT; - typedef scoped_allocator_adaptor< OuterAllocFalsePropagate - , InnerAlloc1FalsePropagate > Scoped1InnerFF; - typedef scoped_allocator_adaptor< OuterAllocFalsePropagate - , InnerAlloc1TruePropagate > Scoped1InnerFT; - typedef scoped_allocator_adaptor< OuterAllocTruePropagate - , InnerAlloc1FalsePropagate > Scoped1InnerTF; - typedef scoped_allocator_adaptor< OuterAllocTruePropagate - , InnerAlloc1TruePropagate > Scoped1InnerTT; - typedef scoped_allocator_adaptor< OuterAllocFalsePropagate - , InnerAlloc1FalsePropagate - , InnerAlloc2FalsePropagate > Scoped2InnerFFF; - typedef scoped_allocator_adaptor< OuterAllocFalsePropagate - , InnerAlloc1FalsePropagate - , InnerAlloc2TruePropagate > Scoped2InnerFFT; - typedef scoped_allocator_adaptor< OuterAllocFalsePropagate - , InnerAlloc1TruePropagate - , InnerAlloc2FalsePropagate > Scoped2InnerFTF; - typedef scoped_allocator_adaptor< OuterAllocFalsePropagate - , InnerAlloc1TruePropagate - , InnerAlloc2TruePropagate > Scoped2InnerFTT; - typedef scoped_allocator_adaptor< OuterAllocTruePropagate - , InnerAlloc1FalsePropagate - , InnerAlloc2FalsePropagate > Scoped2InnerTFF; - typedef scoped_allocator_adaptor< OuterAllocTruePropagate - , InnerAlloc1FalsePropagate - , InnerAlloc2TruePropagate > Scoped2InnerTFT; - typedef scoped_allocator_adaptor< OuterAllocTruePropagate - , InnerAlloc1TruePropagate - , InnerAlloc2FalsePropagate > Scoped2InnerTTF; - typedef scoped_allocator_adaptor< OuterAllocTruePropagate - , InnerAlloc1TruePropagate - , InnerAlloc2TruePropagate > Scoped2InnerTTT; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes > Scoped0InnerF; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes > Scoped0InnerT; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1FalseHasTrueTypes > Scoped1InnerFF; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1TrueHasTrueTypes > Scoped1InnerFT; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1FalseHasTrueTypes > Scoped1InnerTF; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1TrueHasTrueTypes > Scoped1InnerTT; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1FalseHasTrueTypes + , InnerAlloc2FalseHasTrueTypes > Scoped2InnerFFF; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1FalseHasTrueTypes + , InnerAlloc2TrueHasTrueTypes > Scoped2InnerFFT; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1TrueHasTrueTypes + , InnerAlloc2FalseHasTrueTypes > Scoped2InnerFTF; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1TrueHasTrueTypes + , InnerAlloc2TrueHasTrueTypes > Scoped2InnerFTT; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1FalseHasTrueTypes + , InnerAlloc2FalseHasTrueTypes > Scoped2InnerTFF; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1FalseHasTrueTypes + , InnerAlloc2TrueHasTrueTypes > Scoped2InnerTFT; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1TrueHasTrueTypes + , InnerAlloc2FalseHasTrueTypes > Scoped2InnerTTF; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1TrueHasTrueTypes + , InnerAlloc2TrueHasTrueTypes > Scoped2InnerTTT; //propagate_on_container_copy_assignment //0 inner @@ -470,6 +471,24 @@ int main() BOOST_STATIC_ASSERT(( Scoped2InnerTFT::propagate_on_container_swap::value )); BOOST_STATIC_ASSERT(( Scoped2InnerTTF::propagate_on_container_swap::value )); BOOST_STATIC_ASSERT(( Scoped2InnerTTT::propagate_on_container_swap::value )); + //is_always_equal + //0 inner + BOOST_STATIC_ASSERT(( !Scoped0InnerF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( Scoped0InnerT::is_always_equal::value )); + //1 inner + BOOST_STATIC_ASSERT(( !Scoped1InnerFF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped1InnerFT::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped1InnerTF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerTT::is_always_equal::value )); + //2 inner + BOOST_STATIC_ASSERT(( !Scoped2InnerFFF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerFFT::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerFTF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerFTT::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerTFF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerTFT::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerTTF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTTT::is_always_equal::value )); } //Default constructor