From ed0704797ddc89e25605c06f7847a5863d965f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 24 Dec 2013 12:58:28 +0100 Subject: [PATCH] Refactored tree cloners into a single standalone class to avoid unnecessary instantiations and simplify maintenance. --- .../container/detail/node_alloc_holder.hpp | 1 + include/boost/container/detail/tree.hpp | 146 +++++++----------- 2 files changed, 61 insertions(+), 86 deletions(-) diff --git a/include/boost/container/detail/node_alloc_holder.hpp b/include/boost/container/detail/node_alloc_holder.hpp index f34b2c6..3c1b4f6 100644 --- a/include/boost/container/detail/node_alloc_holder.hpp +++ b/include/boost/container/detail/node_alloc_holder.hpp @@ -88,6 +88,7 @@ struct node_alloc_holder typedef allocator_traits allocator_traits_type; typedef typename allocator_traits_type::value_type value_type; + typedef ICont intrusive_container; typedef typename ICont::value_type Node; typedef typename allocator_traits_type::template portable_rebind_alloc::type NodeAlloc; diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index d958dd1..d0d1bc8 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -103,13 +103,13 @@ struct intrusive_tree_hook //This trait is used to type-pun std::pair because in C++03 //compilers std::pair is useless for C++11 features template -struct rbtree_internal_data_type +struct tree_internal_data_type { typedef T type; }; template -struct rbtree_internal_data_type< std::pair > +struct tree_internal_data_type< std::pair > { typedef pair type; }; @@ -128,7 +128,7 @@ struct tree_node typedef typename intrusive_tree_hook::type hook_type; typedef T value_type; - typedef typename rbtree_internal_data_type::type internal_type; + typedef typename tree_internal_data_type::type internal_type; typedef tree_node node_type; @@ -244,6 +244,56 @@ struct intrusive_tree_type 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 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_) + { p->do_assign(other.m_data); } + + static void do_assign(node_ptr_type &p, const node_type &other, bool_) + { p->do_move_assign(const_cast(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_()); + 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 @@ -274,82 +324,6 @@ class tree typedef typename AllocHolder::allocator_v2 allocator_v2; 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(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) public: @@ -371,11 +345,11 @@ class tree allocator_traits::size_type size_type; typedef typename boost::container:: allocator_traits::difference_type difference_type; - typedef difference_type rbtree_difference_type; - typedef pointer rbtree_pointer; - typedef const_pointer rbtree_const_pointer; - typedef reference rbtree_reference; - typedef const_reference rbtree_const_reference; + typedef difference_type tree_difference_type; + typedef pointer tree_pointer; + typedef const_pointer tree_const_pointer; + typedef reference tree_reference; + typedef const_reference tree_const_reference; typedef NodeAlloc stored_allocator_type; private: @@ -573,7 +547,7 @@ class tree //Now recreate the source tree reusing nodes stored by other_tree this->icont().clone_from (x.icont() - , RecyclingCloner(*this, other_tree) + , RecyclingCloner(*this, other_tree) , Destroyer(this->node_alloc())); //If there are remaining nodes, destroy them @@ -608,7 +582,7 @@ class tree //Now recreate the source tree reusing nodes stored by other_tree this->icont().clone_from (x.icont() - , RecyclingMoveCloner(*this, other_tree) + , RecyclingCloner(*this, other_tree) , Destroyer(this->node_alloc())); //If there are remaining nodes, destroy them