source: mainline/uspace/lib/cpp/include/impl/map.hpp@ 48f09f2f

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