Implement storage_can_be_propagated and is_always_equal.

This commit is contained in:
Ion Gaztañaga
2015-02-26 00:25:14 +01:00
parent c2ea5da716
commit 342bd73aeb
2 changed files with 198 additions and 114 deletions

View File

@@ -44,6 +44,8 @@
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#include <boost/move/detail/fwd_macros.hpp> #include <boost/move/detail/fwd_macros.hpp>
#endif #endif
// other boost
#include <boost/static_assert.hpp>
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #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(propagate_on_container_swap)
BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(is_always_equal) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(is_always_equal)
BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(difference_type) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(difference_type)
BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(is_partially_propagable)
} //namespace container_detail { } //namespace container_detail {
@@ -158,6 +161,11 @@ struct allocator_traits
//! Allocator::is_always_equal if such a type exists, otherwise a type //! Allocator::is_always_equal if such a type exists, otherwise a type
//! with an internal constant static boolean member <code>value</code> == is_empty<Allocator>::value //! with an internal constant static boolean member <code>value</code> == is_empty<Allocator>::value
typedef see_documentation is_always_equal; 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 <code>value</code> == false
typedef see_documentation is_partially_propagable;
#endif
//! Defines an allocator: Allocator::rebind<T>::other if such a type exists; otherwise, Allocator<T, Args> //! Defines an allocator: Allocator::rebind<T>::other if such a type exists; otherwise, Allocator<T, Args>
//! if Allocator is a class template instantiation of the form Allocator<U, Args>, where Args is zero or //! if Allocator is a class template instantiation of the form Allocator<U, Args>, where Args is zero or
//! more type arguments ; otherwise, the instantiation of rebind_alloc is ill-formed. //! 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, typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Allocator,
is_always_equal, container_detail::is_empty<Allocator>) is_always_equal, container_detail::is_empty<Allocator>)
is_always_equal; 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) #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
//C++11 //C++11
template <typename T> using rebind_alloc = typename boost::intrusive::pointer_rebind<Allocator, T>::type; template <typename T> using rebind_alloc = typename boost::intrusive::pointer_rebind<Allocator, T>::type;
@@ -256,6 +272,8 @@ struct allocator_traits
: allocator_traits<typename boost::intrusive::pointer_rebind<Allocator, T>::type> : allocator_traits<typename boost::intrusive::pointer_rebind<Allocator, T>::type>
{}; {};
#endif // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) #endif // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
//portable_rebind_alloc
template <class T> template <class T>
struct portable_rebind_alloc struct portable_rebind_alloc
{ typedef typename boost::intrusive::pointer_rebind<Allocator, T>::type type; }; { typedef typename boost::intrusive::pointer_rebind<Allocator, T>::type type; };
@@ -307,16 +325,10 @@ struct allocator_traits
//! <b>Returns</b>: <code>a.select_on_container_copy_construction()</code> if that expression is well-formed; //! <b>Returns</b>: <code>a.select_on_container_copy_construction()</code> if that expression is well-formed;
//! otherwise, a. //! otherwise, a.
static static BOOST_CONTAINER_DOC1ST(Allocator,
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
typename container_detail::if_c typename container_detail::if_c
< allocator_traits_detail::has_select_on_container_copy_construction<Allocator, Allocator (Allocator::*)() const>::value < allocator_traits_detail::has_select_on_container_copy_construction<Allocator BOOST_MOVE_I Allocator (Allocator::*)() const>::value
, Allocator BOOST_MOVE_I Allocator BOOST_MOVE_I const Allocator & >::type)
, const Allocator &
>::type
#else
Allocator
#endif
select_on_container_copy_construction(const Allocator &a) select_on_container_copy_construction(const Allocator &a)
{ {
const bool value = allocator_traits_detail::has_select_on_container_copy_construction const bool value = allocator_traits_detail::has_select_on_container_copy_construction
@@ -335,8 +347,24 @@ struct allocator_traits
allocator_traits::priv_construct(flag, a, p, ::boost::forward<Args>(args)...); allocator_traits::priv_construct(flag, a, p, ::boost::forward<Args>(args)...);
} }
#endif #endif
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Returns</b>: <code>a.storage_can_be_propagated(p, to, propagate_a)</code> if is_partially_propagable::value is true; otherwise,
//! <code>a == to</code>.
static bool storage_can_be_propagated(const Allocator &a, pointer p, const Allocator &to, bool propagate_a) BOOST_NOEXCEPT_OR_NOTHROW
{
container_detail::bool_<is_partially_propagable::value> flag;
return allocator_traits::priv_storage_can_be_propagated(flag, a, p, to, propagate_a);
}
//! <b>Returns</b>: <code>true</code> if <code>is_always_equal::value == true</code>, otherwise,
//! <code>a == b</code>.
static bool equal(const Allocator &a, const Allocator &b) BOOST_NOEXCEPT_OR_NOTHROW
{
container_detail::bool_<is_always_equal::value> flag;
return allocator_traits::priv_equal(flag, a, b);
}
private: private:
static pointer priv_allocate(container_detail::true_type, Allocator &a, size_type n, const_void_pointer p) static pointer priv_allocate(container_detail::true_type, Allocator &a, size_type n, const_void_pointer p)
{ return a.allocate(n, p); } { return a.allocate(n, p); }
@@ -442,9 +470,20 @@ struct allocator_traits
template<class T> template<class T>
static void priv_construct_dispatch_next(container_detail::false_type, Allocator &, T *p, const ::boost::container::default_init_t&) static void priv_construct_dispatch_next(container_detail::false_type, Allocator &, T *p, const ::boost::container::default_init_t&)
{ ::new((void*)p) T; } { ::new((void*)p) T; }
#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 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 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 bool priv_equal(container_detail::true_type, const Allocator &, const Allocator &)
{ return true; }
static bool priv_equal(container_detail::false_type, const Allocator &a, const Allocator &b)
{ return a == b; }
#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
}; };
} //namespace container { } //namespace container {

View File

@@ -27,6 +27,9 @@ class SimpleAllocator
bool allocate_called_; bool allocate_called_;
bool deallocate_called_; bool deallocate_called_;
typedef boost::container::container_detail::
true_type is_always_equal;
typedef T value_type; typedef T value_type;
template <class U> template <class U>
@@ -51,15 +54,26 @@ class SimpleAllocator
bool deallocate_called() const bool deallocate_called() const
{ return deallocate_called_; } { return deallocate_called_; }
friend bool operator==(const SimpleAllocator &, const SimpleAllocator &)
{ return true; }
friend bool operator!=(const SimpleAllocator &, const SimpleAllocator &)
{ return false; }
}; };
template<class T> template<class T>
class SimpleSmartPtr class SimpleSmartPtr
{ {
void unspecified_bool_type_func() const {}
typedef void (SimpleSmartPtr::*unspecified_bool_type)() const;
public: public:
SimpleSmartPtr() typedef T* pointer;
: ptr_(0)
explicit SimpleSmartPtr(pointer p = 0)
: ptr_(p)
{} {}
SimpleSmartPtr(const SimpleSmartPtr &c) SimpleSmartPtr(const SimpleSmartPtr &c)
@@ -68,7 +82,8 @@ class SimpleSmartPtr
SimpleSmartPtr & operator=(const SimpleSmartPtr &c) SimpleSmartPtr & operator=(const SimpleSmartPtr &c)
{ this->ptr_ = c.ptr_; } { this->ptr_ = c.ptr_; }
typedef T* pointer; operator unspecified_bool_type() const
{ return ptr_? &SimpleSmartPtr::unspecified_bool_type_func : 0; }
private: private:
T *ptr_; T *ptr_;
@@ -85,6 +100,7 @@ class ComplexAllocator
mutable bool max_size_called_; mutable bool max_size_called_;
mutable bool select_on_container_copy_construction_called_; mutable bool select_on_container_copy_construction_called_;
bool construct_called_; bool construct_called_;
mutable bool storage_can_be_propagated_;
typedef T value_type; typedef T value_type;
typedef SimpleSmartPtr<T> pointer; typedef SimpleSmartPtr<T> pointer;
@@ -104,7 +120,7 @@ class ComplexAllocator
typedef boost::container::container_detail:: typedef boost::container::container_detail::
true_type propagate_on_container_swap; true_type propagate_on_container_swap;
typedef boost::container::container_detail:: typedef boost::container::container_detail::
true_type is_always_equal; true_type is_partially_propagable;
ComplexAllocator() ComplexAllocator()
: allocate_called_(false) : allocate_called_(false)
@@ -158,6 +174,9 @@ class ComplexAllocator
void construct(U *p, boost::container::default_init_t) void construct(U *p, boost::container::default_init_t)
{ construct_called_ = true; ::new(p)U; } { 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 //getters
bool allocate_called() const bool allocate_called() const
{ return allocate_called_; } { return allocate_called_; }
@@ -179,6 +198,9 @@ class ComplexAllocator
bool construct_called() const bool construct_called() const
{ return construct_called_; } { return construct_called_; }
bool storage_can_be_propagated_called() const
{ return storage_can_be_propagated_; }
}; };
class copymovable class copymovable
@@ -250,7 +272,9 @@ int main()
BOOST_STATIC_ASSERT(( boost::container::allocator_traits BOOST_STATIC_ASSERT(( boost::container::allocator_traits
< SimpleAllocator<int> >::propagate_on_container_swap::value == false )); < SimpleAllocator<int> >::propagate_on_container_swap::value == false ));
BOOST_STATIC_ASSERT(( boost::container::allocator_traits BOOST_STATIC_ASSERT(( boost::container::allocator_traits
< SimpleAllocator<int> >::is_always_equal::value == false )); < SimpleAllocator<int> >::is_always_equal::value == true ));
BOOST_STATIC_ASSERT(( boost::container::allocator_traits
< SimpleAllocator<int> >::is_partially_propagable::value == false ));
BOOST_STATIC_ASSERT(( is_same<boost::container::allocator_traits BOOST_STATIC_ASSERT(( is_same<boost::container::allocator_traits
< SimpleAllocator<int> >::rebind_traits<double>::allocator_type < SimpleAllocator<int> >::rebind_traits<double>::allocator_type
, SimpleAllocator<double> >::value )); , SimpleAllocator<double> >::value ));
@@ -280,7 +304,9 @@ int main()
BOOST_STATIC_ASSERT(( boost::container::allocator_traits BOOST_STATIC_ASSERT(( boost::container::allocator_traits
< ComplexAllocator<int> >::propagate_on_container_swap::value == true )); < ComplexAllocator<int> >::propagate_on_container_swap::value == true ));
BOOST_STATIC_ASSERT(( boost::container::allocator_traits BOOST_STATIC_ASSERT(( boost::container::allocator_traits
< ComplexAllocator<int> >::is_always_equal::value == true )); < ComplexAllocator<int> >::is_always_equal::value == false ));
BOOST_STATIC_ASSERT(( boost::container::allocator_traits
< ComplexAllocator<int> >::is_partially_propagable::value == true ));
BOOST_STATIC_ASSERT(( is_same<boost::container::allocator_traits BOOST_STATIC_ASSERT(( is_same<boost::container::allocator_traits
< ComplexAllocator<int> >::rebind_traits<double>::allocator_type < ComplexAllocator<int> >::rebind_traits<double>::allocator_type
, ComplexAllocator<double> >::value )); , ComplexAllocator<double> >::value ));
@@ -396,6 +422,25 @@ int main()
SAllocTraits::construct(s_alloc, &c, 0, 1, 2); SAllocTraits::construct(s_alloc, &c, 0, 1, 2);
BOOST_TEST(!c.copymoveconstructed() && !c.moved()); 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(); return ::boost::report_errors();
} }