source: mainline/uspace/lib/cpp/include/impl/set.hpp@ 784c8b6

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

cpp: added multiset

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