Hi

    Here is a patch to add recycling of Rb tree nodes when possible.

I replaced the _Rb_tree::_M_move_assign with a move assignment operator to benefit from:
- move of elements when the whole data structure cannot be moved
- faster data structure cloning rather than full regeneration of the tree when _M_move_assign was failing

Note that this patch contains also a cleanup of a useless template parameter _Is_pod_comparator on _Rb_tree_impl. If you want to apply it quickly for 4.9 do not hesitate.

I haven't done any specific test for this feature, existing ones looks good enough to me. If you want me to add some I will when back from vacation. I am mostly submitting this patch to show you that I worked on it and you do not need to do it yourself.

2013-12-27  François Dumont <fdum...@gcc.gnu.org>

    * include/bits/stl_tree.h (_Rb_tree_reuse_or_alloc_node<>): New.
    (_Rb_tree_alloc_node<>): Likewise.
    (_Rb_tree<>::_M_clone_node): Made template to take a node
    generator.
    (_Rb_tree_impl<>): Remove unused _Is_pod_comparator template
    value.
    (_Rb_tree<>::_M_move_assign): Replace by...
    (_Rb_tree<>::operator(_Rb_tree&&)): ...this.
    (_Rb_tree_impl<>::_M_reset): New.
    (_Rb_tree<>::_M_insert_): Add node generator parameter.
    (_Rb_tree<>::_M_copy): Add overload taking a node generator.
    (_Rb_tree<>::_M_insert_unique_): Add node generator parameter.
    (_Rb_tree<>::_M_insert_equal_): Add node generator parameter.
    (_Rb_tree<>::_M_assign_unique): New.
    (_Rb_tree<>::_M_assign_equal): New.
    (_Rb_tree<>): Adapt to use _Rb_tree_impl<>::_M_reset and reuse
    nodes as much as possible.
    * include/bits/stl_set.h (set<>::operator=(set<>&&): Adapt to use
    _Rb_tree move assignment operator.
    (set<>::operator=(initializer_list<>)): Adapt to use
    _Rb_tree<>::_M_assign_unique.
    * include/bits/stl_multiset.h
    (multiset<>::operator=(multiset<>&&)): Adapt to use
    _Rb_tree move assignment operator.
    (multiset<>::operator=(initializer_list<>)): Adapt to use
    _Rb_tree<>::_M_assign_equal.
    * include/bits/stl_map.h (map<>::operator=(map<>&&): Adapt to use
    _Rb_tree move assignment operator.
    (map<>::operator=(initializer_list<>)): Adapt to use
    _Rb_tree<>::_M_assign_unique.
    * include/bits/stl_multimap.h
    (multimap<>::operator=(multimap<>&&)): Adapt to use
    _Rb_tree move assignment operator.
    (multimap<>::operator=(initializer_list<>)): Adapt to use
    _Rb_tree<>::_M_assign_equal.

Tested under Linux x86_64.

Happy new year.

François

Index: include/bits/stl_set.h
===================================================================
--- include/bits/stl_set.h	(revision 206214)
+++ include/bits/stl_set.h	(working copy)
@@ -277,15 +277,7 @@
       set&
       operator=(set&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
       {
-	if (!_M_t._M_move_assign(__x._M_t))
-	  {
-	    // The rvalue's allocator cannot be moved and is not equal,
-	    // so we need to individually move each element.
-	    clear();
-	    insert(std::__make_move_if_noexcept_iterator(__x._M_t.begin()),
-		   std::__make_move_if_noexcept_iterator(__x._M_t.end()));
-	    __x.clear();
-	  }
+	_M_t = std::move(__x._M_t);
       	return *this;
       }
 
@@ -303,8 +295,7 @@
       set&
       operator=(initializer_list<value_type> __l)
       {
-	this->clear();
-	this->insert(__l.begin(), __l.end());
+	_M_t._M_assign_unique(__l.begin(), __l.end());
 	return *this;
       }
 #endif
Index: include/bits/stl_multiset.h
===================================================================
--- include/bits/stl_multiset.h	(revision 206214)
+++ include/bits/stl_multiset.h	(working copy)
@@ -274,15 +274,7 @@
       multiset&
       operator=(multiset&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
       {
-	if (!_M_t._M_move_assign(__x._M_t))
-	  {
-	    // The rvalue's allocator cannot be moved and is not equal,
-	    // so we need to individually move each element.
-	    clear();
-	    insert(std::__make_move_if_noexcept_iterator(__x._M_t.begin()),
-		   std::__make_move_if_noexcept_iterator(__x._M_t.end()));
-	    __x.clear();
-	  }
+	_M_t = std::move(__x._M_t);
 	return *this;
       }
 
@@ -300,8 +292,7 @@
       multiset&
       operator=(initializer_list<value_type> __l)
       {
-	this->clear();
-	this->insert(__l.begin(), __l.end());
+	_M_t._M_assign_equal(__l.begin(), __l.end());
 	return *this;
       }
 #endif
Index: include/bits/stl_map.h
===================================================================
--- include/bits/stl_map.h	(revision 206214)
+++ include/bits/stl_map.h	(working copy)
@@ -307,15 +307,7 @@
       map&
       operator=(map&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
       {
-	if (!_M_t._M_move_assign(__x._M_t))
-	  {
-	    // The rvalue's allocator cannot be moved and is not equal,
-	    // so we need to individually move each element.
-	    clear();
-	    insert(std::__make_move_if_noexcept_iterator(__x.begin()),
-		   std::__make_move_if_noexcept_iterator(__x.end()));
-	    __x.clear();
-	  }
+	_M_t = std::move(__x._M_t);
 	return *this;
       }
 
@@ -333,8 +325,7 @@
       map&
       operator=(initializer_list<value_type> __l)
       {
-	this->clear();
-	this->insert(__l.begin(), __l.end());
+	_M_t._M_assign_unique(__l.begin(), __l.end());
 	return *this;
       }
 #endif
Index: include/bits/stl_multimap.h
===================================================================
--- include/bits/stl_multimap.h	(revision 206214)
+++ include/bits/stl_multimap.h	(working copy)
@@ -301,15 +301,7 @@
       multimap&
       operator=(multimap&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
       {
-	if (!_M_t._M_move_assign(__x._M_t))
-	  {
-	    // The rvalue's allocator cannot be moved and is not equal,
-	    // so we need to individually move each element.
-	    clear();
-	    insert(std::__make_move_if_noexcept_iterator(__x.begin()),
-		   std::__make_move_if_noexcept_iterator(__x.end()));
-	    __x.clear();
-	  }
+	_M_t = std::move(__x._M_t);
 	return *this;
       }
 
@@ -327,8 +319,7 @@
       multimap&
       operator=(initializer_list<value_type> __l)
       {
-	this->clear();
-	this->insert(__l.begin(), __l.end());
+	_M_t._M_assign_equal(__l.begin(), __l.end());
 	return *this;
       }
 #endif
Index: include/bits/stl_tree.h
===================================================================
--- include/bits/stl_tree.h	(revision 206214)
+++ include/bits/stl_tree.h	(working copy)
@@ -330,6 +330,110 @@
                const _Rb_tree_const_iterator<_Val>& __y) _GLIBCXX_NOEXCEPT
     { return __x._M_node != __y._M_node; }
 
+  // Functor recycling a pool of nodes and using allocation once the pool is
+  // empty.
+  template<typename _RbTree>
+    struct _Rb_tree_reuse_or_alloc_node
+    {
+    private:
+      typedef _RbTree __rb_tree;
+      typedef _Rb_tree_node<typename _RbTree::value_type> __node_type;
+
+    public:
+      _Rb_tree_reuse_or_alloc_node(const _Rb_tree_node_base& __header,
+				   __rb_tree& __t)
+	: _M_root(__header._M_parent), _M_nodes(__header._M_right), _M_t(__t)
+      {
+	if (_M_root)
+	  _M_root->_M_parent = 0;
+	else
+	  _M_nodes = 0;
+      }
+
+      ~_Rb_tree_reuse_or_alloc_node()
+      { _M_t._M_erase(static_cast<__node_type*>(_M_root)); }
+
+      template<typename _Arg>
+	__node_type*
+#if __cplusplus < 201103L
+	operator()(const _Arg& __arg) const
+#else
+	operator()(_Arg&& __arg) const
+#endif
+	{
+	  __node_type* __node = static_cast<__node_type*>(_M_extract());
+	  if (__node)
+	    {
+	      _M_t._M_destroy_node(__node);
+	      _M_t._M_construct_node(__node, _GLIBCXX_FORWARD(_Arg, __arg));
+	      return __node;
+	    }
+	  return _M_t._M_create_node(_GLIBCXX_FORWARD(_Arg, __arg));
+	}
+
+    private:
+      typedef _Rb_tree_node_base __node_base;
+
+      __node_base*
+      _M_extract() const
+      {
+	if (!_M_nodes)
+	  return _M_nodes;
+
+	__node_base* __node = _M_nodes;
+	_M_nodes = _M_nodes->_M_parent;
+	if (_M_nodes)
+	  {
+	    if (_M_nodes->_M_right == __node)
+	      {
+		_M_nodes->_M_right = 0;
+
+		if (_M_nodes->_M_left)
+		  {
+		    _M_nodes = _M_nodes->_M_left;
+
+		    while (_M_nodes->_M_right)
+		      _M_nodes = _M_nodes->_M_right;
+		  }
+	      }
+	    else // __node is on the left.
+	      _M_nodes->_M_left = 0;
+	  }
+	else
+	  _M_root = 0;
+
+	return __node;
+      }
+
+      mutable __node_base* _M_root;
+      mutable __node_base* _M_nodes;
+      _RbTree& _M_t;
+    };
+
+  // Functor similar to the previous one but without any pool of node to recycle.
+  template<typename _RbTree>
+    struct _Rb_tree_alloc_node
+    {
+    private:
+      typedef _Rb_tree_node<typename _RbTree::value_type> __node_type;
+
+    public:
+      _Rb_tree_alloc_node(_RbTree& __t)
+	: _M_t(__t) { }
+
+      template<typename _Arg>
+	__node_type*
+#if __cplusplus < 201103L
+	operator()(const _Arg& __arg) const
+#else
+	operator()(_Arg&& __arg) const
+#endif
+	{ return _M_t._M_create_node(_GLIBCXX_FORWARD(_Arg, __arg)); }
+
+    private:
+      _RbTree& _M_t;
+    };
+
   void
   _Rb_tree_insert_and_rebalance(const bool __insert_left,
                                 _Rb_tree_node_base* __x,
@@ -349,6 +453,12 @@
         rebind<_Rb_tree_node<_Val> >::other _Node_allocator;
 
       typedef __gnu_cxx::__alloc_traits<_Node_allocator> _Alloc_traits;
+      template<typename _RT>
+	friend struct _Rb_tree_alloc_node;
+      typedef _Rb_tree_alloc_node<_Rb_tree> __alloc_node_t;
+      template<typename _RT>
+	friend struct _Rb_tree_reuse_or_alloc_node;
+      typedef _Rb_tree_reuse_or_alloc_node<_Rb_tree> __reuse_or_alloc_node_t;
 
     protected:
       typedef _Rb_tree_node_base* 		_Base_ptr;
@@ -389,44 +499,55 @@
       { _Alloc_traits::deallocate(_M_get_Node_allocator(), __p, 1); }
 
 #if __cplusplus < 201103L
-      _Link_type
-      _M_create_node(const value_type& __x)
+      void
+      _M_construct_node(_Link_type __node, const value_type& __x)
       {
-	_Link_type __tmp = _M_get_node();
 	__try
-	  { get_allocator().construct(__tmp->_M_valptr(), __x); }
+	  { get_allocator().construct(__node->_M_valptr(), __x); }
 	__catch(...)
 	  {
-	    _M_put_node(__tmp);
+	    _M_put_node(__node);
 	    __throw_exception_again;
 	  }
+      }
+
+      _Link_type
+      _M_create_node(const value_type& __x)
+      {
+	_Link_type __tmp = _M_get_node();
+	_M_construct_node(__tmp, __x);
 	return __tmp;
       }
 
       void
       _M_destroy_node(_Link_type __p)
-      {
-	get_allocator().destroy(__p->_M_valptr());
-	_M_put_node(__p);
-      }
+      { get_allocator().destroy(__p->_M_valptr()); }
 #else
       template<typename... _Args>
-        _Link_type
-        _M_create_node(_Args&&... __args)
+	void
+	_M_construct_node(_Link_type __node, _Args&&... __args)
 	{
-	  _Link_type __tmp = _M_get_node();
 	  __try
 	    {
-	      ::new(__tmp) _Rb_tree_node<_Val>;
+	      ::new(__node) _Rb_tree_node<_Val>();
 	      _Alloc_traits::construct(_M_get_Node_allocator(),
-				       __tmp->_M_valptr(),
+				       __node->_M_valptr(),
 				       std::forward<_Args>(__args)...);
 	    }
 	  __catch(...)
 	    {
-	      _M_put_node(__tmp);
+	      __node->~_Rb_tree_node<_Val>();
+	      _M_put_node(__node);
 	      __throw_exception_again;
 	    }
+	}
+
+      template<typename... _Args>
+        _Link_type
+        _M_create_node(_Args&&... __args)
+	{
+	  _Link_type __tmp = _M_get_node();
+	  _M_construct_node(__tmp, std::forward<_Args>(__args)...);
 	  return __tmp;
 	}
 
@@ -435,23 +556,29 @@
       {
 	_Alloc_traits::destroy(_M_get_Node_allocator(), __p->_M_valptr());
 	__p->~_Rb_tree_node<_Val>();
-	_M_put_node(__p);
       }
 #endif
 
-      _Link_type
-      _M_clone_node(_Const_Link_type __x)
+      void
+      _M_drop_node(_Link_type __p) _GLIBCXX_NOEXCEPT
       {
-	_Link_type __tmp = _M_create_node(*__x->_M_valptr());
-	__tmp->_M_color = __x->_M_color;
-	__tmp->_M_left = 0;
-	__tmp->_M_right = 0;
-	return __tmp;
+	_M_destroy_node(__p);
+	_M_put_node(__p);
       }
 
+      template<typename _NodeGen>
+	_Link_type
+	_M_clone_node(_Link_type __x, const _NodeGen& __node_gen)
+	{
+	  _Link_type __tmp = __node_gen(*__x->_M_valptr());
+	  __tmp->_M_color = __x->_M_color;
+	  __tmp->_M_left = 0;
+	  __tmp->_M_right = 0;
+	  return __tmp;
+	}
+
     protected:
-      template<typename _Key_compare, 
-	       bool _Is_pod_comparator = __is_pod(_Key_compare)>
+      template<typename _Key_compare>
         struct _Rb_tree_impl : public _Node_allocator
         {
 	  _Key_compare		_M_key_compare;
@@ -475,6 +602,15 @@
 	  { _M_initialize(); }
 #endif
 
+	  void
+	  _M_reset()
+	  {
+	    this->_M_header._M_parent = 0;
+	    this->_M_header._M_left = &this->_M_header;
+	    this->_M_header._M_right = &this->_M_header;
+	    this->_M_node_count = 0;
+	  }
+
 	private:
 	  void
 	  _M_initialize()
@@ -514,11 +650,11 @@
       { return this->_M_impl._M_header._M_right; }
 
       _Link_type
-      _M_begin() _GLIBCXX_NOEXCEPT
+      _M_begin() const _GLIBCXX_NOEXCEPT
       { return static_cast<_Link_type>(this->_M_impl._M_header._M_parent); }
 
       _Const_Link_type
-      _M_begin() const _GLIBCXX_NOEXCEPT
+      _M_cbegin() const _GLIBCXX_NOEXCEPT
       {
 	return static_cast<_Const_Link_type>
 	  (this->_M_impl._M_header._M_parent);
@@ -529,7 +665,7 @@
       { return static_cast<_Link_type>(&this->_M_impl._M_header); }
 
       _Const_Link_type
-      _M_end() const _GLIBCXX_NOEXCEPT
+      _M_cend() const _GLIBCXX_NOEXCEPT
       { return static_cast<_Const_Link_type>(&this->_M_impl._M_header); }
 
       static const_reference
@@ -603,9 +739,9 @@
 				   const key_type& __k);
 
 #if __cplusplus >= 201103L
-      template<typename _Arg>
+      template<typename _Arg, typename _NodeGen>
         iterator
-        _M_insert_(_Base_ptr __x, _Base_ptr __y, _Arg&& __v);
+	_M_insert_(_Base_ptr __x, _Base_ptr __y, _Arg&& __v, const _NodeGen&);
 
       iterator
       _M_insert_node(_Base_ptr __x, _Base_ptr __y, _Link_type __z);
@@ -624,9 +760,10 @@
       iterator
       _M_insert_equal_lower_node(_Link_type __z);
 #else
-      iterator
-      _M_insert_(_Base_ptr __x, _Base_ptr __y,
-		 const value_type& __v);
+      template<typename _NodeGen>
+	iterator
+	_M_insert_(_Base_ptr __x, _Base_ptr __y,
+		   const value_type& __v, const _NodeGen&);
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 233. Insertion hints in associative containers.
@@ -637,8 +774,13 @@
       _M_insert_equal_lower(const value_type& __x);
 #endif
 
+      template<typename _NodeGen>
+	_Link_type
+	_M_copy(_Link_type __x, _Link_type __p, const _NodeGen&);
+
       _Link_type
-      _M_copy(_Const_Link_type __x, _Link_type __p);
+      _M_copy(_Link_type __x, _Link_type __p)
+      { return _M_copy(__x, __p, __alloc_node_t(*this)); }
 
       void
       _M_erase(_Link_type __x);
@@ -688,7 +830,7 @@
       _Rb_tree(const _Rb_tree& __x, const allocator_type& __a)
       : _M_impl(__x._M_impl._M_key_compare, _Node_allocator(__a))
       {
-	if (__x._M_root() != 0)
+	if (__x._M_root() != nullptr)
 	  {
 	    _M_root() = _M_copy(__x._M_begin(), _M_end());
 	    _M_leftmost() = _S_minimum(_M_root());
@@ -789,14 +931,30 @@
         iterator
         _M_insert_equal(_Arg&& __x);
 
-      template<typename _Arg>
+      template<typename _Arg, typename _NodeGen>
         iterator
-        _M_insert_unique_(const_iterator __position, _Arg&& __x);
+	_M_insert_unique_(const_iterator __pos, _Arg&& __x, const _NodeGen&);
 
       template<typename _Arg>
-        iterator
-        _M_insert_equal_(const_iterator __position, _Arg&& __x);
+	iterator
+	_M_insert_unique_(const_iterator __pos, _Arg&& __x)
+	{
+	  return _M_insert_unique_(__pos, std::forward<_Arg>(__x),
+				   __alloc_node_t(*this));
+	}
 
+      template<typename _Arg, typename _NodeGen>
+	iterator
+	_M_insert_equal_(const_iterator __pos, _Arg&& __x, const _NodeGen&);
+
+      template<typename _Arg>
+	iterator
+	_M_insert_equal_(const_iterator __pos, _Arg&& __x)
+	{
+	  return _M_insert_equal_(__pos, std::forward<_Arg>(__x),
+				  __alloc_node_t(*this));
+	}
+
       template<typename... _Args>
 	pair<iterator, bool>
 	_M_emplace_unique(_Args&&... __args);
@@ -819,11 +977,22 @@
       iterator
       _M_insert_equal(const value_type& __x);
 
+      template<typename _NodeGen>
+	iterator
+	_M_insert_unique_(const_iterator __pos, const value_type& __x,
+			  const _NodeGen&);
+
       iterator
-      _M_insert_unique_(const_iterator __position, const value_type& __x);
+      _M_insert_unique_(const_iterator __pos, const value_type& __x)
+      { return _M_insert_unique_(__pos, __x, __alloc_node_t(*this)); }
 
+      template<typename _NodeGen>
+	iterator
+	_M_insert_equal_(const_iterator __pos, const value_type& __x,
+			 const _NodeGen&);
       iterator
-      _M_insert_equal_(const_iterator __position, const value_type& __x);
+      _M_insert_equal_(const_iterator __pos, const value_type& __x)
+      { return _M_insert_equal_(__pos, __x, __alloc_node_t(*this)); }
 #endif
 
       template<typename _InputIterator>
@@ -903,10 +1072,7 @@
       clear() _GLIBCXX_NOEXCEPT
       {
         _M_erase(_M_begin());
-        _M_leftmost() = _M_end();
-        _M_root() = 0;
-        _M_rightmost() = _M_end();
-        _M_impl._M_node_count = 0;
+	_M_impl._M_reset();
       }
 
       // Set operations.
@@ -925,7 +1091,7 @@
 
       const_iterator
       lower_bound(const key_type& __k) const
-      { return _M_lower_bound(_M_begin(), _M_end(), __k); }
+      { return _M_lower_bound(_M_cbegin(), _M_cend(), __k); }
 
       iterator
       upper_bound(const key_type& __k)
@@ -933,7 +1099,7 @@
 
       const_iterator
       upper_bound(const key_type& __k) const
-      { return _M_upper_bound(_M_begin(), _M_end(), __k); }
+      { return _M_upper_bound(_M_cbegin(), _M_cend(), __k); }
 
       pair<iterator, iterator>
       equal_range(const key_type& __k);
@@ -946,8 +1112,16 @@
       __rb_verify() const;
 
 #if __cplusplus >= 201103L
-      bool
-      _M_move_assign(_Rb_tree&);
+      _Rb_tree&
+      operator=(_Rb_tree&&) noexcept(_Alloc_traits::_S_nothrow_move());
+
+      template<typename _Iterator>
+	void
+	_M_assign_unique(_Iterator, _Iterator);
+
+      template<typename _Iterator>
+	void
+	_M_assign_equal(_Iterator, _Iterator);
 #endif
     };
 
@@ -1013,12 +1187,15 @@
     _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a)
     : _M_impl(__x._M_impl._M_key_compare, std::move(__a))
     {
-      if (__x._M_root() != 0)
+      if (__x._M_root() != nullptr)
 	{
 	  if (!_Alloc_traits::_S_always_equal()
 	      && __x._M_get_Node_allocator() != __a)
 	    {
-	      _M_root() = _M_copy(__x._M_begin(), _M_end());
+	      __alloc_node_t __an(*this);
+	      _M_root() = _M_copy(__x._M_begin(), _M_end(),
+				  [&__an](value_type& __val)
+				  { return __an(std::move_if_noexcept(__val)); });
 	      _M_leftmost() = _S_minimum(_M_root());
 	      _M_rightmost() = _S_maximum(_M_root());
 	      _M_impl._M_node_count = __x._M_impl._M_node_count;
@@ -1029,49 +1206,83 @@
 	      _M_leftmost() = __x._M_leftmost();
 	      _M_rightmost() = __x._M_rightmost();
 	      _M_root()->_M_parent = _M_end();
+	      this->_M_impl._M_node_count = __x._M_impl._M_node_count;
 
-	      __x._M_root() = 0;
-	      __x._M_leftmost() = __x._M_end();
-	      __x._M_rightmost() = __x._M_end();
-
-	      this->_M_impl._M_node_count = __x._M_impl._M_node_count;
-	      __x._M_impl._M_node_count = 0;
+	      __x._M_impl._M_reset();
 	    }
 	}
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
-    bool
+    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
-    _M_move_assign(_Rb_tree& __x)
+    operator=(_Rb_tree&& __x)
+    noexcept(_Alloc_traits::_S_nothrow_move())
     {
       if (_Alloc_traits::_S_propagate_on_move_assign()
 	  || _Alloc_traits::_S_always_equal()
 	  || _M_get_Node_allocator() == __x._M_get_Node_allocator())
 	{
 	  clear();
-	  if (__x._M_root() != 0)
+	  if (__x._M_root() != nullptr)
 	    {
 	      _M_root() = __x._M_root();
 	      _M_leftmost() = __x._M_leftmost();
 	      _M_rightmost() = __x._M_rightmost();
 	      _M_root()->_M_parent = _M_end();
+	      this->_M_impl._M_node_count = __x._M_impl._M_node_count;
 
-	      __x._M_root() = 0;
-	      __x._M_leftmost() = __x._M_end();
-	      __x._M_rightmost() = __x._M_end();
-
-	      this->_M_impl._M_node_count = __x._M_impl._M_node_count;
-	      __x._M_impl._M_node_count = 0;
+	      __x._M_impl._M_reset();
 	    }
 	  if (_Alloc_traits::_S_propagate_on_move_assign())
 	    std::__alloc_on_move(_M_get_Node_allocator(),
 				 __x._M_get_Node_allocator());
-	  return true;
+	  return *this;
 	}
-      return false;
+
+      // Try to move each node reusing existing nodes and copying __x nodes
+      // structure.
+      __reuse_or_alloc_node_t __roan(this->_M_impl._M_header, *this);
+      _M_impl._M_reset();
+      if (__x._M_root() != nullptr)
+	{
+	  _M_root() = _M_copy(__x._M_begin(), _M_end(),
+			      [&__roan](value_type& __val)
+			      { return __roan(std::move_if_noexcept(__val)); });
+	  _M_leftmost() = _S_minimum(_M_root());
+	  _M_rightmost() = _S_maximum(_M_root());
+	  _M_impl._M_node_count = __x._M_impl._M_node_count;
+	  __x.clear();
+	}
+      return *this;
     }
+
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+           typename _Compare, typename _Alloc>
+    template<typename _Iterator>
+      void
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_assign_unique(_Iterator __first, _Iterator __last)
+      {
+	__reuse_or_alloc_node_t __roan(this->_M_impl._M_header, *this);
+	_M_impl._M_reset();
+	for (; __first != __last; ++__first)
+	  _M_insert_unique_(end(), *__first, __roan);
+      }
+
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+           typename _Compare, typename _Alloc>
+    template<typename _Iterator>
+      void
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_assign_equal(_Iterator __first, _Iterator __last)
+      {
+	__reuse_or_alloc_node_t __roan(this->_M_impl._M_header, *this);
+	_M_impl._M_reset();
+	for (; __first != __last; ++__first)
+	  _M_insert_equal_(end(), *__first, __roan);
+      }
 #endif
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
@@ -1083,7 +1294,6 @@
       if (this != &__x)
 	{
 	  // Note that _Key may be a constant type.
-	  clear();
 #if __cplusplus >= 201103L
 	  if (_Alloc_traits::_S_propagate_on_copy_assign())
 	    {
@@ -1092,14 +1302,19 @@
 	      if (!_Alloc_traits::_S_always_equal()
 		  && __this_alloc != __that_alloc)
 		{
+		  // Replacement allocator cannot free existing storage, we need
+		  // to erase nodes first.
+		  clear();
 		  std::__alloc_on_copy(__this_alloc, __that_alloc);
 		}
 	    }
 #endif
+	__reuse_or_alloc_node_t __roan(this->_M_impl._M_header, *this);
+	  _M_impl._M_reset();
 	  _M_impl._M_key_compare = __x._M_impl._M_key_compare;
 	  if (__x._M_root() != 0)
 	    {
-	      _M_root() = _M_copy(__x._M_begin(), _M_end());
+	      _M_root() = _M_copy(__x._M_begin(), _M_end(), __roan);
 	      _M_leftmost() = _S_minimum(_M_root());
 	      _M_rightmost() = _S_maximum(_M_root());
 	      _M_impl._M_node_count = __x._M_impl._M_node_count;
@@ -1111,27 +1326,31 @@
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
-    template<typename _Arg>
+    template<typename _Arg, typename _NodeGen>
+#else
+    template<typename _NodeGen>
 #endif
-    typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_insert_(_Base_ptr __x, _Base_ptr __p,
 #if __cplusplus >= 201103L
-    _M_insert_(_Base_ptr __x, _Base_ptr __p, _Arg&& __v)
+		 _Arg&& __v,
 #else
-    _M_insert_(_Base_ptr __x, _Base_ptr __p, const _Val& __v)
+		 const _Val& __v,
 #endif
-    {
-      bool __insert_left = (__x != 0 || __p == _M_end()
-			    || _M_impl._M_key_compare(_KeyOfValue()(__v),
-						      _S_key(__p)));
+		 const _NodeGen& __node_gen)
+      {
+	bool __insert_left = (__x != 0 || __p == _M_end()
+			      || _M_impl._M_key_compare(_KeyOfValue()(__v),
+							_S_key(__p)));
 
-      _Link_type __z = _M_create_node(_GLIBCXX_FORWARD(_Arg, __v));
+	_Link_type __z = __node_gen(_GLIBCXX_FORWARD(_Arg, __v));
 
-      _Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
-				    this->_M_impl._M_header);
-      ++_M_impl._M_node_count;
-      return iterator(__z);
-    }
+	_Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
+				      this->_M_impl._M_header);
+	++_M_impl._M_node_count;
+	return iterator(__z);
+      }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
@@ -1183,40 +1402,41 @@
     }
 
   template<typename _Key, typename _Val, typename _KoV,
-           typename _Compare, typename _Alloc>
-    typename _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::_Link_type
-    _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::
-    _M_copy(_Const_Link_type __x, _Link_type __p)
-    {
-      // Structural copy.  __x and __p must be non-null.
-      _Link_type __top = _M_clone_node(__x);
-      __top->_M_parent = __p;
+	   typename _Compare, typename _Alloc>
+    template<typename _NodeGen>
+      typename _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::_Link_type
+      _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::
+      _M_copy(_Link_type __x, _Link_type __p, const _NodeGen& __node_gen)
+      {
+	// Structural copy. __x and __p must be non-null.
+	_Link_type __top = _M_clone_node(__x, __node_gen);
+	__top->_M_parent = __p;
 
-      __try
-	{
-	  if (__x->_M_right)
-	    __top->_M_right = _M_copy(_S_right(__x), __top);
-	  __p = __top;
-	  __x = _S_left(__x);
+	__try
+	  {
+	    if (__x->_M_right)
+	      __top->_M_right = _M_copy(_S_right(__x), __top, __node_gen);
+	    __p = __top;
+	    __x = _S_left(__x);
 
-	  while (__x != 0)
-	    {
-	      _Link_type __y = _M_clone_node(__x);
-	      __p->_M_left = __y;
-	      __y->_M_parent = __p;
-	      if (__x->_M_right)
-		__y->_M_right = _M_copy(_S_right(__x), __y);
-	      __p = __y;
-	      __x = _S_left(__x);
-	    }
-	}
-      __catch(...)
-	{
-	  _M_erase(__top);
-	  __throw_exception_again;
-	}
-      return __top;
-    }
+	    while (__x != 0)
+	      {
+		_Link_type __y = _M_clone_node(__x, __node_gen);
+		__p->_M_left = __y;
+		__y->_M_parent = __p;
+		if (__x->_M_right)
+		  __y->_M_right = _M_copy(_S_right(__x), __y, __node_gen);
+		__p = __y;
+		__x = _S_left(__x);
+	      }
+	  }
+	__catch(...)
+	  {
+	    _M_erase(__top);
+	    __throw_exception_again;
+	  }
+	return __top;
+      }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
@@ -1229,7 +1449,7 @@
 	{
 	  _M_erase(_S_right(__x));
 	  _Link_type __y = _S_left(__x);
-	  _M_destroy_node(__x);
+	  _M_drop_node(__x);
 	  __x = __y;
 	}
     }
@@ -1338,8 +1558,8 @@
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     equal_range(const _Key& __k) const
     {
-      _Const_Link_type __x = _M_begin();
-      _Const_Link_type __y = _M_end();
+      _Const_Link_type __x = _M_cbegin();
+      _Const_Link_type __y = _M_cend();
       while (__x != 0)
 	{
 	  if (_M_impl._M_key_compare(_S_key(__x), __k))
@@ -1377,10 +1597,9 @@
 	      _M_leftmost() = __t._M_leftmost();
 	      _M_rightmost() = __t._M_rightmost();
 	      _M_root()->_M_parent = _M_end();
+	      _M_impl._M_node_count = __t._M_impl._M_node_count;
 	      
-	      __t._M_root() = 0;
-	      __t._M_leftmost() = __t._M_end();
-	      __t._M_rightmost() = __t._M_end();
+	      __t._M_impl._M_reset();
 	    }
 	}
       else if (__t._M_root() == 0)
@@ -1389,10 +1608,9 @@
 	  __t._M_leftmost() = _M_leftmost();
 	  __t._M_rightmost() = _M_rightmost();
 	  __t._M_root()->_M_parent = __t._M_end();
+	  __t._M_impl._M_node_count = _M_impl._M_node_count;
 	  
-	  _M_root() = 0;
-	  _M_leftmost() = _M_end();
-	  _M_rightmost() = _M_end();
+	  _M_impl._M_reset();
 	}
       else
 	{
@@ -1402,9 +1620,9 @@
 	  
 	  _M_root()->_M_parent = _M_end();
 	  __t._M_root()->_M_parent = __t._M_end();
+	  std::swap(this->_M_impl._M_node_count, __t._M_impl._M_node_count);
 	}
       // No need to swap header's color as it does not change.
-      std::swap(this->_M_impl._M_node_count, __t._M_impl._M_node_count);
       std::swap(this->_M_impl._M_key_compare, __t._M_impl._M_key_compare);
 
       _Alloc_traits::_S_on_swap(_M_get_Node_allocator(),
@@ -1483,9 +1701,12 @@
 	= _M_get_insert_unique_pos(_KeyOfValue()(__v));
 
       if (__res.second)
-	return _Res(_M_insert_(__res.first, __res.second,
-			       _GLIBCXX_FORWARD(_Arg, __v)),
-		    true);
+	{
+	  __alloc_node_t __an(*this);
+	  return _Res(_M_insert_(__res.first, __res.second,
+				 _GLIBCXX_FORWARD(_Arg, __v), __an),
+		      true);
+	}
 
       return _Res(iterator(static_cast<_Link_type>(__res.first)), false);
     }
@@ -1505,7 +1726,9 @@
     {
       pair<_Base_ptr, _Base_ptr> __res
 	= _M_get_insert_equal_pos(_KeyOfValue()(__v));
-      return _M_insert_(__res.first, __res.second, _GLIBCXX_FORWARD(_Arg, __v));
+      __alloc_node_t __an(*this);
+      return _M_insert_(__res.first, __res.second,
+			_GLIBCXX_FORWARD(_Arg, __v), __an);
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
@@ -1570,22 +1793,27 @@
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
-    template<typename _Arg>
+    template<typename _Arg, typename _NodeGen>
+#else
+    template<typename _NodeGen>
 #endif
-    typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_insert_unique_(const_iterator __position,
 #if __cplusplus >= 201103L
-    _M_insert_unique_(const_iterator __position, _Arg&& __v)
+			_Arg&& __v,
 #else
-    _M_insert_unique_(const_iterator __position, const _Val& __v)
+			const _Val& __v,
 #endif
+			const _NodeGen& __node_gen)
     {
       pair<_Base_ptr, _Base_ptr> __res
 	= _M_get_insert_hint_unique_pos(__position, _KeyOfValue()(__v));
 
       if (__res.second)
 	return _M_insert_(__res.first, __res.second,
-			  _GLIBCXX_FORWARD(_Arg, __v));
+			  _GLIBCXX_FORWARD(_Arg, __v),
+			  __node_gen);
       return iterator(static_cast<_Link_type>(__res.first));
     }
 
@@ -1647,25 +1875,30 @@
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
-    template<typename _Arg>
+    template<typename _Arg, typename _NodeGen>
+#else
+    template<typename _NodeGen>
 #endif
-    typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_insert_equal_(const_iterator __position,
 #if __cplusplus >= 201103L
-    _M_insert_equal_(const_iterator __position, _Arg&& __v)
+		       _Arg&& __v,
 #else
-    _M_insert_equal_(const_iterator __position, const _Val& __v)
+		       const _Val& __v,
 #endif
-    {
-      pair<_Base_ptr, _Base_ptr> __res
-	= _M_get_insert_hint_equal_pos(__position, _KeyOfValue()(__v));
+		       const _NodeGen& __node_gen)
+      {
+	pair<_Base_ptr, _Base_ptr> __res
+	  = _M_get_insert_hint_equal_pos(__position, _KeyOfValue()(__v));
 
-      if (__res.second)
-	return _M_insert_(__res.first, __res.second,
-			  _GLIBCXX_FORWARD(_Arg, __v));
+	if (__res.second)
+	  return _M_insert_(__res.first, __res.second,
+			    _GLIBCXX_FORWARD(_Arg, __v),
+			    __node_gen);
 
-      return _M_insert_equal_lower(_GLIBCXX_FORWARD(_Arg, __v));
-    }
+	return _M_insert_equal_lower(_GLIBCXX_FORWARD(_Arg, __v));
+      }
 
 #if __cplusplus >= 201103L
   template<typename _Key, typename _Val, typename _KeyOfValue,
@@ -1734,12 +1967,12 @@
 	    if (__res.second)
 	      return _Res(_M_insert_node(__res.first, __res.second, __z), true);
 	
-	    _M_destroy_node(__z);
+	    _M_drop_node(__z);
 	    return _Res(iterator(static_cast<_Link_type>(__res.first)), false);
 	  }
 	__catch(...)
 	  {
-	    _M_destroy_node(__z);
+	    _M_drop_node(__z);
 	    __throw_exception_again;
 	  }
       }
@@ -1760,7 +1993,7 @@
 	  }
 	__catch(...)
 	  {
-	    _M_destroy_node(__z);
+	    _M_drop_node(__z);
 	    __throw_exception_again;
 	  }
       }
@@ -1781,12 +2014,12 @@
 	    if (__res.second)
 	      return _M_insert_node(__res.first, __res.second, __z);
 
-	    _M_destroy_node(__z);
+	    _M_drop_node(__z);
 	    return iterator(static_cast<_Link_type>(__res.first));
 	  }
 	__catch(...)
 	  {
-	    _M_destroy_node(__z);
+	    _M_drop_node(__z);
 	    __throw_exception_again;
 	  }
       }
@@ -1811,7 +2044,7 @@
 	  }
 	__catch(...)
 	  {
-	    _M_destroy_node(__z);
+	    _M_drop_node(__z);
 	    __throw_exception_again;
 	  }
       }
@@ -1824,8 +2057,9 @@
       _Rb_tree<_Key, _Val, _KoV, _Cmp, _Alloc>::
       _M_insert_unique(_II __first, _II __last)
       {
+	__alloc_node_t __an(*this);
 	for (; __first != __last; ++__first)
-	  _M_insert_unique_(end(), *__first);
+	  _M_insert_unique_(end(), *__first, __an);
       }
 
   template<typename _Key, typename _Val, typename _KoV,
@@ -1835,8 +2069,9 @@
       _Rb_tree<_Key, _Val, _KoV, _Cmp, _Alloc>::
       _M_insert_equal(_II __first, _II __last)
       {
+	__alloc_node_t __an(*this);
 	for (; __first != __last; ++__first)
-	  _M_insert_equal_(end(), *__first);
+	  _M_insert_equal_(end(), *__first, __an);
       }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
@@ -1849,7 +2084,7 @@
 	static_cast<_Link_type>(_Rb_tree_rebalance_for_erase
 				(const_cast<_Base_ptr>(__position._M_node),
 				 this->_M_impl._M_header));
-      _M_destroy_node(__y);
+      _M_drop_node(__y);
       --_M_impl._M_node_count;
     }
 
@@ -1908,7 +2143,7 @@
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     find(const _Key& __k) const
     {
-      const_iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k);
+      const_iterator __j = _M_lower_bound(_M_cbegin(), _M_cend(), __k);
       return (__j == end()
 	      || _M_impl._M_key_compare(__k, 
 					_S_key(__j._M_node))) ? end() : __j;

Reply via email to