Reenginered partially propagable allocator support in vector. storage_is_unpropagable is now the basic building block, which is simpler and less error-prone.

This commit is contained in:
Ion Gaztañaga
2015-03-01 22:25:27 +01:00
parent d39b1c143c
commit e5f069da2b
4 changed files with 55 additions and 51 deletions

View File

@@ -349,12 +349,12 @@ struct allocator_traits
#endif #endif
#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, //! <b>Returns</b>: <code>a.storage_is_unpropagable(p)</code> if is_partially_propagable::value is true; otherwise,
//! <code>a == to</code>. //! <code>false</code>.
static bool storage_can_be_propagated(const Allocator &a, pointer p, const Allocator &to, bool propagate_a) BOOST_NOEXCEPT_OR_NOTHROW static bool storage_is_unpropagable(const Allocator &a, pointer p) BOOST_NOEXCEPT_OR_NOTHROW
{ {
container_detail::bool_<is_partially_propagable::value> flag; container_detail::bool_<is_partially_propagable::value> flag;
return allocator_traits::priv_storage_can_be_propagated(flag, a, p, to, propagate_a); return allocator_traits::priv_storage_is_unpropagable(flag, a, p);
} }
//! <b>Returns</b>: <code>true</code> if <code>is_always_equal::value == true</code>, otherwise, //! <b>Returns</b>: <code>true</code> if <code>is_always_equal::value == true</code>, otherwise,
@@ -471,11 +471,11 @@ struct allocator_traits
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; }
static bool priv_storage_can_be_propagated(container_detail::true_type, const Allocator &a, pointer p, const Allocator &to, const bool propagate_a) static bool priv_storage_is_unpropagable(container_detail::true_type, const Allocator &a, pointer p)
{ return a.storage_can_be_propagated(p, to, propagate_a); } { return a.storage_is_unpropagable(p); }
static bool priv_storage_can_be_propagated(container_detail::false_type, const Allocator &a, pointer, const Allocator &to, const bool propagate_a) static bool priv_storage_is_unpropagable(container_detail::false_type, const Allocator &, pointer)
{ return allocator_traits::equal(a, to) || propagate_a; } { return false; }
static bool priv_equal(container_detail::true_type, const Allocator &, const Allocator &) static bool priv_equal(container_detail::true_type, const Allocator &, const Allocator &)
{ return true; } { return true; }

View File

@@ -193,11 +193,8 @@ class small_vector_allocator
small_vector_allocator select_on_container_copy_construction() const small_vector_allocator select_on_container_copy_construction() const
{ return small_vector_allocator(allocator_traits_type::select_on_container_copy_construction(this->as_base())); } { return small_vector_allocator(allocator_traits_type::select_on_container_copy_construction(this->as_base())); }
bool storage_can_be_propagated(pointer p, const small_vector_allocator &to, const bool propagate_a) const bool storage_is_unpropagable(pointer p) const
{ { return this->is_internal_storage(p) || allocator_traits_type::storage_is_unpropagable(this->as_base(), p); }
return !this->is_internal_storage(p) &&
allocator_traits_type::storage_can_be_propagated(this->as_base(), p, to.as_base(), propagate_a);
}
//!Swaps two allocators, does nothing //!Swaps two allocators, does nothing
//!because this small_vector_allocator is stateless //!because this small_vector_allocator is stateless
@@ -507,7 +504,7 @@ class small_vector : public small_vector_base<T, Allocator>
private: private:
void move_construct_impl(small_vector &x, const allocator_type &a) void move_construct_impl(small_vector &x, const allocator_type &a)
{ {
if(base_type::is_propagable_from(x, a, true)){ if(base_type::is_propagable_from(x.get_stored_allocator(), x.data(), a, true)){
this->steal_resources(x); this->steal_resources(x);
} }
else{ else{

View File

@@ -278,6 +278,23 @@ struct vector_alloc_holder
typedef typename allocator_traits_type::size_type size_type; typedef typename allocator_traits_type::size_type size_type;
typedef typename allocator_traits_type::value_type value_type; typedef typename allocator_traits_type::value_type value_type;
static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator)
{
(void)propagate_allocator; (void)p; (void)to_alloc; (void)from_alloc;
return (!allocator_traits_type::is_partially_propagable::value ||
!allocator_traits_type::storage_is_unpropagable(from_alloc, p)) &&
(propagate_allocator || allocator_traits_type::equal(from_alloc, to_alloc));
}
static bool are_swap_propagable(const allocator_type &l_a, pointer l_p, const allocator_type &r_a, pointer r_p, bool const propagate_allocator)
{
(void)propagate_allocator; (void)l_p; (void)r_p; (void)l_a; (void)r_a;
return (!allocator_traits_type::is_partially_propagable::value ||
(!allocator_traits_type::storage_is_unpropagable(r_a, r_p) &&
!allocator_traits_type::storage_is_unpropagable(l_a, l_p))
) && (propagate_allocator || allocator_traits_type::equal(l_a, r_a));
}
//Constructor, does not throw //Constructor, does not throw
vector_alloc_holder() vector_alloc_holder()
BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible<Allocator>::value) BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible<Allocator>::value)
@@ -335,7 +352,7 @@ struct vector_alloc_holder
{ {
allocator_type &this_alloc = this->alloc(); allocator_type &this_alloc = this->alloc();
allocator_type &x_alloc = holder.alloc(); allocator_type &x_alloc = holder.alloc();
if(allocator_traits_type::storage_can_be_propagated(x_alloc, holder.start(), this_alloc, true)){ if(this->is_propagable_from(x_alloc, holder.start(), this_alloc, true)){
if(this->m_capacity){ if(this->m_capacity){
this->alloc().deallocate(this->m_start, this->m_capacity); this->alloc().deallocate(this->m_start, this->m_capacity);
} }
@@ -624,8 +641,8 @@ class vector
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
typedef typename container_detail::version<Allocator>::type alloc_version; typedef typename container_detail::version<Allocator>::type alloc_version;
boost::container::container_detail::vector_alloc_holder typedef boost::container::container_detail::vector_alloc_holder<Allocator> alloc_holder_t;
<Allocator> m_holder; alloc_holder_t m_holder;
typedef allocator_traits<Allocator> allocator_traits_type; typedef allocator_traits<Allocator> allocator_traits_type;
template <class U, class UAllocator> template <class U, class UAllocator>
friend class vector; friend class vector;
@@ -635,25 +652,12 @@ class vector
typedef container_detail::vec_iterator<pointer_impl, true > const_iterator_impl; typedef container_detail::vec_iterator<pointer_impl, true > const_iterator_impl;
protected: protected:
static bool is_propagable_from(const vector &x, const Allocator &a, bool const propagate_allocator) static bool is_propagable_from(const Allocator &from_alloc, pointer_impl p, const Allocator &to_alloc, bool const propagate_allocator)
{ { return alloc_holder_t::is_propagable_from(from_alloc, p, to_alloc, propagate_allocator); }
(void)propagate_allocator;
return (allocator_traits_type::is_partially_propagable::value &&
allocator_traits_type::storage_can_be_propagated(x.get_stored_allocator(), x.m_holder.start(), a, propagate_allocator)) ||
(!allocator_traits_type::is_partially_propagable::value && allocator_traits_type::equal(a, x.get_stored_allocator()));
}
static bool are_swap_propagable(const vector &l, const vector &r, bool const propagate_allocator) static bool are_swap_propagable( const Allocator &l_a, pointer_impl l_p
{ , const Allocator &r_a, pointer_impl r_p, bool const propagate_allocator)
(void)propagate_allocator; { return alloc_holder_t::are_swap_propagable(l_a, l_p, r_a, r_p, propagate_allocator); }
const allocator_type &l_a = l.get_stored_allocator();
const allocator_type &r_a = r.get_stored_allocator();
return ( allocator_traits_type::is_partially_propagable::value &&
allocator_traits_type::storage_can_be_propagated(r_a, r.m_holder.start(), l_a, propagate_allocator) &&
allocator_traits_type::storage_can_be_propagated(l_a, l.m_holder.start(), r_a, propagate_allocator)
) ||
( !allocator_traits_type::is_partially_propagable::value && allocator_traits_type::equal(l_a, r_a) );
}
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public: public:
@@ -949,9 +953,11 @@ class vector
//! //!
//! <b>Complexity</b>: Constant if a == x.get_allocator(), linear otherwise. //! <b>Complexity</b>: Constant if a == x.get_allocator(), linear otherwise.
vector(BOOST_RV_REF(vector) x, const allocator_type &a) vector(BOOST_RV_REF(vector) x, const allocator_type &a)
: m_holder(container_detail::uninitialized_size, a, is_propagable_from(x, a, true) ? 0 : x.size()) : m_holder( container_detail::uninitialized_size, a
, is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, true) ? 0 : x.size()
)
{ {
if(is_propagable_from(x, a, true)){ if(is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, true)){
this->m_holder.steal_resources(x.m_holder); this->m_holder.steal_resources(x.m_holder);
} }
else{ else{
@@ -2117,8 +2123,8 @@ class vector
allocator_type &x_alloc = x.m_holder.alloc(); allocator_type &x_alloc = x.m_holder.alloc();
const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value;
const bool is_propagable_from_x = is_propagable_from(x, this_alloc, propagate_alloc); const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc);
const bool is_propagable_from_t = is_propagable_from(*this, x_alloc, propagate_alloc); const bool is_propagable_from_t = is_propagable_from(this_alloc, m_holder.start(), x_alloc, propagate_alloc);
const bool are_both_propagable = is_propagable_from_x && is_propagable_from_t; const bool are_both_propagable = is_propagable_from_x && is_propagable_from_t;
//Resources can be transferred if both allocators are //Resources can be transferred if both allocators are
@@ -2187,7 +2193,8 @@ class vector
void priv_swap(Vector &x, container_detail::false_type) //version_N void priv_swap(Vector &x, container_detail::false_type) //version_N
{ {
const bool propagate_alloc = allocator_traits_type::propagate_on_container_swap::value; const bool propagate_alloc = allocator_traits_type::propagate_on_container_swap::value;
if(are_swap_propagable(*this, x, propagate_alloc)){ if(are_swap_propagable( this->get_stored_allocator(), this->m_holder.start()
, x.get_stored_allocator(), this->m_holder.start(), propagate_alloc)){
//Just swap internals //Just swap internals
this->m_holder.swap_resources(x.m_holder); this->m_holder.swap_resources(x.m_holder);
} }

View File

@@ -100,7 +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_; mutable bool storage_is_unpropagable_;
typedef T value_type; typedef T value_type;
typedef SimpleSmartPtr<T> pointer; typedef SimpleSmartPtr<T> pointer;
@@ -174,8 +174,8 @@ 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 bool storage_is_unpropagable(pointer p) const
{ storage_can_be_propagated_ = true; return p ? true : false; } { storage_is_unpropagable_ = true; return !p; }
//getters //getters
bool allocate_called() const bool allocate_called() const
@@ -199,8 +199,8 @@ class ComplexAllocator
bool construct_called() const bool construct_called() const
{ return construct_called_; } { return construct_called_; }
bool storage_can_be_propagated_called() const bool storage_is_unpropagable_called() const
{ return storage_can_be_propagated_; } { return storage_is_unpropagable_; }
}; };
class copymovable class copymovable
@@ -422,22 +422,22 @@ 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 //storage_is_unpropagable
{ {
SAlloc s_alloc2; SAlloc s_alloc2;
BOOST_TEST(SAllocTraits::storage_can_be_propagated(s_alloc, SAllocTraits::pointer(), s_alloc2, true)); BOOST_TEST(!SAllocTraits::storage_is_unpropagable(s_alloc, SAllocTraits::pointer()));
} }
{ {
{ {
CAlloc c_alloc2; CAlloc c_alloc2;
CAlloc::value_type v; CAlloc::value_type v;
BOOST_TEST( CAllocTraits::storage_can_be_propagated(c_alloc, CAllocTraits::pointer(&v), c_alloc2, true)); BOOST_TEST(!CAllocTraits::storage_is_unpropagable(c_alloc, CAllocTraits::pointer(&v)));
BOOST_TEST(c_alloc.storage_can_be_propagated_called()); BOOST_TEST(c_alloc.storage_is_unpropagable_called());
} }
{ {
CAlloc c_alloc2; CAlloc c_alloc2;
BOOST_TEST(!CAllocTraits::storage_can_be_propagated(c_alloc2, CAllocTraits::pointer(), c_alloc, true)); BOOST_TEST( CAllocTraits::storage_is_unpropagable(c_alloc2, CAllocTraits::pointer()));
BOOST_TEST(c_alloc2.storage_can_be_propagated_called()); BOOST_TEST(c_alloc2.storage_is_unpropagable_called());
} }
} }