mirror of
https://github.com/boostorg/container.git
synced 2026-01-27 17:52:44 +01:00
Fixes #280 ("Several containers don't support non-movable types when move assigning")
This commit is contained in:
@@ -1318,28 +1318,13 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
|
||||
|| allocator_traits_type::is_always_equal::value)
|
||||
{
|
||||
if (BOOST_LIKELY(this != &x)) {
|
||||
allocator_type &this_alloc = this->alloc();
|
||||
allocator_type &x_alloc = x.alloc();
|
||||
const bool propagate_alloc = allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value;
|
||||
dtl::bool_<propagate_alloc> flag;
|
||||
const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
|
||||
//Resources can be transferred if both allocators are
|
||||
//going to be equal after this function (either propagated or already equal)
|
||||
if(propagate_alloc || allocators_equal){
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
dtl::move_alloc(this_alloc, x_alloc, flag);
|
||||
dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag);
|
||||
//Nothrow swap
|
||||
this->swap_members(x);
|
||||
}
|
||||
//Else do a one by one move
|
||||
else{
|
||||
this->assign( boost::make_move_iterator(x.begin())
|
||||
, boost::make_move_iterator(x.end()));
|
||||
}
|
||||
//We know resources can be transferred at comiple time if both allocators are
|
||||
//always equal or the allocator is going to be propagated
|
||||
const bool can_steal_resources_alloc
|
||||
= allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value;
|
||||
dtl::bool_<can_steal_resources_alloc> flag;
|
||||
this->priv_move_assign(boost::move(x), flag);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -2378,6 +2363,30 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
private:
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_<true> /*steal_resources*/)
|
||||
{
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
dtl::bool_<allocator_traits_type::propagate_on_container_move_assignment::value> flag;
|
||||
dtl::move_alloc(this->alloc(), x.alloc(), flag);
|
||||
dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag);
|
||||
//Nothrow swap
|
||||
this->swap_members(x);
|
||||
}
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_<false> /*steal_resources*/)
|
||||
{
|
||||
//We can't guarantee a compile-time equal allocator or propagation so fallback to runtime
|
||||
//Resources can be transferred if both allocators are equal
|
||||
if (this->alloc() == x.alloc()) {
|
||||
this->priv_move_assign(boost::move(x), dtl::true_());
|
||||
}
|
||||
else {
|
||||
this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end()));
|
||||
}
|
||||
}
|
||||
|
||||
inline size_type priv_index_of(const_iterator p) const
|
||||
{
|
||||
BOOST_ASSERT(this->cbegin() <= p);
|
||||
@@ -2493,7 +2502,8 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
|
||||
|
||||
void priv_destroy_range(iterator p, iterator p2)
|
||||
{
|
||||
if(!Base::traits_t::trivial_dctr){
|
||||
(void)p; (void)p2;
|
||||
BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){
|
||||
for(;p != p2; ++p){
|
||||
allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p));
|
||||
}
|
||||
@@ -2502,7 +2512,8 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
|
||||
|
||||
void priv_destroy_range(pointer p, pointer p2)
|
||||
{
|
||||
if(!Base::traits_t::trivial_dctr){
|
||||
(void)p; (void)p2;
|
||||
BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){
|
||||
for(;p != p2; ++p){
|
||||
allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p));
|
||||
}
|
||||
|
||||
@@ -688,40 +688,13 @@ class tree
|
||||
boost::container::dtl::is_nothrow_move_assignable<Compare>::value)
|
||||
{
|
||||
if (BOOST_LIKELY(this != &x)) {
|
||||
NodeAlloc &this_alloc = this->node_alloc();
|
||||
NodeAlloc &x_alloc = x.node_alloc();
|
||||
const bool propagate_alloc = allocator_traits<NodeAlloc>::
|
||||
propagate_on_container_move_assignment::value;
|
||||
const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
|
||||
//Resources can be transferred if both allocators are
|
||||
//going to be equal after this function (either propagated or already equal)
|
||||
if(propagate_alloc || allocators_equal){
|
||||
//Destroy
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
this->AllocHolder::move_assign_alloc(x);
|
||||
//Obtain resources
|
||||
this->icont() = boost::move(x.icont());
|
||||
}
|
||||
//Else do a one by one move
|
||||
else{
|
||||
//Transfer all the nodes to a temporary tree
|
||||
//If anything goes wrong, all the nodes will be destroyed
|
||||
//automatically
|
||||
Icont other_tree(::boost::move(this->icont()));
|
||||
|
||||
//Now recreate the source tree reusing nodes stored by other_tree
|
||||
this->icont().clone_from
|
||||
(::boost::move(x.icont())
|
||||
, RecyclingCloner<AllocHolder, true>(*this, other_tree)
|
||||
, Destroyer(this->node_alloc()));
|
||||
|
||||
//If there are remaining nodes, destroy them
|
||||
NodePtr p;
|
||||
while((p = other_tree.unlink_leftmost_without_rebalance())){
|
||||
AllocHolder::destroy_node(p);
|
||||
}
|
||||
}
|
||||
//We know resources can be transferred at comiple time if both allocators are
|
||||
//always equal or the allocator is going to be propagated
|
||||
const bool can_steal_resources_alloc
|
||||
= allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value;
|
||||
dtl::bool_<can_steal_resources_alloc> flag;
|
||||
this->priv_move_assign(boost::move(x), flag);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -895,6 +868,42 @@ class tree
|
||||
|
||||
|
||||
private:
|
||||
void priv_move_assign(BOOST_RV_REF(tree) x, dtl::bool_<true> /*steal_resources*/)
|
||||
{
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
this->AllocHolder::move_assign_alloc(x);
|
||||
//Obtain resources
|
||||
this->icont() = boost::move(x.icont());
|
||||
}
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(tree) x, dtl::bool_<false> /*steal_resources*/)
|
||||
{
|
||||
//We can't guarantee a compile-time equal allocator or propagation so fallback to runtime
|
||||
//Resources can be transferred if both allocators are equal
|
||||
if (this->node_alloc() == x.node_alloc()) {
|
||||
this->priv_move_assign(boost::move(x), dtl::true_());
|
||||
}
|
||||
else {
|
||||
//Transfer all the nodes to a temporary tree
|
||||
//If anything goes wrong, all the nodes will be destroyed
|
||||
//automatically
|
||||
Icont other_tree(::boost::move(this->icont()));
|
||||
|
||||
//Now recreate the source tree reusing nodes stored by other_tree
|
||||
this->icont().clone_from
|
||||
(::boost::move(x.icont())
|
||||
, RecyclingCloner<AllocHolder, true>(*this, other_tree)
|
||||
, Destroyer(this->node_alloc()));
|
||||
|
||||
//If there are remaining nodes, destroy them
|
||||
NodePtr p;
|
||||
while ((p = other_tree.unlink_leftmost_without_rebalance())) {
|
||||
AllocHolder::destroy_node(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class KeyConvertible, class M>
|
||||
iiterator priv_insert_or_assign_commit
|
||||
|
||||
@@ -512,20 +512,21 @@ class devector
|
||||
const devector &x = rhs;
|
||||
if (this == &x) { return *this; } // skip self
|
||||
|
||||
BOOST_IF_CONSTEXPR(allocator_traits_type::propagate_on_container_copy_assignment::value)
|
||||
const bool do_propagate = allocator_traits_type::propagate_on_container_copy_assignment::value;
|
||||
BOOST_IF_CONSTEXPR(do_propagate)
|
||||
{
|
||||
allocator_type &this_alloc = this->get_allocator_ref();
|
||||
const allocator_type &other_alloc = x.get_allocator_ref();
|
||||
if (this_alloc != other_alloc)
|
||||
{
|
||||
// new allocator cannot free existing storage
|
||||
this->clear();
|
||||
this->deallocate_buffer();
|
||||
m_.capacity = 0u;
|
||||
m_.buffer = pointer();
|
||||
}
|
||||
|
||||
this_alloc = other_alloc;
|
||||
allocator_type &this_alloc = this->get_allocator_ref();
|
||||
const allocator_type &other_alloc = x.get_allocator_ref();
|
||||
if (this_alloc != other_alloc)
|
||||
{
|
||||
// new allocator cannot free existing storage
|
||||
this->clear();
|
||||
this->deallocate_buffer();
|
||||
m_.capacity = 0u;
|
||||
m_.buffer = pointer();
|
||||
}
|
||||
dtl::bool_<do_propagate> flag;
|
||||
dtl::assign_alloc(this_alloc, other_alloc, flag);
|
||||
}
|
||||
|
||||
size_type n = x.size();
|
||||
@@ -565,53 +566,16 @@ class devector
|
||||
BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value)
|
||||
{
|
||||
BOOST_CONSTEXPR_OR_CONST bool copy_alloc = allocator_traits_type::propagate_on_container_move_assignment::value;
|
||||
|
||||
BOOST_IF_CONSTEXPR (copy_alloc || get_allocator_ref() == x.get_allocator_ref())
|
||||
{
|
||||
this->clear();
|
||||
this->deallocate_buffer();
|
||||
|
||||
if (copy_alloc)
|
||||
{
|
||||
this->get_allocator_ref() = boost::move(x.get_allocator_ref());
|
||||
}
|
||||
|
||||
m_.capacity = x.m_.capacity;
|
||||
m_.buffer = x.m_.buffer;
|
||||
m_.front_idx = x.m_.front_idx;
|
||||
m_.back_idx = x.m_.back_idx;
|
||||
|
||||
// leave x in valid state
|
||||
x.m_.capacity = 0u;
|
||||
x.m_.buffer = pointer();
|
||||
x.m_.back_idx = x.m_.front_idx = 0;
|
||||
if (BOOST_LIKELY(this != &x)) {
|
||||
//We know resources can be transferred at comiple time if both allocators are
|
||||
//always equal or the allocator is going to be propagated
|
||||
const bool can_steal_resources_alloc
|
||||
= allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value;
|
||||
dtl::bool_<can_steal_resources_alloc> flag;
|
||||
this->priv_move_assign(boost::move(x), flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the allocator shouldn't be copied and they do not compare equal
|
||||
// we can't steal memory.
|
||||
|
||||
move_iterator<iterator> xbegin = boost::make_move_iterator(x.begin());
|
||||
move_iterator<iterator> xend = boost::make_move_iterator(x.end());
|
||||
|
||||
if (copy_alloc)
|
||||
{
|
||||
get_allocator_ref() = boost::move(x.get_allocator_ref());
|
||||
}
|
||||
|
||||
if (m_.capacity >= x.size())
|
||||
{
|
||||
overwrite_buffer(xbegin, xend);
|
||||
}
|
||||
else
|
||||
{
|
||||
allocate_and_copy_range(xbegin, xend);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(invariants_ok());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1309,6 +1273,78 @@ class devector
|
||||
return m_.buffer[m_.front_idx + n];
|
||||
}
|
||||
|
||||
//! <b>Requires</b>: size() >= n.
|
||||
//!
|
||||
//! <b>Effects</b>: Returns an iterator to the nth element
|
||||
//! from the beginning of the container. Returns end()
|
||||
//! if n == size().
|
||||
//!
|
||||
//! <b>Throws</b>: Nothing.
|
||||
//!
|
||||
//! <b>Complexity</b>: Constant.
|
||||
//!
|
||||
//! <b>Note</b>: Non-standard extension
|
||||
BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline
|
||||
iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
BOOST_ASSERT(n <= size());
|
||||
return iterator(m_.buffer + (m_.front_idx + n));
|
||||
}
|
||||
|
||||
//! <b>Requires</b>: size() >= n.
|
||||
//!
|
||||
//! <b>Effects</b>: Returns a const_iterator to the nth element
|
||||
//! from the beginning of the container. Returns end()
|
||||
//! if n == size().
|
||||
//!
|
||||
//! <b>Throws</b>: Nothing.
|
||||
//!
|
||||
//! <b>Complexity</b>: Constant.
|
||||
//!
|
||||
//! <b>Note</b>: Non-standard extension
|
||||
BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline
|
||||
const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
BOOST_ASSERT(n <= size());
|
||||
return const_iterator(m_.buffer + (m_.front_idx + n));
|
||||
}
|
||||
|
||||
//! <b>Requires</b>: begin() <= p <= end().
|
||||
//!
|
||||
//! <b>Effects</b>: Returns the index of the element pointed by p
|
||||
//! and size() if p == end().
|
||||
//!
|
||||
//! <b>Throws</b>: Nothing.
|
||||
//!
|
||||
//! <b>Complexity</b>: Constant.
|
||||
//!
|
||||
//! <b>Note</b>: Non-standard extension
|
||||
BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline
|
||||
size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
BOOST_ASSERT(p >= begin());
|
||||
BOOST_ASSERT(p <= end());
|
||||
return static_cast<size_type>(p - this->begin());
|
||||
}
|
||||
|
||||
//! <b>Requires</b>: begin() <= p <= end().
|
||||
//!
|
||||
//! <b>Effects</b>: Returns the index of the element pointed by p
|
||||
//! and size() if p == end().
|
||||
//!
|
||||
//! <b>Throws</b>: Nothing.
|
||||
//!
|
||||
//! <b>Complexity</b>: Constant.
|
||||
//!
|
||||
//! <b>Note</b>: Non-standard extension
|
||||
BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline
|
||||
size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
BOOST_ASSERT(p >= cbegin());
|
||||
BOOST_ASSERT(p <= cend());
|
||||
return static_cast<size_type>(p - this->cbegin());
|
||||
}
|
||||
|
||||
/**
|
||||
* **Returns**: A reference to the `n`th element in the devector.
|
||||
*
|
||||
@@ -2136,6 +2172,53 @@ class devector
|
||||
|
||||
private:
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(devector) x, dtl::bool_<true> /*steal_resources*/)
|
||||
{
|
||||
this->clear();
|
||||
this->deallocate_buffer();
|
||||
|
||||
//Move allocator if needed
|
||||
dtl::bool_<allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value> flag;
|
||||
dtl::move_alloc(this->get_allocator_ref(), x.get_allocator_ref(), flag);
|
||||
|
||||
m_.capacity = x.m_.capacity;
|
||||
m_.buffer = x.m_.buffer;
|
||||
m_.front_idx = x.m_.front_idx;
|
||||
m_.back_idx = x.m_.back_idx;
|
||||
|
||||
// leave x in valid state
|
||||
x.m_.capacity = 0u;
|
||||
x.m_.buffer = pointer();
|
||||
x.m_.back_idx = x.m_.front_idx = 0;
|
||||
}
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(devector) x, dtl::bool_<false> /*steal_resources*/)
|
||||
{
|
||||
//We can't guarantee a compile-time equal allocator or propagation so fallback to runtime
|
||||
//Resources can be transferred if both allocators are equal
|
||||
if (get_allocator_ref() == x.get_allocator_ref()) {
|
||||
this->priv_move_assign(boost::move(x), dtl::true_());
|
||||
}
|
||||
else {
|
||||
// We can't steal memory.
|
||||
move_iterator<iterator> xbegin = boost::make_move_iterator(x.begin());
|
||||
move_iterator<iterator> xend = boost::make_move_iterator(x.end());
|
||||
|
||||
//Move allocator if needed
|
||||
dtl::bool_<allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value> flag;
|
||||
dtl::move_alloc(this->get_allocator_ref(), x.get_allocator_ref(), flag);
|
||||
|
||||
if (m_.capacity >= x.size()) {
|
||||
overwrite_buffer(xbegin, xend);
|
||||
}
|
||||
else {
|
||||
allocate_and_copy_range(xbegin, xend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline
|
||||
size_type pos_to_index(const_iterator i) const
|
||||
{
|
||||
|
||||
@@ -343,26 +343,13 @@ class list
|
||||
|| allocator_traits_type::is_always_equal::value)
|
||||
{
|
||||
if (BOOST_LIKELY(this != &x)) {
|
||||
NodeAlloc &this_alloc = this->node_alloc();
|
||||
NodeAlloc &x_alloc = x.node_alloc();
|
||||
const bool propagate_alloc = allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value;
|
||||
const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
|
||||
//Resources can be transferred if both allocators are
|
||||
//going to be equal after this function (either propagated or already equal)
|
||||
if(propagate_alloc || allocators_equal){
|
||||
//Destroy
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
this->AllocHolder::move_assign_alloc(x);
|
||||
//Obtain resources
|
||||
this->icont() = boost::move(x.icont());
|
||||
}
|
||||
//Else do a one by one move
|
||||
else{
|
||||
this->assign( boost::make_move_iterator(x.begin())
|
||||
, boost::make_move_iterator(x.end()));
|
||||
}
|
||||
//We know resources can be transferred at comiple time if both allocators are
|
||||
//always equal or the allocator is going to be propagated
|
||||
const bool can_steal_resources_alloc
|
||||
= allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value;
|
||||
dtl::bool_<can_steal_resources_alloc> flag;
|
||||
this->priv_move_assign(boost::move(x), flag);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -1391,6 +1378,28 @@ class list
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
private:
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(list) x, dtl::bool_<true> /*steal_resources*/)
|
||||
{
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
this->AllocHolder::move_assign_alloc(x);
|
||||
//Obtain resources
|
||||
this->icont() = boost::move(x.icont());
|
||||
}
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(list) x, dtl::bool_<false> /*steal_resources*/)
|
||||
{
|
||||
//We can't guarantee a compile-time equal allocator or propagation so fallback to runtime
|
||||
//Resources can be transferred if both allocators are equal
|
||||
if (this->node_alloc() == x.node_alloc()) {
|
||||
this->priv_move_assign(boost::move(x), dtl::true_());
|
||||
}
|
||||
else {
|
||||
this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end()));
|
||||
}
|
||||
}
|
||||
|
||||
static bool priv_is_linked(const_iterator const position)
|
||||
{
|
||||
const_iterator cur(position);
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP
|
||||
#define BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP
|
||||
#ifndef BOOST_CONTAINER_NODE_ALLOCATOR_HPP
|
||||
#define BOOST_CONTAINER_NODE_ALLOCATOR_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <boost/container/detail/node_pool.hpp>
|
||||
#include <boost/container/detail/mpl.hpp>
|
||||
#include <boost/container/detail/multiallocation_chain.hpp>
|
||||
#include <boost/move/detail/iterator_to_raw_pointer.hpp>
|
||||
#include <boost/container/detail/dlmalloc.hpp>
|
||||
#include <boost/container/detail/singleton.hpp>
|
||||
|
||||
@@ -225,7 +226,10 @@ class node_allocator
|
||||
typedef dtl::singleton_default<shared_pool_t> singleton_t;
|
||||
typename shared_pool_t::multiallocation_chain ch;
|
||||
singleton_t::instance().allocate_nodes(num_elements, ch);
|
||||
chain.incorporate_after(chain.before_begin(), (T*)&*ch.begin(), (T*)&*ch.last(), ch.size());
|
||||
chain.incorporate_after(chain.before_begin()
|
||||
, (T*)boost::movelib::iterator_to_raw_pointer(ch.begin())
|
||||
, (T*)boost::movelib::iterator_to_raw_pointer(ch.last())
|
||||
, ch.size());
|
||||
}
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
@@ -246,7 +250,10 @@ class node_allocator
|
||||
typedef dtl::shared_node_pool
|
||||
<sizeof(T), NodesPerBlock> shared_pool_t;
|
||||
typedef dtl::singleton_default<shared_pool_t> singleton_t;
|
||||
typename shared_pool_t::multiallocation_chain ch(&*chain.begin(), &*chain.last(), chain.size());
|
||||
typename shared_pool_t::multiallocation_chain ch
|
||||
( boost::movelib::iterator_to_raw_pointer(chain.begin())
|
||||
, boost::movelib::iterator_to_raw_pointer(chain.last())
|
||||
, chain.size());
|
||||
singleton_t::instance().deallocate_nodes(ch);
|
||||
}
|
||||
|
||||
@@ -285,8 +292,8 @@ class node_allocator
|
||||
void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
BOOST_CONTAINER_STATIC_ASSERT(( Version > 1 ));
|
||||
void *first = &*chain.begin();
|
||||
void *last = &*chain.last();
|
||||
void *first = boost::movelib::iterator_to_raw_pointer(chain.begin());
|
||||
void *last = boost::movelib::iterator_to_raw_pointer(chain.last());
|
||||
size_t num = chain.size();
|
||||
dlmalloc_memchain ch;
|
||||
BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, first, last, num);
|
||||
@@ -337,4 +344,4 @@ class node_allocator
|
||||
|
||||
#include <boost/container/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP
|
||||
#endif //#ifndef BOOST_CONTAINER_NODE_ALLOCATOR_HPP
|
||||
|
||||
@@ -232,7 +232,7 @@ class node_handle
|
||||
if(was_nh_non_null){
|
||||
if(was_this_non_null){
|
||||
this->destroy_deallocate_node();
|
||||
if(nator_traits::propagate_on_container_move_assignment::value){
|
||||
BOOST_IF_CONSTEXPR(nator_traits::propagate_on_container_move_assignment::value){
|
||||
this->node_alloc() = ::boost::move(nh.node_alloc());
|
||||
}
|
||||
}
|
||||
@@ -336,7 +336,7 @@ class node_handle
|
||||
|
||||
if(was_nh_non_null){
|
||||
if(was_this_non_null){
|
||||
if(nator_traits::propagate_on_container_swap::value){
|
||||
BOOST_IF_CONSTEXPR(nator_traits::propagate_on_container_swap::value){
|
||||
::boost::adl_move_swap(this->node_alloc(), nh.node_alloc());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,28 +368,14 @@ class slist
|
||||
BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value)
|
||||
{
|
||||
slist & sr = x;
|
||||
if (BOOST_LIKELY(this != &sr)) {
|
||||
NodeAlloc &this_alloc = this->node_alloc();
|
||||
NodeAlloc &x_alloc = sr.node_alloc();
|
||||
const bool propagate_alloc = allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value;
|
||||
const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
|
||||
//Resources can be transferred if both allocators are
|
||||
//going to be equal after this function (either propagated or already equal)
|
||||
if(propagate_alloc || allocators_equal){
|
||||
//Destroy
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
this->AllocHolder::move_assign_alloc(sr);
|
||||
//Obtain resources
|
||||
this->icont() = boost::move(sr.icont());
|
||||
}
|
||||
//Else do a one by one move
|
||||
else{
|
||||
this->assign( boost::make_move_iterator(sr.begin())
|
||||
, boost::make_move_iterator(sr.end()));
|
||||
}
|
||||
if (BOOST_LIKELY(this != &x)) {
|
||||
//We know resources can be transferred at comiple time if both allocators are
|
||||
//always equal or the allocator is going to be propagated
|
||||
const bool can_steal_resources_alloc
|
||||
= allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value;
|
||||
dtl::bool_<can_steal_resources_alloc> flag;
|
||||
this->priv_move_assign(boost::move(x), flag);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -1579,6 +1565,27 @@ class slist
|
||||
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
private:
|
||||
void priv_move_assign(BOOST_RV_REF(slist) x, dtl::bool_<true> /*steal_resources*/)
|
||||
{
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
this->AllocHolder::move_assign_alloc(x);
|
||||
//Obtain resources
|
||||
this->icont() = boost::move(x.icont());
|
||||
}
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(slist) x, dtl::bool_<false> /*steal_resources*/)
|
||||
{
|
||||
//We can't guarantee a compile-time equal allocator or propagation so fallback to runtime
|
||||
//Resources can be transferred if both allocators are equal
|
||||
if (this->node_alloc() == x.node_alloc()) {
|
||||
this->priv_move_assign(boost::move(x), dtl::true_());
|
||||
}
|
||||
else {
|
||||
this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end()));
|
||||
}
|
||||
}
|
||||
|
||||
template<class U>
|
||||
void priv_push_front(BOOST_FWD_REF(U) x)
|
||||
|
||||
@@ -346,9 +346,10 @@ class small_vector_base
|
||||
public:
|
||||
//Make it public as it will be inherited by small_vector and container
|
||||
//must have this public member
|
||||
typedef typename real_allocator<T, SecAlloc>::type allocator_type;
|
||||
typedef typename allocator_traits<allocator_type>::
|
||||
template portable_rebind_alloc<void>::type void_allocator_t;
|
||||
typedef typename real_allocator<T, SecAlloc>::type underlying_allocator_t;
|
||||
typedef typename allocator_traits<underlying_allocator_t>::
|
||||
template portable_rebind_alloc<void>::type void_underlying_allocator_t;
|
||||
typedef small_vector_allocator<T, void_underlying_allocator_t, Options>allocator_type;
|
||||
typedef typename dtl::get_small_vector_opt<Options>::type options_t;
|
||||
typedef typename dtl::vector_for_small_vector
|
||||
<T, SecAlloc, Options>::type base_type;
|
||||
@@ -356,12 +357,12 @@ class small_vector_base
|
||||
typedef typename allocator_traits<allocator_type>::const_pointer const_pointer;
|
||||
typedef typename allocator_traits<allocator_type>::void_pointer void_pointer;
|
||||
typedef typename allocator_traits<allocator_type>::const_void_pointer const_void_pointer;
|
||||
typedef small_vector_allocator<T, void_allocator_t, Options> small_allocator_type;
|
||||
|
||||
|
||||
private:
|
||||
BOOST_COPYABLE_AND_MOVABLE(small_vector_base)
|
||||
|
||||
friend class small_vector_allocator<T, void_allocator_t, Options>;
|
||||
friend class small_vector_allocator<T, void_underlying_allocator_t, Options>;
|
||||
|
||||
inline
|
||||
const_pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
|
||||
@@ -872,31 +872,14 @@ class stable_vector
|
||||
BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value)
|
||||
{
|
||||
//for move constructor, no aliasing (&x != this) is assumed.
|
||||
if (BOOST_LIKELY(this != &x)) {
|
||||
node_allocator_type &this_alloc = this->priv_node_alloc();
|
||||
node_allocator_type &x_alloc = x.priv_node_alloc();
|
||||
const bool propagate_alloc = allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value;
|
||||
dtl::bool_<propagate_alloc> flag;
|
||||
const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
|
||||
//Resources can be transferred if both allocators are
|
||||
//going to be equal after this function (either propagated or already equal)
|
||||
if(propagate_alloc || allocators_equal){
|
||||
BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
dtl::move_alloc(this_alloc, x_alloc, flag);
|
||||
//Take resources
|
||||
this->index.swap(x.index);
|
||||
this->priv_swap_members(x);
|
||||
}
|
||||
//Else do a one by one move
|
||||
else{
|
||||
this->assign( boost::make_move_iterator(x.begin())
|
||||
, boost::make_move_iterator(x.end()));
|
||||
}
|
||||
//We know resources can be transferred at comiple time if both allocators are
|
||||
//always equal or the allocator is going to be propagated
|
||||
const bool can_steal_resources_alloc
|
||||
= allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value;
|
||||
dtl::bool_<can_steal_resources_alloc> flag;
|
||||
this->priv_move_assign(boost::move(x), flag);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -1852,6 +1835,35 @@ class stable_vector
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
private:
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(stable_vector) x, dtl::bool_<true> /*steal_resources*/)
|
||||
{
|
||||
//Resources can be transferred if both allocators are
|
||||
//going to be equal after this function (either propagated or already equal)
|
||||
BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
dtl::bool_<allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value> flag;
|
||||
dtl::move_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag);
|
||||
|
||||
//Take resources
|
||||
this->index = boost::move(x.index); //this also moves the vector's allocator if needed
|
||||
this->priv_swap_members(x);
|
||||
}
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(stable_vector) x, dtl::bool_<false> /*steal_resources*/)
|
||||
{
|
||||
//We can't guarantee a compile-time equal allocator or propagation so fallback to runtime
|
||||
//Resources can be transferred if both allocators are equal
|
||||
if (this->priv_node_alloc() == x.priv_node_alloc()) {
|
||||
this->priv_move_assign(boost::move(x), dtl::true_());
|
||||
}
|
||||
else {
|
||||
this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end()));
|
||||
}
|
||||
}
|
||||
|
||||
bool priv_in_range(const_iterator pos) const
|
||||
{
|
||||
return (this->begin() <= pos) && (pos < this->end());
|
||||
|
||||
@@ -913,26 +913,13 @@ class basic_string
|
||||
|| allocator_traits_type::is_always_equal::value)
|
||||
{
|
||||
if (BOOST_LIKELY(this != &x)) {
|
||||
allocator_type &this_alloc = this->alloc();
|
||||
allocator_type &x_alloc = x.alloc();
|
||||
const bool propagate_alloc = allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value;
|
||||
dtl::bool_<propagate_alloc> flag;
|
||||
const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
|
||||
//Resources can be transferred if both allocators are
|
||||
//going to be equal after this function (either propagated or already equal)
|
||||
if(propagate_alloc || allocators_equal){
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
dtl::move_alloc(this_alloc, x_alloc, flag);
|
||||
//Nothrow swap
|
||||
this->swap_data(x);
|
||||
}
|
||||
//Else do a one by one move
|
||||
else{
|
||||
this->assign( x.begin(), x.end());
|
||||
}
|
||||
//We know resources can be transferred at comiple time if both allocators are
|
||||
//always equal or the allocator is going to be propagated
|
||||
const bool can_steal_resources_alloc
|
||||
= allocator_traits_type::propagate_on_container_move_assignment::value
|
||||
|| allocator_traits_type::is_always_equal::value;
|
||||
dtl::bool_<can_steal_resources_alloc> flag;
|
||||
this->priv_move_assign(boost::move(x), flag);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -2908,6 +2895,30 @@ class basic_string
|
||||
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
private:
|
||||
void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_<true> /*steal_resources*/)
|
||||
{
|
||||
//Destroy objects but retain memory in case x reuses it in the future
|
||||
this->clear();
|
||||
//Move allocator if needed
|
||||
dtl::bool_<allocator_traits_type::
|
||||
propagate_on_container_move_assignment::value> flag;
|
||||
dtl::move_alloc(this->alloc(), x.alloc(), flag);
|
||||
//Nothrow swap
|
||||
this->swap_data(x);
|
||||
}
|
||||
|
||||
void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_<false> /*steal_resources*/)
|
||||
{
|
||||
//We can't guarantee a compile-time equal allocator or propagation so fallback to runtime
|
||||
//Resources can be transferred if both allocators are equal
|
||||
if (this->alloc() == x.alloc()) {
|
||||
this->priv_move_assign(boost::move(x), dtl::true_());
|
||||
}
|
||||
else {
|
||||
this->assign(x.begin(), x.end());
|
||||
}
|
||||
}
|
||||
|
||||
bool priv_reserve_no_null_end(size_type res_arg)
|
||||
{
|
||||
if (res_arg > this->max_size()){
|
||||
|
||||
@@ -2531,6 +2531,38 @@ private:
|
||||
x.clear();
|
||||
}
|
||||
|
||||
template<class OtherA>
|
||||
void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x, dtl::true_type /*data_can_be_always_stolen*/)
|
||||
{
|
||||
this->clear();
|
||||
if (BOOST_LIKELY(!!this->m_holder.m_start))
|
||||
this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity);
|
||||
this->m_holder.steal_resources(x.m_holder);
|
||||
}
|
||||
|
||||
template<class OtherA>
|
||||
void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x, dtl::false_type /*data_can_be_always_stolen*/)
|
||||
{
|
||||
const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value;
|
||||
allocator_type& this_alloc = this->m_holder.alloc();
|
||||
allocator_type& x_alloc = x.m_holder.alloc();
|
||||
|
||||
//In this allocator move constructor the allocator might will be propagated, but to support small_vector-like
|
||||
//types, we need to check the currently owned buffers to know if they are propagable.
|
||||
const bool is_buffer_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc);
|
||||
|
||||
if (is_buffer_propagable_from_x) {
|
||||
this->priv_move_assign_steal_or_assign(boost::move(x), dtl::true_type());
|
||||
}
|
||||
//Else do a one by one move. Also, clear the source as users find confusing
|
||||
//elements are still alive in the source container.
|
||||
else {
|
||||
this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin()))
|
||||
, boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end())) );
|
||||
x.clear();
|
||||
}
|
||||
}
|
||||
|
||||
template<class OtherA>
|
||||
void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x
|
||||
, typename dtl::disable_if_or
|
||||
@@ -2542,30 +2574,16 @@ private:
|
||||
//for move assignment, no aliasing (&x != this) is assumed.
|
||||
//x.size() == 0 is allowed for buggy std libraries.
|
||||
BOOST_ASSERT(this != &x || x.size() == 0);
|
||||
allocator_type &this_alloc = this->m_holder.alloc();
|
||||
allocator_type &x_alloc = x.m_holder.alloc();
|
||||
const bool alloc_is_always_equal = allocator_traits_type::is_always_equal::value;
|
||||
const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value;
|
||||
const bool partially_propagable_alloc = allocator_traits_type::is_partially_propagable::value;
|
||||
const bool data_can_be_always_be_stolen = alloc_is_always_equal || (propagate_alloc && !partially_propagable_alloc);
|
||||
|
||||
//In this allocator move constructor the allocator maybe will be propagated -----------------------v
|
||||
const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc);
|
||||
this->priv_move_assign_steal_or_assign(boost::move(x), dtl::bool_<data_can_be_always_be_stolen>());
|
||||
|
||||
//Resources can be transferred if both allocators are
|
||||
//going to be equal after this function (either propagated or already equal)
|
||||
if(is_propagable_from_x){
|
||||
this->clear();
|
||||
if(BOOST_LIKELY(!!this->m_holder.m_start))
|
||||
this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity);
|
||||
this->m_holder.steal_resources(x.m_holder);
|
||||
}
|
||||
//Else do a one by one move. Also, clear the source as users find confusing
|
||||
//elements are still alive in the source container.
|
||||
else{
|
||||
this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin()))
|
||||
, boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end() ))
|
||||
);
|
||||
x.clear();
|
||||
}
|
||||
//Move allocator if needed
|
||||
allocator_type& this_alloc = this->m_holder.alloc();
|
||||
allocator_type& x_alloc = x.m_holder.alloc();
|
||||
dtl::move_alloc(this_alloc, x_alloc, dtl::bool_<propagate_alloc>());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user