Add new clone_from overload to implement move semantics

This commit is contained in:
Ion Gaztañaga
2015-02-26 00:02:24 +01:00
parent b5fd69e628
commit 4f20e7279d
6 changed files with 52 additions and 10 deletions

View File

@@ -945,8 +945,8 @@ class bstree_impl
detail::exception_disposer<bstree_impl, Disposer> detail::exception_disposer<bstree_impl, Disposer>
rollback(*this, disposer); rollback(*this, disposer);
node_algorithms::clone node_algorithms::clone
(const_node_ptr(src.header_ptr()) (src.header_ptr()
,node_ptr(this->header_ptr()) ,this->header_ptr()
,detail::node_cloner <Cloner, value_traits, AlgoType>(cloner, &this->get_value_traits()) ,detail::node_cloner <Cloner, value_traits, AlgoType>(cloner, &this->get_value_traits())
,detail::node_disposer<Disposer, value_traits, AlgoType>(disposer, &this->get_value_traits())); ,detail::node_disposer<Disposer, value_traits, AlgoType>(disposer, &this->get_value_traits()));
this->sz_traits().set_size(src.sz_traits().get_size()); this->sz_traits().set_size(src.sz_traits().get_size());
@@ -955,6 +955,41 @@ class bstree_impl
} }
} }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//! Cloner should yield to nodes equivalent to the original nodes.
//!
//! <b>Effects</b>: Erases all the elements from *this
//! calling Disposer::operator()(pointer), clones all the
//! elements from src calling Cloner::operator()(const_reference )
//! and inserts them on *this. Copies the predicate from the source container.
//!
//! If cloner throws, all cloned elements are unlinked and disposed
//! calling Disposer::operator()(pointer).
//!
//! <b>Complexity</b>: Linear to erased plus inserted elements.
//!
//! <b>Throws</b>: If cloner throws or predicate copy assignment throws. Basic guarantee.
//!
//! <b>Note</b>: This version can modify the source container, useful to implement
//! move semantics.
template <class Cloner, class Disposer>
void clone_from(bstree_impl &src, Cloner cloner, Disposer disposer)
{
this->clear_and_dispose(disposer);
if(!src.empty()){
detail::exception_disposer<bstree_impl, Disposer>
rollback(*this, disposer);
node_algorithms::clone
(src.header_ptr()
,this->header_ptr()
,detail::node_cloner <Cloner, value_traits, AlgoType, false>(cloner, &this->get_value_traits())
,detail::node_disposer<Disposer, value_traits, AlgoType>(disposer, &this->get_value_traits()));
this->sz_traits().set_size(src.sz_traits().get_size());
this->comp() = src.comp();
rollback.release();
}
}
//! <b>Requires</b>: value must be an lvalue //! <b>Requires</b>: value must be an lvalue
//! //!
//! <b>Effects</b>: Inserts value into the container before the upper bound. //! <b>Effects</b>: Inserts value into the container before the upper bound.

View File

@@ -1285,7 +1285,7 @@ class bstree_algorithms : public bstree_algorithms_base<NodeTraits>
//! the nodes of the target tree. If "cloner" throws, the cloned target nodes //! the nodes of the target tree. If "cloner" throws, the cloned target nodes
//! are disposed using <tt>void disposer(const node_ptr &)</tt>. //! are disposed using <tt>void disposer(const node_ptr &)</tt>.
//! //!
//! <b>Complexity</b>: Linear to the number of element of the source tree plus the. //! <b>Complexity</b>: Linear to the number of element of the source tree plus the
//! number of elements of tree target tree when calling this function. //! number of elements of tree target tree when calling this function.
//! //!
//! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed. //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.

View File

@@ -183,7 +183,7 @@ class ebo_functor_holder_impl<T, false>
public: public:
ebo_functor_holder_impl() ebo_functor_holder_impl()
{} {}
ebo_functor_holder_impl(const T& t) explicit ebo_functor_holder_impl(const T& t)
: T(t) : T(t)
{} {}
template<class Arg1, class Arg2> template<class Arg1, class Arg2>
@@ -204,7 +204,7 @@ class ebo_functor_holder
public: public:
ebo_functor_holder(){} ebo_functor_holder(){}
ebo_functor_holder(const T& t) explicit ebo_functor_holder(const T& t)
: super(t) : super(t)
{} {}

View File

@@ -22,6 +22,7 @@
#endif #endif
#include <boost/intrusive/link_mode.hpp> #include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/detail/ebo_functor_holder.hpp> #include <boost/intrusive/detail/ebo_functor_holder.hpp>
#include <boost/intrusive/detail/algo_type.hpp> #include <boost/intrusive/detail/algo_type.hpp>
#include <boost/intrusive/detail/assert.hpp> #include <boost/intrusive/detail/assert.hpp>
@@ -30,7 +31,7 @@ namespace boost {
namespace intrusive { namespace intrusive {
namespace detail { namespace detail {
template<class F, class ValueTraits, algo_types AlgoType> template<class F, class ValueTraits, algo_types AlgoType, bool IsConst = true>
struct node_cloner struct node_cloner
//Use public inheritance to avoid MSVC bugs with closures //Use public inheritance to avoid MSVC bugs with closures
: public ebo_functor_holder<F> : public ebo_functor_holder<F>
@@ -50,6 +51,8 @@ struct node_cloner
typedef typename value_traits::reference reference; typedef typename value_traits::reference reference;
typedef typename value_traits::const_reference const_reference; typedef typename value_traits::const_reference const_reference;
typedef typename if_c<IsConst, const_reference, reference>::type reference_type;
node_cloner(F f, const ValueTraits *traits) node_cloner(F f, const ValueTraits *traits)
: base_t(f), traits_(traits) : base_t(f), traits_(traits)
{} {}
@@ -57,7 +60,7 @@ struct node_cloner
// tree-based containers use this method, which is proxy-reference friendly // tree-based containers use this method, which is proxy-reference friendly
node_ptr operator()(const node_ptr & p) node_ptr operator()(const node_ptr & p)
{ {
const_reference v = *traits_->to_value_ptr(p); reference_type v = *traits_->to_value_ptr(p);
node_ptr n = traits_->to_node_ptr(*base_t::get()(v)); node_ptr n = traits_->to_node_ptr(*base_t::get()(v));
//Cloned node must be in default mode if the linking mode requires it //Cloned node must be in default mode if the linking mode requires it
if(safemode_or_autounlink) if(safemode_or_autounlink)
@@ -68,7 +71,7 @@ struct node_cloner
// hashtables use this method, which is proxy-reference unfriendly // hashtables use this method, which is proxy-reference unfriendly
node_ptr operator()(const node &to_clone) node_ptr operator()(const node &to_clone)
{ {
const value_type &v = reference_type v =
*traits_->to_value_ptr *traits_->to_value_ptr
(pointer_traits<const_node_ptr>::pointer_to(to_clone)); (pointer_traits<const_node_ptr>::pointer_to(to_clone));
node_ptr n = traits_->to_node_ptr(*base_t::get()(v)); node_ptr n = traits_->to_node_ptr(*base_t::get()(v));

View File

@@ -213,10 +213,14 @@ class rbtree_impl
//! @copydoc ::boost::intrusive::bstree::swap //! @copydoc ::boost::intrusive::bstree::swap
void swap(rbtree_impl& other); void swap(rbtree_impl& other);
//! @copydoc ::boost::intrusive::bstree::clone_from //! @copydoc ::boost::intrusive::bstree::clone_from(const bstree &src, cloner, Disposer)
template <class Cloner, class Disposer> template <class Cloner, class Disposer>
void clone_from(const rbtree_impl &src, Cloner cloner, Disposer disposer); void clone_from(const rbtree_impl &src, Cloner cloner, Disposer disposer);
//! @copydoc ::boost::intrusive::bstree::clone_from(bstree &src, cloner, Disposer)
template <class Cloner, class Disposer>
void clone_from(rbtree_impl &src, Cloner cloner, Disposer disposer);
//! @copydoc ::boost::intrusive::bstree::insert_equal(reference) //! @copydoc ::boost::intrusive::bstree::insert_equal(reference)
iterator insert_equal(reference value); iterator insert_equal(reference value);

View File

@@ -50,7 +50,7 @@ struct rbtree_node_cloner
typedef typename NodeTraits::node_ptr node_ptr; typedef typename NodeTraits::node_ptr node_ptr;
typedef detail::ebo_functor_holder<F> base_t; typedef detail::ebo_functor_holder<F> base_t;
rbtree_node_cloner(F f) explicit rbtree_node_cloner(F f)
: base_t(f) : base_t(f)
{} {}