Refactored tree cloners into a single standalone class to avoid unnecessary instantiations and simplify maintenance.

This commit is contained in:
Ion Gaztañaga
2013-12-24 12:58:28 +01:00
parent 41c2056ec6
commit ed0704797d
2 changed files with 61 additions and 86 deletions

View File

@@ -88,6 +88,7 @@ struct node_alloc_holder
typedef allocator_traits<A> allocator_traits_type; typedef allocator_traits<A> allocator_traits_type;
typedef typename allocator_traits_type::value_type value_type; typedef typename allocator_traits_type::value_type value_type;
typedef ICont intrusive_container;
typedef typename ICont::value_type Node; typedef typename ICont::value_type Node;
typedef typename allocator_traits_type::template typedef typename allocator_traits_type::template
portable_rebind_alloc<Node>::type NodeAlloc; portable_rebind_alloc<Node>::type NodeAlloc;

View File

@@ -103,13 +103,13 @@ struct intrusive_tree_hook
//This trait is used to type-pun std::pair because in C++03 //This trait is used to type-pun std::pair because in C++03
//compilers std::pair is useless for C++11 features //compilers std::pair is useless for C++11 features
template<class T> template<class T>
struct rbtree_internal_data_type struct tree_internal_data_type
{ {
typedef T type; typedef T type;
}; };
template<class T1, class T2> template<class T1, class T2>
struct rbtree_internal_data_type< std::pair<T1, T2> > struct tree_internal_data_type< std::pair<T1, T2> >
{ {
typedef pair<T1, T2> type; typedef pair<T1, T2> type;
}; };
@@ -128,7 +128,7 @@ struct tree_node
typedef typename intrusive_tree_hook<VoidPointer>::type hook_type; typedef typename intrusive_tree_hook<VoidPointer>::type hook_type;
typedef T value_type; typedef T value_type;
typedef typename rbtree_internal_data_type<T>::type internal_type; typedef typename tree_internal_data_type<T>::type internal_type;
typedef tree_node<T, VoidPointer> node_type; typedef tree_node<T, VoidPointer> node_type;
@@ -244,6 +244,56 @@ struct intrusive_tree_type<A, ValueCompare, boost::container::red_black_tree>
namespace container_detail { namespace container_detail {
//This functor will be used with Intrusive clone functions to obtain
//already allocated nodes from a intrusive container instead of
//allocating new ones. When the intrusive container runs out of nodes
//the node holder is used instead.
template<class AllocHolder, bool DoMove>
class RecyclingCloner
{
typedef typename AllocHolder::intrusive_container intrusive_container;
typedef typename AllocHolder::Node node_type;
typedef typename AllocHolder::NodePtr node_ptr_type;
public:
RecyclingCloner(AllocHolder &holder, intrusive_container &itree)
: m_holder(holder), m_icont(itree)
{}
static void do_assign(node_ptr_type &p, const node_type &other, bool_<true>)
{ p->do_assign(other.m_data); }
static void do_assign(node_ptr_type &p, const node_type &other, bool_<false>)
{ p->do_move_assign(const_cast<node_type &>(other).m_data); }
node_ptr_type operator()(const node_type &other) const
{
if(node_ptr_type p = m_icont.unlink_leftmost_without_rebalance()){
//First recycle a node (this can't throw)
BOOST_TRY{
//This can throw
this->do_assign(p, other, bool_<DoMove>());
return p;
}
BOOST_CATCH(...){
//If there is an exception destroy the whole source
m_holder.destroy_node(p);
while((p = m_icont.unlink_leftmost_without_rebalance())){
m_holder.destroy_node(p);
}
BOOST_RETHROW
}
BOOST_CATCH_END
}
else{
return m_holder.create_node(other.m_data);
}
}
AllocHolder &m_holder;
intrusive_container &m_icont;
};
template <class Key, class Value, class KeyOfValue, template <class Key, class Value, class KeyOfValue,
class KeyCompare, class A, class KeyCompare, class A,
boost::container::tree_type tree_type_value> boost::container::tree_type tree_type_value>
@@ -274,82 +324,6 @@ class tree
typedef typename AllocHolder::allocator_v2 allocator_v2; typedef typename AllocHolder::allocator_v2 allocator_v2;
typedef typename AllocHolder::alloc_version alloc_version; typedef typename AllocHolder::alloc_version alloc_version;
class RecyclingCloner;
friend class RecyclingCloner;
class RecyclingCloner
{
public:
RecyclingCloner(AllocHolder &holder, Icont &irbtree)
: m_holder(holder), m_icont(irbtree)
{}
NodePtr operator()(const Node &other) const
{
if(NodePtr p = m_icont.unlink_leftmost_without_rebalance()){
//First recycle a node (this can't throw)
BOOST_TRY{
//This can throw
p->do_assign(other.m_data);
return p;
}
BOOST_CATCH(...){
//If there is an exception destroy the whole source
m_holder.destroy_node(p);
while((p = m_icont.unlink_leftmost_without_rebalance())){
m_holder.destroy_node(p);
}
BOOST_RETHROW
}
BOOST_CATCH_END
}
else{
return m_holder.create_node(other.m_data);
}
}
AllocHolder &m_holder;
Icont &m_icont;
};
class RecyclingMoveCloner;
friend class RecyclingMoveCloner;
class RecyclingMoveCloner
{
public:
RecyclingMoveCloner(AllocHolder &holder, Icont &irbtree)
: m_holder(holder), m_icont(irbtree)
{}
NodePtr operator()(const Node &other) const
{
if(NodePtr p = m_icont.unlink_leftmost_without_rebalance()){
//First recycle a node (this can't throw)
BOOST_TRY{
//This can throw
p->do_move_assign(const_cast<Node &>(other).m_data);
return p;
}
BOOST_CATCH(...){
//If there is an exception destroy the whole source
m_holder.destroy_node(p);
while((p = m_icont.unlink_leftmost_without_rebalance())){
m_holder.destroy_node(p);
}
BOOST_RETHROW
}
BOOST_CATCH_END
}
else{
return m_holder.create_node(other.m_data);
}
}
AllocHolder &m_holder;
Icont &m_icont;
};
BOOST_COPYABLE_AND_MOVABLE(tree) BOOST_COPYABLE_AND_MOVABLE(tree)
public: public:
@@ -371,11 +345,11 @@ class tree
allocator_traits<A>::size_type size_type; allocator_traits<A>::size_type size_type;
typedef typename boost::container:: typedef typename boost::container::
allocator_traits<A>::difference_type difference_type; allocator_traits<A>::difference_type difference_type;
typedef difference_type rbtree_difference_type; typedef difference_type tree_difference_type;
typedef pointer rbtree_pointer; typedef pointer tree_pointer;
typedef const_pointer rbtree_const_pointer; typedef const_pointer tree_const_pointer;
typedef reference rbtree_reference; typedef reference tree_reference;
typedef const_reference rbtree_const_reference; typedef const_reference tree_const_reference;
typedef NodeAlloc stored_allocator_type; typedef NodeAlloc stored_allocator_type;
private: private:
@@ -573,7 +547,7 @@ class tree
//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(*this, other_tree) , RecyclingCloner<AllocHolder, false>(*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
@@ -608,7 +582,7 @@ class tree
//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()
, RecyclingMoveCloner(*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