source: mainline/uspace/lib/cpp/include/impl/unordered_set.hpp@ 90adbd7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 90adbd7 was 90adbd7, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: added unordered_multiset, thanks to the aux::hash_table refactoring, this is a pure copypasta with a substituted name

  • Property mode set to 100644
File size: 30.2 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_UNORDERED_SET
30#define LIBCPP_UNORDERED_SET
31
32#include <initializer_list>
33#include <internal/hash_table.hpp>
34#include <functional>
35#include <memory>
36#include <utility>
37
38namespace std
39{
40 /**
41 * 23.5.6, class template unordered_set:
42 */
43
44 template<
45 class Key,
46 class Hash = hash<Key>,
47 class Pred = equal_to<Key>,
48 class Alloc = allocator<Key>
49 >
50 class unordered_set
51 {
52 public:
53 using key_type = Key;
54 using value_type = Key;
55 using hasher = Hash;
56 using key_equal = Pred;
57 using allocator_type = Alloc;
58 using pointer = typename allocator_traits<allocator_type>::pointer;
59 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
60 using reference = value_type&;
61 using const_reference = const value_type&;
62 using size_type = size_t;
63 using difference_type = ptrdiff_t;
64
65 /**
66 * Note: Both the iterator and const_iterator (and their local variants)
67 * types are constant iterators, the standard does not require them
68 * to be the same type, but why not? :)
69 */
70 using iterator = aux::hash_table_const_iterator<
71 value_type, const_reference, const_pointer, size_type
72 >;
73 using const_iterator = iterator;
74 using local_iterator = aux::hash_table_const_local_iterator<
75 value_type, const_reference, const_pointer
76 >;
77 using const_local_iterator = local_iterator;
78
79 /**
80 * Note: We need () to delegate the constructor,
81 * otherwise it could be deduced as the initializer
82 * list constructor when size_type is convertible
83 * to value_type.
84 */
85 unordered_set()
86 : unordered_set(default_bucket_count_)
87 { /* DUMMY BODY */ }
88
89 explicit unordered_set(size_type bucket_count,
90 const hasher& hf = hasher{},
91 const key_equal& eql = key_equal{},
92 const allocator_type& alloc = allocator_type{})
93 : table_{bucket_count, hf, eql}, allocator_{alloc}
94 { /* DUMMY BODY */ }
95
96 template<class InputIterator>
97 unordered_set(InputIterator first, InputIterator last,
98 size_type bucket_count = default_bucket_count_,
99 const hasher& hf = hasher{},
100 const key_equal& eql = key_equal{},
101 const allocator_type& alloc = allocator_type{})
102 : unordered_set{bucket_count, hf, eql, alloc}
103 {
104 insert(first, last);
105 }
106
107 unordered_set(const unordered_set& other)
108 : unordered_set{other, other.allocator_}
109 { /* DUMMY BODY */ }
110
111 unordered_set(unordered_set&& other)
112 : table_{move(other.table_)}, allocator_{move(other.allocator_)}
113 { /* DUMMY BODY */ }
114
115 explicit unordered_set(const allocator_type& alloc)
116 : table_{default_bucket_count_}, allocator_{alloc}
117 { /* DUMMY BODY */ }
118
119 unordered_set(const unordered_set& other, const allocator_type& alloc)
120 : table_{other.table_}, allocator_{alloc}
121 { /* DUMMY BODY */ }
122
123 unordered_set(unordered_set&& other, const allocator_type& alloc)
124 : table_{move(other.table_)}, allocator_{alloc}
125 { /* DUMMY BODY */ }
126
127 unordered_set(initializer_list<value_type> init,
128 size_type bucket_count = default_bucket_count_,
129 const hasher& hf = hasher{},
130 const key_equal& eql = key_equal{},
131 const allocator_type& alloc = allocator_type{})
132 : unordered_set{bucket_count, hf, eql, alloc}
133 {
134 insert(init.begin(), init.end());
135 }
136
137 unordered_set(size_type bucket_count, const allocator_type& alloc)
138 : unordered_set{bucket_count, hasher{}, key_equal{}, alloc}
139 { /* DUMMY BODY */ }
140
141 unordered_set(size_type bucket_count, const hasher& hf, const allocator_type& alloc)
142 : unordered_set{bucket_count, hf, key_equal{}, alloc}
143 { /* DUMMY BODY */ }
144
145 template<class InputIterator>
146 unordered_set(InputIterator first, InputIterator last,
147 size_type bucket_count, const allocator_type& alloc)
148 : unordered_set{first, last, bucket_count, hasher{}, key_equal{}, alloc}
149 { /* DUMMY BODY */ }
150
151 template<class InputIterator>
152 unordered_set(InputIterator first, InputIterator last,
153 size_type bucket_count, const hasher& hf, const allocator_type& alloc)
154 : unordered_set{first, last, bucket_count, hf, key_equal{}, alloc}
155 { /* DUMMY BODY */ }
156
157 unordered_set(initializer_list<value_type> init, size_type bucket_count,
158 const allocator_type& alloc)
159 : unordered_set{init, bucket_count, hasher{}, key_equal{}, alloc}
160 { /* DUMMY BODY */ }
161
162 unordered_set(initializer_list<value_type> init, size_type bucket_count,
163 const hasher& hf, const allocator_type& alloc)
164 : unordered_set{init, bucket_count, hf, key_equal{}, alloc}
165 { /* DUMMY BODY */ }
166
167 ~unordered_set()
168 { /* DUMMY BODY */ }
169
170 unordered_set& operator=(const unordered_set& other)
171 {
172 table_ = other.table_;
173 allocator_ = other.allocator_;
174
175 return *this;
176 }
177
178 unordered_set& operator=(unordered_set&& other)
179 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
180 is_nothrow_move_assignable<hasher>::value &&
181 is_nothrow_move_assignable<key_equal>::value)
182 {
183 table_ = move(other.table_);
184 allocator_ = move(other.allocator_);
185
186 return *this;
187 }
188
189 unordered_set& operator=(initializer_list<value_type>& init)
190 {
191 table_.clear();
192 table_.reserve(init.size());
193
194 insert(init.begin(), init.end());
195
196 return *this;
197 }
198
199 allocator_type get_allocator() const noexcept
200 {
201 return allocator_;
202 }
203
204 bool empty() const noexcept
205 {
206 return table_.empty();
207 }
208
209 size_type size() const noexcept
210 {
211 return table_.size();
212 }
213
214 size_type max_size() const noexcept
215 {
216 return table_.max_size(allocator_);
217 }
218
219 iterator begin() noexcept
220 {
221 return table_.begin();
222 }
223
224 const_iterator begin() const noexcept
225 {
226 return table_.begin();
227 }
228
229 iterator end() noexcept
230 {
231 return table_.end();
232 }
233
234 const_iterator end() const noexcept
235 {
236 return table_.end();
237 }
238
239 const_iterator cbegin() const noexcept
240 {
241 return table_.cbegin();
242 }
243
244 const_iterator cend() const noexcept
245 {
246 return table_.cend();
247 }
248
249 template<class... Args>
250 pair<iterator, bool> emplace(Args&&... args)
251 {
252 return table_.emplace(forward<Args>(args)...);
253 }
254
255 template<class... Args>
256 iterator emplace_hint(const_iterator, Args&&... args)
257 {
258 return emplace(forward<Args>(args)...).first;
259 }
260
261 pair<iterator, bool> insert(const value_type& val)
262 {
263 return table_.insert(val);
264 }
265
266 pair<iterator, bool> insert(value_type&& val)
267 {
268 return table_.insert(forward<value_type>(val));
269 }
270
271 iterator insert(const_iterator, const value_type& val)
272 {
273 return insert(val).first;
274 }
275
276 iterator insert(const_iterator, value_type&& val)
277 {
278 return insert(forward<value_type>(val)).first;
279 }
280
281 template<class InputIterator>
282 void insert(InputIterator first, InputIterator last)
283 {
284 while (first != last)
285 insert(*first++);
286 }
287
288 void insert(initializer_list<value_type> init)
289 {
290 insert(init.begin(), init.end());
291 }
292
293 iterator erase(const_iterator position)
294 {
295 return table_.erase(position);
296 }
297
298 size_type erase(const key_type& key)
299 {
300 return table_.erase(key);
301 }
302
303 iterator erase(const_iterator first, const_iterator last)
304 {
305 while (first != last)
306 first = erase(first);
307
308 return iterator{
309 table_.table(), first.idx(),
310 table_.bucket_count(), table_.head(first.idx())
311 }; // TODO: why do we pass table_.head(first.idx()) here?
312 }
313
314 void clear() noexcept
315 {
316 table_.clear();
317 }
318
319 void swap(unordered_set& other)
320 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
321 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
322 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
323 {
324 table_.swap(other.table_);
325 std::swap(allocator_, other.allocator_);
326 }
327
328 hasher hash_function() const
329 {
330 return table_.hash_function();
331 }
332
333 key_equal key_eq() const
334 {
335 return table_.key_eq();
336 }
337
338 iterator find(const key_type& key)
339 {
340 return table_.find(key);
341 }
342
343 const_iterator find(const key_type& key) const
344 {
345 return table_.find(key);
346 }
347
348 size_type count(const key_type& key) const
349 {
350 return table_.count(key);
351 }
352
353 pair<iterator, iterator> equal_range(const key_type& key)
354 {
355 return table_.equal_range(key);
356 }
357
358 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
359 {
360 return table_.equal_range(key);
361 }
362
363 size_type bucket_count() const noexcept
364 {
365 return table_.bucket_count();
366 }
367
368 size_type max_bucket_count() const noexcept
369 {
370 return table_.max_bucket_count();
371 }
372
373 size_type bucket_size(size_type idx) const
374 {
375 return table_.bucket_size(idx);
376 }
377
378 size_type bucket(const key_type& key) const
379 {
380 return table_.bucket(key);
381 }
382
383 local_iterator begin(size_type idx)
384 {
385 return table_.begin(idx);
386 }
387
388 const_local_iterator begin(size_type idx) const
389 {
390 return table_.begin(idx);
391 }
392
393 local_iterator end(size_type idx)
394 {
395 return table_.end(idx);
396 }
397
398 const_local_iterator end(size_type idx) const
399 {
400 return table_.end(idx);
401 }
402
403 const_local_iterator cbegin(size_type idx) const
404 {
405 return table_.cbegin(idx);
406 }
407
408 const_local_iterator cend(size_type idx) const
409 {
410 return table_.cend(idx);
411 }
412
413 float load_factor() const noexcept
414 {
415 return table_.load_factor();
416 }
417
418 float max_load_factor() const noexcept
419 {
420 return table_.max_load_factor();
421 }
422
423 void max_load_factor(float factor)
424 {
425 table_.max_load_factor(factor);
426 }
427
428 void rehash(size_type bucket_count)
429 {
430 table_.rehash(bucket_count);
431 }
432
433 void reserve(size_type count)
434 {
435 table_.reserve(count);
436 }
437
438 private:
439 using table_type = aux::hash_table<
440 key_type, key_type, aux::key_no_value_key_extractor<key_type>,
441 hasher, key_equal, allocator_type, size_type,
442 iterator, const_iterator, local_iterator, const_local_iterator,
443 aux::hash_single_policy
444 >;
445 using node_type = typename table_type::node_type;
446
447 table_type table_;
448 allocator_type allocator_;
449
450 static constexpr size_type default_bucket_count_{16};
451
452 template<class K, class H, class P, class A>
453 friend bool operator==(unordered_set<K, H, P, A>&,
454 unordered_set<K, H, P, A>&);
455 };
456
457 /**
458 * 23.5.7, class template unordered_multiset:
459 */
460
461 template<
462 class Key,
463 class Hash = hash<Key>,
464 class Pred = equal_to<Key>,
465 class Alloc = allocator<Key>
466 >
467 class unordered_multiset
468 {
469 public:
470 using key_type = Key;
471 using value_type = Key;
472 using hasher = Hash;
473 using key_equal = Pred;
474 using allocator_type = Alloc;
475 using pointer = typename allocator_traits<allocator_type>::pointer;
476 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
477 using reference = value_type&;
478 using const_reference = const value_type&;
479 using size_type = size_t;
480 using difference_type = ptrdiff_t;
481
482 /**
483 * Note: Both the iterator and const_iterator (and their local variants)
484 * types are constant iterators, the standard does not require them
485 * to be the same type, but why not? :)
486 */
487 using iterator = aux::hash_table_const_iterator<
488 value_type, const_reference, const_pointer, size_type
489 >;
490 using const_iterator = iterator;
491 using local_iterator = aux::hash_table_const_local_iterator<
492 value_type, const_reference, const_pointer
493 >;
494 using const_local_iterator = local_iterator;
495
496 /**
497 * Note: We need () to delegate the constructor,
498 * otherwise it could be deduced as the initializer
499 * list constructor when size_type is convertible
500 * to value_type.
501 */
502 unordered_multiset()
503 : unordered_multiset(default_bucket_count_)
504 { /* DUMMY BODY */ }
505
506 explicit unordered_multiset(size_type bucket_count,
507 const hasher& hf = hasher{},
508 const key_equal& eql = key_equal{},
509 const allocator_type& alloc = allocator_type{})
510 : table_{bucket_count, hf, eql}, allocator_{alloc}
511 { /* DUMMY BODY */ }
512
513 template<class InputIterator>
514 unordered_multiset(InputIterator first, InputIterator last,
515 size_type bucket_count = default_bucket_count_,
516 const hasher& hf = hasher{},
517 const key_equal& eql = key_equal{},
518 const allocator_type& alloc = allocator_type{})
519 : unordered_multiset{bucket_count, hf, eql, alloc}
520 {
521 insert(first, last);
522 }
523
524 unordered_multiset(const unordered_multiset& other)
525 : unordered_multiset{other, other.allocator_}
526 { /* DUMMY BODY */ }
527
528 unordered_multiset(unordered_multiset&& other)
529 : table_{move(other.table_)}, allocator_{move(other.allocator_)}
530 { /* DUMMY BODY */ }
531
532 explicit unordered_multiset(const allocator_type& alloc)
533 : table_{default_bucket_count_}, allocator_{alloc}
534 { /* DUMMY BODY */ }
535
536 unordered_multiset(const unordered_multiset& other, const allocator_type& alloc)
537 : table_{other.table_}, allocator_{alloc}
538 { /* DUMMY BODY */ }
539
540 unordered_multiset(unordered_multiset&& other, const allocator_type& alloc)
541 : table_{move(other.table_)}, allocator_{alloc}
542 { /* DUMMY BODY */ }
543
544 unordered_multiset(initializer_list<value_type> init,
545 size_type bucket_count = default_bucket_count_,
546 const hasher& hf = hasher{},
547 const key_equal& eql = key_equal{},
548 const allocator_type& alloc = allocator_type{})
549 : unordered_multiset{bucket_count, hf, eql, alloc}
550 {
551 insert(init.begin(), init.end());
552 }
553
554 unordered_multiset(size_type bucket_count, const allocator_type& alloc)
555 : unordered_multiset{bucket_count, hasher{}, key_equal{}, alloc}
556 { /* DUMMY BODY */ }
557
558 unordered_multiset(size_type bucket_count, const hasher& hf, const allocator_type& alloc)
559 : unordered_multiset{bucket_count, hf, key_equal{}, alloc}
560 { /* DUMMY BODY */ }
561
562 template<class InputIterator>
563 unordered_multiset(InputIterator first, InputIterator last,
564 size_type bucket_count, const allocator_type& alloc)
565 : unordered_multiset{first, last, bucket_count, hasher{}, key_equal{}, alloc}
566 { /* DUMMY BODY */ }
567
568 template<class InputIterator>
569 unordered_multiset(InputIterator first, InputIterator last,
570 size_type bucket_count, const hasher& hf, const allocator_type& alloc)
571 : unordered_multiset{first, last, bucket_count, hf, key_equal{}, alloc}
572 { /* DUMMY BODY */ }
573
574 unordered_multiset(initializer_list<value_type> init, size_type bucket_count,
575 const allocator_type& alloc)
576 : unordered_multiset{init, bucket_count, hasher{}, key_equal{}, alloc}
577 { /* DUMMY BODY */ }
578
579 unordered_multiset(initializer_list<value_type> init, size_type bucket_count,
580 const hasher& hf, const allocator_type& alloc)
581 : unordered_multiset{init, bucket_count, hf, key_equal{}, alloc}
582 { /* DUMMY BODY */ }
583
584 ~unordered_multiset()
585 { /* DUMMY BODY */ }
586
587 unordered_multiset& operator=(const unordered_multiset& other)
588 {
589 table_ = other.table_;
590 allocator_ = other.allocator_;
591
592 return *this;
593 }
594
595 unordered_multiset& operator=(unordered_multiset&& other)
596 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
597 is_nothrow_move_assignable<hasher>::value &&
598 is_nothrow_move_assignable<key_equal>::value)
599 {
600 table_ = move(other.table_);
601 allocator_ = move(other.allocator_);
602
603 return *this;
604 }
605
606 unordered_multiset& operator=(initializer_list<value_type>& init)
607 {
608 table_.clear();
609 table_.reserve(init.size());
610
611 insert(init.begin(), init.end());
612
613 return *this;
614 }
615
616 allocator_type get_allocator() const noexcept
617 {
618 return allocator_;
619 }
620
621 bool empty() const noexcept
622 {
623 return table_.empty();
624 }
625
626 size_type size() const noexcept
627 {
628 return table_.size();
629 }
630
631 size_type max_size() const noexcept
632 {
633 return table_.max_size(allocator_);
634 }
635
636 iterator begin() noexcept
637 {
638 return table_.begin();
639 }
640
641 const_iterator begin() const noexcept
642 {
643 return table_.begin();
644 }
645
646 iterator end() noexcept
647 {
648 return table_.end();
649 }
650
651 const_iterator end() const noexcept
652 {
653 return table_.end();
654 }
655
656 const_iterator cbegin() const noexcept
657 {
658 return table_.cbegin();
659 }
660
661 const_iterator cend() const noexcept
662 {
663 return table_.cend();
664 }
665
666 template<class... Args>
667 pair<iterator, bool> emplace(Args&&... args)
668 {
669 return table_.emplace(forward<Args>(args)...);
670 }
671
672 template<class... Args>
673 iterator emplace_hint(const_iterator, Args&&... args)
674 {
675 return emplace(forward<Args>(args)...).first;
676 }
677
678 pair<iterator, bool> insert(const value_type& val)
679 {
680 return table_.insert(val);
681 }
682
683 pair<iterator, bool> insert(value_type&& val)
684 {
685 return table_.insert(forward<value_type>(val));
686 }
687
688 iterator insert(const_iterator, const value_type& val)
689 {
690 return insert(val).first;
691 }
692
693 iterator insert(const_iterator, value_type&& val)
694 {
695 return insert(forward<value_type>(val)).first;
696 }
697
698 template<class InputIterator>
699 void insert(InputIterator first, InputIterator last)
700 {
701 while (first != last)
702 insert(*first++);
703 }
704
705 void insert(initializer_list<value_type> init)
706 {
707 insert(init.begin(), init.end());
708 }
709
710 iterator erase(const_iterator position)
711 {
712 return table_.erase(position);
713 }
714
715 size_type erase(const key_type& key)
716 {
717 return table_.erase(key);
718 }
719
720 iterator erase(const_iterator first, const_iterator last)
721 {
722 while (first != last)
723 first = erase(first);
724
725 return iterator{
726 table_.table(), first.idx(),
727 table_.bucket_count(), table_.head(first.idx())
728 };
729 }
730
731 void clear() noexcept
732 {
733 table_.clear();
734 }
735
736 void swap(unordered_multiset& other)
737 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
738 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
739 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
740 {
741 table_.swap(other.table_);
742 std::swap(allocator_, other.allocator_);
743 }
744
745 hasher hash_function() const
746 {
747 return table_.hash_function();
748 }
749
750 key_equal key_eq() const
751 {
752 return table_.key_eq();
753 }
754
755 iterator find(const key_type& key)
756 {
757 return table_.find(key);
758 }
759
760 const_iterator find(const key_type& key) const
761 {
762 return table_.find(key);
763 }
764
765 size_type count(const key_type& key) const
766 {
767 return table_.count(key);
768 }
769
770 pair<iterator, iterator> equal_range(const key_type& key)
771 {
772 return table_.equal_range(key);
773 }
774
775 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
776 {
777 return table_.equal_range(key);
778 }
779
780 size_type bucket_count() const noexcept
781 {
782 return table_.bucket_count();
783 }
784
785 size_type max_bucket_count() const noexcept
786 {
787 return table_.max_bucket_count();
788 }
789
790 size_type bucket_size(size_type idx) const
791 {
792 return table_.bucket_size(idx);
793 }
794
795 size_type bucket(const key_type& key) const
796 {
797 return table_.bucket(key);
798 }
799
800 local_iterator begin(size_type idx)
801 {
802 return table_.begin(idx);
803 }
804
805 const_local_iterator begin(size_type idx) const
806 {
807 return table_.begin(idx);
808 }
809
810 local_iterator end(size_type idx)
811 {
812 return table_.end(idx);
813 }
814
815 const_local_iterator end(size_type idx) const
816 {
817 return table_.end(idx);
818 }
819
820 const_local_iterator cbegin(size_type idx) const
821 {
822 return table_.cbegin(idx);
823 }
824
825 const_local_iterator cend(size_type idx) const
826 {
827 return table_.cend(idx);
828 }
829
830 float load_factor() const noexcept
831 {
832 return table_.load_factor();
833 }
834
835 float max_load_factor() const noexcept
836 {
837 return table_.max_load_factor();
838 }
839
840 void max_load_factor(float factor)
841 {
842 table_.max_load_factor(factor);
843 }
844
845 void rehash(size_type bucket_count)
846 {
847 table_.rehash(bucket_count);
848 }
849
850 void reserve(size_type count)
851 {
852 table_.reserve(count);
853 }
854
855 private:
856 using table_type = aux::hash_table<
857 key_type, key_type, aux::key_no_value_key_extractor<key_type>,
858 hasher, key_equal, allocator_type, size_type,
859 iterator, const_iterator, local_iterator, const_local_iterator,
860 aux::hash_multi_policy
861 >;
862 using node_type = typename table_type::node_type;
863
864 table_type table_;
865 allocator_type allocator_;
866
867 static constexpr size_type default_bucket_count_{16};
868
869 template<class K, class H, class P, class A>
870 friend bool operator==(unordered_multiset<K, H, P, A>&,
871 unordered_multiset<K, H, P, A>&);
872 };
873
874 template<class Key, class Hash, class Pred, class Alloc>
875 void swap(unordered_set<Key, Hash, Pred, Alloc>& lhs,
876 unordered_set<Key, Hash, Pred, Alloc>& rhs)
877 noexcept(noexcept(lhs.swap(rhs)))
878 {
879 lhs.swap(rhs);
880 }
881
882 template<class Key, class Hash, class Pred, class Alloc>
883 void swap(unordered_multiset<Key, Hash, Pred, Alloc>& lhs,
884 unordered_multiset<Key, Hash, Pred, Alloc>& rhs)
885 noexcept(noexcept(lhs.swap(rhs)))
886 {
887 lhs.swap(rhs);
888 }
889
890 template<class Key, class Hash, class Pred, class Alloc>
891 bool operator==(unordered_set<Key, Hash, Pred, Alloc>& lhs,
892 unordered_set<Key, Hash, Pred, Alloc>& rhs)
893 {
894 return lhs.table_.is_eq_to(rhs.table_);
895 }
896
897 template<class Key, class Hash, class Pred, class Alloc>
898 bool operator!=(unordered_set<Key, Hash, Pred, Alloc>& lhs,
899 unordered_set<Key, Hash, Pred, Alloc>& rhs)
900 {
901 return !(lhs == rhs);
902 }
903
904 template<class Key, class Hash, class Pred, class Alloc>
905 bool operator==(unordered_multiset<Key, Hash, Pred, Alloc>& lhs,
906 unordered_multiset<Key, Hash, Pred, Alloc>& rhs)
907 {
908 return lhs.table_.is_eq_to(rhs.table_);
909 }
910
911 template<class Key, class Value, class Hash, class Pred, class Alloc>
912 bool operator!=(unordered_multiset<Key, Hash, Pred, Alloc>& lhs,
913 unordered_multiset<Key, Hash, Pred, Alloc>& rhs)
914 {
915 return !(lhs == rhs);
916 }
917}
918
919#endif
Note: See TracBrowser for help on using the repository browser.