mirror of
https://github.com/boostorg/container.git
synced 2025-08-02 14:04:26 +02:00
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:
@@ -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; }
|
||||||
|
@@ -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{
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user