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

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

cpp: fixed bugs found by set tests and fixed the enable_ifs

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