source: mainline/uspace/lib/cpp/include/__bits/adt/set.hpp@ 34b2f54d

Last change on this file since 34b2f54d was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 28.4 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2018 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_ADT_SET
8#define LIBCPP_BITS_ADT_SET
9
10#include <__bits/adt/rbtree.hpp>
11#include <functional>
12#include <iterator>
13#include <memory>
14#include <utility>
15
16namespace std
17{
18 /**
19 * 23.4.6, class template set:
20 */
21
22 template<
23 class Key,
24 class Compare = less<Key>,
25 class Alloc = allocator<Key>
26 >
27 class set
28 {
29 public:
30 using key_type = Key;
31 using value_type = Key;
32 using key_compare = Compare;
33 using value_compare = Compare;
34 using allocator_type = Alloc;
35 using pointer = typename allocator_traits<allocator_type>::pointer;
36 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
37 using reference = value_type&;
38 using const_reference = const value_type&;
39 using size_type = size_t;
40 using difference_type = ptrdiff_t;
41
42 using node_type = aux::rbtree_single_node<value_type>;
43
44 /**
45 * Note: Both the iterator and const_iterator (and their local variants)
46 * types are constant iterators, the standard does not require them
47 * to be the same type, but why not? :)
48 */
49 using iterator = aux::rbtree_const_iterator<
50 value_type, const_reference, const_pointer, size_type, node_type
51 >;
52 using const_iterator = iterator;
53
54 using reverse_iterator = std::reverse_iterator<iterator>;
55 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
56
57 set()
58 : set{key_compare{}}
59 { /* DUMMY BODY */ }
60
61 explicit set(const key_compare& comp,
62 const allocator_type& alloc = allocator_type{})
63 : tree_{comp}, allocator_{alloc}
64 { /* DUMMY BODY */ }
65
66 template<class InputIterator>
67 set(InputIterator first, InputIterator last,
68 const key_compare& comp = key_compare{},
69 const allocator_type& alloc = allocator_type{})
70 : set{comp, alloc}
71 {
72 insert(first, last);
73 }
74
75 set(const set& other)
76 : set{other, other.allocator_}
77 { /* DUMMY BODY */ }
78
79 set(set&& other)
80 : tree_{move(other.tree_)}, allocator_{move(other.allocator_)}
81 { /* DUMMY BODY */ }
82
83 explicit set(const allocator_type& alloc)
84 : tree_{}, allocator_{alloc}
85 { /* DUMMY BODY */ }
86
87 set(const set& other, const allocator_type& alloc)
88 : tree_{other.tree_}, allocator_{alloc}
89 { /* DUMMY BODY */ }
90
91 set(set&& other, const allocator_type& alloc)
92 : tree_{move(other.tree_)}, allocator_{alloc}
93 { /* DUMMY BODY */ }
94
95 set(initializer_list<value_type> init,
96 const key_compare& comp = key_compare{},
97 const allocator_type& alloc = allocator_type{})
98 : set{comp, alloc}
99 {
100 insert(init.begin(), init.end());
101 }
102
103 template<class InputIterator>
104 set(InputIterator first, InputIterator last,
105 const allocator_type& alloc)
106 : set{first, last, key_compare{}, alloc}
107 { /* DUMMY BODY */ }
108
109 set(initializer_list<value_type> init,
110 const allocator_type& alloc)
111 : set{init, key_compare{}, alloc}
112 { /* DUMMY BODY */ }
113
114 ~set()
115 { /* DUMMY BODY */ }
116
117 set& operator=(const set& other)
118 {
119 tree_ = other.tree_;
120 allocator_ = other.allocator_;
121
122 return *this;
123 }
124
125 set& operator=(set&& other)
126 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
127 is_nothrow_move_assignable<key_compare>::value)
128 {
129 tree_ = move(other.tree_);
130 allocator_ = move(other.allocator_);
131
132 return *this;
133 }
134
135 set& operator=(initializer_list<value_type>& init)
136 {
137 tree_.clear();
138
139 insert(init.begin(), init.end());
140
141 return *this;
142 }
143
144 allocator_type get_allocator() const noexcept
145 {
146 return allocator_;
147 }
148
149 iterator begin() noexcept
150 {
151 return tree_.begin();
152 }
153
154 const_iterator begin() const noexcept
155 {
156 return tree_.begin();
157 }
158
159 iterator end() noexcept
160 {
161 return tree_.end();
162 }
163
164 const_iterator end() const noexcept
165 {
166 return tree_.end();
167 }
168
169 reverse_iterator rbegin() noexcept
170 {
171 return tree_.rbegin();
172 }
173
174 const_reverse_iterator rbegin() const noexcept
175 {
176 return tree_.rbegin();
177 }
178
179 reverse_iterator rend() noexcept
180 {
181 return tree_.rend();
182 }
183
184 const_reverse_iterator rend() const noexcept
185 {
186 return tree_.rend();
187 }
188
189 const_iterator cbegin() const noexcept
190 {
191 return tree_.cbegin();
192 }
193
194 const_iterator cend() const noexcept
195 {
196 return tree_.cend();
197 }
198
199 const_reverse_iterator crbegin() const noexcept
200 {
201 return tree_.crbegin();
202 }
203
204 const_reverse_iterator crend() const noexcept
205 {
206 return tree_.crend();
207 }
208
209 bool empty() const noexcept
210 {
211 return tree_.empty();
212 }
213
214 size_type size() const noexcept
215 {
216 return tree_.size();
217 }
218
219 size_type max_size() const noexcept
220 {
221 return tree_.max_size(allocator_);
222 }
223
224 template<class... Args>
225 pair<iterator, bool> emplace(Args&&... args)
226 {
227 return tree_.emplace(forward<Args>(args)...);
228 }
229
230 template<class... Args>
231 iterator emplace_hint(const_iterator, Args&&... args)
232 {
233 return emplace(forward<Args>(args)...).first;
234 }
235
236 pair<iterator, bool> insert(const value_type& val)
237 {
238 return tree_.insert(val);
239 }
240
241 pair<iterator, bool> insert(value_type&& val)
242 {
243 return tree_.insert(forward<value_type>(val));
244 }
245
246 iterator insert(const_iterator, const value_type& val)
247 {
248 return insert(val).first;
249 }
250
251 iterator insert(const_iterator, value_type&& val)
252 {
253 return insert(forward<value_type>(val)).first;
254 }
255
256 template<class InputIterator>
257 void insert(InputIterator first, InputIterator last)
258 {
259 while (first != last)
260 insert(*first++);
261 }
262
263 void insert(initializer_list<value_type> init)
264 {
265 insert(init.begin(), init.end());
266 }
267
268 iterator erase(const_iterator position)
269 {
270 return tree_.erase(position);
271 }
272
273 size_type erase(const key_type& key)
274 {
275 return tree_.erase(key);
276 }
277
278 iterator erase(const_iterator first, const_iterator last)
279 {
280 while (first != last)
281 first = erase(first);
282
283 return iterator{
284 first.node(), first.end()
285 };
286 }
287
288 void swap(set& other)
289 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
290 noexcept(std::swap(declval<key_compare>(), declval<key_compare>())))
291 {
292 tree_.swap(other.tree_);
293 std::swap(allocator_, other.allocator_);
294 }
295
296 void clear() noexcept
297 {
298 tree_.clear();
299 }
300
301 key_compare key_comp() const
302 {
303 return tree_.key_comp();
304 }
305
306 value_compare value_comp() const
307 {
308 return tree_.value_comp();
309 }
310
311 iterator find(const key_type& key)
312 {
313 return tree_.find(key);
314 }
315
316 const_iterator find(const key_type& key) const
317 {
318 return tree_.find(key);
319 }
320
321 template<class K>
322 iterator find(
323 const K& key,
324 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
325 )
326 {
327 return tree_.find(key);
328 }
329
330 template<class K>
331 const_iterator find(
332 const K& key,
333 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
334 ) const
335 {
336 return tree_.find(key);
337 }
338
339 size_type count(const key_type& key) const
340 {
341 return tree_.count(key);
342 }
343
344 template<class K>
345 size_type count(
346 const K& key,
347 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
348 ) const
349 {
350 return tree_.count(key);
351 }
352
353 iterator lower_bound(const key_type& key)
354 {
355 return tree_.lower_bound(key);
356 }
357
358 const_iterator lower_bound(const key_type& key) const
359 {
360 return tree_.lower_bound(key);
361 }
362
363 template<class K>
364 iterator lower_bound(
365 const K& key,
366 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
367 )
368 {
369 return tree_.lower_bound(key);
370 }
371
372 template<class K>
373 const_iterator lower_bound(
374 const K& key,
375 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
376 ) const
377 {
378 return tree_.lower_bound(key);
379 }
380
381 iterator upper_bound(const key_type& key)
382 {
383 return tree_.upper_bound(key);
384 }
385
386 const_iterator upper_bound(const key_type& key) const
387 {
388 return tree_.upper_bound(key);
389 }
390
391 template<class K>
392 iterator upper_bound(
393 const K& key,
394 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
395 )
396 {
397 return tree_.upper_bound(key);
398 }
399
400 template<class K>
401 const_iterator upper_bound(
402 const K& key,
403 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
404 ) const
405 {
406 return tree_.upper_bound(key);
407 }
408
409 pair<iterator, iterator> equal_range(const key_type& key)
410 {
411 return tree_.equal_range(key);
412 }
413
414 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
415 {
416 return tree_.equal_range(key);
417 }
418
419 template<class K>
420 pair<iterator, iterator> equal_range(
421 const K& key,
422 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
423 )
424 {
425 return tree_.equal_range(key);
426 }
427
428 template<class K>
429 pair<const_iterator, const_iterator> equal_range(
430 const K& key,
431 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
432 ) const
433 {
434 return tree_.equal_range(key);
435 }
436
437 private:
438 using tree_type = aux::rbtree<
439 key_type, key_type, aux::key_no_value_key_extractor<key_type>,
440 key_compare, allocator_type, size_type,
441 iterator, const_iterator,
442 aux::rbtree_single_policy, node_type
443 >;
444
445 tree_type tree_;
446 allocator_type allocator_;
447
448 template<class K, class C, class A>
449 friend bool operator==(const set<K, C, A>&,
450 const set<K, C, A>&);
451 };
452
453 template<class Key, class Compare, class Allocator>
454 bool operator==(const set<Key, Compare, Allocator>& lhs,
455 const set<Key, Compare, Allocator>& rhs)
456 {
457 return lhs.tree_.is_eq_to(rhs.tree_);
458 }
459
460 template<class Key, class Compare, class Allocator>
461 bool operator<(const set<Key, Compare, Allocator>& lhs,
462 const set<Key, Compare, Allocator>& rhs)
463 {
464 return lexicographical_compare(
465 lhs.begin(), lhs.end(),
466 rhs.begin(), rhs.end(),
467 lhs.key_comp()
468 );
469 }
470
471 template<class Key, class Compare, class Allocator>
472 bool operator!=(const set<Key, Compare, Allocator>& lhs,
473 const set<Key, Compare, Allocator>& rhs)
474 {
475 return !(lhs == rhs);
476 }
477
478 template<class Key, class Compare, class Allocator>
479 bool operator>(const set<Key, Compare, Allocator>& lhs,
480 const set<Key, Compare, Allocator>& rhs)
481 {
482 return rhs < lhs;
483 }
484
485 template<class Key, class Compare, class Allocator>
486 bool operator>=(const set<Key, Compare, Allocator>& lhs,
487 const set<Key, Compare, Allocator>& rhs)
488 {
489 return !(lhs < rhs);
490 }
491
492 template<class Key, class Compare, class Allocator>
493 bool operator<=(const set<Key, Compare, Allocator>& lhs,
494 const set<Key, Compare, Allocator>& rhs)
495 {
496 return !(rhs < lhs);
497 }
498
499 /**
500 * 23.4.7, class template multiset:
501 */
502
503 template<
504 class Key,
505 class Compare = less<Key>,
506 class Alloc = allocator<Key>
507 >
508 class multiset
509 {
510 public:
511 using key_type = Key;
512 using value_type = Key;
513 using key_compare = Compare;
514 using value_compare = Compare;
515 using allocator_type = Alloc;
516 using pointer = typename allocator_traits<allocator_type>::pointer;
517 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
518 using reference = value_type&;
519 using const_reference = const value_type&;
520 using size_type = size_t;
521 using difference_type = ptrdiff_t;
522
523 using node_type = aux::rbtree_multi_node<value_type>;
524
525 /**
526 * Note: Both the iterator and const_iterator types are constant
527 * iterators, the standard does not require them
528 * to be the same type, but why not? :)
529 */
530 using iterator = aux::rbtree_const_iterator<
531 value_type, const_reference, const_pointer, size_type, node_type
532 >;
533 using const_iterator = iterator;
534
535 using reverse_iterator = std::reverse_iterator<iterator>;
536 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
537
538 multiset()
539 : multiset{key_compare{}}
540 { /* DUMMY BODY */ }
541
542 explicit multiset(const key_compare& comp,
543 const allocator_type& alloc = allocator_type{})
544 : tree_{comp}, allocator_{alloc}
545 { /* DUMMY BODY */ }
546
547 template<class InputIterator>
548 multiset(InputIterator first, InputIterator last,
549 const key_compare& comp = key_compare{},
550 const allocator_type& alloc = allocator_type{})
551 : multiset{comp, alloc}
552 {
553 insert(first, last);
554 }
555
556 multiset(const multiset& other)
557 : multiset{other, other.allocator_}
558 { /* DUMMY BODY */ }
559
560 multiset(multiset&& other)
561 : tree_{move(other.tree_)}, allocator_{move(other.allocator_)}
562 { /* DUMMY BODY */ }
563
564 explicit multiset(const allocator_type& alloc)
565 : tree_{}, allocator_{alloc}
566 { /* DUMMY BODY */ }
567
568 multiset(const multiset& other, const allocator_type& alloc)
569 : tree_{other.tree_}, allocator_{alloc}
570 { /* DUMMY BODY */ }
571
572 multiset(multiset&& other, const allocator_type& alloc)
573 : tree_{move(other.tree_)}, allocator_{alloc}
574 { /* DUMMY BODY */ }
575
576 multiset(initializer_list<value_type> init,
577 const key_compare& comp = key_compare{},
578 const allocator_type& alloc = allocator_type{})
579 : multiset{comp, alloc}
580 {
581 insert(init.begin(), init.end());
582 }
583
584 template<class InputIterator>
585 multiset(InputIterator first, InputIterator last,
586 const allocator_type& alloc)
587 : multiset{first, last, key_compare{}, alloc}
588 { /* DUMMY BODY */ }
589
590 multiset(initializer_list<value_type> init,
591 const allocator_type& alloc)
592 : multiset{init, key_compare{}, alloc}
593 { /* DUMMY BODY */ }
594
595 ~multiset()
596 { /* DUMMY BODY */ }
597
598 multiset& operator=(const multiset& other)
599 {
600 tree_ = other.tree_;
601 allocator_ = other.allocator_;
602
603 return *this;
604 }
605
606 multiset& operator=(multiset&& other)
607 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
608 is_nothrow_move_assignable<key_compare>::value)
609 {
610 tree_ = move(other.tree_);
611 allocator_ = move(other.allocator_);
612
613 return *this;
614 }
615
616 multiset& operator=(initializer_list<value_type>& init)
617 {
618 tree_.clear();
619
620 insert(init.begin(), init.end());
621
622 return *this;
623 }
624
625 allocator_type get_allocator() const noexcept
626 {
627 return allocator_;
628 }
629
630 iterator begin() noexcept
631 {
632 return tree_.begin();
633 }
634
635 const_iterator begin() const noexcept
636 {
637 return tree_.begin();
638 }
639
640 iterator end() noexcept
641 {
642 return tree_.end();
643 }
644
645 const_iterator end() const noexcept
646 {
647 return tree_.end();
648 }
649
650 reverse_iterator rbegin() noexcept
651 {
652 return tree_.rbegin();
653 }
654
655 const_reverse_iterator rbegin() const noexcept
656 {
657 return tree_.rbegin();
658 }
659
660 reverse_iterator rend() noexcept
661 {
662 return tree_.rend();
663 }
664
665 const_reverse_iterator rend() const noexcept
666 {
667 return tree_.rend();
668 }
669
670 const_iterator cbegin() const noexcept
671 {
672 return tree_.cbegin();
673 }
674
675 const_iterator cend() const noexcept
676 {
677 return tree_.cend();
678 }
679
680 const_reverse_iterator crbegin() const noexcept
681 {
682 return tree_.crbegin();
683 }
684
685 const_reverse_iterator crend() const noexcept
686 {
687 return tree_.crend();
688 }
689
690 bool empty() const noexcept
691 {
692 return tree_.empty();
693 }
694
695 size_type size() const noexcept
696 {
697 return tree_.size();
698 }
699
700 size_type max_size() const noexcept
701 {
702 return tree_.max_size(allocator_);
703 }
704
705 template<class... Args>
706 iterator emplace(Args&&... args)
707 {
708 return tree_.emplace(forward<Args>(args)...);
709 }
710
711 template<class... Args>
712 iterator emplace_hint(const_iterator, Args&&... args)
713 {
714 return emplace(forward<Args>(args)...);
715 }
716
717 iterator insert(const value_type& val)
718 {
719 return tree_.insert(val);
720 }
721
722 iterator insert(value_type&& val)
723 {
724 return tree_.insert(forward<value_type>(val));
725 }
726
727 iterator insert(const_iterator, const value_type& val)
728 {
729 return insert(val);
730 }
731
732 iterator insert(const_iterator, value_type&& val)
733 {
734 return insert(forward<value_type>(val));
735 }
736
737 template<class InputIterator>
738 void insert(InputIterator first, InputIterator last)
739 {
740 while (first != last)
741 insert(*first++);
742 }
743
744 void insert(initializer_list<value_type> init)
745 {
746 insert(init.begin(), init.end());
747 }
748
749 iterator erase(const_iterator position)
750 {
751 return tree_.erase(position);
752 }
753
754 size_type erase(const key_type& key)
755 {
756 return tree_.erase(key);
757 }
758
759 iterator erase(const_iterator first, const_iterator last)
760 {
761 while (first != last)
762 first = erase(first);
763
764 return iterator{
765 first.node(), first.end()
766 };
767 }
768
769 void swap(multiset& other)
770 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
771 noexcept(std::swap(declval<key_compare>(), declval<key_compare>())))
772 {
773 tree_.swap(other.tree_);
774 std::swap(allocator_, other.allocator_);
775 }
776
777 void clear() noexcept
778 {
779 tree_.clear();
780 }
781
782 key_compare key_comp() const
783 {
784 return tree_.key_comp();
785 }
786
787 value_compare value_comp() const
788 {
789 return tree_.value_comp();
790 }
791
792 iterator find(const key_type& key)
793 {
794 return tree_.find(key);
795 }
796
797 const_iterator find(const key_type& key) const
798 {
799 return tree_.find(key);
800 }
801
802 template<class K>
803 iterator find(
804 const K& key,
805 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
806 )
807 {
808 return tree_.find(key);
809 }
810
811 template<class K>
812 const_iterator find(
813 const K& key,
814 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
815 ) const
816 {
817 return tree_.find(key);
818 }
819
820 size_type count(const key_type& key) const
821 {
822 return tree_.count(key);
823 }
824
825 template<class K>
826 size_type count(
827 const K& key,
828 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
829 ) const
830 {
831 return tree_.count(key);
832 }
833
834 iterator lower_bound(const key_type& key)
835 {
836 return tree_.lower_bound(key);
837 }
838
839 const_iterator lower_bound(const key_type& key) const
840 {
841 return tree_.lower_bound(key);
842 }
843
844 template<class K>
845 iterator lower_bound(
846 const K& key,
847 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
848 )
849 {
850 return tree_.lower_bound(key);
851 }
852
853 template<class K>
854 const_iterator lower_bound(
855 const K& key,
856 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
857 ) const
858 {
859 return tree_.lower_bound(key);
860 }
861
862 iterator upper_bound(const key_type& key)
863 {
864 return tree_.upper_bound(key);
865 }
866
867 const_iterator upper_bound(const key_type& key) const
868 {
869 return tree_.upper_bound(key);
870 }
871
872 template<class K>
873 iterator upper_bound(
874 const K& key,
875 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
876 )
877 {
878 return tree_.upper_bound(key);
879 }
880
881 template<class K>
882 const_iterator upper_bound(
883 const K& key,
884 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
885 ) const
886 {
887 return tree_.upper_bound(key);
888 }
889
890 pair<iterator, iterator> equal_range(const key_type& key)
891 {
892 return tree_.equal_range(key);
893 }
894
895 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
896 {
897 return tree_.equal_range(key);
898 }
899
900 template<class K>
901 pair<iterator, iterator> equal_range(
902 const K& key,
903 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
904 )
905 {
906 return tree_.equal_range(key);
907 }
908
909 template<class K>
910 pair<const_iterator, const_iterator> equal_range(
911 const K& key,
912 enable_if_t<aux::is_transparent_v<key_compare>, K>* = nullptr
913 ) const
914 {
915 return tree_.equal_range(key);
916 }
917
918 private:
919 using tree_type = aux::rbtree<
920 key_type, key_type, aux::key_no_value_key_extractor<key_type>,
921 key_compare, allocator_type, size_type,
922 iterator, const_iterator,
923 aux::rbtree_multi_policy, node_type
924 >;
925
926 tree_type tree_;
927 allocator_type allocator_;
928
929 template<class K, class C, class A>
930 friend bool operator==(const multiset<K, C, A>&,
931 const multiset<K, C, A>&);
932 };
933
934 template<class Key, class Compare, class Allocator>
935 bool operator==(const multiset<Key, Compare, Allocator>& lhs,
936 const multiset<Key, Compare, Allocator>& rhs)
937 {
938 return lhs.tree_.is_eq_to(rhs.tree_);
939 }
940
941 template<class Key, class Compare, class Allocator>
942 bool operator<(const multiset<Key, Compare, Allocator>& lhs,
943 const multiset<Key, Compare, Allocator>& rhs)
944 {
945 return lexicographical_compare(
946 lhs.begin(), lhs.end(),
947 rhs.begin(), rhs.end(),
948 lhs.value_comp()
949 );
950 }
951
952 template<class Key, class Compare, class Allocator>
953 bool operator!=(const multiset<Key, Compare, Allocator>& lhs,
954 const multiset<Key, Compare, Allocator>& rhs)
955 {
956 return !(lhs == rhs);
957 }
958
959 template<class Key, class Compare, class Allocator>
960 bool operator>(const multiset<Key, Compare, Allocator>& lhs,
961 const multiset<Key, Compare, Allocator>& rhs)
962 {
963 return rhs < lhs;
964 }
965
966 template<class Key, class Compare, class Allocator>
967 bool operator>=(const multiset<Key, Compare, Allocator>& lhs,
968 const multiset<Key, Compare, Allocator>& rhs)
969 {
970 return !(lhs < rhs);
971 }
972
973 template<class Key, class Compare, class Allocator>
974 bool operator<=(const multiset<Key, Compare, Allocator>& lhs,
975 const multiset<Key, Compare, Allocator>& rhs)
976 {
977 return !(rhs < lhs);
978 }
979}
980
981#endif
Note: See TracBrowser for help on using the repository browser.