Fixed #9916: "Allocator propagation incorrect in the assignment operator of most".

Fixed #9932: "Missing assignment operator from related static_vector".
Added missing details from issue #9915
This commit is contained in:
Ion Gaztañaga
2014-04-21 13:59:49 +02:00
parent bffd6c036c
commit 0b720f82b4
16 changed files with 372 additions and 283 deletions

View File

@@ -964,6 +964,8 @@ use [*Boost.Container]? There are several reasons for that:
* [@https://svn.boost.org/trac/boost/ticket/9338 #9338: ['"VS2005 compiler errors in swap() definition after including container/memory_util.hpp"]]. * [@https://svn.boost.org/trac/boost/ticket/9338 #9338: ['"VS2005 compiler errors in swap() definition after including container/memory_util.hpp"]].
* [@https://svn.boost.org/trac/boost/ticket/9648 #9648: ['"string construction optimization - char_traits::copy could be used ..."]]. * [@https://svn.boost.org/trac/boost/ticket/9648 #9648: ['"string construction optimization - char_traits::copy could be used ..."]].
* [@https://svn.boost.org/trac/boost/ticket/9915 #9915: ['"Documentation issues regarding vector constructors and resize methods - value/default initialization"]]. * [@https://svn.boost.org/trac/boost/ticket/9915 #9915: ['"Documentation issues regarding vector constructors and resize methods - value/default initialization"]].
* [@https://svn.boost.org/trac/boost/ticket/9916 #9916: ['"Allocator propagation incorrect in the assignment operator of most"]].
* [@https://svn.boost.org/trac/boost/ticket/9932 #9932: ['"Missing assignment operator from related static_vector"]].
[endsect] [endsect]

View File

@@ -542,7 +542,7 @@ class deque : protected deque_base<Allocator>
//! and inserts n value initialized values. //! and inserts n value initialized values.
//! //!
//! <b>Throws</b>: If allocator_type's default constructor //! <b>Throws</b>: If allocator_type's default constructor
//! throws or T's value initialization or copy constructor throws. //! throws or T's value initialization throws.
//! //!
//! <b>Complexity</b>: Linear to n. //! <b>Complexity</b>: Linear to n.
explicit deque(size_type n) explicit deque(size_type n)
@@ -704,35 +704,39 @@ class deque : protected deque_base<Allocator>
return *this; return *this;
} }
//! <b>Effects</b>: Move assignment. All mx's values are transferred to *this. //! <b>Effects</b>: Move assignment. All x's values are transferred to *this.
//! //!
//! <b>Postcondition</b>: x.empty(). *this contains a the elements x had //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! before the function. //! is false and (allocation throws or value_type's move constructor throws)
//! //!
//! <b>Throws</b>: If allocator_type's copy constructor throws. //! <b>Complexity</b>: Constant if allocator_traits_type::
//! //! propagate_on_container_move_assignment is true or
//! <b>Complexity</b>: Linear. //! this->get>allocator() == x.get_allocator(). Linear otherwise.
deque& operator= (BOOST_RV_REF(deque) x) deque& operator= (BOOST_RV_REF(deque) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ {
if (&x != this){ BOOST_ASSERT(this != &x);
allocator_type &this_alloc = this->alloc(); allocator_type &this_alloc = this->alloc();
allocator_type &x_alloc = x.alloc(); allocator_type &x_alloc = x.alloc();
//If allocators are equal we can just swap pointers const bool propagate_alloc = allocator_traits_type::
if(this_alloc == x_alloc){ propagate_on_container_move_assignment::value;
//Destroy objects but retain memory in case x reuses it in the future container_detail::bool_<propagate_alloc> flag;
this->clear(); const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
this->swap_members(x); //Resources can be transferred if both allocators are
//Move allocator if needed //going to be equal after this function (either propagated or already equal)
container_detail::bool_<allocator_traits_type:: if(propagate_alloc || allocators_equal){
propagate_on_container_move_assignment::value> flag; //Destroy objects but retain memory in case x reuses it in the future
container_detail::move_alloc(this_alloc, x_alloc, flag); this->clear();
container_detail::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); //Move allocator if needed
} container_detail::move_alloc(this_alloc, x_alloc, flag);
//If unequal allocators, then do a one by one move container_detail::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag);
else{ //Nothrow swap
this->assign( boost::make_move_iterator(x.begin()) this->swap_members(x);
, boost::make_move_iterator(x.end())); }
} //Else do a one by one move
else{
this->assign( boost::make_move_iterator(x.begin())
, boost::make_move_iterator(x.end()));
} }
return *this; return *this;
} }

View File

@@ -685,35 +685,39 @@ class tree
tree& operator=(BOOST_RV_REF(tree) x) tree& operator=(BOOST_RV_REF(tree) x)
{ {
if (&x != this){ BOOST_ASSERT(this != &x);
NodeAlloc &this_alloc = this->get_stored_allocator(); NodeAlloc &this_alloc = this->node_alloc();
const NodeAlloc &x_alloc = x.get_stored_allocator(); NodeAlloc &x_alloc = x.node_alloc();
//If allocators are equal we can just swap pointers const bool propagate_alloc = allocator_traits<NodeAlloc>::
if(this_alloc == x_alloc){ propagate_on_container_move_assignment::value;
//Destroy and swap pointers const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
this->clear(); //Resources can be transferred if both allocators are
this->icont() = ::boost::move(x.icont()); //going to be equal after this function (either propagated or already equal)
//Move allocator if needed if(propagate_alloc || allocators_equal){
this->AllocHolder::move_assign_alloc(x); //Destroy
} this->clear();
//If unequal allocators, then do a one by one move //Move allocator if needed
else{ this->AllocHolder::move_assign_alloc(x);
//Transfer all the nodes to a temporary tree //Obtain resources
//If anything goes wrong, all the nodes will be destroyed this->icont() = boost::move(x.icont());
//automatically }
Icont other_tree(::boost::move(this->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 //Now recreate the source tree reusing nodes stored by other_tree
this->icont().clone_from this->icont().clone_from
(x.icont() (x.icont()
, RecyclingCloner<AllocHolder, true>(*this, other_tree) , RecyclingCloner<AllocHolder, true>(*this, other_tree)
, Destroyer(this->node_alloc())); , Destroyer(this->node_alloc()));
//If there are remaining nodes, destroy them //If there are remaining nodes, destroy them
NodePtr p; NodePtr p;
while((p = other_tree.unlink_leftmost_without_rebalance())){ while((p = other_tree.unlink_leftmost_without_rebalance())){
AllocHolder::destroy_node(p); AllocHolder::destroy_node(p);
}
} }
} }
return *this; return *this;

View File

@@ -81,7 +81,13 @@ struct version<T, true>
template <class T> template <class T>
struct version struct version
: public container_detail::integral_constant<unsigned, impl::version<T>::value> : public container_detail::integral_constant<unsigned, impl::version<T>::value>
{};
template<class T, unsigned N>
struct is_version
{ {
static const bool value =
is_same< typename version<T>::type, integral_constant<unsigned, N> >::value;
}; };
} //namespace container_detail { } //namespace container_detail {

View File

@@ -135,6 +135,7 @@ class flat_map
typedef Key key_type; typedef Key key_type;
typedef T mapped_type; typedef T mapped_type;
typedef std::pair<Key, T> value_type; typedef std::pair<Key, T> value_type;
typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
typedef typename boost::container::allocator_traits<Allocator>::pointer pointer; typedef typename boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename boost::container::allocator_traits<Allocator>::const_pointer const_pointer; typedef typename boost::container::allocator_traits<Allocator>::const_pointer const_pointer;
typedef typename boost::container::allocator_traits<Allocator>::reference reference; typedef typename boost::container::allocator_traits<Allocator>::reference reference;
@@ -275,11 +276,15 @@ class flat_map
//! <b>Effects</b>: Move constructs a flat_map. //! <b>Effects</b>: Move constructs a flat_map.
//! Constructs *this using x's resources. //! Constructs *this using x's resources.
//! //!
//! <b>Complexity</b>: Construct. //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is false and (allocation throws or value_type's move constructor throws)
//! //!
//! <b>Postcondition</b>: x is emptied. //! <b>Complexity</b>: Constant if allocator_traits_type::
flat_map& operator=(BOOST_RV_REF(flat_map) mx) //! propagate_on_container_move_assignment is true or
{ m_flat_tree = boost::move(mx.m_flat_tree); return *this; } //! this->get>allocator() == x.get_allocator(). Linear otherwise.
flat_map& operator=(BOOST_RV_REF(flat_map) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ m_flat_tree = boost::move(x.m_flat_tree); return *this; }
//! <b>Effects</b>: Returns a copy of the Allocator that //! <b>Effects</b>: Returns a copy of the Allocator that
//! was passed to the object's constructor. //! was passed to the object's constructor.
@@ -1029,6 +1034,7 @@ class flat_multimap
typedef Key key_type; typedef Key key_type;
typedef T mapped_type; typedef T mapped_type;
typedef std::pair<Key, T> value_type; typedef std::pair<Key, T> value_type;
typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
typedef typename boost::container::allocator_traits<Allocator>::pointer pointer; typedef typename boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename boost::container::allocator_traits<Allocator>::const_pointer const_pointer; typedef typename boost::container::allocator_traits<Allocator>::const_pointer const_pointer;
typedef typename boost::container::allocator_traits<Allocator>::reference reference; typedef typename boost::container::allocator_traits<Allocator>::reference reference;
@@ -1169,8 +1175,9 @@ class flat_multimap
//! <b>Effects</b>: this->swap(x.get()). //! <b>Effects</b>: this->swap(x.get()).
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
flat_multimap& operator=(BOOST_RV_REF(flat_multimap) mx) flat_multimap& operator=(BOOST_RV_REF(flat_multimap) x)
{ m_flat_tree = boost::move(mx.m_flat_tree); return *this; } BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ m_flat_tree = boost::move(x.m_flat_tree); return *this; }
//! <b>Effects</b>: Returns a copy of the Allocator that //! <b>Effects</b>: Returns a copy of the Allocator that
//! was passed to the object's constructor. //! was passed to the object's constructor.

View File

@@ -72,6 +72,7 @@ class flat_set
typedef Key value_type; typedef Key value_type;
typedef Compare key_compare; typedef Compare key_compare;
typedef Compare value_compare; typedef Compare value_compare;
typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer; typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer; typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer;
typedef typename ::boost::container::allocator_traits<Allocator>::reference reference; typedef typename ::boost::container::allocator_traits<Allocator>::reference reference;
@@ -181,11 +182,15 @@ class flat_set
flat_set& operator=(BOOST_COPY_ASSIGN_REF(flat_set) x) flat_set& operator=(BOOST_COPY_ASSIGN_REF(flat_set) x)
{ return static_cast<flat_set&>(this->base_t::operator=(static_cast<const base_t&>(x))); } { return static_cast<flat_set&>(this->base_t::operator=(static_cast<const base_t&>(x))); }
//! <b>Effects</b>: Makes *this a copy of the previous value of mx. //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is false and (allocation throws or value_type's move constructor throws)
//! //!
//! <b>Complexity</b>: Linear in x.size(). //! <b>Complexity</b>: Constant if allocator_traits_type::
flat_set& operator=(BOOST_RV_REF(flat_set) mx) //! propagate_on_container_move_assignment is true or
{ return static_cast<flat_set&>(this->base_t::operator=(boost::move(static_cast<base_t&>(mx)))); } //! this->get>allocator() == x.get_allocator(). Linear otherwise.
flat_set& operator=(BOOST_RV_REF(flat_set) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ return static_cast<flat_set&>(this->base_t::operator=(boost::move(static_cast<base_t&>(x)))); }
#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
//! <b>Effects</b>: Returns a copy of the Allocator that //! <b>Effects</b>: Returns a copy of the Allocator that
@@ -725,6 +730,7 @@ class flat_multiset
typedef Key value_type; typedef Key value_type;
typedef Compare key_compare; typedef Compare key_compare;
typedef Compare value_compare; typedef Compare value_compare;
typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer; typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer; typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer;
typedef typename ::boost::container::allocator_traits<Allocator>::reference reference; typedef typename ::boost::container::allocator_traits<Allocator>::reference reference;
@@ -804,6 +810,7 @@ class flat_multiset
//! @copydoc ::boost::container::flat_set::operator=(flat_set &&) //! @copydoc ::boost::container::flat_set::operator=(flat_set &&)
flat_multiset& operator=(BOOST_RV_REF(flat_multiset) mx) flat_multiset& operator=(BOOST_RV_REF(flat_multiset) mx)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ return static_cast<flat_multiset&>(this->base_t::operator=(boost::move(static_cast<base_t&>(mx)))); } { return static_cast<flat_multiset&>(this->base_t::operator=(boost::move(static_cast<base_t&>(mx)))); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)

View File

@@ -332,32 +332,40 @@ class list
return *this; return *this;
} }
//! <b>Effects</b>: Move assignment. All mx's values are transferred to *this. //! <b>Effects</b>: Move assignment. All x's values are transferred to *this.
//! //!
//! <b>Postcondition</b>: x.empty(). *this contains a the elements x had //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
//! before the function. //! before the function.
//! //!
//! <b>Throws</b>: If allocator_type's copy constructor throws. //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is false and (allocation throws or value_type's move constructor throws)
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant if allocator_traits_type::
//! propagate_on_container_move_assignment is true or
//! this->get>allocator() == x.get_allocator(). Linear otherwise.
list& operator=(BOOST_RV_REF(list) x) list& operator=(BOOST_RV_REF(list) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ {
if (&x != this){ BOOST_ASSERT(this != &x);
NodeAlloc &this_alloc = this->node_alloc(); NodeAlloc &this_alloc = this->node_alloc();
NodeAlloc &x_alloc = x.node_alloc(); NodeAlloc &x_alloc = x.node_alloc();
//If allocators are equal we can just swap pointers const bool propagate_alloc = allocator_traits_type::
if(this_alloc == x_alloc){ propagate_on_container_move_assignment::value;
//Destroy and swap pointers const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
this->clear(); //Resources can be transferred if both allocators are
this->icont() = boost::move(x.icont()); //going to be equal after this function (either propagated or already equal)
//Move allocator if needed if(propagate_alloc || allocators_equal){
this->AllocHolder::move_assign_alloc(x); //Destroy
} this->clear();
//If unequal allocators, then do a one by one move //Move allocator if needed
else{ this->AllocHolder::move_assign_alloc(x);
this->assign( boost::make_move_iterator(x.begin()) //Obtain resources
, boost::make_move_iterator(x.end())); 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()));
} }
return *this; return *this;
} }

View File

@@ -89,6 +89,7 @@ class map
////////////////////////////////////////////// //////////////////////////////////////////////
typedef Key key_type; typedef Key key_type;
typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
typedef T mapped_type; typedef T mapped_type;
typedef std::pair<const Key, T> value_type; typedef std::pair<const Key, T> value_type;
typedef typename boost::container::allocator_traits<Allocator>::pointer pointer; typedef typename boost::container::allocator_traits<Allocator>::pointer pointer;
@@ -232,8 +233,14 @@ class map
//! <b>Effects</b>: this->swap(x.get()). //! <b>Effects</b>: this->swap(x.get()).
//! //!
//! <b>Complexity</b>: Constant. //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is false and (allocation throws or value_type's move constructor throws)
//!
//! <b>Complexity</b>: Constant if allocator_traits_type::
//! propagate_on_container_move_assignment is true or
//! this->get>allocator() == x.get_allocator(). Linear otherwise.
map& operator=(BOOST_RV_REF(map) x) map& operator=(BOOST_RV_REF(map) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ return static_cast<map&>(this->base_t::operator=(boost::move(static_cast<base_t&>(x)))); } { return static_cast<map&>(this->base_t::operator=(boost::move(static_cast<base_t&>(x)))); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)

View File

@@ -76,6 +76,7 @@ class set
typedef Key value_type; typedef Key value_type;
typedef Compare key_compare; typedef Compare key_compare;
typedef Compare value_compare; typedef Compare value_compare;
typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer; typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer; typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer;
typedef typename ::boost::container::allocator_traits<Allocator>::reference reference; typedef typename ::boost::container::allocator_traits<Allocator>::reference reference;
@@ -184,8 +185,14 @@ class set
//! <b>Effects</b>: this->swap(x.get()). //! <b>Effects</b>: this->swap(x.get()).
//! //!
//! <b>Complexity</b>: Constant. //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is false and (allocation throws or value_type's move constructor throws)
//!
//! <b>Complexity</b>: Constant if allocator_traits_type::
//! propagate_on_container_move_assignment is true or
//! this->get>allocator() == x.get_allocator(). Linear otherwise.
set& operator=(BOOST_RV_REF(set) x) set& operator=(BOOST_RV_REF(set) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ return static_cast<set&>(this->base_t::operator=(boost::move(static_cast<base_t&>(x)))); } { return static_cast<set&>(this->base_t::operator=(boost::move(static_cast<base_t&>(x)))); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
@@ -678,6 +685,7 @@ class multiset
typedef Key value_type; typedef Key value_type;
typedef Compare key_compare; typedef Compare key_compare;
typedef Compare value_compare; typedef Compare value_compare;
typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer; typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer; typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer;
typedef typename ::boost::container::allocator_traits<Allocator>::reference reference; typedef typename ::boost::container::allocator_traits<Allocator>::reference reference;

View File

@@ -358,27 +358,35 @@ class slist
//! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy //! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy
//! of each of x's elements. //! of each of x's elements.
//! //!
//! <b>Throws</b>: If memory allocation throws or T's copy constructor throws. //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is false and (allocation throws or value_type's move constructor throws)
//! //!
//! <b>Complexity</b>: Linear to the number of elements in x. //! <b>Complexity</b>: Constant if allocator_traits_type::
//! propagate_on_container_move_assignment is true or
//! this->get>allocator() == x.get_allocator(). Linear otherwise.
slist& operator= (BOOST_RV_REF(slist) x) slist& operator= (BOOST_RV_REF(slist) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ {
if (&x != this){ BOOST_ASSERT(this != &x);
NodeAlloc &this_alloc = this->node_alloc(); NodeAlloc &this_alloc = this->node_alloc();
NodeAlloc &x_alloc = x.node_alloc(); NodeAlloc &x_alloc = x.node_alloc();
//If allocators a re equal we can just swap pointers const bool propagate_alloc = allocator_traits_type::
if(this_alloc == x_alloc){ propagate_on_container_move_assignment::value;
//Destroy and swap pointers const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
this->clear(); //Resources can be transferred if both allocators are
this->icont() = boost::move(x.icont()); //going to be equal after this function (either propagated or already equal)
//Move allocator if needed if(propagate_alloc || allocators_equal){
this->AllocHolder::move_assign_alloc(x); //Destroy
} this->clear();
//If unequal allocators, then do a one by one move //Move allocator if needed
else{ this->AllocHolder::move_assign_alloc(x);
this->assign( boost::make_move_iterator(x.begin()) //Obtain resources
, boost::make_move_iterator(x.end())); 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()));
} }
return *this; return *this;
} }

View File

@@ -743,35 +743,42 @@ class stable_vector
//! <b>Postcondition</b>: x.empty(). *this contains a the elements x had //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
//! before the function. //! before the function.
//! //!
//! <b>Throws</b>: If allocator_type's copy constructor throws. //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is false and (allocation throws or T's move constructor throws)
//! //!
//! <b>Complexity</b>: Linear. //! <b>Complexity</b>: Constant if allocator_traits_type::
//! propagate_on_container_move_assignment is true or
//! this->get>allocator() == x.get_allocator(). Linear otherwise.
stable_vector& operator=(BOOST_RV_REF(stable_vector) x) stable_vector& operator=(BOOST_RV_REF(stable_vector) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ {
if (&x != this){ //for move constructor, no aliasing (&x != this) is assummed.
node_allocator_type &this_alloc = this->priv_node_alloc(); BOOST_ASSERT(this != &x);
node_allocator_type &x_alloc = x.priv_node_alloc(); node_allocator_type &this_alloc = this->priv_node_alloc();
//If allocators are equal we can just swap pointers node_allocator_type &x_alloc = x.priv_node_alloc();
if(this_alloc == x_alloc){ const bool propagate_alloc = allocator_traits_type::
//Destroy objects but retain memory propagate_on_container_move_assignment::value;
this->clear(); container_detail::bool_<propagate_alloc> flag;
this->index = boost::move(x.index); const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
this->priv_swap_members(x); //Resources can be transferred if both allocators are
//Move allocator if needed //going to be equal after this function (either propagated or already equal)
container_detail::bool_<allocator_traits_type:: if(propagate_alloc || allocators_equal){
propagate_on_container_move_assignment::value> flag; //Destroy objects but retain memory in case x reuses it in the future
container_detail::move_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); this->clear();
} //Move allocator if needed
//If unequal allocators, then do a one by one move container_detail::move_alloc(this_alloc, x_alloc, flag);
else{ //Take resources
this->assign( boost::make_move_iterator(x.begin()) this->index = boost::move(x.index);
, boost::make_move_iterator(x.end())); 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()));
} }
return *this; return *this;
} }
//! <b>Effects</b>: Assigns the n copies of val to *this. //! <b>Effects</b>: Assigns the n copies of val to *this.
//! //!
//! <b>Throws</b>: If memory allocation throws or T's copy constructor throws. //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.

View File

@@ -2,6 +2,7 @@
// //
// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2011-2013 Andrew Hundt. // Copyright (c) 2011-2013 Andrew Hundt.
// Copyright (c) 2013-2014 Ion Gaztanaga
// //
// Use, modification and distribution is subject to the Boost Software License, // Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -231,45 +232,9 @@ public:
//! @par Complexity //! @par Complexity
//! Linear O(N). //! Linear O(N).
template <std::size_t C> template <std::size_t C>
static_vector(static_vector<value_type, C> const& other) : base_t(other) {} static_vector(static_vector<value_type, C> const& other)
: base_t(other)
//! @brief Copy assigns Values stored in the other static_vector to this one. {}
//!
//! @param other The static_vector which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
static_vector & operator=(BOOST_COPY_ASSIGN_REF(static_vector) other)
{
base_t::operator=(static_cast<base_t const&>(other));
return *this;
}
//! @pre <tt>other.size() <= capacity()</tt>
//!
//! @brief Copy assigns Values stored in the other static_vector to this one.
//!
//! @param other The static_vector which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
// TEMPORARY WORKAROUND
#if defined(BOOST_NO_RVALUE_REFERENCES)
static_vector & operator=(::boost::rv< static_vector<value_type, C> > const& other)
#else
static_vector & operator=(static_vector<value_type, C> const& other)
#endif
{
base_t::operator=(static_cast<static_vector<value_type, C> const&>(other));
return *this;
}
//! @brief Move constructor. Moves Values stored in the other static_vector to this one. //! @brief Move constructor. Moves Values stored in the other static_vector to this one.
//! //!
@@ -302,6 +267,38 @@ public:
: base_t(boost::move(static_cast<typename static_vector<value_type, C>::base_t&>(other))) : base_t(boost::move(static_cast<typename static_vector<value_type, C>::base_t&>(other)))
{} {}
//! @brief Copy assigns Values stored in the other static_vector to this one.
//!
//! @param other The static_vector which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
static_vector & operator=(BOOST_COPY_ASSIGN_REF(static_vector) other)
{
return static_cast<static_vector&>(base_t::operator=(static_cast<base_t const&>(other)));
}
//! @pre <tt>other.size() <= capacity()</tt>
//!
//! @brief Copy assigns Values stored in the other static_vector to this one.
//!
//! @param other The static_vector which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
static_vector & operator=(static_vector<value_type, C> const& other)
{
return static_cast<static_vector&>(base_t::operator=
(static_cast<typename static_vector<value_type, C>::base_t const&>(other)));
}
//! @brief Move assignment. Moves Values stored in the other static_vector to this one. //! @brief Move assignment. Moves Values stored in the other static_vector to this one.
//! //!
//! @param other The static_vector which content will be moved to this one. //! @param other The static_vector which content will be moved to this one.
@@ -314,8 +311,7 @@ public:
//! Linear O(N). //! Linear O(N).
static_vector & operator=(BOOST_RV_REF(static_vector) other) static_vector & operator=(BOOST_RV_REF(static_vector) other)
{ {
base_t::operator=(boost::move(static_cast<base_t&>(other))); return static_cast<static_vector&>(base_t::operator=(boost::move(static_cast<base_t&>(other))));
return *this;
} }
//! @pre <tt>other.size() <= capacity()</tt> //! @pre <tt>other.size() <= capacity()</tt>
@@ -333,8 +329,8 @@ public:
template <std::size_t C> template <std::size_t C>
static_vector & operator=(BOOST_RV_REF_BEG static_vector<value_type, C> BOOST_RV_REF_END other) static_vector & operator=(BOOST_RV_REF_BEG static_vector<value_type, C> BOOST_RV_REF_END other)
{ {
base_t::operator=(boost::move(static_cast<typename static_vector<value_type, C>::base_t&>(other))); return static_cast<static_vector&>(base_t::operator=
return *this; (boost::move(static_cast<typename static_vector<value_type, C>::base_t&>(other))));
} }
#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED

View File

@@ -733,34 +733,38 @@ class basic_string
return *this; return *this;
} }
//! <b>Effects</b>: Move constructor. Moves mx's resources to *this. //! <b>Effects</b>: Move constructor. Moves x's resources to *this.
//! //!
//! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is true, when allocator_type's move assignment throws. //! is false and allocation throws
//! If allocator_traits_type::propagate_on_container_move_assignment
//! is false, when allocator_type's allocation throws.
//! //!
//! <b>Complexity</b>: Constant if allocator_traits_type::propagate_on_container_move_assignment. //! <b>Complexity</b>: Constant if allocator_traits_type::
//! is true, linear otherwise //! propagate_on_container_move_assignment is true or
basic_string& operator=(BOOST_RV_REF(basic_string) x) BOOST_CONTAINER_NOEXCEPT //! this->get>allocator() == x.get_allocator(). Linear otherwise.
basic_string& operator=(BOOST_RV_REF(basic_string) x)
BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
{ {
if (&x != this){ //for move constructor, no aliasing (&x != this) is assummed.
allocator_type &this_alloc = this->alloc(); BOOST_ASSERT(this != &x);
allocator_type &x_alloc = x.alloc(); allocator_type &this_alloc = this->alloc();
//If allocators are equal we can just swap pointers allocator_type &x_alloc = x.alloc();
if(this_alloc == x_alloc){ const bool propagate_alloc = allocator_traits_type::
//Destroy objects but retain memory in case x reuses it in the future propagate_on_container_move_assignment::value;
this->clear(); container_detail::bool_<propagate_alloc> flag;
this->swap_data(x); const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
//Move allocator if needed //Resources can be transferred if both allocators are
container_detail::bool_<allocator_traits_type:: //going to be equal after this function (either propagated or already equal)
propagate_on_container_move_assignment::value> flag; if(propagate_alloc || allocators_equal){
container_detail::move_alloc(this_alloc, x_alloc, flag); //Destroy objects but retain memory in case x reuses it in the future
} this->clear();
//If unequal allocators, then do a one by one move //Move allocator if needed
else{ container_detail::move_alloc(this_alloc, x_alloc, flag);
this->assign( x.begin(), x.end()); //Nothrow swap
} this->swap_data(x);
}
//Else do a one by one move
else{
this->assign( x.begin(), x.end());
} }
return *this; return *this;
} }

View File

@@ -65,7 +65,7 @@ template <class Pointer, bool IsConst>
class vec_iterator class vec_iterator
{ {
public: public:
typedef std::random_access_iterator_tag iterator_category; typedef std::random_access_iterator_tag iterator_category;
typedef typename boost::intrusive::pointer_traits<Pointer>::element_type value_type; typedef typename boost::intrusive::pointer_traits<Pointer>::element_type value_type;
typedef typename boost::intrusive::pointer_traits<Pointer>::difference_type difference_type; typedef typename boost::intrusive::pointer_traits<Pointer>::difference_type difference_type;
typedef typename if_c typedef typename if_c
@@ -256,10 +256,7 @@ struct vector_value_traits
//!This struct deallocates and allocated memory //!This struct deallocates and allocated memory
template < class Allocator template < class Allocator
, class AllocatorVersion = container_detail::integral_constant , class AllocatorVersion = typename container_detail::version<Allocator>::type
< unsigned
, boost::container::container_detail::version<Allocator>::value
>
> >
struct vector_alloc_holder struct vector_alloc_holder
: public Allocator : public Allocator
@@ -370,8 +367,8 @@ struct vector_alloc_holder
void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT
{ {
//this->m_size was previously initialized
this->m_start = x.m_start; this->m_start = x.m_start;
this->m_size = x.m_size;
this->m_capacity = x.m_capacity; this->m_capacity = x.m_capacity;
x.m_start = pointer(); x.m_start = pointer();
x.m_size = x.m_capacity = 0; x.m_size = x.m_capacity = 0;
@@ -538,9 +535,8 @@ template <class T, class Allocator>
class vector class vector
{ {
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
typedef container_detail::integral_constant
<unsigned, boost::container::container_detail::version typedef typename container_detail::version<Allocator>::type alloc_version;
<Allocator>::value > alloc_version;
boost::container::container_detail::vector_alloc_holder boost::container::container_detail::vector_alloc_holder
<Allocator, alloc_version> m_holder; <Allocator, alloc_version> m_holder;
typedef allocator_traits<Allocator> allocator_traits_type; typedef allocator_traits<Allocator> allocator_traits_type;
@@ -717,27 +713,30 @@ class vector
, x.size(), container_detail::to_raw_pointer(this->m_holder.start())); , x.size(), container_detail::to_raw_pointer(this->m_holder.start()));
} }
//! <b>Effects</b>: Move constructor. Moves mx's resources to *this. //! <b>Effects</b>: Move constructor. Moves x's resources to *this.
//! //!
//! <b>Throws</b>: Nothing //! <b>Throws</b>: Nothing
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
vector(BOOST_RV_REF(vector) mx) BOOST_CONTAINER_NOEXCEPT vector(BOOST_RV_REF(vector) x) BOOST_CONTAINER_NOEXCEPT
: m_holder(boost::move(mx.m_holder)) : m_holder(boost::move(x.m_holder))
{} {}
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Move constructor. Moves mx's resources to *this. //! <b>Effects</b>: Move constructor. Moves x's resources to *this.
//! //!
//! <b>Throws</b>: If T's move constructor or allocation throws //! <b>Throws</b>: If T's move constructor or allocation throws
//! //!
//! <b>Complexity</b>: Linear. //! <b>Complexity</b>: Linear.
//! //!
//! <b>Note</b>: Non-standard extension //! <b>Note</b>: Non-standard extension to support static_vector
template<class OtherAllocator> template<class OtherAllocator>
vector(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END mx) vector(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
: m_holder(boost::move(mx.m_holder)) , typename container_detail::enable_if_c
< container_detail::is_version<OtherAllocator, 0>::value>::type * = 0
)
: m_holder(boost::move(x.m_holder))
{} {}
#endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
@@ -759,25 +758,24 @@ class vector
} }
//! <b>Effects</b>: Move constructor using the specified allocator. //! <b>Effects</b>: Move constructor using the specified allocator.
//! Moves mx's resources to *this if a == allocator_type(). //! Moves x's resources to *this if a == allocator_type().
//! Otherwise copies values from x to *this. //! Otherwise copies values from x to *this.
//! //!
//! <b>Throws</b>: If allocation or T's copy constructor throws. //! <b>Throws</b>: If allocation or T's copy constructor throws.
//! //!
//! <b>Complexity</b>: Constant if a == mx.get_allocator(), linear otherwise. //! <b>Complexity</b>: Constant if a == x.get_allocator(), linear otherwise.
vector(BOOST_RV_REF(vector) mx, const allocator_type &a) vector(BOOST_RV_REF(vector) x, const allocator_type &a)
: m_holder(a) : m_holder(container_detail::uninitialized_size, a, x.size())
{ {
if(mx.m_holder.alloc() == a){ if(x.m_holder.alloc() == a){
this->m_holder.move_from_empty(mx.m_holder); this->m_holder.move_from_empty(x.m_holder);
} }
else{ else{
const size_type n = mx.size(); const size_type n = x.size();
this->m_holder.first_allocation_same_allocator_type(n); this->m_holder.first_allocation_same_allocator_type(n);
::boost::container::uninitialized_move_alloc_n_source ::boost::container::uninitialized_move_alloc_n_source
( this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start()) ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())
, n, container_detail::to_raw_pointer(this->m_holder.start())); , n, container_detail::to_raw_pointer(this->m_holder.start()));
this->m_holder.m_size = n;
} }
} }
@@ -805,30 +803,32 @@ class vector
vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x) vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x)
{ {
if (&x != this){ if (&x != this){
this->priv_copy_assign(x, alloc_version()); this->priv_copy_assign(x);
} }
return *this; return *this;
} }
//! <b>Effects</b>: Move assignment. All mx's values are transferred to *this. //! <b>Effects</b>: Move assignment. All x's values are transferred to *this.
//! //!
//! <b>Postcondition</b>: x.empty(). *this contains a the elements x had //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
//! before the function. //! before the function.
//! //!
//! <b>Throws</b>: Nothing //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
//! is false and (allocation throws or value_type's move constructor throws)
//! //!
//! <b>Complexity</b>: Linear. //! <b>Complexity</b>: Constant if allocator_traits_type::
//! propagate_on_container_move_assignment is true or
//! this->get>allocator() == x.get_allocator(). Linear otherwise.
vector& operator=(BOOST_RV_REF(vector) x) vector& operator=(BOOST_RV_REF(vector) x)
//iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable<allocator_type>::value);) BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment)
BOOST_CONTAINER_NOEXCEPT
{ {
this->priv_move_assign(boost::move(x), alloc_version()); this->priv_move_assign(boost::move(x));
return *this; return *this;
} }
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Move assignment. All mx's values are transferred to *this. //! <b>Effects</b>: Move assignment. All x's values are transferred to *this.
//! //!
//! <b>Postcondition</b>: x.empty(). *this contains a the elements x had //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
//! before the function. //! before the function.
@@ -836,10 +836,37 @@ class vector
//! <b>Throws</b>: If move constructor/assignment of T throws or allocation throws //! <b>Throws</b>: If move constructor/assignment of T throws or allocation throws
//! //!
//! <b>Complexity</b>: Linear. //! <b>Complexity</b>: Linear.
template<class OtherAllocator, class OtherAllocatorVersion> //!
vector& operator=(BOOST_RV_REF_BEG vector<OtherAllocator, OtherAllocatorVersion> BOOST_RV_REF_END x) //! <b>Note</b>: Non-standard extension to support static_vector
template<class OtherAllocator>
typename container_detail::enable_if_c
< container_detail::is_version<OtherAllocator, 0>::value &&
!container_detail::is_same<OtherAllocator, allocator_type>::value
, vector& >::type
operator=(BOOST_RV_REF_BEG vector<value_type, OtherAllocator> BOOST_RV_REF_END x)
{ {
this->priv_move_assign(boost::move(x), alloc_version()); this->priv_move_assign(boost::move(x));
return *this;
}
//! <b>Effects</b>: Copy assignment. All x's values are copied to *this.
//!
//! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
//! before the function.
//!
//! <b>Throws</b>: If move constructor/assignment of T throws or allocation throws
//!
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: Non-standard extension to support static_vector
template<class OtherAllocator>
typename container_detail::enable_if_c
< container_detail::is_version<OtherAllocator, 0>::value &&
!container_detail::is_same<OtherAllocator, allocator_type>::value
, vector& >::type
operator=(const vector<value_type, OtherAllocator> &x)
{
this->priv_copy_assign(x);
return *this; return *this;
} }
@@ -898,7 +925,7 @@ class vector
#endif #endif
) )
{ {
//For Fwd iterators the standard only requires EmplaceConstructible and assignble from *first //For Fwd iterators the standard only requires EmplaceConstructible and assignable from *first
//so we can't do any backwards allocation //so we can't do any backwards allocation
const size_type input_sz = static_cast<size_type>(std::distance(first, last)); const size_type input_sz = static_cast<size_type>(std::distance(first, last));
const size_type old_capacity = this->capacity(); const size_type old_capacity = this->capacity();
@@ -1124,7 +1151,7 @@ class vector
{ this->priv_resize(new_size, value_init); } { this->priv_resize(new_size, value_init); }
//! <b>Effects</b>: Inserts or erases elements at the end such that //! <b>Effects</b>: Inserts or erases elements at the end such that
//! the size becomes n. New elements are value initialized. //! the size becomes n. New elements are default initialized.
//! //!
//! <b>Throws</b>: If memory allocation throws, or T's copy/move or default initialization throws. //! <b>Throws</b>: If memory allocation throws, or T's copy/move or default initialization throws.
//! //!
@@ -1413,7 +1440,7 @@ class vector
//! <b>Requires</b>: position must be a valid iterator of *this. //! <b>Requires</b>: position must be a valid iterator of *this.
//! //!
//! <b>Effects</b>: Insert a new element before position with mx's resources. //! <b>Effects</b>: Insert a new element before position with x's resources.
//! //!
//! <b>Throws</b>: If memory allocation throws. //! <b>Throws</b>: If memory allocation throws.
//! //!
@@ -1537,7 +1564,7 @@ class vector
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
void swap(vector& x) BOOST_CONTAINER_NOEXCEPT_IF((!container_detail::is_same<alloc_version, allocator_v0>::value)) void swap(vector& x) BOOST_CONTAINER_NOEXCEPT_IF((!container_detail::is_version<Allocator, 0>::value))
{ {
//Just swap internals in case of !allocator_v0. Otherwise, deep swap //Just swap internals in case of !allocator_v0. Otherwise, deep swap
this->m_holder.swap(x.m_holder); this->m_holder.swap(x.m_holder);
@@ -1554,9 +1581,13 @@ class vector
//! //!
//! <b>Complexity</b>: Linear //! <b>Complexity</b>: Linear
//! //!
//! <b>Note</b>: non-standard extension. //! <b>Note</b>: Non-standard extension to support static_vector
template<class OtherAllocator> template<class OtherAllocator>
void swap(vector<T, OtherAllocator> & x) void swap(vector<T, OtherAllocator> & x
, typename container_detail::enable_if_c
< container_detail::is_version<OtherAllocator, 0>::value &&
!container_detail::is_same<OtherAllocator, allocator_type>::value >::type * = 0
)
{ this->m_holder.swap(x.m_holder); } { this->m_holder.swap(x.m_holder); }
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -1631,36 +1662,15 @@ class vector
private: private:
template<class OtherAllocator, class AllocVersion> template<class OtherAllocator>
void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
, AllocVersion
, typename container_detail::enable_if_c , typename container_detail::enable_if_c
< container_detail::is_same<AllocVersion, allocator_v0>::value && < container_detail::is_version<OtherAllocator, 0>::value >::type * = 0)
!container_detail::is_same<OtherAllocator, allocator_type>::value
>::type * = 0)
{ {
if(this->capacity() < x.size()){ if(!container_detail::is_same<OtherAllocator, allocator_type>::value &&
this->capacity() < x.size()){
throw_bad_alloc(); throw_bad_alloc();
} }
this->priv_move_assign_impl(boost::move(x), AllocVersion());
}
template<class OtherAllocator, class AllocVersion>
void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
, AllocVersion
, typename container_detail::enable_if_c
< !container_detail::is_same<AllocVersion, allocator_v0>::value ||
container_detail::is_same<OtherAllocator, allocator_type>::value
>::type * = 0)
{ this->priv_move_assign_impl(boost::move(x), AllocVersion()); }
template<class OtherAllocator, class AllocVersion>
void priv_move_assign_impl(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
, AllocVersion
, typename container_detail::enable_if_c
< container_detail::is_same<AllocVersion, allocator_v0>::value
>::type * = 0)
{
T* const this_start = container_detail::to_raw_pointer(m_holder.start()); T* const this_start = container_detail::to_raw_pointer(m_holder.start());
T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); T* const other_start = container_detail::to_raw_pointer(x.m_holder.start());
const size_type this_sz = m_holder.m_size; const size_type this_sz = m_holder.m_size;
@@ -1669,40 +1679,46 @@ class vector
this->m_holder.m_size = other_sz; this->m_holder.m_size = other_sz;
} }
template<class OtherAllocator, class AllocVersion> template<class OtherAllocator>
void priv_move_assign_impl(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
, AllocVersion
, typename container_detail::enable_if_c , typename container_detail::enable_if_c
< !container_detail::is_same<AllocVersion, allocator_v0>::value < !container_detail::is_version<OtherAllocator, 0>::value &&
>::type * = 0) container_detail::is_same<OtherAllocator, allocator_type>::value>::type * = 0)
{ {
//for move constructor, no aliasing (&x != this) is assummed. //for move constructor, no aliasing (&x != this) is assummed.
BOOST_ASSERT(this != &x);
allocator_type &this_alloc = this->m_holder.alloc(); allocator_type &this_alloc = this->m_holder.alloc();
allocator_type &x_alloc = x.m_holder.alloc(); allocator_type &x_alloc = x.m_holder.alloc();
//If allocators are equal we can just swap pointers const bool propagate_alloc = allocator_traits_type::
if(this_alloc == x_alloc){ propagate_on_container_move_assignment::value;
container_detail::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 //Destroy objects but retain memory in case x reuses it in the future
this->clear(); this->clear();
this->m_holder.swap(x.m_holder);
//Move allocator if needed //Move allocator if needed
container_detail::bool_<allocator_traits_type::
propagate_on_container_move_assignment::value> flag;
container_detail::move_alloc(this_alloc, x_alloc, flag); container_detail::move_alloc(this_alloc, x_alloc, flag);
//Nothrow swap
this->m_holder.swap(x.m_holder);
} }
//If unequal allocators, then do a one by one move //Else do a one by one move
else{ else{
//TO-DO: optimize this this->assign( boost::make_move_iterator(x.begin())
this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start())) , boost::make_move_iterator(x.end()));
, boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)));
} }
} }
template<class AllocVersion> template<class OtherAllocator>
void priv_copy_assign(const vector &x, AllocVersion void priv_copy_assign(const vector<T, OtherAllocator> &x
, typename container_detail::enable_if_c , typename container_detail::enable_if_c
< container_detail::is_same<AllocVersion, allocator_v0>::value < container_detail::is_version<OtherAllocator, 0>::value >::type * = 0)
>::type * = 0)
{ {
if(!container_detail::is_same<OtherAllocator, allocator_type>::value &&
this->capacity() < x.size()){
throw_bad_alloc();
}
T* const this_start = container_detail::to_raw_pointer(m_holder.start()); T* const this_start = container_detail::to_raw_pointer(m_holder.start());
T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); T* const other_start = container_detail::to_raw_pointer(x.m_holder.start());
const size_type this_sz = m_holder.m_size; const size_type this_sz = m_holder.m_size;
@@ -1711,11 +1727,11 @@ class vector
this->m_holder.m_size = other_sz; this->m_holder.m_size = other_sz;
} }
template<class AllocVersion> template<class OtherAllocator>
void priv_copy_assign(const vector &x, AllocVersion void priv_copy_assign(const vector<T, OtherAllocator> &x
, typename container_detail::enable_if_c , typename container_detail::enable_if_c
< !container_detail::is_same<AllocVersion, allocator_v0>::value < !container_detail::is_version<OtherAllocator, 0>::value &&
>::type * = 0) container_detail::is_same<OtherAllocator, allocator_type>::value >::type * = 0)
{ {
allocator_type &this_alloc = this->m_holder.alloc(); allocator_type &this_alloc = this->m_holder.alloc();
const allocator_type &x_alloc = x.m_holder.alloc(); const allocator_type &x_alloc = x.m_holder.alloc();

View File

@@ -486,7 +486,7 @@ void test_swap_and_move_nd()
} }
{ {
static_vector<T, N> v1, v2, v3; static_vector<T, N> v1, v2, v3;
static_vector<T, N/2> s1, s2; static_vector<T, N/2> s1, s2, s3;
for (size_t i = 0 ; i < N/2 ; ++i ) for (size_t i = 0 ; i < N/2 ; ++i )
{ {
@@ -501,17 +501,19 @@ void test_swap_and_move_nd()
} }
s1.swap(v1); s1.swap(v1);
s3 = v2;
s2 = boost::move(v2); s2 = boost::move(v2);
static_vector<T, N/2> s3(boost::move(v3)); static_vector<T, N/2> s4(boost::move(v3));
BOOST_TEST(v1.size() == N/3); BOOST_TEST(v1.size() == N/3);
BOOST_TEST(s1.size() == N/2); BOOST_TEST(s1.size() == N/2);
//iG moving does not imply emptying source //iG moving does not imply emptying source
//BOOST_TEST(v2.size() == 0); //BOOST_TEST(v2.size() == 0);
BOOST_TEST(s2.size() == N/2); BOOST_TEST(s2.size() == N/2);
BOOST_TEST(s3.size() == N/2);
//iG moving does not imply emptying source //iG moving does not imply emptying source
//BOOST_TEST(v3.size() == 0); //BOOST_TEST(v3.size() == 0);
BOOST_TEST(s3.size() == N/2); BOOST_TEST(s4.size() == N/2);
for (size_t i = 0 ; i < N/3 ; ++i ) for (size_t i = 0 ; i < N/3 ; ++i )
BOOST_TEST(v1[i] == T(100 + i)); BOOST_TEST(v1[i] == T(100 + i));
for (size_t i = 0 ; i < N/2 ; ++i ) for (size_t i = 0 ; i < N/2 ; ++i )
@@ -519,6 +521,7 @@ void test_swap_and_move_nd()
BOOST_TEST(s1[i] == T(i)); BOOST_TEST(s1[i] == T(i));
BOOST_TEST(s2[i] == T(i)); BOOST_TEST(s2[i] == T(i));
BOOST_TEST(s3[i] == T(i)); BOOST_TEST(s3[i] == T(i));
BOOST_TEST(s4[i] == T(i));
} }
} }
{ {
@@ -528,6 +531,7 @@ void test_swap_and_move_nd()
BOOST_TEST_THROWS(s.swap(v), std::bad_alloc); BOOST_TEST_THROWS(s.swap(v), std::bad_alloc);
v.resize(N, T(0)); v.resize(N, T(0));
BOOST_TEST_THROWS(s = boost::move(v), std::bad_alloc); BOOST_TEST_THROWS(s = boost::move(v), std::bad_alloc);
BOOST_TEST_THROWS(s = v, std::bad_alloc);
v.resize(N, T(0)); v.resize(N, T(0));
BOOST_TEST_THROWS(small_vector_t s2(boost::move(v)), std::bad_alloc); BOOST_TEST_THROWS(small_vector_t s2(boost::move(v)), std::bad_alloc);
} }

View File

@@ -13,6 +13,7 @@
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#define BOOST_SP_DISABLE_THREADS
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include "movable_int.hpp" #include "movable_int.hpp"