source: mainline/uspace/lib/cpp/include/impl/set.hpp@ 6b81ca5

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

cpp: added comparison operators for set and map

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