libstdc++
debug/unordered_set
Go to the documentation of this file.
1// Debugging unordered_set/unordered_multiset implementation -*- C++ -*-
2
3// Copyright (C) 2003-2022 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/unordered_set
26 * This file is a GNU debug extension to the Standard C++ Library.
27 */
28
29#ifndef _GLIBCXX_DEBUG_UNORDERED_SET
30#define _GLIBCXX_DEBUG_UNORDERED_SET 1
31
32#pragma GCC system_header
33
34#if __cplusplus < 201103L
35# include <bits/c++0x_warning.h>
36#else
37# include <bits/c++config.h>
38namespace std _GLIBCXX_VISIBILITY(default) { namespace __debug {
39 template<typename _Key, typename _Hash, typename _Pred, typename _Allocator>
40 class unordered_set;
41 template<typename _Key, typename _Hash, typename _Pred, typename _Allocator>
42 class unordered_multiset;
43} } // namespace std::__debug
44# include <unordered_set>
45
46#include <debug/safe_unordered_container.h>
47#include <debug/safe_container.h>
48#include <debug/safe_iterator.h>
49#include <debug/safe_local_iterator.h>
50
51namespace std _GLIBCXX_VISIBILITY(default)
52{
53namespace __debug
54{
55 /// Class std::unordered_set with safety/checking/debug instrumentation.
56 template<typename _Value,
57 typename _Hash = std::hash<_Value>,
58 typename _Pred = std::equal_to<_Value>,
59 typename _Alloc = std::allocator<_Value> >
60 class unordered_set
61 : public __gnu_debug::_Safe_container<
62 unordered_set<_Value, _Hash, _Pred, _Alloc>, _Alloc,
63 __gnu_debug::_Safe_unordered_container>,
64 public _GLIBCXX_STD_C::unordered_set<_Value, _Hash, _Pred, _Alloc>
65 {
66 typedef _GLIBCXX_STD_C::unordered_set<
67 _Value, _Hash, _Pred, _Alloc> _Base;
68 typedef __gnu_debug::_Safe_container<
69 unordered_set, _Alloc, __gnu_debug::_Safe_unordered_container> _Safe;
70
71 typedef typename _Base::const_iterator _Base_const_iterator;
72 typedef typename _Base::iterator _Base_iterator;
73 typedef typename _Base::const_local_iterator _Base_const_local_iterator;
74 typedef typename _Base::local_iterator _Base_local_iterator;
75
76 template<typename _ItT, typename _SeqT, typename _CatT>
77 friend class ::__gnu_debug::_Safe_iterator;
78 template<typename _ItT, typename _SeqT>
79 friend class ::__gnu_debug::_Safe_local_iterator;
80
81 // Reference wrapper for base class. See PR libstdc++/90102.
82 struct _Base_ref
83 {
84 _Base_ref(const _Base& __r) : _M_ref(__r) { }
85
86 const _Base& _M_ref;
87 };
88
89 public:
90 typedef typename _Base::size_type size_type;
91 typedef typename _Base::difference_type difference_type;
92 typedef typename _Base::hasher hasher;
93 typedef typename _Base::key_equal key_equal;
94 typedef typename _Base::allocator_type allocator_type;
95
96 typedef typename _Base::key_type key_type;
97 typedef typename _Base::value_type value_type;
98
99 typedef typename _Base::pointer pointer;
100 typedef typename _Base::const_pointer const_pointer;
101 typedef typename _Base::reference reference;
102 typedef typename _Base::const_reference const_reference;
103 typedef __gnu_debug::_Safe_iterator<
104 _Base_iterator, unordered_set> iterator;
105 typedef __gnu_debug::_Safe_iterator<
106 _Base_const_iterator, unordered_set> const_iterator;
107 typedef __gnu_debug::_Safe_local_iterator<
108 _Base_local_iterator, unordered_set> local_iterator;
109 typedef __gnu_debug::_Safe_local_iterator<
110 _Base_const_local_iterator, unordered_set> const_local_iterator;
111
112 unordered_set() = default;
113
114 explicit
115 unordered_set(size_type __n,
116 const hasher& __hf = hasher(),
117 const key_equal& __eql = key_equal(),
118 const allocator_type& __a = allocator_type())
119 : _Base(__n, __hf, __eql, __a) { }
120
121 template<typename _InputIterator>
122 unordered_set(_InputIterator __first, _InputIterator __last,
123 size_type __n = 0,
124 const hasher& __hf = hasher(),
125 const key_equal& __eql = key_equal(),
126 const allocator_type& __a = allocator_type())
127 : _Base(__gnu_debug::__base(
128 __glibcxx_check_valid_constructor_range(__first, __last)),
129 __gnu_debug::__base(__last), __n,
130 __hf, __eql, __a) { }
131
132 unordered_set(const unordered_set&) = default;
133
134 unordered_set(_Base_ref __x)
135 : _Base(__x._M_ref) { }
136
137 unordered_set(unordered_set&&) = default;
138
139 explicit
140 unordered_set(const allocator_type& __a)
141 : _Base(__a) { }
142
143 unordered_set(const unordered_set& __uset,
144 const allocator_type& __a)
145 : _Base(__uset, __a) { }
146
147 unordered_set(unordered_set&& __uset,
148 const allocator_type& __a)
149 noexcept( noexcept(_Base(std::move(__uset), __a)) )
150 : _Safe(std::move(__uset), __a),
151 _Base(std::move(__uset), __a) { }
152
153 unordered_set(initializer_list<value_type> __l,
154 size_type __n = 0,
155 const hasher& __hf = hasher(),
156 const key_equal& __eql = key_equal(),
157 const allocator_type& __a = allocator_type())
158 : _Base(__l, __n, __hf, __eql, __a) { }
159
160 unordered_set(size_type __n, const allocator_type& __a)
161 : unordered_set(__n, hasher(), key_equal(), __a)
162 { }
163
164 unordered_set(size_type __n, const hasher& __hf,
165 const allocator_type& __a)
166 : unordered_set(__n, __hf, key_equal(), __a)
167 { }
168
169 template<typename _InputIterator>
170 unordered_set(_InputIterator __first, _InputIterator __last,
171 size_type __n,
172 const allocator_type& __a)
173 : unordered_set(__first, __last, __n, hasher(), key_equal(), __a)
174 { }
175
176 template<typename _InputIterator>
177 unordered_set(_InputIterator __first, _InputIterator __last,
178 size_type __n, const hasher& __hf,
179 const allocator_type& __a)
180 : unordered_set(__first, __last, __n, __hf, key_equal(), __a)
181 { }
182
183 unordered_set(initializer_list<value_type> __l,
184 size_type __n,
185 const allocator_type& __a)
186 : unordered_set(__l, __n, hasher(), key_equal(), __a)
187 { }
188
189 unordered_set(initializer_list<value_type> __l,
190 size_type __n, const hasher& __hf,
191 const allocator_type& __a)
192 : unordered_set(__l, __n, __hf, key_equal(), __a)
193 { }
194
195 ~unordered_set() = default;
196
197 unordered_set&
198 operator=(const unordered_set&) = default;
199
200 unordered_set&
201 operator=(unordered_set&&) = default;
202
203 unordered_set&
204 operator=(initializer_list<value_type> __l)
205 {
206 _Base::operator=(__l);
207 this->_M_invalidate_all();
208 return *this;
209 }
210
211 using _Base::get_allocator;
212 using _Base::empty;
213 using _Base::size;
214 using _Base::max_size;
215
216 void
217 swap(unordered_set& __x)
218 noexcept( noexcept(declval<_Base&>().swap(__x)) )
219 {
220 _Safe::_M_swap(__x);
221 _Base::swap(__x);
222 }
223
224 void
225 clear() noexcept
226 {
227 _Base::clear();
228 this->_M_invalidate_all();
229 }
230
231 iterator
232 begin() noexcept
233 { return { _Base::begin(), this }; }
234
235 const_iterator
236 begin() const noexcept
237 { return { _Base::begin(), this }; }
238
239 iterator
240 end() noexcept
241 { return { _Base::end(), this }; }
242
243 const_iterator
244 end() const noexcept
245 { return { _Base::end(), this }; }
246
247 const_iterator
248 cbegin() const noexcept
249 { return { _Base::cbegin(), this }; }
250
251 const_iterator
252 cend() const noexcept
253 { return { _Base::cend(), this }; }
254
255 // local versions
256 local_iterator
257 begin(size_type __b)
258 {
259 __glibcxx_check_bucket_index(__b);
260 return { _Base::begin(__b), this };
261 }
262
263 local_iterator
264 end(size_type __b)
265 {
266 __glibcxx_check_bucket_index(__b);
267 return { _Base::end(__b), this };
268 }
269
270 const_local_iterator
271 begin(size_type __b) const
272 {
273 __glibcxx_check_bucket_index(__b);
274 return { _Base::begin(__b), this };
275 }
276
277 const_local_iterator
278 end(size_type __b) const
279 {
280 __glibcxx_check_bucket_index(__b);
281 return { _Base::end(__b), this };
282 }
283
284 const_local_iterator
285 cbegin(size_type __b) const
286 {
287 __glibcxx_check_bucket_index(__b);
288 return { _Base::cbegin(__b), this };
289 }
290
291 const_local_iterator
292 cend(size_type __b) const
293 {
294 __glibcxx_check_bucket_index(__b);
295 return { _Base::cend(__b), this };
296 }
297
298 using _Base::bucket_count;
299 using _Base::max_bucket_count;
300
301 size_type
302 bucket_size(size_type __b) const
303 {
304 __glibcxx_check_bucket_index(__b);
305 return _Base::bucket_size(__b);
306 }
307
308 using _Base::bucket;
309 using _Base::load_factor;
310
311 float
312 max_load_factor() const noexcept
313 { return _Base::max_load_factor(); }
314
315 void
316 max_load_factor(float __f)
317 {
318 __glibcxx_check_max_load_factor(__f);
319 _Base::max_load_factor(__f);
320 }
321
322 using _Base::rehash;
323 using _Base::reserve;
324
325 template<typename... _Args>
326 std::pair<iterator, bool>
327 emplace(_Args&&... __args)
328 {
329 size_type __bucket_count = this->bucket_count();
330 auto __res = _Base::emplace(std::forward<_Args>(__args)...);
331 _M_check_rehashed(__bucket_count);
332 return { { __res.first, this }, __res.second };
333 }
334
335 template<typename... _Args>
336 iterator
337 emplace_hint(const_iterator __hint, _Args&&... __args)
338 {
339 __glibcxx_check_insert(__hint);
340 size_type __bucket_count = this->bucket_count();
341 auto __it = _Base::emplace_hint(__hint.base(),
342 std::forward<_Args>(__args)...);
343 _M_check_rehashed(__bucket_count);
344 return { __it, this };
345 }
346
347 std::pair<iterator, bool>
348 insert(const value_type& __obj)
349 {
350 size_type __bucket_count = this->bucket_count();
351 auto __res = _Base::insert(__obj);
352 _M_check_rehashed(__bucket_count);
353 return { { __res.first, this }, __res.second };
354 }
355
356 iterator
357 insert(const_iterator __hint, const value_type& __obj)
358 {
359 __glibcxx_check_insert(__hint);
360 size_type __bucket_count = this->bucket_count();
361 auto __it = _Base::insert(__hint.base(), __obj);
362 _M_check_rehashed(__bucket_count);
363 return { __it, this };
364 }
365
366 std::pair<iterator, bool>
367 insert(value_type&& __obj)
368 {
369 size_type __bucket_count = this->bucket_count();
370 auto __res = _Base::insert(std::move(__obj));
371 _M_check_rehashed(__bucket_count);
372 return { { __res.first, this }, __res.second };
373 }
374
375 iterator
376 insert(const_iterator __hint, value_type&& __obj)
377 {
378 __glibcxx_check_insert(__hint);
379 size_type __bucket_count = this->bucket_count();
380 auto __it = _Base::insert(__hint.base(), std::move(__obj));
381 _M_check_rehashed(__bucket_count);
382 return { __it, this };
383 }
384
385 void
386 insert(std::initializer_list<value_type> __l)
387 {
388 size_type __bucket_count = this->bucket_count();
389 _Base::insert(__l);
390 _M_check_rehashed(__bucket_count);
391 }
392
393 template<typename _InputIterator>
394 void
395 insert(_InputIterator __first, _InputIterator __last)
396 {
397 typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
398 __glibcxx_check_valid_range2(__first, __last, __dist);
399 size_type __bucket_count = this->bucket_count();
400
401 if (__dist.second >= __gnu_debug::__dp_sign)
402 _Base::insert(__gnu_debug::__unsafe(__first),
403 __gnu_debug::__unsafe(__last));
404 else
405 _Base::insert(__first, __last);
406
407 _M_check_rehashed(__bucket_count);
408 }
409
410#if __cplusplus > 201402L
411 using node_type = typename _Base::node_type;
412 using insert_return_type = _Node_insert_return<iterator, node_type>;
413
414 node_type
415 extract(const_iterator __position)
416 {
417 __glibcxx_check_erase(__position);
418 return _M_extract(__position.base());
419 }
420
421 node_type
422 extract(const key_type& __key)
423 {
424 const auto __position = _Base::find(__key);
425 if (__position != _Base::end())
426 return _M_extract(__position);
427 return {};
428 }
429
430 insert_return_type
431 insert(node_type&& __nh)
432 {
433 auto __ret = _Base::insert(std::move(__nh));
434 return
435 { { __ret.position, this }, __ret.inserted, std::move(__ret.node) };
436 }
437
438 iterator
439 insert(const_iterator __hint, node_type&& __nh)
440 {
441 __glibcxx_check_insert(__hint);
442 return { _Base::insert(__hint.base(), std::move(__nh)), this };
443 }
444
445 template<typename _H2, typename _P2>
446 void
447 merge(unordered_set<_Value, _H2, _P2, _Alloc>& __source)
448 {
449 auto __guard
450 = _Safe::_S_uc_guard(std::__detail::_Identity{}, __source);
451 _Base::merge(__source);
452 }
453
454 template<typename _H2, typename _P2>
455 void
456 merge(unordered_set<_Value, _H2, _P2, _Alloc>&& __source)
457 { merge(__source); }
458
459 template<typename _H2, typename _P2>
460 void
461 merge(unordered_multiset<_Value, _H2, _P2, _Alloc>& __source)
462 {
463 auto __guard
464 = _Safe::_S_umc_guard(std::__detail::_Identity{}, __source);
465 _Base::merge(__source);
466 }
467
468 template<typename _H2, typename _P2>
469 void
470 merge(unordered_multiset<_Value, _H2, _P2, _Alloc>&& __source)
471 { merge(__source); }
472#endif // C++17
473
474 using _Base::hash_function;
475 using _Base::key_eq;
476
477 iterator
478 find(const key_type& __key)
479 { return { _Base::find(__key), this }; }
480
481#if __cplusplus > 201703L
482 template<typename _Kt,
483 typename = std::__has_is_transparent_t<_Hash, _Kt>,
484 typename = std::__has_is_transparent_t<_Pred, _Kt>>
485 iterator
486 find(const _Kt& __k)
487 { return { _Base::find(__k), this }; }
488#endif
489
490 const_iterator
491 find(const key_type& __key) const
492 { return { _Base::find(__key), this }; }
493
494#if __cplusplus > 201703L
495 template<typename _Kt,
496 typename = std::__has_is_transparent_t<_Hash, _Kt>,
497 typename = std::__has_is_transparent_t<_Pred, _Kt>>
498 const_iterator
499 find(const _Kt& __k) const
500 { return { _Base::find(__k), this }; }
501#endif
502
503 using _Base::count;
504
505#if __cplusplus > 201703L
506 using _Base::contains;
507#endif
508
509 std::pair<iterator, iterator>
510 equal_range(const key_type& __key)
511 {
512 auto __res = _Base::equal_range(__key);
513 return { { __res.first, this }, { __res.second, this } };
514 }
515
516#if __cplusplus > 201703L
517 template<typename _Kt,
518 typename = std::__has_is_transparent_t<_Hash, _Kt>,
519 typename = std::__has_is_transparent_t<_Pred, _Kt>>
520 std::pair<iterator, iterator>
521 equal_range(const _Kt& __k)
522 {
523 auto __res = _Base::equal_range(__k);
524 return { { __res.first, this }, { __res.second, this } };
525 }
526#endif
527
528 std::pair<const_iterator, const_iterator>
529 equal_range(const key_type& __key) const
530 {
531 auto __res = _Base::equal_range(__key);
532 return { { __res.first, this }, { __res.second, this } };
533 }
534
535#if __cplusplus > 201703L
536 template<typename _Kt,
537 typename = std::__has_is_transparent_t<_Hash, _Kt>,
538 typename = std::__has_is_transparent_t<_Pred, _Kt>>
539 std::pair<const_iterator, const_iterator>
540 equal_range(const _Kt& __k) const
541 {
542 auto __res = _Base::equal_range(__k);
543 return { { __res.first, this }, { __res.second, this } };
544 }
545#endif
546
547 size_type
548 erase(const key_type& __key)
549 {
550 size_type __ret(0);
551 auto __victim = _Base::find(__key);
552 if (__victim != _Base::end())
553 {
554 _M_erase(__victim);
555 __ret = 1;
556 }
557 return __ret;
558 }
559
560 iterator
561 erase(const_iterator __it)
562 {
563 __glibcxx_check_erase(__it);
564 return { _M_erase(__it.base()), this };
565 }
566
567 _Base_iterator
568 erase(_Base_const_iterator __it)
569 {
570 __glibcxx_check_erase2(__it);
571 return _M_erase(__it);
572 }
573
574 iterator
575 erase(iterator __it)
576 {
577 __glibcxx_check_erase(__it);
578 return { _M_erase(__it.base()), this };
579 }
580
581 iterator
582 erase(const_iterator __first, const_iterator __last)
583 {
584 __glibcxx_check_erase_range(__first, __last);
585 for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
586 {
587 _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
588 _M_message(__gnu_debug::__msg_valid_range)
589 ._M_iterator(__first, "first")
590 ._M_iterator(__last, "last"));
591 _M_invalidate(__tmp);
592 }
593
594 size_type __bucket_count = this->bucket_count();
595 auto __next = _Base::erase(__first.base(), __last.base());
596 _M_check_rehashed(__bucket_count);
597 return { __next, this };
598 }
599
600 _Base&
601 _M_base() noexcept { return *this; }
602
603 const _Base&
604 _M_base() const noexcept { return *this; }
605
606 private:
607 void
608 _M_check_rehashed(size_type __prev_count)
609 {
610 if (__prev_count != this->bucket_count())
611 this->_M_invalidate_all();
612 }
613
614 void
615 _M_invalidate(_Base_const_iterator __victim)
616 {
617 this->_M_invalidate_if(
618 [__victim](_Base_const_iterator __it) { return __it == __victim; });
619 this->_M_invalidate_local_if(
620 [__victim](_Base_const_local_iterator __it)
621 { return __it == __victim; });
622 }
623
624 _Base_iterator
625 _M_erase(_Base_const_iterator __victim)
626 {
627 _M_invalidate(__victim);
628 size_type __bucket_count = this->bucket_count();
629 _Base_iterator __next = _Base::erase(__victim);
630 _M_check_rehashed(__bucket_count);
631 return __next;
632 }
633
634#if __cplusplus > 201402L
635 node_type
636 _M_extract(_Base_const_iterator __victim)
637 {
638 _M_invalidate(__victim);
639 return _Base::extract(__victim);
640 }
641#endif
642 };
643
644#if __cpp_deduction_guides >= 201606
645
646 template<typename _InputIterator,
647 typename _Hash =
648 hash<typename iterator_traits<_InputIterator>::value_type>,
649 typename _Pred =
650 equal_to<typename iterator_traits<_InputIterator>::value_type>,
651 typename _Allocator =
652 allocator<typename iterator_traits<_InputIterator>::value_type>,
653 typename = _RequireInputIter<_InputIterator>,
654 typename = _RequireNotAllocatorOrIntegral<_Hash>,
655 typename = _RequireNotAllocator<_Pred>,
656 typename = _RequireAllocator<_Allocator>>
657 unordered_set(_InputIterator, _InputIterator,
658 unordered_set<int>::size_type = {},
659 _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator())
660 -> unordered_set<typename iterator_traits<_InputIterator>::value_type,
661 _Hash, _Pred, _Allocator>;
662
663 template<typename _Tp, typename _Hash = hash<_Tp>,
664 typename _Pred = equal_to<_Tp>,
665 typename _Allocator = allocator<_Tp>,
666 typename = _RequireNotAllocatorOrIntegral<_Hash>,
667 typename = _RequireNotAllocator<_Pred>,
668 typename = _RequireAllocator<_Allocator>>
669 unordered_set(initializer_list<_Tp>,
670 unordered_set<int>::size_type = {},
671 _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator())
672 -> unordered_set<_Tp, _Hash, _Pred, _Allocator>;
673
674 template<typename _InputIterator, typename _Allocator,
675 typename = _RequireInputIter<_InputIterator>,
676 typename = _RequireAllocator<_Allocator>>
677 unordered_set(_InputIterator, _InputIterator,
678 unordered_set<int>::size_type, _Allocator)
679 -> unordered_set<typename iterator_traits<_InputIterator>::value_type,
680 hash<
681 typename iterator_traits<_InputIterator>::value_type>,
682 equal_to<
683 typename iterator_traits<_InputIterator>::value_type>,
684 _Allocator>;
685
686 template<typename _InputIterator, typename _Hash, typename _Allocator,
687 typename = _RequireInputIter<_InputIterator>,
688 typename = _RequireNotAllocatorOrIntegral<_Hash>,
689 typename = _RequireAllocator<_Allocator>>
690 unordered_set(_InputIterator, _InputIterator,
691 unordered_set<int>::size_type,
692 _Hash, _Allocator)
693 -> unordered_set<typename iterator_traits<_InputIterator>::value_type,
694 _Hash,
695 equal_to<
696 typename iterator_traits<_InputIterator>::value_type>,
697 _Allocator>;
698
699 template<typename _Tp, typename _Allocator,
700 typename = _RequireAllocator<_Allocator>>
701 unordered_set(initializer_list<_Tp>,
702 unordered_set<int>::size_type, _Allocator)
703 -> unordered_set<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>;
704
705 template<typename _Tp, typename _Hash, typename _Allocator,
706 typename = _RequireNotAllocatorOrIntegral<_Hash>,
707 typename = _RequireAllocator<_Allocator>>
708 unordered_set(initializer_list<_Tp>,
709 unordered_set<int>::size_type, _Hash, _Allocator)
710 -> unordered_set<_Tp, _Hash, equal_to<_Tp>, _Allocator>;
711
712#endif
713
714 template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
715 inline void
716 swap(unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
717 unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
718 noexcept(noexcept(__x.swap(__y)))
719 { __x.swap(__y); }
720
721 template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
722 inline bool
723 operator==(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
724 const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
725 { return __x._M_base() == __y._M_base(); }
726
727#if __cpp_impl_three_way_comparison < 201907L
728 template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
729 inline bool
730 operator!=(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
731 const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
732 { return !(__x == __y); }
733#endif
734
735 /// Class std::unordered_multiset with safety/checking/debug instrumentation.
736 template<typename _Value,
737 typename _Hash = std::hash<_Value>,
738 typename _Pred = std::equal_to<_Value>,
739 typename _Alloc = std::allocator<_Value> >
740 class unordered_multiset
741 : public __gnu_debug::_Safe_container<
742 unordered_multiset<_Value, _Hash, _Pred, _Alloc>, _Alloc,
743 __gnu_debug::_Safe_unordered_container>,
744 public _GLIBCXX_STD_C::unordered_multiset<_Value, _Hash, _Pred, _Alloc>
745 {
746 typedef _GLIBCXX_STD_C::unordered_multiset<
747 _Value, _Hash, _Pred, _Alloc> _Base;
748 typedef __gnu_debug::_Safe_container<unordered_multiset,
749 _Alloc, __gnu_debug::_Safe_unordered_container> _Safe;
750 typedef typename _Base::const_iterator _Base_const_iterator;
751 typedef typename _Base::iterator _Base_iterator;
752 typedef typename _Base::const_local_iterator
753 _Base_const_local_iterator;
754 typedef typename _Base::local_iterator _Base_local_iterator;
755
756 template<typename _ItT, typename _SeqT, typename _CatT>
757 friend class ::__gnu_debug::_Safe_iterator;
758 template<typename _ItT, typename _SeqT>
759 friend class ::__gnu_debug::_Safe_local_iterator;
760
761 // Reference wrapper for base class. See PR libstdc++/90102.
762 struct _Base_ref
763 {
764 _Base_ref(const _Base& __r) : _M_ref(__r) { }
765
766 const _Base& _M_ref;
767 };
768
769 public:
770 typedef typename _Base::size_type size_type;
771 typedef typename _Base::difference_type difference_type;
772 typedef typename _Base::hasher hasher;
773 typedef typename _Base::key_equal key_equal;
774 typedef typename _Base::allocator_type allocator_type;
775
776 typedef typename _Base::key_type key_type;
777 typedef typename _Base::value_type value_type;
778
779 typedef typename _Base::pointer pointer;
780 typedef typename _Base::const_pointer const_pointer;
781 typedef typename _Base::reference reference;
782 typedef typename _Base::const_reference const_reference;
783 typedef __gnu_debug::_Safe_iterator<
784 _Base_iterator, unordered_multiset> iterator;
785 typedef __gnu_debug::_Safe_iterator<
786 _Base_const_iterator, unordered_multiset> const_iterator;
787 typedef __gnu_debug::_Safe_local_iterator<
788 _Base_local_iterator, unordered_multiset> local_iterator;
789 typedef __gnu_debug::_Safe_local_iterator<
790 _Base_const_local_iterator, unordered_multiset> const_local_iterator;
791
792 unordered_multiset() = default;
793
794 explicit
795 unordered_multiset(size_type __n,
796 const hasher& __hf = hasher(),
797 const key_equal& __eql = key_equal(),
798 const allocator_type& __a = allocator_type())
799 : _Base(__n, __hf, __eql, __a) { }
800
801 template<typename _InputIterator>
802 unordered_multiset(_InputIterator __first, _InputIterator __last,
803 size_type __n = 0,
804 const hasher& __hf = hasher(),
805 const key_equal& __eql = key_equal(),
806 const allocator_type& __a = allocator_type())
807 : _Base(__gnu_debug::__base(
808 __glibcxx_check_valid_constructor_range(__first, __last)),
809 __gnu_debug::__base(__last), __n,
810 __hf, __eql, __a) { }
811
812 unordered_multiset(const unordered_multiset&) = default;
813
814 unordered_multiset(_Base_ref __x)
815 : _Base(__x._M_ref) { }
816
817 unordered_multiset(unordered_multiset&&) = default;
818
819 explicit
820 unordered_multiset(const allocator_type& __a)
821 : _Base(__a) { }
822
823 unordered_multiset(const unordered_multiset& __uset,
824 const allocator_type& __a)
825 : _Base(__uset, __a) { }
826
827 unordered_multiset(unordered_multiset&& __uset,
828 const allocator_type& __a)
829 noexcept( noexcept(_Base(std::move(__uset), __a)) )
830 : _Safe(std::move(__uset), __a),
831 _Base(std::move(__uset), __a) { }
832
833 unordered_multiset(initializer_list<value_type> __l,
834 size_type __n = 0,
835 const hasher& __hf = hasher(),
836 const key_equal& __eql = key_equal(),
837 const allocator_type& __a = allocator_type())
838 : _Base(__l, __n, __hf, __eql, __a) { }
839
840 unordered_multiset(size_type __n, const allocator_type& __a)
841 : unordered_multiset(__n, hasher(), key_equal(), __a)
842 { }
843
844 unordered_multiset(size_type __n, const hasher& __hf,
845 const allocator_type& __a)
846 : unordered_multiset(__n, __hf, key_equal(), __a)
847 { }
848
849 template<typename _InputIterator>
850 unordered_multiset(_InputIterator __first, _InputIterator __last,
851 size_type __n,
852 const allocator_type& __a)
853 : unordered_multiset(__first, __last, __n, hasher(), key_equal(), __a)
854 { }
855
856 template<typename _InputIterator>
857 unordered_multiset(_InputIterator __first, _InputIterator __last,
858 size_type __n, const hasher& __hf,
859 const allocator_type& __a)
860 : unordered_multiset(__first, __last, __n, __hf, key_equal(), __a)
861 { }
862
863 unordered_multiset(initializer_list<value_type> __l,
864 size_type __n,
865 const allocator_type& __a)
866 : unordered_multiset(__l, __n, hasher(), key_equal(), __a)
867 { }
868
869 unordered_multiset(initializer_list<value_type> __l,
870 size_type __n, const hasher& __hf,
871 const allocator_type& __a)
872 : unordered_multiset(__l, __n, __hf, key_equal(), __a)
873 { }
874
875 ~unordered_multiset() = default;
876
877 unordered_multiset&
878 operator=(const unordered_multiset&) = default;
879
880 unordered_multiset&
881 operator=(unordered_multiset&&) = default;
882
883 unordered_multiset&
884 operator=(initializer_list<value_type> __l)
885 {
886 _Base::operator=(__l);
887 this->_M_invalidate_all();
888 return *this;
889 }
890
891 using _Base::get_allocator;
892 using _Base::empty;
893 using _Base::size;
894 using _Base::max_size;
895
896 void
897 swap(unordered_multiset& __x)
898 noexcept( noexcept(declval<_Base&>().swap(__x)) )
899 {
900 _Safe::_M_swap(__x);
901 _Base::swap(__x);
902 }
903
904 void
905 clear() noexcept
906 {
907 _Base::clear();
908 this->_M_invalidate_all();
909 }
910
911 iterator
912 begin() noexcept
913 { return { _Base::begin(), this }; }
914
915 const_iterator
916 begin() const noexcept
917 { return { _Base::begin(), this }; }
918
919 iterator
920 end() noexcept
921 { return { _Base::end(), this }; }
922
923 const_iterator
924 end() const noexcept
925 { return { _Base::end(), this }; }
926
927 const_iterator
928 cbegin() const noexcept
929 { return { _Base::cbegin(), this }; }
930
931 const_iterator
932 cend() const noexcept
933 { return { _Base::cend(), this }; }
934
935 // local versions
936 local_iterator
937 begin(size_type __b)
938 {
939 __glibcxx_check_bucket_index(__b);
940 return { _Base::begin(__b), this };
941 }
942
943 local_iterator
944 end(size_type __b)
945 {
946 __glibcxx_check_bucket_index(__b);
947 return { _Base::end(__b), this };
948 }
949
950 const_local_iterator
951 begin(size_type __b) const
952 {
953 __glibcxx_check_bucket_index(__b);
954 return { _Base::begin(__b), this };
955 }
956
957 const_local_iterator
958 end(size_type __b) const
959 {
960 __glibcxx_check_bucket_index(__b);
961 return { _Base::end(__b), this };
962 }
963
964 const_local_iterator
965 cbegin(size_type __b) const
966 {
967 __glibcxx_check_bucket_index(__b);
968 return { _Base::cbegin(__b), this };
969 }
970
971 const_local_iterator
972 cend(size_type __b) const
973 {
974 __glibcxx_check_bucket_index(__b);
975 return { _Base::cend(__b), this };
976 }
977
978 using _Base::bucket_count;
979 using _Base::max_bucket_count;
980
981 size_type
982 bucket_size(size_type __b) const
983 {
984 __glibcxx_check_bucket_index(__b);
985 return _Base::bucket_size(__b);
986 }
987
988 using _Base::bucket;
989 using _Base::load_factor;
990
991 float
992 max_load_factor() const noexcept
993 { return _Base::max_load_factor(); }
994
995 void
996 max_load_factor(float __f)
997 {
998 __glibcxx_check_max_load_factor(__f);
999 _Base::max_load_factor(__f);
1000 }
1001
1002 using _Base::rehash;
1003 using _Base::reserve;
1004
1005 template<typename... _Args>
1006 iterator
1007 emplace(_Args&&... __args)
1008 {
1009 size_type __bucket_count = this->bucket_count();
1010 auto __it = _Base::emplace(std::forward<_Args>(__args)...);
1011 _M_check_rehashed(__bucket_count);
1012 return { __it, this };
1013 }
1014
1015 template<typename... _Args>
1016 iterator
1017 emplace_hint(const_iterator __hint, _Args&&... __args)
1018 {
1019 __glibcxx_check_insert(__hint);
1020 size_type __bucket_count = this->bucket_count();
1021 auto __it = _Base::emplace_hint(__hint.base(),
1022 std::forward<_Args>(__args)...);
1023 _M_check_rehashed(__bucket_count);
1024 return { __it, this };
1025 }
1026
1027 iterator
1028 insert(const value_type& __obj)
1029 {
1030 size_type __bucket_count = this->bucket_count();
1031 auto __it = _Base::insert(__obj);
1032 _M_check_rehashed(__bucket_count);
1033 return { __it, this };
1034 }
1035
1036 iterator
1037 insert(const_iterator __hint, const value_type& __obj)
1038 {
1039 __glibcxx_check_insert(__hint);
1040 size_type __bucket_count = this->bucket_count();
1041 auto __it = _Base::insert(__hint.base(), __obj);
1042 _M_check_rehashed(__bucket_count);
1043 return { __it, this };
1044 }
1045
1046 iterator
1047 insert(value_type&& __obj)
1048 {
1049 size_type __bucket_count = this->bucket_count();
1050 auto __it = _Base::insert(std::move(__obj));
1051 _M_check_rehashed(__bucket_count);
1052 return { __it, this };
1053 }
1054
1055 iterator
1056 insert(const_iterator __hint, value_type&& __obj)
1057 {
1058 __glibcxx_check_insert(__hint);
1059 size_type __bucket_count = this->bucket_count();
1060 auto __it = _Base::insert(__hint.base(), std::move(__obj));
1061 _M_check_rehashed(__bucket_count);
1062 return { __it, this };
1063 }
1064
1065 void
1066 insert(std::initializer_list<value_type> __l)
1067 {
1068 size_type __bucket_count = this->bucket_count();
1069 _Base::insert(__l);
1070 _M_check_rehashed(__bucket_count);
1071 }
1072
1073 template<typename _InputIterator>
1074 void
1075 insert(_InputIterator __first, _InputIterator __last)
1076 {
1077 typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
1078 __glibcxx_check_valid_range2(__first, __last, __dist);
1079 size_type __bucket_count = this->bucket_count();
1080
1081 if (__dist.second >= __gnu_debug::__dp_sign)
1082 _Base::insert(__gnu_debug::__unsafe(__first),
1083 __gnu_debug::__unsafe(__last));
1084 else
1085 _Base::insert(__first, __last);
1086
1087 _M_check_rehashed(__bucket_count);
1088 }
1089
1090#if __cplusplus > 201402L
1091 using node_type = typename _Base::node_type;
1092
1093 node_type
1094 extract(const_iterator __position)
1095 {
1096 __glibcxx_check_erase(__position);
1097 return _M_extract(__position.base());
1098 }
1099
1100 node_type
1101 extract(const key_type& __key)
1102 {
1103 const auto __position = _Base::find(__key);
1104 if (__position != _Base::end())
1105 return _M_extract(__position);
1106 return {};
1107 }
1108
1109 iterator
1110 insert(node_type&& __nh)
1111 { return { _Base::insert(std::move(__nh)), this }; }
1112
1113 iterator
1114 insert(const_iterator __hint, node_type&& __nh)
1115 {
1116 __glibcxx_check_insert(__hint);
1117 return { _Base::insert(__hint.base(), std::move(__nh)), this };
1118 }
1119
1120 template<typename _H2, typename _P2>
1121 void
1122 merge(unordered_multiset<_Value, _H2, _P2, _Alloc>& __source)
1123 {
1124 auto __guard
1125 = _Safe::_S_umc_guard(std::__detail::_Identity{}, __source);
1126 _Base::merge(__source);
1127 }
1128
1129 template<typename _H2, typename _P2>
1130 void
1131 merge(unordered_multiset<_Value, _H2, _P2, _Alloc>&& __source)
1132 { merge(__source); }
1133
1134 template<typename _H2, typename _P2>
1135 void
1136 merge(unordered_set<_Value, _H2, _P2, _Alloc>& __source)
1137 {
1138 auto __guard
1139 = _Safe::_S_uc_guard(std::__detail::_Identity{}, __source);
1140 _Base::merge(__source);
1141 }
1142
1143 template<typename _H2, typename _P2>
1144 void
1145 merge(unordered_set<_Value, _H2, _P2, _Alloc>&& __source)
1146 { merge(__source); }
1147#endif // C++17
1148
1149 using _Base::hash_function;
1150 using _Base::key_eq;
1151
1152 iterator
1153 find(const key_type& __key)
1154 { return { _Base::find(__key), this }; }
1155
1156#if __cplusplus > 201703L
1157 template<typename _Kt,
1158 typename = std::__has_is_transparent_t<_Hash, _Kt>,
1159 typename = std::__has_is_transparent_t<_Pred, _Kt>>
1160 iterator
1161 find(const _Kt& __k)
1162 { return { _Base::find(__k), this }; }
1163#endif
1164
1165 const_iterator
1166 find(const key_type& __key) const
1167 { return { _Base::find(__key), this }; }
1168
1169#if __cplusplus > 201703L
1170 template<typename _Kt,
1171 typename = std::__has_is_transparent_t<_Hash, _Kt>,
1172 typename = std::__has_is_transparent_t<_Pred, _Kt>>
1173 const_iterator
1174 find(const _Kt& __k) const
1175 { return { _Base::find(__k), this }; }
1176#endif
1177
1178 using _Base::count;
1179
1180#if __cplusplus > 201703L
1181 using _Base::contains;
1182#endif
1183
1184 std::pair<iterator, iterator>
1185 equal_range(const key_type& __key)
1186 {
1187 auto __res = _Base::equal_range(__key);
1188 return { { __res.first, this }, { __res.second, this } };
1189 }
1190
1191#if __cplusplus > 201703L
1192 template<typename _Kt,
1193 typename = std::__has_is_transparent_t<_Hash, _Kt>,
1194 typename = std::__has_is_transparent_t<_Pred, _Kt>>
1195 std::pair<iterator, iterator>
1196 equal_range(const _Kt& __k)
1197 {
1198 auto __res = _Base::equal_range(__k);
1199 return { { __res.first, this }, { __res.second, this } };
1200 }
1201#endif
1202
1203 std::pair<const_iterator, const_iterator>
1204 equal_range(const key_type& __key) const
1205 {
1206 auto __res = _Base::equal_range(__key);
1207 return { { __res.first, this }, { __res.second, this } };
1208 }
1209
1210#if __cplusplus > 201703L
1211 template<typename _Kt,
1212 typename = std::__has_is_transparent_t<_Hash, _Kt>,
1213 typename = std::__has_is_transparent_t<_Pred, _Kt>>
1214 std::pair<const_iterator, const_iterator>
1215 equal_range(const _Kt& __k) const
1216 {
1217 auto __res = _Base::equal_range(__k);
1218 return { { __res.first, this }, { __res.second, this } };
1219 }
1220#endif
1221
1222 size_type
1223 erase(const key_type& __key)
1224 {
1225 size_type __ret(0);
1226 auto __pair = _Base::equal_range(__key);
1227 for (auto __victim = __pair.first; __victim != __pair.second;)
1228 {
1229 _M_invalidate(__victim);
1230 __victim = _Base::erase(__victim);
1231 ++__ret;
1232 }
1233
1234 return __ret;
1235 }
1236
1237 iterator
1238 erase(const_iterator __it)
1239 {
1240 __glibcxx_check_erase(__it);
1241 return { _M_erase(__it.base()), this };
1242 }
1243
1244 _Base_iterator
1245 erase(_Base_const_iterator __it)
1246 {
1247 __glibcxx_check_erase2(__it);
1248 return _M_erase(__it);
1249 }
1250
1251 iterator
1252 erase(iterator __it)
1253 {
1254 __glibcxx_check_erase(__it);
1255 return { _M_erase(__it.base()), this };
1256 }
1257
1258 iterator
1259 erase(const_iterator __first, const_iterator __last)
1260 {
1261 __glibcxx_check_erase_range(__first, __last);
1262 for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
1263 {
1264 _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
1265 _M_message(__gnu_debug::__msg_valid_range)
1266 ._M_iterator(__first, "first")
1267 ._M_iterator(__last, "last"));
1268 _M_invalidate(__tmp);
1269 }
1270 return { _Base::erase(__first.base(), __last.base()), this };
1271 }
1272
1273 _Base&
1274 _M_base() noexcept { return *this; }
1275
1276 const _Base&
1277 _M_base() const noexcept { return *this; }
1278
1279 private:
1280 void
1281 _M_check_rehashed(size_type __prev_count)
1282 {
1283 if (__prev_count != this->bucket_count())
1284 this->_M_invalidate_all();
1285 }
1286
1287 void
1288 _M_invalidate(_Base_const_iterator __victim)
1289 {
1290 this->_M_invalidate_if(
1291 [__victim](_Base_const_iterator __it) { return __it == __victim; });
1292 this->_M_invalidate_local_if(
1293 [__victim](_Base_const_local_iterator __it)
1294 { return __it == __victim; });
1295 }
1296
1297 _Base_iterator
1298 _M_erase(_Base_const_iterator __victim)
1299 {
1300 _M_invalidate(__victim);
1301 size_type __bucket_count = this->bucket_count();
1302 _Base_iterator __next = _Base::erase(__victim);
1303 _M_check_rehashed(__bucket_count);
1304 return __next;
1305 }
1306
1307#if __cplusplus > 201402L
1308 node_type
1309 _M_extract(_Base_const_iterator __victim)
1310 {
1311 _M_invalidate(__victim);
1312 return _Base::extract(__victim);
1313 }
1314#endif
1315 };
1316
1317#if __cpp_deduction_guides >= 201606
1318
1319 template<typename _InputIterator,
1320 typename _Hash =
1321 hash<typename iterator_traits<_InputIterator>::value_type>,
1322 typename _Pred =
1323 equal_to<typename iterator_traits<_InputIterator>::value_type>,
1324 typename _Allocator =
1325 allocator<typename iterator_traits<_InputIterator>::value_type>,
1326 typename = _RequireInputIter<_InputIterator>,
1327 typename = _RequireNotAllocatorOrIntegral<_Hash>,
1328 typename = _RequireNotAllocator<_Pred>,
1329 typename = _RequireAllocator<_Allocator>>
1330 unordered_multiset(_InputIterator, _InputIterator,
1331 unordered_multiset<int>::size_type = {},
1332 _Hash = _Hash(), _Pred = _Pred(),
1333 _Allocator = _Allocator())
1334 -> unordered_multiset<typename iterator_traits<_InputIterator>::value_type,
1335 _Hash, _Pred, _Allocator>;
1336
1337 template<typename _Tp, typename _Hash = hash<_Tp>,
1338 typename _Pred = equal_to<_Tp>,
1339 typename _Allocator = allocator<_Tp>,
1340 typename = _RequireNotAllocatorOrIntegral<_Hash>,
1341 typename = _RequireNotAllocator<_Pred>,
1342 typename = _RequireAllocator<_Allocator>>
1343 unordered_multiset(initializer_list<_Tp>,
1344 unordered_multiset<int>::size_type = {},
1345 _Hash = _Hash(), _Pred = _Pred(),
1346 _Allocator = _Allocator())
1347 -> unordered_multiset<_Tp, _Hash, _Pred, _Allocator>;
1348
1349 template<typename _InputIterator, typename _Allocator,
1350 typename = _RequireInputIter<_InputIterator>,
1351 typename = _RequireAllocator<_Allocator>>
1352 unordered_multiset(_InputIterator, _InputIterator,
1353 unordered_multiset<int>::size_type, _Allocator)
1354 -> unordered_multiset<typename iterator_traits<_InputIterator>::value_type,
1355 hash<typename
1356 iterator_traits<_InputIterator>::value_type>,
1357 equal_to<typename
1358 iterator_traits<_InputIterator>::value_type>,
1359 _Allocator>;
1360
1361 template<typename _InputIterator, typename _Hash, typename _Allocator,
1362 typename = _RequireInputIter<_InputIterator>,
1363 typename = _RequireNotAllocatorOrIntegral<_Hash>,
1364 typename = _RequireAllocator<_Allocator>>
1365 unordered_multiset(_InputIterator, _InputIterator,
1366 unordered_multiset<int>::size_type,
1367 _Hash, _Allocator)
1368 -> unordered_multiset<typename
1369 iterator_traits<_InputIterator>::value_type,
1370 _Hash,
1371 equal_to<
1372 typename
1373 iterator_traits<_InputIterator>::value_type>,
1374 _Allocator>;
1375
1376 template<typename _Tp, typename _Allocator,
1377 typename = _RequireAllocator<_Allocator>>
1378 unordered_multiset(initializer_list<_Tp>,
1379 unordered_multiset<int>::size_type, _Allocator)
1380 -> unordered_multiset<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>;
1381
1382 template<typename _Tp, typename _Hash, typename _Allocator,
1383 typename = _RequireNotAllocatorOrIntegral<_Hash>,
1384 typename = _RequireAllocator<_Allocator>>
1385 unordered_multiset(initializer_list<_Tp>,
1386 unordered_multiset<int>::size_type, _Hash, _Allocator)
1387 -> unordered_multiset<_Tp, _Hash, equal_to<_Tp>, _Allocator>;
1388
1389#endif
1390
1391 template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
1392 inline void
1393 swap(unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
1394 unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
1395 noexcept(noexcept(__x.swap(__y)))
1396 { __x.swap(__y); }
1397
1398 template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
1399 inline bool
1400 operator==(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
1401 const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
1402 { return __x._M_base() == __y._M_base(); }
1403
1404#if __cpp_impl_three_way_comparison < 201907L
1405 template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
1406 inline bool
1407 operator!=(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
1408 const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
1409 { return !(__x == __y); }
1410#endif
1411
1412} // namespace __debug
1413} // namespace std
1414
1415#endif // C++11
1416
1417#endif