1 // Debugging unordered_map/unordered_multimap implementation -*- C++ -*-
3 // Copyright (C) 2003-2013 Free Software Foundation, Inc.
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)
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.
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.
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/>.
25 /** @file debug/unordered_map
26 * This file is a GNU debug extension to the Standard C++ Library.
29 #ifndef _GLIBCXX_DEBUG_UNORDERED_MAP
30 #define _GLIBCXX_DEBUG_UNORDERED_MAP 1
32 #if __cplusplus < 201103L
33 # include <bits/c++0x_warning.h>
35 # include <unordered_map>
37 #include <debug/safe_unordered_container.h>
38 #include <debug/safe_iterator.h>
39 #include <debug/safe_local_iterator.h>
41 namespace std _GLIBCXX_VISIBILITY(default)
45 /// Class std::unordered_map with safety/checking/debug instrumentation.
46 template<typename _Key, typename _Tp,
47 typename _Hash = std::hash<_Key>,
48 typename _Pred = std::equal_to<_Key>,
49 typename _Alloc = std::allocator<_Key> >
51 : public _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>,
52 public __gnu_debug::_Safe_unordered_container<unordered_map<_Key, _Tp,
53 _Hash, _Pred, _Alloc> >
55 typedef _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash,
57 typedef __gnu_debug::_Safe_unordered_container<unordered_map> _Safe_base;
58 typedef typename _Base::const_iterator _Base_const_iterator;
59 typedef typename _Base::iterator _Base_iterator;
60 typedef typename _Base::const_local_iterator _Base_const_local_iterator;
61 typedef typename _Base::local_iterator _Base_local_iterator;
64 typedef typename _Base::size_type size_type;
65 typedef typename _Base::hasher hasher;
66 typedef typename _Base::key_equal key_equal;
67 typedef typename _Base::allocator_type allocator_type;
69 typedef typename _Base::key_type key_type;
70 typedef typename _Base::value_type value_type;
72 typedef __gnu_debug::_Safe_iterator<_Base_iterator,
73 unordered_map> iterator;
74 typedef __gnu_debug::_Safe_iterator<_Base_const_iterator,
75 unordered_map> const_iterator;
76 typedef __gnu_debug::_Safe_local_iterator<_Base_local_iterator,
77 unordered_map> local_iterator;
78 typedef __gnu_debug::_Safe_local_iterator<_Base_const_local_iterator,
79 unordered_map> const_local_iterator;
82 unordered_map(size_type __n = 10,
83 const hasher& __hf = hasher(),
84 const key_equal& __eql = key_equal(),
85 const allocator_type& __a = allocator_type())
86 : _Base(__n, __hf, __eql, __a) { }
88 template<typename _InputIterator>
89 unordered_map(_InputIterator __first, _InputIterator __last,
91 const hasher& __hf = hasher(),
92 const key_equal& __eql = key_equal(),
93 const allocator_type& __a = allocator_type())
94 : _Base(__gnu_debug::__base(__gnu_debug::__check_valid_range(__first,
96 __gnu_debug::__base(__last), __n,
99 unordered_map(const unordered_map& __x) = default;
101 unordered_map(const _Base& __x)
104 unordered_map(unordered_map&& __x) = default;
106 unordered_map(initializer_list<value_type> __l,
108 const hasher& __hf = hasher(),
109 const key_equal& __eql = key_equal(),
110 const allocator_type& __a = allocator_type())
111 : _Base(__l, __n, __hf, __eql, __a) { }
113 ~unordered_map() noexcept { }
116 operator=(const unordered_map& __x)
118 *static_cast<_Base*>(this) = __x;
119 this->_M_invalidate_all();
124 operator=(unordered_map&& __x)
128 __glibcxx_check_self_move_assign(__x);
135 operator=(initializer_list<value_type> __l)
143 swap(unordered_map& __x)
146 _Safe_base::_M_swap(__x);
153 this->_M_invalidate_all();
158 { return iterator(_Base::begin(), this); }
161 begin() const noexcept
162 { return const_iterator(_Base::begin(), this); }
166 { return iterator(_Base::end(), this); }
170 { return const_iterator(_Base::end(), this); }
173 cbegin() const noexcept
174 { return const_iterator(_Base::begin(), this); }
177 cend() const noexcept
178 { return const_iterator(_Base::end(), this); }
184 __glibcxx_check_bucket_index(__b);
185 return local_iterator(_Base::begin(__b), __b, this);
191 __glibcxx_check_bucket_index(__b);
192 return local_iterator(_Base::end(__b), __b, this);
196 begin(size_type __b) const
198 __glibcxx_check_bucket_index(__b);
199 return const_local_iterator(_Base::begin(__b), __b, this);
203 end(size_type __b) const
205 __glibcxx_check_bucket_index(__b);
206 return const_local_iterator(_Base::end(__b), __b, this);
210 cbegin(size_type __b) const
212 __glibcxx_check_bucket_index(__b);
213 return const_local_iterator(_Base::cbegin(__b), __b, this);
217 cend(size_type __b) const
219 __glibcxx_check_bucket_index(__b);
220 return const_local_iterator(_Base::cend(__b), __b, this);
224 bucket_size(size_type __b) const
226 __glibcxx_check_bucket_index(__b);
227 return _Base::bucket_size(__b);
231 max_load_factor() const noexcept
232 { return _Base::max_load_factor(); }
235 max_load_factor(float __f)
237 __glibcxx_check_max_load_factor(__f);
238 _Base::max_load_factor(__f);
241 template<typename... _Args>
242 std::pair<iterator, bool>
243 emplace(_Args&&... __args)
245 size_type __bucket_count = this->bucket_count();
246 std::pair<_Base_iterator, bool> __res
247 = _Base::emplace(std::forward<_Args>(__args)...);
248 _M_check_rehashed(__bucket_count);
249 return std::make_pair(iterator(__res.first, this), __res.second);
252 template<typename... _Args>
254 emplace_hint(const_iterator __hint, _Args&&... __args)
256 __glibcxx_check_insert(__hint);
257 size_type __bucket_count = this->bucket_count();
258 _Base_iterator __it = _Base::emplace_hint(__hint.base(),
259 std::forward<_Args>(__args)...);
260 _M_check_rehashed(__bucket_count);
261 return iterator(__it, this);
264 std::pair<iterator, bool>
265 insert(const value_type& __obj)
267 size_type __bucket_count = this->bucket_count();
268 std::pair<_Base_iterator, bool> __res = _Base::insert(__obj);
269 _M_check_rehashed(__bucket_count);
270 return std::make_pair(iterator(__res.first, this), __res.second);
274 insert(const_iterator __hint, const value_type& __obj)
276 __glibcxx_check_insert(__hint);
277 size_type __bucket_count = this->bucket_count();
278 _Base_iterator __it = _Base::insert(__hint.base(), __obj);
279 _M_check_rehashed(__bucket_count);
280 return iterator(__it, this);
283 template<typename _Pair, typename = typename
284 std::enable_if<std::is_constructible<value_type,
285 _Pair&&>::value>::type>
286 std::pair<iterator, bool>
287 insert(_Pair&& __obj)
289 size_type __bucket_count = this->bucket_count();
290 std::pair<_Base_iterator, bool> __res =
291 _Base::insert(std::forward<_Pair>(__obj));
292 _M_check_rehashed(__bucket_count);
293 return std::make_pair(iterator(__res.first, this), __res.second);
296 template<typename _Pair, typename = typename
297 std::enable_if<std::is_constructible<value_type,
298 _Pair&&>::value>::type>
300 insert(const_iterator __hint, _Pair&& __obj)
302 __glibcxx_check_insert(__hint);
303 size_type __bucket_count = this->bucket_count();
304 _Base_iterator __it =
305 _Base::insert(__hint.base(), std::forward<_Pair>(__obj));
306 _M_check_rehashed(__bucket_count);
307 return iterator(__it, this);
311 insert(std::initializer_list<value_type> __l)
313 size_type __bucket_count = this->bucket_count();
315 _M_check_rehashed(__bucket_count);
318 template<typename _InputIterator>
320 insert(_InputIterator __first, _InputIterator __last)
322 __glibcxx_check_valid_range(__first, __last);
323 size_type __bucket_count = this->bucket_count();
324 _Base::insert(__gnu_debug::__base(__first),
325 __gnu_debug::__base(__last));
326 _M_check_rehashed(__bucket_count);
330 find(const key_type& __key)
331 { return iterator(_Base::find(__key), this); }
334 find(const key_type& __key) const
335 { return const_iterator(_Base::find(__key), this); }
337 std::pair<iterator, iterator>
338 equal_range(const key_type& __key)
340 std::pair<_Base_iterator, _Base_iterator> __res =
341 _Base::equal_range(__key);
342 return std::make_pair(iterator(__res.first, this),
343 iterator(__res.second, this));
346 std::pair<const_iterator, const_iterator>
347 equal_range(const key_type& __key) const
349 std::pair<_Base_const_iterator, _Base_const_iterator> __res =
350 _Base::equal_range(__key);
351 return std::make_pair(const_iterator(__res.first, this),
352 const_iterator(__res.second, this));
356 erase(const key_type& __key)
359 _Base_iterator __victim(_Base::find(__key));
360 if (__victim != _Base::end())
362 this->_M_invalidate_if([__victim](_Base_const_iterator __it)
363 { return __it == __victim; });
364 this->_M_invalidate_local_if(
365 [__victim](_Base_const_local_iterator __it)
366 { return __it._M_cur == __victim._M_cur; });
367 size_type __bucket_count = this->bucket_count();
368 _Base::erase(__victim);
369 _M_check_rehashed(__bucket_count);
376 erase(const_iterator __it)
378 __glibcxx_check_erase(__it);
379 _Base_const_iterator __victim = __it.base();
380 this->_M_invalidate_if([__victim](_Base_const_iterator __it)
381 { return __it == __victim; });
382 this->_M_invalidate_local_if(
383 [__victim](_Base_const_local_iterator __it)
384 { return __it._M_cur == __victim._M_cur; });
385 size_type __bucket_count = this->bucket_count();
386 _Base_iterator __next = _Base::erase(__it.base());
387 _M_check_rehashed(__bucket_count);
388 return iterator(__next, this);
393 { return erase(const_iterator(__it)); }
396 erase(const_iterator __first, const_iterator __last)
398 __glibcxx_check_erase_range(__first, __last);
399 for (_Base_const_iterator __tmp = __first.base();
400 __tmp != __last.base(); ++__tmp)
402 _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::end(),
403 _M_message(__gnu_debug::__msg_valid_range)
404 ._M_iterator(__first, "first")
405 ._M_iterator(__last, "last"));
406 this->_M_invalidate_if([__tmp](_Base_const_iterator __it)
407 { return __it == __tmp; });
408 this->_M_invalidate_local_if(
409 [__tmp](_Base_const_local_iterator __it)
410 { return __it._M_cur == __tmp._M_cur; });
412 size_type __bucket_count = this->bucket_count();
413 _Base_iterator __next = _Base::erase(__first.base(), __last.base());
414 _M_check_rehashed(__bucket_count);
415 return iterator(__next, this);
419 _M_base() noexcept { return *this; }
422 _M_base() const noexcept { return *this; }
426 _M_invalidate_locals()
428 _Base_local_iterator __local_end = _Base::end(0);
429 this->_M_invalidate_local_if(
430 [__local_end](_Base_const_local_iterator __it)
431 { return __it != __local_end; });
437 _Base_iterator __end = _Base::end();
438 this->_M_invalidate_if([__end](_Base_const_iterator __it)
439 { return __it != __end; });
440 _M_invalidate_locals();
444 _M_check_rehashed(size_type __prev_count)
446 if (__prev_count != this->bucket_count())
447 _M_invalidate_locals();
451 template<typename _Key, typename _Tp, typename _Hash,
452 typename _Pred, typename _Alloc>
454 swap(unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
455 unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
458 template<typename _Key, typename _Tp, typename _Hash,
459 typename _Pred, typename _Alloc>
461 operator==(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
462 const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
463 { return __x._M_base() == __y._M_base(); }
465 template<typename _Key, typename _Tp, typename _Hash,
466 typename _Pred, typename _Alloc>
468 operator!=(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
469 const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
470 { return !(__x == __y); }
473 /// Class std::unordered_multimap with safety/checking/debug instrumentation.
474 template<typename _Key, typename _Tp,
475 typename _Hash = std::hash<_Key>,
476 typename _Pred = std::equal_to<_Key>,
477 typename _Alloc = std::allocator<_Key> >
478 class unordered_multimap
479 : public _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash,
481 public __gnu_debug::_Safe_unordered_container<unordered_multimap<_Key,
482 _Tp, _Hash, _Pred, _Alloc> >
484 typedef _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash,
485 _Pred, _Alloc> _Base;
486 typedef __gnu_debug::_Safe_unordered_container<unordered_multimap>
488 typedef typename _Base::const_iterator _Base_const_iterator;
489 typedef typename _Base::iterator _Base_iterator;
490 typedef typename _Base::const_local_iterator _Base_const_local_iterator;
491 typedef typename _Base::local_iterator _Base_local_iterator;
494 typedef typename _Base::size_type size_type;
495 typedef typename _Base::hasher hasher;
496 typedef typename _Base::key_equal key_equal;
497 typedef typename _Base::allocator_type allocator_type;
499 typedef typename _Base::key_type key_type;
500 typedef typename _Base::value_type value_type;
502 typedef __gnu_debug::_Safe_iterator<_Base_iterator,
503 unordered_multimap> iterator;
504 typedef __gnu_debug::_Safe_iterator<_Base_const_iterator,
505 unordered_multimap> const_iterator;
506 typedef __gnu_debug::_Safe_local_iterator<
507 _Base_local_iterator, unordered_multimap> local_iterator;
508 typedef __gnu_debug::_Safe_local_iterator<
509 _Base_const_local_iterator, unordered_multimap> const_local_iterator;
512 unordered_multimap(size_type __n = 10,
513 const hasher& __hf = hasher(),
514 const key_equal& __eql = key_equal(),
515 const allocator_type& __a = allocator_type())
516 : _Base(__n, __hf, __eql, __a) { }
518 template<typename _InputIterator>
519 unordered_multimap(_InputIterator __first, _InputIterator __last,
521 const hasher& __hf = hasher(),
522 const key_equal& __eql = key_equal(),
523 const allocator_type& __a = allocator_type())
524 : _Base(__gnu_debug::__base(__gnu_debug::__check_valid_range(__first,
526 __gnu_debug::__base(__last), __n,
527 __hf, __eql, __a) { }
529 unordered_multimap(const unordered_multimap& __x) = default;
531 unordered_multimap(const _Base& __x)
534 unordered_multimap(unordered_multimap&& __x) = default;
536 unordered_multimap(initializer_list<value_type> __l,
538 const hasher& __hf = hasher(),
539 const key_equal& __eql = key_equal(),
540 const allocator_type& __a = allocator_type())
541 : _Base(__l, __n, __hf, __eql, __a) { }
543 ~unordered_multimap() noexcept { }
546 operator=(const unordered_multimap& __x)
548 *static_cast<_Base*>(this) = __x;
549 this->_M_invalidate_all();
554 operator=(unordered_multimap&& __x)
558 __glibcxx_check_self_move_assign(__x);
565 operator=(initializer_list<value_type> __l)
573 swap(unordered_multimap& __x)
576 _Safe_base::_M_swap(__x);
583 this->_M_invalidate_all();
588 { return iterator(_Base::begin(), this); }
591 begin() const noexcept
592 { return const_iterator(_Base::begin(), this); }
596 { return iterator(_Base::end(), this); }
600 { return const_iterator(_Base::end(), this); }
603 cbegin() const noexcept
604 { return const_iterator(_Base::begin(), this); }
607 cend() const noexcept
608 { return const_iterator(_Base::end(), this); }
614 __glibcxx_check_bucket_index(__b);
615 return local_iterator(_Base::begin(__b), __b, this);
621 __glibcxx_check_bucket_index(__b);
622 return local_iterator(_Base::end(__b), __b, this);
626 begin(size_type __b) const
628 __glibcxx_check_bucket_index(__b);
629 return const_local_iterator(_Base::begin(__b), __b, this);
633 end(size_type __b) const
635 __glibcxx_check_bucket_index(__b);
636 return const_local_iterator(_Base::end(__b), __b, this);
640 cbegin(size_type __b) const
642 __glibcxx_check_bucket_index(__b);
643 return const_local_iterator(_Base::cbegin(__b), __b, this);
647 cend(size_type __b) const
649 __glibcxx_check_bucket_index(__b);
650 return const_local_iterator(_Base::cend(__b), __b, this);
654 bucket_size(size_type __b) const
656 __glibcxx_check_bucket_index(__b);
657 return _Base::bucket_size(__b);
661 max_load_factor() const noexcept
662 { return _Base::max_load_factor(); }
665 max_load_factor(float __f)
667 __glibcxx_check_max_load_factor(__f);
668 _Base::max_load_factor(__f);
671 template<typename... _Args>
673 emplace(_Args&&... __args)
675 size_type __bucket_count = this->bucket_count();
677 = _Base::emplace(std::forward<_Args>(__args)...);
678 _M_check_rehashed(__bucket_count);
679 return iterator(__it, this);
682 template<typename... _Args>
684 emplace_hint(const_iterator __hint, _Args&&... __args)
686 __glibcxx_check_insert(__hint);
687 size_type __bucket_count = this->bucket_count();
688 _Base_iterator __it = _Base::emplace_hint(__hint.base(),
689 std::forward<_Args>(__args)...);
690 _M_check_rehashed(__bucket_count);
691 return iterator(__it, this);
695 insert(const value_type& __obj)
697 size_type __bucket_count = this->bucket_count();
698 _Base_iterator __it = _Base::insert(__obj);
699 _M_check_rehashed(__bucket_count);
700 return iterator(__it, this);
704 insert(const_iterator __hint, const value_type& __obj)
706 __glibcxx_check_insert(__hint);
707 size_type __bucket_count = this->bucket_count();
708 _Base_iterator __it = _Base::insert(__hint.base(), __obj);
709 _M_check_rehashed(__bucket_count);
710 return iterator(__it, this);
713 template<typename _Pair, typename = typename
714 std::enable_if<std::is_constructible<value_type,
715 _Pair&&>::value>::type>
717 insert(_Pair&& __obj)
719 size_type __bucket_count = this->bucket_count();
720 _Base_iterator __it = _Base::insert(std::forward<_Pair>(__obj));
721 _M_check_rehashed(__bucket_count);
722 return iterator(__it, this);
725 template<typename _Pair, typename = typename
726 std::enable_if<std::is_constructible<value_type,
727 _Pair&&>::value>::type>
729 insert(const_iterator __hint, _Pair&& __obj)
731 __glibcxx_check_insert(__hint);
732 size_type __bucket_count = this->bucket_count();
733 _Base_iterator __it =
734 _Base::insert(__hint.base(), std::forward<_Pair>(__obj));
735 _M_check_rehashed(__bucket_count);
736 return iterator(__it, this);
740 insert(std::initializer_list<value_type> __l)
741 { _Base::insert(__l); }
743 template<typename _InputIterator>
745 insert(_InputIterator __first, _InputIterator __last)
747 __glibcxx_check_valid_range(__first, __last);
748 size_type __bucket_count = this->bucket_count();
749 _Base::insert(__gnu_debug::__base(__first),
750 __gnu_debug::__base(__last));
751 _M_check_rehashed(__bucket_count);
755 find(const key_type& __key)
756 { return iterator(_Base::find(__key), this); }
759 find(const key_type& __key) const
760 { return const_iterator(_Base::find(__key), this); }
762 std::pair<iterator, iterator>
763 equal_range(const key_type& __key)
765 std::pair<_Base_iterator, _Base_iterator> __res =
766 _Base::equal_range(__key);
767 return std::make_pair(iterator(__res.first, this),
768 iterator(__res.second, this));
771 std::pair<const_iterator, const_iterator>
772 equal_range(const key_type& __key) const
774 std::pair<_Base_const_iterator, _Base_const_iterator> __res =
775 _Base::equal_range(__key);
776 return std::make_pair(const_iterator(__res.first, this),
777 const_iterator(__res.second, this));
781 erase(const key_type& __key)
784 size_type __bucket_count = this->bucket_count();
785 std::pair<_Base_iterator, _Base_iterator> __pair =
786 _Base::equal_range(__key);
787 for (_Base_iterator __victim = __pair.first; __victim != __pair.second;)
789 this->_M_invalidate_if([__victim](_Base_const_iterator __it)
790 { return __it == __victim; });
791 this->_M_invalidate_local_if(
792 [__victim](_Base_const_local_iterator __it)
793 { return __it._M_cur == __victim._M_cur; });
794 _Base::erase(__victim++);
797 _M_check_rehashed(__bucket_count);
802 erase(const_iterator __it)
804 __glibcxx_check_erase(__it);
805 _Base_const_iterator __victim = __it.base();
806 this->_M_invalidate_if([__victim](_Base_const_iterator __it)
807 { return __it == __victim; });
808 this->_M_invalidate_local_if(
809 [__victim](_Base_const_local_iterator __it)
810 { return __it._M_cur == __victim._M_cur; });
811 size_type __bucket_count = this->bucket_count();
812 _Base_iterator __next = _Base::erase(__it.base());
813 _M_check_rehashed(__bucket_count);
814 return iterator(__next, this);
819 { return erase(const_iterator(__it)); }
822 erase(const_iterator __first, const_iterator __last)
824 __glibcxx_check_erase_range(__first, __last);
825 for (_Base_const_iterator __tmp = __first.base();
826 __tmp != __last.base(); ++__tmp)
828 _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::end(),
829 _M_message(__gnu_debug::__msg_valid_range)
830 ._M_iterator(__first, "first")
831 ._M_iterator(__last, "last"));
832 this->_M_invalidate_if([__tmp](_Base_const_iterator __it)
833 { return __it == __tmp; });
834 this->_M_invalidate_local_if(
835 [__tmp](_Base_const_local_iterator __it)
836 { return __it._M_cur == __tmp._M_cur; });
838 size_type __bucket_count = this->bucket_count();
839 _Base_iterator __next = _Base::erase(__first.base(), __last.base());
840 _M_check_rehashed(__bucket_count);
841 return iterator(__next, this);
845 _M_base() noexcept { return *this; }
848 _M_base() const noexcept { return *this; }
852 _M_invalidate_locals()
854 _Base_local_iterator __local_end = _Base::end(0);
855 this->_M_invalidate_local_if(
856 [__local_end](_Base_const_local_iterator __it)
857 { return __it != __local_end; });
863 _Base_iterator __end = _Base::end();
864 this->_M_invalidate_if([__end](_Base_const_iterator __it)
865 { return __it != __end; });
866 _M_invalidate_locals();
870 _M_check_rehashed(size_type __prev_count)
872 if (__prev_count != this->bucket_count())
873 _M_invalidate_locals();
877 template<typename _Key, typename _Tp, typename _Hash,
878 typename _Pred, typename _Alloc>
880 swap(unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
881 unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
884 template<typename _Key, typename _Tp, typename _Hash,
885 typename _Pred, typename _Alloc>
887 operator==(const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
888 const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
889 { return __x._M_base() == __y._M_base(); }
891 template<typename _Key, typename _Tp, typename _Hash,
892 typename _Pred, typename _Alloc>
894 operator!=(const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
895 const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
896 { return !(__x == __y); }
898 } // namespace __debug