1  // Debugging multiset implementation -*- C++ -*-
       2  
       3  // Copyright (C) 2003-2023 Free Software Foundation, Inc.
       4  //
       5  // This file is part of the GNU ISO C++ Library.  This library is free
       6  // software; you can redistribute it and/or modify it under the
       7  // terms of the GNU General Public License as published by the
       8  // Free Software Foundation; either version 3, or (at your option)
       9  // any later version.
      10  
      11  // This library is distributed in the hope that it will be useful,
      12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14  // GNU General Public License for more details.
      15  
      16  // Under Section 7 of GPL version 3, you are granted additional
      17  // permissions described in the GCC Runtime Library Exception, version
      18  // 3.1, as published by the Free Software Foundation.
      19  
      20  // You should have received a copy of the GNU General Public License and
      21  // a copy of the GCC Runtime Library Exception along with this program;
      22  // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23  // <http://www.gnu.org/licenses/>.
      24  
      25  /** @file debug/multiset.h
      26   *  This file is a GNU debug extension to the Standard C++ Library.
      27   */
      28  
      29  #ifndef _GLIBCXX_DEBUG_MULTISET_H
      30  #define _GLIBCXX_DEBUG_MULTISET_H 1
      31  
      32  #include <debug/safe_sequence.h>
      33  #include <debug/safe_container.h>
      34  #include <debug/safe_iterator.h>
      35  #include <bits/stl_pair.h>
      36  
      37  namespace std _GLIBCXX_VISIBILITY(default)
      38  {
      39  namespace __debug
      40  {
      41    /// Class std::multiset with safety/checking/debug instrumentation.
      42    template<typename _Key, typename _Compare = std::less<_Key>,
      43  	   typename _Allocator = std::allocator<_Key> >
      44      class multiset
      45      : public __gnu_debug::_Safe_container<
      46  	multiset<_Key, _Compare, _Allocator>, _Allocator,
      47  	__gnu_debug::_Safe_node_sequence>,
      48        public _GLIBCXX_STD_C::multiset<_Key, _Compare, _Allocator>
      49      {
      50        typedef _GLIBCXX_STD_C::multiset<_Key, _Compare, _Allocator>	_Base;
      51        typedef __gnu_debug::_Safe_container<
      52  	multiset, _Allocator, __gnu_debug::_Safe_node_sequence>		_Safe;
      53  
      54        typedef typename _Base::const_iterator	_Base_const_iterator;
      55        typedef typename _Base::iterator		_Base_iterator;
      56        typedef __gnu_debug::_Equal_to<_Base_const_iterator> _Equal;
      57  
      58        template<typename _ItT, typename _SeqT, typename _CatT>
      59  	friend class ::__gnu_debug::_Safe_iterator;
      60  
      61        // Reference wrapper for base class. Disambiguates multiset(const _Base&)
      62        // from copy constructor by requiring a user-defined conversion.
      63        // See PR libstdc++/90102.
      64        struct _Base_ref
      65        {
      66  	_Base_ref(const _Base& __r) : _M_ref(__r) { }
      67  
      68  	const _Base& _M_ref;
      69        };
      70  
      71      public:
      72        // types:
      73        typedef _Key					key_type;
      74        typedef _Key					value_type;
      75        typedef _Compare					key_compare;
      76        typedef _Compare					value_compare;
      77        typedef _Allocator				allocator_type;
      78        typedef typename _Base::reference			reference;
      79        typedef typename _Base::const_reference		const_reference;
      80  
      81        typedef __gnu_debug::_Safe_iterator<_Base_iterator, multiset>
      82  							iterator;
      83        typedef __gnu_debug::_Safe_iterator<_Base_const_iterator,
      84  					  multiset>	const_iterator;
      85  
      86        typedef typename _Base::size_type			size_type;
      87        typedef typename _Base::difference_type		difference_type;
      88        typedef typename _Base::pointer			pointer;
      89        typedef typename _Base::const_pointer		const_pointer;
      90        typedef std::reverse_iterator<iterator>		reverse_iterator;
      91        typedef std::reverse_iterator<const_iterator>	const_reverse_iterator;
      92  
      93        // 23.3.3.1 construct/copy/destroy:
      94  
      95  #if __cplusplus < 201103L
      96        multiset() : _Base() { }
      97  
      98        multiset(const multiset& __x)
      99        : _Base(__x) { }
     100  
     101        ~multiset() { }
     102  #else
     103        multiset() = default;
     104        multiset(const multiset&) = default;
     105        multiset(multiset&&) = default;
     106  
     107        multiset(initializer_list<value_type> __l,
     108  	       const _Compare& __comp = _Compare(),
     109  	       const allocator_type& __a = allocator_type())
     110        : _Base(__l, __comp, __a) { }
     111  
     112        explicit
     113        multiset(const allocator_type& __a)
     114        : _Base(__a) { }
     115  
     116        multiset(const multiset& __m,
     117  	       const __type_identity_t<allocator_type>& __a)
     118        : _Base(__m, __a) { }
     119  
     120        multiset(multiset&& __m, const __type_identity_t<allocator_type>& __a)
     121        noexcept( noexcept(_Base(std::move(__m), __a)) )
     122        : _Safe(std::move(__m), __a),
     123  	_Base(std::move(__m), __a) { }
     124  
     125        multiset(initializer_list<value_type> __l, const allocator_type& __a)
     126  	: _Base(__l, __a)
     127        { }
     128  
     129        template<typename _InputIterator>
     130  	multiset(_InputIterator __first, _InputIterator __last,
     131  		 const allocator_type& __a)
     132  	: _Base(__gnu_debug::__base(
     133  		  __glibcxx_check_valid_constructor_range(__first, __last)),
     134  		__gnu_debug::__base(__last), __a) { }
     135  
     136        ~multiset() = default;
     137  #endif
     138  
     139        explicit multiset(const _Compare& __comp,
     140  			const _Allocator& __a = _Allocator())
     141        : _Base(__comp, __a) { }
     142  
     143        template<typename _InputIterator>
     144  	multiset(_InputIterator __first, _InputIterator __last,
     145  		 const _Compare& __comp = _Compare(),
     146  		 const _Allocator& __a = _Allocator())
     147  	: _Base(__gnu_debug::__base(
     148  		  __glibcxx_check_valid_constructor_range(__first, __last)),
     149  		__gnu_debug::__base(__last),
     150  		__comp, __a) { }
     151  
     152        multiset(_Base_ref __x)
     153        : _Base(__x._M_ref) { }
     154  
     155  #if __cplusplus >= 201103L
     156        multiset&
     157        operator=(const multiset&) = default;
     158  
     159        multiset&
     160        operator=(multiset&&) = default;
     161  
     162        multiset&
     163        operator=(initializer_list<value_type> __l)
     164        {
     165  	_Base::operator=(__l);
     166  	this->_M_invalidate_all();
     167  	return *this;
     168        }
     169  #endif
     170  
     171        using _Base::get_allocator;
     172  
     173        // iterators:
     174        iterator
     175        begin() _GLIBCXX_NOEXCEPT
     176        { return iterator(_Base::begin(), this); }
     177  
     178        const_iterator
     179        begin() const _GLIBCXX_NOEXCEPT
     180        { return const_iterator(_Base::begin(), this); }
     181  
     182        iterator
     183        end() _GLIBCXX_NOEXCEPT
     184        { return iterator(_Base::end(), this); }
     185  
     186        const_iterator
     187        end() const _GLIBCXX_NOEXCEPT
     188        { return const_iterator(_Base::end(), this); }
     189  
     190        reverse_iterator
     191        rbegin() _GLIBCXX_NOEXCEPT
     192        { return reverse_iterator(end()); }
     193  
     194        const_reverse_iterator
     195        rbegin() const _GLIBCXX_NOEXCEPT
     196        { return const_reverse_iterator(end()); }
     197  
     198        reverse_iterator
     199        rend() _GLIBCXX_NOEXCEPT
     200        { return reverse_iterator(begin()); }
     201  
     202        const_reverse_iterator
     203        rend() const _GLIBCXX_NOEXCEPT
     204        { return const_reverse_iterator(begin()); }
     205  
     206  #if __cplusplus >= 201103L
     207        const_iterator
     208        cbegin() const noexcept
     209        { return const_iterator(_Base::begin(), this); }
     210  
     211        const_iterator
     212        cend() const noexcept
     213        { return const_iterator(_Base::end(), this); }
     214  
     215        const_reverse_iterator
     216        crbegin() const noexcept
     217        { return const_reverse_iterator(end()); }
     218  
     219        const_reverse_iterator
     220        crend() const noexcept
     221        { return const_reverse_iterator(begin()); }
     222  #endif
     223  
     224        // capacity:
     225        using _Base::empty;
     226        using _Base::size;
     227        using _Base::max_size;
     228  
     229        // modifiers:
     230  #if __cplusplus >= 201103L
     231        template<typename... _Args>
     232  	iterator
     233  	emplace(_Args&&... __args)
     234  	{ return { _Base::emplace(std::forward<_Args>(__args)...), this }; }
     235  
     236        template<typename... _Args>
     237  	iterator
     238  	emplace_hint(const_iterator __pos, _Args&&... __args)
     239  	{
     240  	  __glibcxx_check_insert(__pos);
     241  	  return
     242  	    {
     243  	      _Base::emplace_hint(__pos.base(), std::forward<_Args>(__args)...),
     244  	      this
     245  	    };
     246  	}
     247  #endif
     248  
     249        iterator
     250        insert(const value_type& __x)
     251        { return iterator(_Base::insert(__x), this); }
     252  
     253  #if __cplusplus >= 201103L
     254        iterator
     255        insert(value_type&& __x)
     256        { return { _Base::insert(std::move(__x)), this }; }
     257  #endif
     258  
     259        iterator
     260        insert(const_iterator __position, const value_type& __x)
     261        {
     262  	__glibcxx_check_insert(__position);
     263  	return iterator(_Base::insert(__position.base(), __x), this);
     264        }
     265  
     266  #if __cplusplus >= 201103L
     267        iterator
     268        insert(const_iterator __position, value_type&& __x)
     269        {
     270  	__glibcxx_check_insert(__position);
     271  	return { _Base::insert(__position.base(), std::move(__x)), this };
     272        }
     273  #endif
     274  
     275        template<typename _InputIterator>
     276  	void
     277  	insert(_InputIterator __first, _InputIterator __last)
     278  	{
     279  	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
     280  	  __glibcxx_check_valid_range2(__first, __last, __dist);
     281  
     282  	  if (__dist.second >= __gnu_debug::__dp_sign)
     283  	    _Base::insert(__gnu_debug::__unsafe(__first),
     284  			  __gnu_debug::__unsafe(__last));
     285  	  else
     286  	    _Base::insert(__first, __last);
     287  	}
     288  
     289  #if __cplusplus >= 201103L
     290        void
     291        insert(initializer_list<value_type> __l)
     292        { _Base::insert(__l); }
     293  #endif
     294  
     295  #if __cplusplus > 201402L
     296        using node_type = typename _Base::node_type;
     297  
     298        node_type
     299        extract(const_iterator __position)
     300        {
     301  	__glibcxx_check_erase(__position);
     302  	this->_M_invalidate_if(_Equal(__position.base()));
     303  	return _Base::extract(__position.base());
     304        }
     305  
     306        node_type
     307        extract(const key_type& __key)
     308        {
     309  	const auto __position = find(__key);
     310  	if (__position != end())
     311  	  return extract(__position);
     312  	return {};
     313        }
     314  
     315        iterator
     316        insert(node_type&& __nh)
     317        { return { _Base::insert(std::move(__nh)), this }; }
     318  
     319        iterator
     320        insert(const_iterator __hint, node_type&& __nh)
     321        {
     322  	__glibcxx_check_insert(__hint);
     323  	return { _Base::insert(__hint.base(), std::move(__nh)), this };
     324        }
     325  
     326        using _Base::merge;
     327  #endif // C++17
     328  
     329  #if __cplusplus >= 201103L
     330        _GLIBCXX_ABI_TAG_CXX11
     331        iterator
     332        erase(const_iterator __position)
     333        {
     334  	__glibcxx_check_erase(__position);
     335  	return { erase(__position.base()), this };
     336        }
     337  
     338        _Base_iterator
     339        erase(_Base_const_iterator __position)
     340        {
     341  	__glibcxx_check_erase2(__position);
     342  	this->_M_invalidate_if(_Equal(__position));
     343  	return _Base::erase(__position);
     344        }
     345  #else
     346        void
     347        erase(iterator __position)
     348        {
     349  	__glibcxx_check_erase(__position);
     350  	this->_M_invalidate_if(_Equal(__position.base()));
     351  	_Base::erase(__position.base());
     352        }
     353  #endif
     354  
     355        size_type
     356        erase(const key_type& __x)
     357        {
     358  	std::pair<_Base_iterator, _Base_iterator> __victims =
     359  	  _Base::equal_range(__x);
     360  	size_type __count = 0;
     361  	_Base_iterator __victim = __victims.first;
     362  	while (__victim != __victims.second)
     363  	  {
     364  	    this->_M_invalidate_if(_Equal(__victim));
     365  	    _Base::erase(__victim++);
     366  	    ++__count;
     367  	  }
     368  	return __count;
     369        }
     370  
     371  #if __cplusplus >= 201103L
     372        _GLIBCXX_ABI_TAG_CXX11
     373        iterator
     374        erase(const_iterator __first, const_iterator __last)
     375        {
     376  	// _GLIBCXX_RESOLVE_LIB_DEFECTS
     377  	// 151. can't currently clear() empty container
     378  	__glibcxx_check_erase_range(__first, __last);
     379  	for (_Base_const_iterator __victim = __first.base();
     380  	     __victim != __last.base(); ++__victim)
     381  	  {
     382  	    _GLIBCXX_DEBUG_VERIFY(__victim != _Base::cend(),
     383  				  _M_message(__gnu_debug::__msg_valid_range)
     384  				  ._M_iterator(__first, "first")
     385  				  ._M_iterator(__last, "last"));
     386  	    this->_M_invalidate_if(_Equal(__victim));
     387  	  }
     388  
     389  	return { _Base::erase(__first.base(), __last.base()), this };
     390        }
     391  #else
     392        void
     393        erase(iterator __first, iterator __last)
     394        {
     395  	// _GLIBCXX_RESOLVE_LIB_DEFECTS
     396  	// 151. can't currently clear() empty container
     397  	__glibcxx_check_erase_range(__first, __last);
     398  	for (_Base_iterator __victim = __first.base();
     399  	     __victim != __last.base(); ++__victim)
     400  	  {
     401  	    _GLIBCXX_DEBUG_VERIFY(__victim != _Base::end(),
     402  				  _M_message(__gnu_debug::__msg_valid_range)
     403  				  ._M_iterator(__first, "first")
     404  				  ._M_iterator(__last, "last"));
     405  	    this->_M_invalidate_if(_Equal(__victim));
     406  	  }
     407  	_Base::erase(__first.base(), __last.base());
     408        }
     409  #endif
     410  
     411        void
     412        swap(multiset& __x)
     413        _GLIBCXX_NOEXCEPT_IF( noexcept(declval<_Base&>().swap(__x)) )
     414        {
     415  	_Safe::_M_swap(__x);
     416  	_Base::swap(__x);
     417        }
     418  
     419        void
     420        clear() _GLIBCXX_NOEXCEPT
     421        {
     422  	this->_M_invalidate_all();
     423  	_Base::clear();
     424        }
     425  
     426        // observers:
     427        using _Base::key_comp;
     428        using _Base::value_comp;
     429  
     430        // multiset operations:
     431        iterator
     432        find(const key_type& __x)
     433        { return iterator(_Base::find(__x), this); }
     434  
     435        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     436        // 214. set::find() missing const overload
     437        const_iterator
     438        find(const key_type& __x) const
     439        { return const_iterator(_Base::find(__x), this); }
     440  
     441  #if __cplusplus > 201103L
     442        template<typename _Kt,
     443  	       typename _Req =
     444  		 typename __has_is_transparent<_Compare, _Kt>::type>
     445  	iterator
     446  	find(const _Kt& __x)
     447  	{ return { _Base::find(__x), this }; }
     448  
     449        template<typename _Kt,
     450  	       typename _Req =
     451  		 typename __has_is_transparent<_Compare, _Kt>::type>
     452  	const_iterator
     453  	find(const _Kt& __x) const
     454  	{ return { _Base::find(__x), this }; }
     455  #endif
     456  
     457        using _Base::count;
     458  
     459        iterator
     460        lower_bound(const key_type& __x)
     461        { return iterator(_Base::lower_bound(__x), this); }
     462  
     463        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     464        // 214. set::find() missing const overload
     465        const_iterator
     466        lower_bound(const key_type& __x) const
     467        { return const_iterator(_Base::lower_bound(__x), this); }
     468  
     469  #if __cplusplus > 201103L
     470        template<typename _Kt,
     471  	       typename _Req =
     472  		 typename __has_is_transparent<_Compare, _Kt>::type>
     473  	iterator
     474  	lower_bound(const _Kt& __x)
     475  	{ return { _Base::lower_bound(__x), this }; }
     476  
     477        template<typename _Kt,
     478  	       typename _Req =
     479  		 typename __has_is_transparent<_Compare, _Kt>::type>
     480  	const_iterator
     481  	lower_bound(const _Kt& __x) const
     482  	{ return { _Base::lower_bound(__x), this }; }
     483  #endif
     484  
     485        iterator
     486        upper_bound(const key_type& __x)
     487        { return iterator(_Base::upper_bound(__x), this); }
     488  
     489        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     490        // 214. set::find() missing const overload
     491        const_iterator
     492        upper_bound(const key_type& __x) const
     493        { return const_iterator(_Base::upper_bound(__x), this); }
     494  
     495  #if __cplusplus > 201103L
     496        template<typename _Kt,
     497  	       typename _Req =
     498  		 typename __has_is_transparent<_Compare, _Kt>::type>
     499  	iterator
     500  	upper_bound(const _Kt& __x)
     501  	{ return { _Base::upper_bound(__x), this }; }
     502  
     503        template<typename _Kt,
     504  	       typename _Req =
     505  		 typename __has_is_transparent<_Compare, _Kt>::type>
     506  	const_iterator
     507  	upper_bound(const _Kt& __x) const
     508  	{ return { _Base::upper_bound(__x), this }; }
     509  #endif
     510  
     511        std::pair<iterator,iterator>
     512        equal_range(const key_type& __x)
     513        {
     514  	std::pair<_Base_iterator, _Base_iterator> __res =
     515  	  _Base::equal_range(__x);
     516  	return std::make_pair(iterator(__res.first, this),
     517  			      iterator(__res.second, this));
     518        }
     519  
     520        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     521        // 214. set::find() missing const overload
     522        std::pair<const_iterator,const_iterator>
     523        equal_range(const key_type& __x) const
     524        {
     525  	std::pair<_Base_const_iterator, _Base_const_iterator> __res =
     526  	  _Base::equal_range(__x);
     527  	return std::make_pair(const_iterator(__res.first, this),
     528  			      const_iterator(__res.second, this));
     529        }
     530  
     531  #if __cplusplus > 201103L
     532        template<typename _Kt,
     533  	       typename _Req =
     534  		 typename __has_is_transparent<_Compare, _Kt>::type>
     535  	std::pair<iterator, iterator>
     536  	equal_range(const _Kt& __x)
     537  	{
     538  	  auto __res = _Base::equal_range(__x);
     539  	  return { { __res.first, this }, { __res.second, this } };
     540  	}
     541  
     542        template<typename _Kt,
     543  	       typename _Req =
     544  		 typename __has_is_transparent<_Compare, _Kt>::type>
     545  	std::pair<const_iterator, const_iterator>
     546  	equal_range(const _Kt& __x) const
     547  	{
     548  	  auto __res = _Base::equal_range(__x);
     549  	  return { { __res.first, this }, { __res.second, this } };
     550  	}
     551  #endif
     552  
     553        _Base&
     554        _M_base() _GLIBCXX_NOEXCEPT { return *this; }
     555  
     556        const _Base&
     557        _M_base() const _GLIBCXX_NOEXCEPT { return *this; }
     558      };
     559  
     560  #if __cpp_deduction_guides >= 201606
     561  
     562    template<typename _InputIterator,
     563  	   typename _Compare =
     564  	     less<typename iterator_traits<_InputIterator>::value_type>,
     565  	   typename _Allocator =
     566  	     allocator<typename iterator_traits<_InputIterator>::value_type>,
     567  	   typename = _RequireInputIter<_InputIterator>,
     568  	   typename = _RequireNotAllocator<_Compare>,
     569  	   typename = _RequireAllocator<_Allocator>>
     570      multiset(_InputIterator, _InputIterator,
     571  	     _Compare = _Compare(), _Allocator = _Allocator())
     572      -> multiset<typename iterator_traits<_InputIterator>::value_type,
     573  		_Compare, _Allocator>;
     574  
     575    template<typename _Key,
     576  	   typename _Compare = less<_Key>,
     577  	   typename _Allocator = allocator<_Key>,
     578  	   typename = _RequireNotAllocator<_Compare>,
     579  	   typename = _RequireAllocator<_Allocator>>
     580      multiset(initializer_list<_Key>,
     581  	     _Compare = _Compare(), _Allocator = _Allocator())
     582      -> multiset<_Key, _Compare, _Allocator>;
     583  
     584    template<typename _InputIterator, typename _Allocator,
     585  	   typename = _RequireInputIter<_InputIterator>,
     586  	   typename = _RequireAllocator<_Allocator>>
     587      multiset(_InputIterator, _InputIterator, _Allocator)
     588      -> multiset<typename iterator_traits<_InputIterator>::value_type,
     589  		less<typename iterator_traits<_InputIterator>::value_type>,
     590  		_Allocator>;
     591  
     592    template<typename _Key, typename _Allocator,
     593  	   typename = _RequireAllocator<_Allocator>>
     594      multiset(initializer_list<_Key>, _Allocator)
     595      -> multiset<_Key, less<_Key>, _Allocator>;
     596  
     597  #endif // deduction guides
     598  
     599    template<typename _Key, typename _Compare, typename _Allocator>
     600      inline bool
     601      operator==(const multiset<_Key, _Compare, _Allocator>& __lhs,
     602  	       const multiset<_Key, _Compare, _Allocator>& __rhs)
     603      { return __lhs._M_base() == __rhs._M_base(); }
     604  
     605  #if __cpp_lib_three_way_comparison
     606    template<typename _Key, typename _Compare, typename _Alloc>
     607      inline __detail::__synth3way_t<_Key>
     608      operator<=>(const multiset<_Key, _Compare, _Alloc>& __lhs,
     609  		const multiset<_Key, _Compare, _Alloc>& __rhs)
     610      { return __lhs._M_base() <=> __rhs._M_base(); }
     611  #else
     612    template<typename _Key, typename _Compare, typename _Allocator>
     613      inline bool
     614      operator!=(const multiset<_Key, _Compare, _Allocator>& __lhs,
     615  	       const multiset<_Key, _Compare, _Allocator>& __rhs)
     616      { return __lhs._M_base() != __rhs._M_base(); }
     617  
     618    template<typename _Key, typename _Compare, typename _Allocator>
     619      inline bool
     620      operator<(const multiset<_Key, _Compare, _Allocator>& __lhs,
     621  	      const multiset<_Key, _Compare, _Allocator>& __rhs)
     622      { return __lhs._M_base() < __rhs._M_base(); }
     623  
     624    template<typename _Key, typename _Compare, typename _Allocator>
     625      inline bool
     626      operator<=(const multiset<_Key, _Compare, _Allocator>& __lhs,
     627  	       const multiset<_Key, _Compare, _Allocator>& __rhs)
     628      { return __lhs._M_base() <= __rhs._M_base(); }
     629  
     630    template<typename _Key, typename _Compare, typename _Allocator>
     631      inline bool
     632      operator>=(const multiset<_Key, _Compare, _Allocator>& __lhs,
     633  	       const multiset<_Key, _Compare, _Allocator>& __rhs)
     634      { return __lhs._M_base() >= __rhs._M_base(); }
     635  
     636    template<typename _Key, typename _Compare, typename _Allocator>
     637      inline bool
     638      operator>(const multiset<_Key, _Compare, _Allocator>& __lhs,
     639  	      const multiset<_Key, _Compare, _Allocator>& __rhs)
     640      { return __lhs._M_base() > __rhs._M_base(); }
     641  #endif // three-way comparison
     642  
     643    template<typename _Key, typename _Compare, typename _Allocator>
     644      void
     645      swap(multiset<_Key, _Compare, _Allocator>& __x,
     646  	 multiset<_Key, _Compare, _Allocator>& __y)
     647      _GLIBCXX_NOEXCEPT_IF(noexcept(__x.swap(__y)))
     648      { return __x.swap(__y); }
     649  
     650  } // namespace __debug
     651  } // namespace std
     652  
     653  #endif