]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libstdc++-v3/include/bits/stl_tree.h
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / include / bits / stl_tree.h
index a9ca3facf9943953a4a62bdc30a6dbc9893b1b46..12ba3181dd9814ee7ecb36dc13cb6af8a95b26c3 100644 (file)
@@ -1,6 +1,6 @@
 // RB tree implementation -*- C++ -*-
 
-// Copyright (C) 2001-2016 Free Software Foundation, Inc.
+// Copyright (C) 2001-2020 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
 #include <bits/cpp_type_traits.h>
 #include <ext/alloc_traits.h>
 #if __cplusplus >= 201103L
-#include <ext/aligned_buffer.h>
+# include <ext/aligned_buffer.h>
+#endif
+#if __cplusplus > 201402L
+# include <bits/node_handle.h>
 #endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+#if __cplusplus > 201103L
+# define __cpp_lib_generic_associative_lookup 201304
+#endif
+
   // Red-black tree class, designed for use in implementing STL
   // associative containers (set, multiset, map, and multimap). The
   // insertion and deletion algorithms are based on those in Cormen,
@@ -84,7 +91,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // time begin(), and to the rightmost node of the tree, to enable
   // linear time performance when used with the generic set algorithms
   // (set_union, etc.)
-  // 
+  //
   // (2) when a node being deleted has two children its successor node
   // is relinked into its place, rather than copied, so that the only
   // iterators invalidated are those referring to the deleted node.
@@ -130,6 +137,81 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
   };
 
+  // Helper type offering value initialization guarantee on the compare functor.
+  template<typename _Key_compare>
+    struct _Rb_tree_key_compare
+    {
+      _Key_compare             _M_key_compare;
+
+      _Rb_tree_key_compare()
+      _GLIBCXX_NOEXCEPT_IF(
+       is_nothrow_default_constructible<_Key_compare>::value)
+      : _M_key_compare()
+      { }
+
+      _Rb_tree_key_compare(const _Key_compare& __comp)
+      : _M_key_compare(__comp)
+      { }
+
+#if __cplusplus >= 201103L
+      // Copy constructor added for consistency with C++98 mode.
+      _Rb_tree_key_compare(const _Rb_tree_key_compare&) = default;
+
+      _Rb_tree_key_compare(_Rb_tree_key_compare&& __x)
+       noexcept(is_nothrow_copy_constructible<_Key_compare>::value)
+      : _M_key_compare(__x._M_key_compare)
+      { }
+#endif
+    };
+
+  // Helper type to manage default initialization of node count and header.
+  struct _Rb_tree_header
+  {
+    _Rb_tree_node_base _M_header;
+    size_t             _M_node_count; // Keeps track of size of tree.
+
+    _Rb_tree_header() _GLIBCXX_NOEXCEPT
+    {
+      _M_header._M_color = _S_red;
+      _M_reset();
+    }
+
+#if __cplusplus >= 201103L
+    _Rb_tree_header(_Rb_tree_header&& __x) noexcept
+    {
+      if (__x._M_header._M_parent != nullptr)
+       _M_move_data(__x);
+      else
+       {
+         _M_header._M_color = _S_red;
+         _M_reset();
+       }
+    }
+#endif
+
+    void
+    _M_move_data(_Rb_tree_header& __from)
+    {
+      _M_header._M_color = __from._M_header._M_color;
+      _M_header._M_parent = __from._M_header._M_parent;
+      _M_header._M_left = __from._M_header._M_left;
+      _M_header._M_right = __from._M_header._M_right;
+      _M_header._M_parent->_M_parent = &_M_header;
+      _M_node_count = __from._M_node_count;
+
+      __from._M_reset();
+    }
+
+    void
+    _M_reset()
+    {
+      _M_header._M_parent = 0;
+      _M_header._M_left = &_M_header;
+      _M_header._M_right = &_M_header;
+      _M_node_count = 0;
+    }
+  };
+
   template<typename _Val>
     struct _Rb_tree_node : public _Rb_tree_node_base
     {
@@ -178,11 +260,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef _Tp* pointer;
 
       typedef bidirectional_iterator_tag iterator_category;
-      typedef ptrdiff_t                  difference_type;
+      typedef ptrdiff_t                         difference_type;
 
-      typedef _Rb_tree_iterator<_Tp>        _Self;
-      typedef _Rb_tree_node_base::_Base_ptr _Base_ptr;
-      typedef _Rb_tree_node<_Tp>*           _Link_type;
+      typedef _Rb_tree_iterator<_Tp>           _Self;
+      typedef _Rb_tree_node_base::_Base_ptr    _Base_ptr;
+      typedef _Rb_tree_node<_Tp>*              _Link_type;
 
       _Rb_tree_iterator() _GLIBCXX_NOEXCEPT
       : _M_node() { }
@@ -229,13 +311,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        return __tmp;
       }
 
-      bool
-      operator==(const _Self& __x) const _GLIBCXX_NOEXCEPT
-      { return _M_node == __x._M_node; }
+      friend bool
+      operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
+      { return __x._M_node == __y._M_node; }
 
-      bool
-      operator!=(const _Self& __x) const _GLIBCXX_NOEXCEPT
-      { return _M_node != __x._M_node; }
+      friend bool
+      operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
+      { return __x._M_node != __y._M_node; }
 
       _Base_ptr _M_node;
   };
@@ -243,18 +325,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct _Rb_tree_const_iterator
     {
-      typedef _Tp        value_type;
+      typedef _Tp       value_type;
       typedef const _Tp& reference;
       typedef const _Tp* pointer;
 
       typedef _Rb_tree_iterator<_Tp> iterator;
 
       typedef bidirectional_iterator_tag iterator_category;
-      typedef ptrdiff_t                  difference_type;
+      typedef ptrdiff_t                         difference_type;
 
-      typedef _Rb_tree_const_iterator<_Tp>        _Self;
-      typedef _Rb_tree_node_base::_Const_Base_ptr _Base_ptr;
-      typedef const _Rb_tree_node<_Tp>*           _Link_type;
+      typedef _Rb_tree_const_iterator<_Tp>             _Self;
+      typedef _Rb_tree_node_base::_Const_Base_ptr      _Base_ptr;
+      typedef const _Rb_tree_node<_Tp>*                        _Link_type;
 
       _Rb_tree_const_iterator() _GLIBCXX_NOEXCEPT
       : _M_node() { }
@@ -308,40 +390,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        return __tmp;
       }
 
-      bool
-      operator==(const _Self& __x) const _GLIBCXX_NOEXCEPT
-      { return _M_node == __x._M_node; }
+      friend bool
+      operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
+      { return __x._M_node == __y._M_node; }
 
-      bool
-      operator!=(const _Self& __x) const _GLIBCXX_NOEXCEPT
-      { return _M_node != __x._M_node; }
+      friend bool
+      operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
+      { return __x._M_node != __y._M_node; }
 
       _Base_ptr _M_node;
     };
 
-  template<typename _Val>
-    inline bool
-    operator==(const _Rb_tree_iterator<_Val>& __x,
-               const _Rb_tree_const_iterator<_Val>& __y) _GLIBCXX_NOEXCEPT
-    { return __x._M_node == __y._M_node; }
-
-  template<typename _Val>
-    inline bool
-    operator!=(const _Rb_tree_iterator<_Val>& __x,
-               const _Rb_tree_const_iterator<_Val>& __y) _GLIBCXX_NOEXCEPT
-    { return __x._M_node != __y._M_node; }
-
   void
   _Rb_tree_insert_and_rebalance(const bool __insert_left,
-                                _Rb_tree_node_base* __x,
-                                _Rb_tree_node_base* __p,
-                                _Rb_tree_node_base& __header) throw ();
+                               _Rb_tree_node_base* __x,
+                               _Rb_tree_node_base* __p,
+                               _Rb_tree_node_base& __header) throw ();
 
   _Rb_tree_node_base*
   _Rb_tree_rebalance_for_erase(_Rb_tree_node_base* const __z,
                               _Rb_tree_node_base& __header) throw ();
 
-#if __cplusplus > 201103L
+#if __cplusplus >= 201402L
   template<typename _Cmp, typename _SfinaeType, typename = __void_t<>>
     struct __has_is_transparent
     { };
@@ -350,14 +420,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __has_is_transparent<_Cmp, _SfinaeType,
                                __void_t<typename _Cmp::is_transparent>>
     { typedef void type; };
+
+  template<typename _Cmp, typename _SfinaeType>
+    using __has_is_transparent_t
+      = typename __has_is_transparent<_Cmp, _SfinaeType>::type;
+#endif
+
+#if __cplusplus > 201402L
+  template<typename _Tree1, typename _Cmp2>
+    struct _Rb_tree_merge_helper { };
 #endif
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc = allocator<_Val> >
+          typename _Compare, typename _Alloc = allocator<_Val> >
     class _Rb_tree
     {
       typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
-        rebind<_Rb_tree_node<_Val> >::other _Node_allocator;
+       rebind<_Rb_tree_node<_Val> >::other _Node_allocator;
 
       typedef __gnu_cxx::__alloc_traits<_Node_allocator> _Alloc_traits;
 
@@ -373,7 +452,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       struct _Reuse_or_alloc_node
       {
        _Reuse_or_alloc_node(_Rb_tree& __t)
-         : _M_root(__t._M_root()), _M_nodes(__t._M_rightmost()), _M_t(__t)
+       : _M_root(__t._M_root()), _M_nodes(__t._M_rightmost()), _M_t(__t)
        {
          if (_M_root)
            {
@@ -457,7 +536,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       struct _Alloc_node
       {
        _Alloc_node(_Rb_tree& __t)
-         : _M_t(__t) { }
+       : _M_t(__t) { }
 
        template<typename _Arg>
          _Link_type
@@ -485,11 +564,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Node_allocator&
       _M_get_Node_allocator() _GLIBCXX_NOEXCEPT
-      { return *static_cast<_Node_allocator*>(&this->_M_impl); }
-      
+      { return this->_M_impl; }
+
       const _Node_allocator&
       _M_get_Node_allocator() const _GLIBCXX_NOEXCEPT
-      { return *static_cast<const _Node_allocator*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
@@ -524,10 +603,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _M_construct_node(__tmp, __x);
        return __tmp;
       }
-
-      void
-      _M_destroy_node(_Link_type __p)
-      { get_allocator().destroy(__p->_M_valptr()); }
 #else
       template<typename... _Args>
        void
@@ -549,21 +624,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename... _Args>
-        _Link_type
-        _M_create_node(_Args&&... __args)
+       _Link_type
+       _M_create_node(_Args&&... __args)
        {
          _Link_type __tmp = _M_get_node();
          _M_construct_node(__tmp, std::forward<_Args>(__args)...);
          return __tmp;
        }
+#endif
 
       void
-      _M_destroy_node(_Link_type __p) noexcept
+      _M_destroy_node(_Link_type __p) _GLIBCXX_NOEXCEPT
       {
+#if __cplusplus < 201103L
+       get_allocator().destroy(__p->_M_valptr());
+#else
        _Alloc_traits::destroy(_M_get_Node_allocator(), __p->_M_valptr());
        __p->~_Rb_tree_node<_Val>();
-      }
 #endif
+      }
 
       void
       _M_drop_node(_Link_type __p) _GLIBCXX_NOEXCEPT
@@ -584,50 +663,54 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
     protected:
+#if _GLIBCXX_INLINE_VERSION
+      template<typename _Key_compare>
+#else
       // Unused _Is_pod_comparator is kept as it is part of mangled name.
       template<typename _Key_compare,
               bool /* _Is_pod_comparator */ = __is_pod(_Key_compare)>
-        struct _Rb_tree_impl : public _Node_allocator
-        {
-         _Key_compare          _M_key_compare;
-         _Rb_tree_node_base    _M_header;
-         size_type             _M_node_count; // Keeps track of size of tree.
+#endif
+       struct _Rb_tree_impl
+       : public _Node_allocator
+       , public _Rb_tree_key_compare<_Key_compare>
+       , public _Rb_tree_header
+       {
+         typedef _Rb_tree_key_compare<_Key_compare> _Base_key_compare;
 
          _Rb_tree_impl()
-         : _Node_allocator(), _M_key_compare(), _M_header(),
-           _M_node_count(0)
-         { _M_initialize(); }
+           _GLIBCXX_NOEXCEPT_IF(
+               is_nothrow_default_constructible<_Node_allocator>::value
+               && is_nothrow_default_constructible<_Base_key_compare>::value )
+         : _Node_allocator()
+         { }
+
+         _Rb_tree_impl(const _Rb_tree_impl& __x)
+         : _Node_allocator(_Alloc_traits::_S_select_on_copy(__x))
+         , _Base_key_compare(__x._M_key_compare)
+         { }
 
+#if __cplusplus < 201103L
          _Rb_tree_impl(const _Key_compare& __comp, const _Node_allocator& __a)
-         : _Node_allocator(__a), _M_key_compare(__comp), _M_header(),
-           _M_node_count(0)
-         { _M_initialize(); }
+         : _Node_allocator(__a), _Base_key_compare(__comp)
+         { }
+#else
+         _Rb_tree_impl(_Rb_tree_impl&&) = default;
 
-#if __cplusplus >= 201103L
-         _Rb_tree_impl(const _Key_compare& __comp, _Node_allocator&& __a)
-         : _Node_allocator(std::move(__a)), _M_key_compare(__comp),
-           _M_header(), _M_node_count(0)
-         { _M_initialize(); }
-#endif
+         explicit
+         _Rb_tree_impl(_Node_allocator&& __a)
+         : _Node_allocator(std::move(__a))
+         { }
 
-         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;
-         }
+         _Rb_tree_impl(_Rb_tree_impl&& __x, _Node_allocator&& __a)
+         : _Node_allocator(std::move(__a)),
+           _Base_key_compare(std::move(__x)),
+           _Rb_tree_header(std::move(__x))
+         { }
 
-       private:
-         void
-         _M_initialize()
-         {
-           this->_M_header._M_color = _S_red;
-           this->_M_header._M_parent = 0;
-           this->_M_header._M_left = &this->_M_header;
-           this->_M_header._M_right = &this->_M_header;
-         }         
+         _Rb_tree_impl(const _Key_compare& __comp, _Node_allocator&& __a)
+         : _Node_allocator(std::move(__a)), _Base_key_compare(__comp)
+         { }
+#endif
        };
 
       _Rb_tree_impl<_Compare> _M_impl;
@@ -676,13 +759,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_end() const _GLIBCXX_NOEXCEPT
       { return &this->_M_impl._M_header; }
 
-      static const_reference
-      _S_value(_Const_Link_type __x)
-      { return *__x->_M_valptr(); }
-
       static const _Key&
       _S_key(_Const_Link_type __x)
-      { return _KeyOfValue()(_S_value(__x)); }
+      {
+#if __cplusplus >= 201103L
+       // If we're asking for the key we're presumably using the comparison
+       // object, and so this is a good place to sanity check it.
+       static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},
+                     "comparison object must be invocable "
+                     "with two arguments of key type");
+# if __cplusplus >= 201703L
+       // _GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 2542. Missing const requirements for associative containers
+       if constexpr (__is_invocable<_Compare&, const _Key&, const _Key&>{})
+         static_assert(
+             is_invocable_v<const _Compare&, const _Key&, const _Key&>,
+             "comparison object must be invocable as const");
+# endif // C++17
+#endif // C++11
+
+       return _KeyOfValue()(*__x->_M_valptr());
+      }
 
       static _Link_type
       _S_left(_Base_ptr __x) _GLIBCXX_NOEXCEPT
@@ -700,13 +797,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _S_right(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT
       { return static_cast<_Const_Link_type>(__x->_M_right); }
 
-      static const_reference
-      _S_value(_Const_Base_ptr __x)
-      { return *static_cast<_Const_Link_type>(__x)->_M_valptr(); }
-
       static const _Key&
       _S_key(_Const_Base_ptr __x)
-      { return _KeyOfValue()(_S_value(__x)); }
+      { return _S_key(static_cast<_Const_Link_type>(__x)); }
 
       static _Base_ptr
       _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT
@@ -731,6 +824,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef std::reverse_iterator<iterator>       reverse_iterator;
       typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
 
+#if __cplusplus > 201402L
+      using node_type = _Node_handle<_Key, _Val, _Node_allocator>;
+      using insert_return_type = _Node_insert_return<
+       conditional_t<is_same_v<_Key, _Val>, const_iterator, iterator>,
+       node_type>;
+#endif
+
       pair<_Base_ptr, _Base_ptr>
       _M_get_insert_unique_pos(const key_type& __k);
 
@@ -748,19 +848,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     private:
 #if __cplusplus >= 201103L
       template<typename _Arg, typename _NodeGen>
-        iterator
+       iterator
        _M_insert_(_Base_ptr __x, _Base_ptr __y, _Arg&& __v, _NodeGen&);
 
       iterator
       _M_insert_node(_Base_ptr __x, _Base_ptr __y, _Link_type __z);
 
       template<typename _Arg>
-        iterator
-        _M_insert_lower(_Base_ptr __y, _Arg&& __v);
+       iterator
+       _M_insert_lower(_Base_ptr __y, _Arg&& __v);
 
       template<typename _Arg>
-        iterator
-        _M_insert_equal_lower(_Arg&& __x);
+       iterator
+       _M_insert_equal_lower(_Arg&& __x);
 
       iterator
       _M_insert_lower_node(_Base_ptr __p, _Link_type __z);
@@ -786,11 +886,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _Link_type
        _M_copy(_Const_Link_type __x, _Base_ptr __p, _NodeGen&);
 
+      template<typename _NodeGen>
+       _Link_type
+       _M_copy(const _Rb_tree& __x, _NodeGen& __gen)
+       {
+         _Link_type __root = _M_copy(__x._M_begin(), _M_end(), __gen);
+         _M_leftmost() = _S_minimum(__root);
+         _M_rightmost() = _S_maximum(__root);
+         _M_impl._M_node_count = __x._M_impl._M_node_count;
+         return __root;
+       }
+
       _Link_type
-      _M_copy(_Const_Link_type __x, _Base_ptr __p)
+      _M_copy(const _Rb_tree& __x)
       {
        _Alloc_node __an(*this);
-       return _M_copy(__x, __p, __an);
+       return _M_copy(__x, __an);
       }
 
       void
@@ -814,54 +925,62 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     public:
       // allocation/deallocation
+#if __cplusplus < 201103L
       _Rb_tree() { }
+#else
+      _Rb_tree() = default;
+#endif
 
       _Rb_tree(const _Compare& __comp,
               const allocator_type& __a = allocator_type())
       : _M_impl(__comp, _Node_allocator(__a)) { }
 
       _Rb_tree(const _Rb_tree& __x)
-      : _M_impl(__x._M_impl._M_key_compare,
-               _Alloc_traits::_S_select_on_copy(__x._M_get_Node_allocator()))
+      : _M_impl(__x._M_impl)
       {
        if (__x._M_root() != 0)
-         {
-           _M_root() = _M_copy(__x._M_begin(), _M_end());
-           _M_leftmost() = _S_minimum(_M_root());
-           _M_rightmost() = _S_maximum(_M_root());
-           _M_impl._M_node_count = __x._M_impl._M_node_count;
-         }
+         _M_root() = _M_copy(__x);
       }
 
 #if __cplusplus >= 201103L
       _Rb_tree(const allocator_type& __a)
-      : _M_impl(_Compare(), _Node_allocator(__a))
+      : _M_impl(_Node_allocator(__a))
       { }
 
       _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() != nullptr)
-         {
-           _M_root() = _M_copy(__x._M_begin(), _M_end());
-           _M_leftmost() = _S_minimum(_M_root());
-           _M_rightmost() = _S_maximum(_M_root());
-           _M_impl._M_node_count = __x._M_impl._M_node_count;
-         }
+         _M_root() = _M_copy(__x);
       }
 
-      _Rb_tree(_Rb_tree&& __x)
-      : _M_impl(__x._M_impl._M_key_compare, __x._M_get_Node_allocator())
-      {
-       if (__x._M_root() != 0)
-         _M_move_data(__x, std::true_type());
-      }
+      _Rb_tree(_Rb_tree&&) = default;
 
       _Rb_tree(_Rb_tree&& __x, const allocator_type& __a)
       : _Rb_tree(std::move(__x), _Node_allocator(__a))
       { }
 
-      _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a);
+    private:
+      _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a, true_type)
+      noexcept(is_nothrow_default_constructible<_Compare>::value)
+      : _M_impl(std::move(__x._M_impl), std::move(__a))
+      { }
+
+      _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a, false_type)
+      : _M_impl(__x._M_impl._M_key_compare, std::move(__a))
+      {
+       if (__x._M_root() != nullptr)
+         _M_move_data(__x, false_type{});
+      }
+
+    public:
+      _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a)
+      noexcept( noexcept(
+       _Rb_tree(std::declval<_Rb_tree&&>(), std::declval<_Node_allocator&&>(),
+                std::declval<typename _Alloc_traits::is_always_equal>())) )
+      : _Rb_tree(std::move(__x), std::move(__a),
+                typename _Alloc_traits::is_always_equal{})
+      { }
 #endif
 
       ~_Rb_tree() _GLIBCXX_NOEXCEPT
@@ -907,12 +1026,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       rend() const _GLIBCXX_NOEXCEPT
       { return const_reverse_iterator(begin()); }
 
-      bool
+      _GLIBCXX_NODISCARD bool
       empty() const _GLIBCXX_NOEXCEPT
       { return _M_impl._M_node_count == 0; }
 
       size_type
-      size() const _GLIBCXX_NOEXCEPT 
+      size() const _GLIBCXX_NOEXCEPT
       { return _M_impl._M_node_count; }
 
       size_type
@@ -926,15 +1045,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Insert/erase.
 #if __cplusplus >= 201103L
       template<typename _Arg>
-        pair<iterator, bool>
-        _M_insert_unique(_Arg&& __x);
+       pair<iterator, bool>
+       _M_insert_unique(_Arg&& __x);
 
       template<typename _Arg>
-        iterator
-        _M_insert_equal(_Arg&& __x);
+       iterator
+       _M_insert_equal(_Arg&& __x);
 
       template<typename _Arg, typename _NodeGen>
-        iterator
+       iterator
        _M_insert_unique_(const_iterator __pos, _Arg&& __x, _NodeGen&);
 
       template<typename _Arg>
@@ -972,6 +1091,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename... _Args>
        iterator
        _M_emplace_hint_equal(const_iterator __pos, _Args&&... __args);
+
+      template<typename _Iter>
+       using __same_value_type
+         = is_same<value_type, typename iterator_traits<_Iter>::value_type>;
+
+      template<typename _InputIterator>
+       __enable_if_t<__same_value_type<_InputIterator>::value>
+       _M_insert_range_unique(_InputIterator __first, _InputIterator __last)
+       {
+         _Alloc_node __an(*this);
+         for (; __first != __last; ++__first)
+           _M_insert_unique_(end(), *__first, __an);
+       }
+
+      template<typename _InputIterator>
+       __enable_if_t<!__same_value_type<_InputIterator>::value>
+       _M_insert_range_unique(_InputIterator __first, _InputIterator __last)
+       {
+         for (; __first != __last; ++__first)
+           _M_emplace_unique(*__first);
+       }
+
+      template<typename _InputIterator>
+       __enable_if_t<__same_value_type<_InputIterator>::value>
+       _M_insert_range_equal(_InputIterator __first, _InputIterator __last)
+       {
+         _Alloc_node __an(*this);
+         for (; __first != __last; ++__first)
+           _M_insert_equal_(end(), *__first, __an);
+       }
+
+      template<typename _InputIterator>
+       __enable_if_t<!__same_value_type<_InputIterator>::value>
+       _M_insert_range_equal(_InputIterator __first, _InputIterator __last)
+       {
+         _Alloc_node __an(*this);
+         for (; __first != __last; ++__first)
+           _M_emplace_equal(*__first);
+       }
 #else
       pair<iterator, bool>
       _M_insert_unique(const value_type& __x);
@@ -1001,15 +1159,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _Alloc_node __an(*this);
        return _M_insert_equal_(__pos, __x, __an);
       }
-#endif
 
       template<typename _InputIterator>
-        void
-        _M_insert_unique(_InputIterator __first, _InputIterator __last);
+       void
+       _M_insert_range_unique(_InputIterator __first, _InputIterator __last)
+       {
+         _Alloc_node __an(*this);
+         for (; __first != __last; ++__first)
+           _M_insert_unique_(end(), *__first, __an);
+       }
 
       template<typename _InputIterator>
-        void
-        _M_insert_equal(_InputIterator __first, _InputIterator __last);
+       void
+       _M_insert_range_equal(_InputIterator __first, _InputIterator __last)
+       {
+         _Alloc_node __an(*this);
+         for (; __first != __last; ++__first)
+           _M_insert_equal_(end(), *__first, __an);
+       }
+#endif
 
     private:
       void
@@ -1026,6 +1194,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       iterator
       erase(const_iterator __position)
       {
+       __glibcxx_assert(__position != end());
        const_iterator __result = __position;
        ++__result;
        _M_erase_aux(__position);
@@ -1037,6 +1206,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       iterator
       erase(iterator __position)
       {
+       __glibcxx_assert(__position != end());
        iterator __result = __position;
        ++__result;
        _M_erase_aux(__position);
@@ -1045,12 +1215,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #else
       void
       erase(iterator __position)
-      { _M_erase_aux(__position); }
+      {
+       __glibcxx_assert(__position != end());
+       _M_erase_aux(__position);
+      }
 
       void
       erase(const_iterator __position)
-      { _M_erase_aux(__position); }
+      {
+       __glibcxx_assert(__position != end());
+       _M_erase_aux(__position);
+      }
 #endif
+
       size_type
       erase(const key_type& __x);
 
@@ -1073,13 +1250,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       erase(const_iterator __first, const_iterator __last)
       { _M_erase_aux(__first, __last); }
 #endif
-      void
-      erase(const key_type* __first, const key_type* __last);
 
       void
       clear() _GLIBCXX_NOEXCEPT
       {
-        _M_erase(_M_begin());
+       _M_erase(_M_begin());
        _M_impl._M_reset();
       }
 
@@ -1115,10 +1290,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       pair<const_iterator, const_iterator>
       equal_range(const key_type& __k) const;
 
-#if __cplusplus > 201103L
+#if __cplusplus >= 201402L
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        iterator
        _M_find_tr(const _Kt& __k)
        {
@@ -1127,8 +1301,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        const_iterator
        _M_find_tr(const _Kt& __k) const
        {
@@ -1139,8 +1312,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        size_type
        _M_count_tr(const _Kt& __k) const
        {
@@ -1149,8 +1321,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        iterator
        _M_lower_bound_tr(const _Kt& __k)
        {
@@ -1159,8 +1330,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        const_iterator
        _M_lower_bound_tr(const _Kt& __k) const
        {
@@ -1178,8 +1348,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        iterator
        _M_upper_bound_tr(const _Kt& __k)
        {
@@ -1188,8 +1357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        const_iterator
        _M_upper_bound_tr(const _Kt& __k) const
        {
@@ -1207,8 +1375,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        pair<iterator, iterator>
        _M_equal_range_tr(const _Kt& __k)
        {
@@ -1218,8 +1385,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
 
       template<typename _Kt,
-              typename _Req =
-                typename __has_is_transparent<_Compare, _Kt>::type>
+              typename _Req = __has_is_transparent_t<_Compare, _Kt>>
        pair<const_iterator, const_iterator>
        _M_equal_range_tr(const _Kt& __k) const
        {
@@ -1253,65 +1419,223 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     private:
       // Move elements from container with equal allocator.
       void
-      _M_move_data(_Rb_tree&, std::true_type);
+      _M_move_data(_Rb_tree& __x, true_type)
+      { _M_impl._M_move_data(__x._M_impl); }
 
       // Move elements from container with possibly non-equal allocator,
       // which might result in a copy not a move.
       void
-      _M_move_data(_Rb_tree&, std::false_type);
+      _M_move_data(_Rb_tree&, false_type);
+
+      // Move assignment from container with equal allocator.
+      void
+      _M_move_assign(_Rb_tree&, true_type);
+
+      // Move assignment from container with possibly non-equal allocator,
+      // which might result in a copy not a move.
+      void
+      _M_move_assign(_Rb_tree&, false_type);
 #endif
-    };
 
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    inline bool
-    operator==(const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,
-              const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __y)
-    {
-      return __x.size() == __y.size()
-            && std::equal(__x.begin(), __x.end(), __y.begin());
-    }
+#if __cplusplus > 201402L
+    public:
+      /// Re-insert an extracted node.
+      insert_return_type
+      _M_reinsert_node_unique(node_type&& __nh)
+      {
+       insert_return_type __ret;
+       if (__nh.empty())
+         __ret.position = end();
+       else
+         {
+           __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc);
 
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    inline bool
-    operator<(const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,
-             const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __y)
-    {
-      return std::lexicographical_compare(__x.begin(), __x.end(), 
-                                         __y.begin(), __y.end());
-    }
+           auto __res = _M_get_insert_unique_pos(__nh._M_key());
+           if (__res.second)
+             {
+               __ret.position
+                 = _M_insert_node(__res.first, __res.second, __nh._M_ptr);
+               __nh._M_ptr = nullptr;
+               __ret.inserted = true;
+             }
+           else
+             {
+               __ret.node = std::move(__nh);
+               __ret.position = iterator(__res.first);
+               __ret.inserted = false;
+             }
+         }
+       return __ret;
+      }
 
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    inline bool
-    operator!=(const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,
-              const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __y)
-    { return !(__x == __y); }
+      /// Re-insert an extracted node.
+      iterator
+      _M_reinsert_node_equal(node_type&& __nh)
+      {
+       iterator __ret;
+       if (__nh.empty())
+         __ret = end();
+       else
+         {
+           __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc);
+           auto __res = _M_get_insert_equal_pos(__nh._M_key());
+           if (__res.second)
+             __ret = _M_insert_node(__res.first, __res.second, __nh._M_ptr);
+           else
+             __ret = _M_insert_equal_lower_node(__nh._M_ptr);
+           __nh._M_ptr = nullptr;
+         }
+       return __ret;
+      }
 
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    inline bool
-    operator>(const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,
-             const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __y)
-    { return __y < __x; }
+      /// Re-insert an extracted node.
+      iterator
+      _M_reinsert_node_hint_unique(const_iterator __hint, node_type&& __nh)
+      {
+       iterator __ret;
+       if (__nh.empty())
+         __ret = end();
+       else
+         {
+           __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc);
+           auto __res = _M_get_insert_hint_unique_pos(__hint, __nh._M_key());
+           if (__res.second)
+             {
+               __ret = _M_insert_node(__res.first, __res.second, __nh._M_ptr);
+               __nh._M_ptr = nullptr;
+             }
+           else
+             __ret = iterator(__res.first);
+         }
+       return __ret;
+      }
 
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    inline bool
-    operator<=(const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,
-              const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __y)
-    { return !(__y < __x); }
+      /// Re-insert an extracted node.
+      iterator
+      _M_reinsert_node_hint_equal(const_iterator __hint, node_type&& __nh)
+      {
+       iterator __ret;
+       if (__nh.empty())
+         __ret = end();
+       else
+         {
+           __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc);
+           auto __res = _M_get_insert_hint_equal_pos(__hint, __nh._M_key());
+           if (__res.second)
+             __ret = _M_insert_node(__res.first, __res.second, __nh._M_ptr);
+           else
+             __ret = _M_insert_equal_lower_node(__nh._M_ptr);
+           __nh._M_ptr = nullptr;
+         }
+       return __ret;
+      }
 
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    inline bool
-    operator>=(const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,
-              const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __y)
-    { return !(__x < __y); }
+      /// Extract a node.
+      node_type
+      extract(const_iterator __pos)
+      {
+       auto __ptr = _Rb_tree_rebalance_for_erase(
+           __pos._M_const_cast()._M_node, _M_impl._M_header);
+       --_M_impl._M_node_count;
+       return { static_cast<_Link_type>(__ptr), _M_get_Node_allocator() };
+      }
+
+      /// Extract a node.
+      node_type
+      extract(const key_type& __k)
+      {
+       node_type __nh;
+       auto __pos = find(__k);
+       if (__pos != end())
+         __nh = extract(const_iterator(__pos));
+       return __nh;
+      }
+
+      template<typename _Compare2>
+       using _Compatible_tree
+         = _Rb_tree<_Key, _Val, _KeyOfValue, _Compare2, _Alloc>;
+
+      template<typename, typename>
+       friend class _Rb_tree_merge_helper;
+
+      /// Merge from a compatible container into one with unique keys.
+      template<typename _Compare2>
+       void
+       _M_merge_unique(_Compatible_tree<_Compare2>& __src) noexcept
+       {
+         using _Merge_helper = _Rb_tree_merge_helper<_Rb_tree, _Compare2>;
+         for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
+           {
+             auto __pos = __i++;
+             auto __res = _M_get_insert_unique_pos(_KeyOfValue()(*__pos));
+             if (__res.second)
+               {
+                 auto& __src_impl = _Merge_helper::_S_get_impl(__src);
+                 auto __ptr = _Rb_tree_rebalance_for_erase(
+                     __pos._M_node, __src_impl._M_header);
+                 --__src_impl._M_node_count;
+                 _M_insert_node(__res.first, __res.second,
+                                static_cast<_Link_type>(__ptr));
+               }
+           }
+       }
+
+      /// Merge from a compatible container into one with equivalent keys.
+      template<typename _Compare2>
+       void
+       _M_merge_equal(_Compatible_tree<_Compare2>& __src) noexcept
+       {
+         using _Merge_helper = _Rb_tree_merge_helper<_Rb_tree, _Compare2>;
+         for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
+           {
+             auto __pos = __i++;
+             auto __res = _M_get_insert_equal_pos(_KeyOfValue()(*__pos));
+             if (__res.second)
+               {
+                 auto& __src_impl = _Merge_helper::_S_get_impl(__src);
+                 auto __ptr = _Rb_tree_rebalance_for_erase(
+                     __pos._M_node, __src_impl._M_header);
+                 --__src_impl._M_node_count;
+                 _M_insert_node(__res.first, __res.second,
+                                static_cast<_Link_type>(__ptr));
+               }
+           }
+       }
+#endif // C++17
+
+      friend bool
+      operator==(const _Rb_tree& __x, const _Rb_tree& __y)
+      {
+       return __x.size() == __y.size()
+         && std::equal(__x.begin(), __x.end(), __y.begin());
+      }
+
+      friend bool
+      operator<(const _Rb_tree& __x, const _Rb_tree& __y)
+      {
+       return std::lexicographical_compare(__x.begin(), __x.end(),
+                                           __y.begin(), __y.end());
+      }
+
+      friend bool _GLIBCXX_DEPRECATED
+      operator!=(const _Rb_tree& __x, const _Rb_tree& __y)
+      { return !(__x == __y); }
+
+      friend bool _GLIBCXX_DEPRECATED
+      operator>(const _Rb_tree& __x, const _Rb_tree& __y)
+      { return __y < __x; }
+
+      friend bool _GLIBCXX_DEPRECATED
+      operator<=(const _Rb_tree& __x, const _Rb_tree& __y)
+      { return !(__y < __x); }
+
+      friend bool _GLIBCXX_DEPRECATED
+      operator>=(const _Rb_tree& __x, const _Rb_tree& __y)
+      { return !(__x < __y); }
+    };
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     inline void
     swap(_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,
         _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __y)
@@ -1319,43 +1643,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus >= 201103L
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
-    _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a)
-    : _M_impl(__x._M_impl._M_key_compare, std::move(__a))
-    {
-      using __eq = typename _Alloc_traits::is_always_equal;
-      if (__x._M_root() != nullptr)
-       _M_move_data(__x, __eq());
-    }
-
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    void
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
-    _M_move_data(_Rb_tree& __x, std::true_type)
-    {
-      _M_root() = __x._M_root();
-      _M_leftmost() = __x._M_leftmost();
-      _M_rightmost() = __x._M_rightmost();
-      _M_root()->_M_parent = _M_end();
-
-      __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;
-    }
-
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     void
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
-    _M_move_data(_Rb_tree& __x, std::false_type)
+    _M_move_data(_Rb_tree& __x, false_type)
     {
       if (_M_get_Node_allocator() == __x._M_get_Node_allocator())
-         _M_move_data(__x, std::true_type());
+       _M_move_data(__x, true_type());
       else
        {
          _Alloc_node __an(*this);
@@ -1365,33 +1659,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              auto& __val = const_cast<value_type&>(__cval);
              return __an(std::move_if_noexcept(__val));
            };
-         _M_root() = _M_copy(__x._M_begin(), _M_end(), __lbd);
-         _M_leftmost() = _S_minimum(_M_root());
-         _M_rightmost() = _S_maximum(_M_root());
-         _M_impl._M_node_count = __x._M_impl._M_node_count;
+         _M_root() = _M_copy(__x, __lbd);
        }
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
+          typename _Compare, typename _Alloc>
+    inline void
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
-    operator=(_Rb_tree&& __x)
-    noexcept(_Alloc_traits::_S_nothrow_move()
-            && is_nothrow_move_assignable<_Compare>::value)
+    _M_move_assign(_Rb_tree& __x, true_type)
     {
-      _M_impl._M_key_compare = __x._M_impl._M_key_compare;
-      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() != nullptr)
-           _M_move_data(__x, std::true_type());
-         std::__alloc_on_move(_M_get_Node_allocator(),
-                              __x._M_get_Node_allocator());
-         return *this;
-       }
+      clear();
+      if (__x._M_root() != nullptr)
+       _M_move_data(__x, true_type());
+      std::__alloc_on_move(_M_get_Node_allocator(),
+                          __x._M_get_Node_allocator());
+    }
+
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+          typename _Compare, typename _Alloc>
+    void
+    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+    _M_move_assign(_Rb_tree& __x, false_type)
+    {
+      if (_M_get_Node_allocator() == __x._M_get_Node_allocator())
+       return _M_move_assign(__x, true_type{});
 
       // Try to move each node reusing existing nodes and copying __x nodes
       // structure.
@@ -1405,17 +1697,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              auto& __val = const_cast<value_type&>(__cval);
              return __roan(std::move_if_noexcept(__val));
            };
-         _M_root() = _M_copy(__x._M_begin(), _M_end(), __lbd);
-         _M_leftmost() = _S_minimum(_M_root());
-         _M_rightmost() = _S_maximum(_M_root());
-         _M_impl._M_node_count = __x._M_impl._M_node_count;
+         _M_root() = _M_copy(__x, __lbd);
          __x.clear();
        }
+    }
+
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+          typename _Compare, typename _Alloc>
+    inline _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
+    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+    operator=(_Rb_tree&& __x)
+    noexcept(_Alloc_traits::_S_nothrow_move()
+            && is_nothrow_move_assignable<_Compare>::value)
+    {
+      _M_impl._M_key_compare = std::move(__x._M_impl._M_key_compare);
+      _M_move_assign(__x, __bool_constant<_Alloc_traits::_S_nothrow_move()>());
       return *this;
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     template<typename _Iterator>
       void
       _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -1428,7 +1729,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     template<typename _Iterator>
       void
       _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -1442,7 +1743,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     operator=(const _Rb_tree& __x)
@@ -1470,19 +1771,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _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(), __roan);
-             _M_leftmost() = _S_minimum(_M_root());
-             _M_rightmost() = _S_maximum(_M_root());
-             _M_impl._M_node_count = __x._M_impl._M_node_count;
-           }
+           _M_root() = _M_copy(__x, __roan);
        }
 
       return *this;
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
     template<typename _Arg, typename _NodeGen>
 #else
@@ -1511,7 +1807,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
     template<typename _Arg>
 #endif
@@ -1536,7 +1832,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
     template<typename _Arg>
 #endif
@@ -1554,7 +1850,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        {
          __y = __x;
          __x = !_M_impl._M_key_compare(_S_key(__x), _KeyOfValue()(__v)) ?
-               _S_left(__x) : _S_right(__x);
+               _S_left(__x) : _S_right(__x);
        }
       return _M_insert_lower(__y, _GLIBCXX_FORWARD(_Arg, __v));
     }
@@ -1597,7 +1893,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     void
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     _M_erase(_Link_type __x)
@@ -1613,7 +1909,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue,
                      _Compare, _Alloc>::iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -1629,7 +1925,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue,
                      _Compare, _Alloc>::const_iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -1645,7 +1941,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue,
                      _Compare, _Alloc>::iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -1661,7 +1957,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue,
                      _Compare, _Alloc>::const_iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -1677,7 +1973,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
                           _Compare, _Alloc>::iterator,
         typename _Rb_tree<_Key, _Val, _KeyOfValue,
@@ -1700,7 +1996,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              __y = __x, __x = _S_left(__x);
              __xu = _S_right(__xu);
              return pair<iterator,
-                         iterator>(_M_lower_bound(__x, __y, __k),
+                         iterator>(_M_lower_bound(__x, __y, __k),
                                    _M_upper_bound(__xu, __yu, __k));
            }
        }
@@ -1709,7 +2005,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
                           _Compare, _Alloc>::const_iterator,
         typename _Rb_tree<_Key, _Val, _KeyOfValue,
@@ -1732,7 +2028,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              __y = __x, __x = _S_left(__x);
              __xu = _S_right(__xu);
              return pair<const_iterator,
-                         const_iterator>(_M_lower_bound(__x, __y, __k),
+                         const_iterator>(_M_lower_bound(__x, __y, __k),
                                          _M_upper_bound(__xu, __yu, __k));
            }
        }
@@ -1741,7 +2037,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     void
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     swap(_Rb_tree& __t)
@@ -1750,32 +2046,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (_M_root() == 0)
        {
          if (__t._M_root() != 0)
-           {
-             _M_root() = __t._M_root();
-             _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_impl._M_reset();
-           }
+           _M_impl._M_move_data(__t._M_impl);
        }
       else if (__t._M_root() == 0)
-       {
-         __t._M_root() = _M_root();
-         __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_impl._M_reset();
-       }
+       __t._M_impl._M_move_data(_M_impl);
       else
        {
          std::swap(_M_root(),__t._M_root());
          std::swap(_M_leftmost(),__t._M_leftmost());
          std::swap(_M_rightmost(),__t._M_rightmost());
-         
+
          _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);
@@ -1788,7 +2068,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
                           _Compare, _Alloc>::_Base_ptr,
         typename _Rb_tree<_Key, _Val, _KeyOfValue,
@@ -1820,7 +2100,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
                           _Compare, _Alloc>::_Base_ptr,
         typename _Rb_tree<_Key, _Val, _KeyOfValue,
@@ -1835,13 +2115,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        {
          __y = __x;
          __x = _M_impl._M_key_compare(__k, _S_key(__x)) ?
-               _S_left(__x) : _S_right(__x);
+               _S_left(__x) : _S_right(__x);
        }
       return _Res(__x, __y);
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
     template<typename _Arg>
 #endif
@@ -1870,7 +2150,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
     template<typename _Arg>
 #endif
@@ -1890,10 +2170,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
                           _Compare, _Alloc>::_Base_ptr,
-         typename _Rb_tree<_Key, _Val, _KeyOfValue,
+        typename _Rb_tree<_Key, _Val, _KeyOfValue,
                           _Compare, _Alloc>::_Base_ptr>
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     _M_get_insert_hint_unique_pos(const_iterator __position,
@@ -1949,7 +2229,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
     template<typename _Arg, typename _NodeGen>
 #else
@@ -1976,10 +2256,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
                           _Compare, _Alloc>::_Base_ptr,
-         typename _Rb_tree<_Key, _Val, _KeyOfValue,
+        typename _Rb_tree<_Key, _Val, _KeyOfValue,
                           _Compare, _Alloc>::_Base_ptr>
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     _M_get_insert_hint_equal_pos(const_iterator __position, const key_type& __k)
@@ -2014,7 +2294,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
       else
        {
-         // ... then try after.  
+         // ... then try after.
          iterator __after = __pos;
          if (__pos._M_node == _M_rightmost())
            return _Res(0, _M_rightmost());
@@ -2031,7 +2311,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
     template<typename _Arg, typename _NodeGen>
 #else
@@ -2060,7 +2340,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus >= 201103L
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     _M_insert_node(_Base_ptr __x, _Base_ptr __p, _Link_type __z)
@@ -2076,7 +2356,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     _M_insert_lower_node(_Base_ptr __p, _Link_type __z)
@@ -2092,7 +2372,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     _M_insert_equal_lower_node(_Link_type __z)
@@ -2103,13 +2383,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        {
          __y = __x;
          __x = !_M_impl._M_key_compare(_S_key(__x), _S_key(__z)) ?
-               _S_left(__x) : _S_right(__x);
+               _S_left(__x) : _S_right(__x);
        }
       return _M_insert_lower_node(__y, __z);
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     template<typename... _Args>
       pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
                             _Compare, _Alloc>::iterator, bool>
@@ -2136,7 +2416,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     template<typename... _Args>
       typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
       _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -2157,7 +2437,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     template<typename... _Args>
       typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
       _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -2183,7 +2463,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     template<typename... _Args>
       typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
       _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -2208,32 +2488,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 #endif
 
-  template<typename _Key, typename _Val, typename _KoV,
-           typename _Cmp, typename _Alloc>
-    template<class _II>
-      void
-      _Rb_tree<_Key, _Val, _KoV, _Cmp, _Alloc>::
-      _M_insert_unique(_II __first, _II __last)
-      {
-       _Alloc_node __an(*this);
-       for (; __first != __last; ++__first)
-         _M_insert_unique_(end(), *__first, __an);
-      }
-
-  template<typename _Key, typename _Val, typename _KoV,
-           typename _Cmp, typename _Alloc>
-    template<class _II>
-      void
-      _Rb_tree<_Key, _Val, _KoV, _Cmp, _Alloc>::
-      _M_insert_equal(_II __first, _II __last)
-      {
-       _Alloc_node __an(*this);
-       for (; __first != __last; ++__first)
-         _M_insert_equal_(end(), *__first, __an);
-      }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     void
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     _M_erase_aux(const_iterator __position)
@@ -2247,7 +2504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     void
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     _M_erase_aux(const_iterator __first, const_iterator __last)
@@ -2256,33 +2513,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        clear();
       else
        while (__first != __last)
-         erase(__first++);
+         _M_erase_aux(__first++);
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     erase(const _Key& __x)
     {
       pair<iterator, iterator> __p = equal_range(__x);
       const size_type __old_size = size();
-      erase(__p.first, __p.second);
+      _M_erase_aux(__p.first, __p.second);
       return __old_size - size();
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
-    void
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
-    erase(const _Key* __first, const _Key* __last)
-    {
-      while (__first != __last)
-       erase(*__first++);
-    }
-
-  template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue,
                      _Compare, _Alloc>::iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -2295,7 +2542,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue,
                      _Compare, _Alloc>::const_iterator
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
@@ -2303,12 +2550,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       const_iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k);
       return (__j == end()
-             || _M_impl._M_key_compare(__k, 
+             || _M_impl._M_key_compare(__k,
                                        _S_key(__j._M_node))) ? end() : __j;
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
     count(const _Key& __k) const
@@ -2320,10 +2567,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   _GLIBCXX_PURE unsigned int
   _Rb_tree_black_count(const _Rb_tree_node_base* __node,
-                       const _Rb_tree_node_base* __root) throw ();
+                      const _Rb_tree_node_base* __root) throw ();
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
-           typename _Compare, typename _Alloc>
+          typename _Compare, typename _Alloc>
     bool
     _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::__rb_verify() const
     {
@@ -2360,6 +2607,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return true;
     }
 
+#if __cplusplus > 201402L
+  // Allow access to internals of compatible _Rb_tree specializations.
+  template<typename _Key, typename _Val, typename _Sel, typename _Cmp1,
+          typename _Alloc, typename _Cmp2>
+    struct _Rb_tree_merge_helper<_Rb_tree<_Key, _Val, _Sel, _Cmp1, _Alloc>,
+                                _Cmp2>
+    {
+    private:
+      friend class _Rb_tree<_Key, _Val, _Sel, _Cmp1, _Alloc>;
+
+      static auto&
+      _S_get_impl(_Rb_tree<_Key, _Val, _Sel, _Cmp2, _Alloc>& __tree)
+      { return __tree._M_impl; }
+    };
+#endif // C++17
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace