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

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

cpp: added map::operator[]

  • Property mode set to 100644
File size: 32.4 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_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 mapped_type& operator[](const key_type& key)
273 {
274 auto parent = tree_.find_parent_for_insertion(key);
275 if (parent && tree_.keys_equal(tree_.get_key(parent->value), key))
276 return parent->value.second;
277
278 auto node = new node_type{value_type{key, mapped_type{}}};
279 tree_.insert_node(node, parent);
280
281 return node->value.second;
282 }
283
284 mapped_type& operator[](key_type&& key)
285 {
286 auto parent = tree_.find_parent_for_insertion(key);
287 if (parent && tree_.keys_equal(tree_.get_key(parent->value), key))
288 return parent->value.second;
289
290 auto node = new node_type{value_type{move(key), mapped_type{}}};
291 tree_.insert_node(node, parent);
292
293 return node->value.second;
294 }
295
296 /**
297 * 23.4.4.4, modifiers:
298 */
299
300 template<class... Args>
301 pair<iterator, bool> emplace(Args&&... args)
302 {
303 return tree_.emplace(forward<Args>(args)...);
304 }
305
306 template<class... Args>
307 iterator emplace_hint(const_iterator, Args&&... args)
308 {
309 return emplace(forward<Args>(args)...).first;
310 }
311
312 pair<iterator, bool> insert(const value_type& val)
313 {
314 return tree_.insert(val);
315 }
316
317 pair<iterator, bool> insert(value_type&& val)
318 {
319 return tree_.insert(forward<value_type>(val));
320 }
321
322 template<class T>
323 pair<iterator, bool> insert(
324 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val)
325 {
326 return emplace(forward<T>(val));
327 }
328
329 iterator insert(const_iterator, const value_type& val)
330 {
331 return insert(val).first;
332 }
333
334 iterator insert(const_iterator, value_type&& val)
335 {
336 return insert(forward<value_type>(val)).first;
337 }
338
339 template<class T>
340 iterator insert(
341 const_iterator hint,
342 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val
343 )
344 {
345 return emplace_hint(hint, forward<T>(val));
346 }
347
348 template<class InputIterator>
349 void insert(InputIterator first, InputIterator last)
350 {
351 while (first != last)
352 insert(*first++);
353 }
354
355 void insert(initializer_list<value_type> init)
356 {
357 insert(init.begin(), init.end());
358 }
359
360 // TODO: try_emplace, insert_or_assign
361
362 iterator erase(const_iterator position)
363 {
364 return tree_.erase(position);
365 }
366
367 size_type erase(const key_type& key)
368 {
369 return tree_.erase(key);
370 }
371
372 iterator erase(const_iterator first, const_iterator last)
373 {
374 while (first != last)
375 first = erase(first);
376
377 return iterator{
378 first.node(), first.end()
379 };
380 }
381
382 void swap(map& other)
383 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
384 noexcept(std::swap(declval<key_compare>(), declval<key_compare>())))
385 {
386 tree_.swap(other.tree_);
387 std::swap(allocator_, other.allocator_);
388 }
389
390 void clear() noexcept
391 {
392 tree_.clear();
393 }
394
395 key_compare key_comp() const
396 {
397 return tree_.key_comp();
398 }
399
400 value_compare value_comp() const
401 {
402 return value_compare{tree_.key_comp()};
403 }
404
405 iterator find(const key_type& key)
406 {
407 return tree_.find(key);
408 }
409
410 const_iterator find(const key_type& key) const
411 {
412 return tree_.find(key);
413 }
414
415 template<class K>
416 iterator find(
417 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
418 )
419 {
420 return tree_.find(key);
421 }
422
423 template<class K>
424 const_iterator find(
425 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
426 ) const
427 {
428 return tree_.find(key);
429 }
430
431 size_type count(const key_type& key) const
432 {
433 return tree_.count(key);
434 }
435
436 template<class K>
437 size_type count(
438 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
439 ) const
440 {
441 return tree_.count(key);
442 }
443
444 iterator lower_bound(const key_type& key)
445 {
446 return tree_.lower_bound(key);
447 }
448
449 const_iterator lower_bound(const key_type& key) const
450 {
451 return tree_.lower_bound(key);
452 }
453
454 template<class K>
455 iterator lower_bound(
456 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
457 )
458 {
459 return tree_.lower_bound(key);
460 }
461
462 template<class K>
463 const_iterator lower_bound(
464 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
465 ) const
466 {
467 return tree_.lower_bound(key);
468 }
469
470 iterator upper_bound(const key_type& key)
471 {
472 return tree_.upper_bound(key);
473 }
474
475 const_iterator upper_bound(const key_type& key) const
476 {
477 return tree_.upper_bound(key);
478 }
479
480 template<class K>
481 iterator upper_bound(
482 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
483 )
484 {
485 return tree_.upper_bound(key);
486 }
487
488 template<class K>
489 const_iterator upper_bound(
490 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
491 ) const
492 {
493 return tree_.upper_bound(key);
494 }
495
496 pair<iterator, iterator> equal_range(const key_type& key)
497 {
498 return tree_.equal_range(key);
499 }
500
501 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
502 {
503 return tree_.equal_range(key);
504 }
505
506 template<class K>
507 pair<iterator, iterator> equal_range(
508 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
509 )
510 {
511 return tree_.equal_range(key);
512 }
513
514 template<class K>
515 pair<const_iterator, const_iterator> equal_range(
516 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
517 ) const
518 {
519 return tree_.equal_range(key);
520 }
521
522 private:
523 using tree_type = aux::rbtree<
524 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
525 key_compare, allocator_type, size_type,
526 iterator, const_iterator,
527 aux::rbtree_single_policy
528 >;
529
530 using node_type = typename tree_type::node_type;
531
532 tree_type tree_;
533 allocator_type allocator_;
534
535 template<class K, class C, class A>
536 friend bool operator==(const map<K, C, A>&,
537 const map<K, C, A>&);
538 };
539
540 template<class Key, class Compare, class Allocator>
541 bool operator==(const map<Key, Compare, Allocator>& lhs,
542 const map<Key, Compare, Allocator>& rhs)
543 {
544 return lhs.tree_.is_eq_to(rhs.tree_);
545 }
546
547 template<class Key, class Compare, class Allocator>
548 bool operator<(const map<Key, Compare, Allocator>& lhs,
549 const map<Key, Compare, Allocator>& rhs)
550 {
551 return lexicographical_compare(
552 lhs.begin(), lhs.end(),
553 rhs.begin(), rhs.end(),
554 lhs.value_comp()
555 );
556 }
557
558 template<class Key, class Compare, class Allocator>
559 bool operator!=(const map<Key, Compare, Allocator>& lhs,
560 const map<Key, Compare, Allocator>& rhs)
561 {
562 return !(lhs == rhs);
563 }
564
565 template<class Key, class Compare, class Allocator>
566 bool operator>(const map<Key, Compare, Allocator>& lhs,
567 const map<Key, Compare, Allocator>& rhs)
568 {
569 return rhs < lhs;
570 }
571
572 template<class Key, class Compare, class Allocator>
573 bool operator>=(const map<Key, Compare, Allocator>& lhs,
574 const map<Key, Compare, Allocator>& rhs)
575 {
576 return !(lhs < rhs);
577 }
578
579 template<class Key, class Compare, class Allocator>
580 bool operator<=(const map<Key, Compare, Allocator>& lhs,
581 const map<Key, Compare, Allocator>& rhs)
582 {
583 return !(rhs < lhs);
584 }
585
586 /**
587 * 23.4.5, class template multimap:
588 */
589
590 template<
591 class Key, class Value,
592 class Compare = less<Key>,
593 class Alloc = allocator<pair<const Key, Value>>
594 >
595 class multimap
596 {
597 public:
598 using key_type = Key;
599 using mapped_type = Value;
600 using value_type = pair<const key_type, mapped_type>;
601 using key_compare = Compare;
602 using allocator_type = Alloc;
603 using pointer = typename allocator_traits<allocator_type>::pointer;
604 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
605 using reference = value_type&;
606 using const_reference = const value_type&;
607 using size_type = size_t;
608 using difference_type = ptrdiff_t;
609
610 class value_compare
611 {
612 friend class multimap;
613
614 protected:
615 key_compare comp;
616
617 value_compare(key_compare c)
618 : comp{c}
619 { /* DUMMY BODY */ }
620
621 public:
622 using result_type = bool;
623 using first_argument_type = value_type;
624 using second_argument_type = value_type;
625
626 bool operator()(const value_type& lhs, const value_type& rhs) const
627 {
628 return comp(lhs.first, rhs.first);
629 }
630 };
631
632 using iterator = aux::rbtree_iterator<
633 value_type, reference, pointer, size_type
634 >;
635 using const_iterator = aux::rbtree_const_iterator<
636 value_type, const_reference, const_pointer, size_type
637 >;
638
639 using reverse_iterator = std::reverse_iterator<iterator>;
640 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
641
642 multimap()
643 : multimap{key_compare{}}
644 { /* DUMMY BODY */ }
645
646 explicit multimap(const key_compare& comp,
647 const allocator_type& alloc = allocator_type{})
648 : tree_{comp}, allocator_{alloc}
649 { /* DUMMY BODY */ }
650
651 template<class InputIterator>
652 multimap(InputIterator first, InputIterator last,
653 const key_compare& comp = key_compare{},
654 const allocator_type& alloc = allocator_type{})
655 : multimap{comp, alloc}
656 {
657 insert(first, last);
658 }
659
660 multimap(const multimap& other)
661 : multimap{other, other.allocator_}
662 { /* DUMMY BODY */ }
663
664 multimap(multimap&& other)
665 : tree_{move(other.tree_)}, allocator_{move(other.allocator_)}
666 { /* DUMMY BODY */ }
667
668 explicit multimap(const allocator_type& alloc)
669 : tree_{}, allocator_{alloc}
670 { /* DUMMY BODY */ }
671
672 multimap(const multimap& other, const allocator_type& alloc)
673 : tree_{other.tree_}, allocator_{alloc}
674 { /* DUMMY BODY */ }
675
676 multimap(multimap&& other, const allocator_type& alloc)
677 : tree_{move(other.tree_)}, allocator_{alloc}
678 { /* DUMMY BODY */ }
679
680 multimap(initializer_list<value_type> init,
681 const key_compare& comp = key_compare{},
682 const allocator_type& alloc = allocator_type{})
683 : multimap{comp, alloc}
684 {
685 insert(init.begin(), init.end());
686 }
687
688 template<class InputIterator>
689 multimap(InputIterator first, InputIterator last,
690 const allocator_type& alloc)
691 : multimap{first, last, key_compare{}, alloc}
692 { /* DUMMY BODY */ }
693
694 multimap(initializer_list<value_type> init,
695 const allocator_type& alloc)
696 : multimap{init, key_compare{}, alloc}
697 { /* DUMMY BODY */ }
698
699 ~multimap()
700 { /* DUMMY BODY */ }
701
702 multimap& operator=(const multimap& other)
703 {
704 tree_ = other.tree_;
705 allocator_ = other.allocator_;
706
707 return *this;
708 }
709
710 multimap& operator=(multimap&& other)
711 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
712 is_nothrow_move_assignable<key_compare>::value)
713 {
714 tree_ = move(other.tree_);
715 allocator_ = move(other.allocator_);
716
717 return *this;
718 }
719
720 multimap& operator=(initializer_list<value_type>& init)
721 {
722 tree_.clear();
723
724 insert(init.begin(), init.end());
725
726 return *this;
727 }
728
729 allocator_type get_allocator() const noexcept
730 {
731 return allocator_;
732 }
733
734 iterator begin() noexcept
735 {
736 return tree_.begin();
737 }
738
739 const_iterator begin() const noexcept
740 {
741 return tree_.begin();
742 }
743
744 iterator end() noexcept
745 {
746 return tree_.end();
747 }
748
749 const_iterator end() const noexcept
750 {
751 return tree_.end();
752 }
753
754 reverse_iterator rbegin() noexcept
755 {
756 return tree_.rbegin();
757 }
758
759 const_reverse_iterator rbegin() const noexcept
760 {
761 return tree_.rbegin();
762 }
763
764 reverse_iterator rend() noexcept
765 {
766 return tree_.rend();
767 }
768
769 const_reverse_iterator rend() const noexcept
770 {
771 return tree_.rend();
772 }
773
774 const_iterator cbegin() const noexcept
775 {
776 return tree_.cbegin();
777 }
778
779 const_iterator cend() const noexcept
780 {
781 return tree_.cend();
782 }
783
784 const_reverse_iterator crbegin() const noexcept
785 {
786 return tree_.crbegin();
787 }
788
789 const_reverse_iterator crend() const noexcept
790 {
791 return tree_.crend();
792 }
793
794 bool empty() const noexcept
795 {
796 return tree_.empty();
797 }
798
799 size_type size() const noexcept
800 {
801 return tree_.size();
802 }
803
804 size_type max_size() const noexcept
805 {
806 return tree_.max_size(allocator_);
807 }
808
809 template<class... Args>
810 iterator emplace(Args&&... args)
811 {
812 return tree_.emplace(forward<Args>(args)...);
813 }
814
815 template<class... Args>
816 iterator emplace_hint(const_iterator, Args&&... args)
817 {
818 return emplace(forward<Args>(args)...);
819 }
820
821 iterator insert(const value_type& val)
822 {
823 return tree_.insert(val);
824 }
825
826 iterator insert(value_type&& val)
827 {
828 return tree_.insert(forward<value_type>(val));
829 }
830
831 template<class T>
832 iterator insert(
833 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val
834 )
835 {
836 return emplace(forward<T>(val));
837 }
838
839 iterator insert(const_iterator, const value_type& val)
840 {
841 return insert(val);
842 }
843
844 iterator insert(const_iterator, value_type&& val)
845 {
846 return insert(forward<value_type>(val));
847 }
848
849 template<class T>
850 iterator insert(
851 const_iterator hint,
852 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val
853 )
854 {
855 return emplace_hint(hint, forward<T>(val));
856 }
857
858 template<class InputIterator>
859 void insert(InputIterator first, InputIterator last)
860 {
861 while (first != last)
862 insert(*first++);
863 }
864
865 void insert(initializer_list<value_type> init)
866 {
867 insert(init.begin(), init.end());
868 }
869
870 iterator erase(const_iterator position)
871 {
872 return tree_.erase(position);
873 }
874
875 size_type erase(const key_type& key)
876 {
877 return tree_.erase(key);
878 }
879
880 iterator erase(const_iterator first, const_iterator last)
881 {
882 while (first != last)
883 first = erase(first);
884
885 return iterator{
886 first.node(), first.end()
887 };
888 }
889
890 void swap(multimap& other)
891 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
892 noexcept(std::swap(declval<key_compare>(), declval<key_compare>())))
893 {
894 tree_.swap(other.tree_);
895 std::swap(allocator_, other.allocator_);
896 }
897
898 void clear() noexcept
899 {
900 tree_.clear();
901 }
902
903 key_compare key_comp() const
904 {
905 return tree_.key_comp();
906 }
907
908 value_compare value_comp() const
909 {
910 return value_compare{tree_.key_comp()};
911 }
912
913 iterator find(const key_type& key)
914 {
915 return tree_.find(key);
916 }
917
918 const_iterator find(const key_type& key) const
919 {
920 return tree_.find(key);
921 }
922
923 template<class K>
924 iterator find(
925 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
926 )
927 {
928 return tree_.find(key);
929 }
930
931 template<class K>
932 const_iterator find(
933 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
934 ) const
935 {
936 return tree_.find(key);
937 }
938
939 size_type count(const key_type& key) const
940 {
941 return tree_.count(key);
942 }
943
944 template<class K>
945 size_type count(
946 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
947 ) const
948 {
949 return tree_.count(key);
950 }
951
952 iterator lower_bound(const key_type& key)
953 {
954 return tree_.lower_bound(key);
955 }
956
957 const_iterator lower_bound(const key_type& key) const
958 {
959 return tree_.lower_bound(key);
960 }
961
962 template<class K>
963 iterator lower_bound(
964 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
965 )
966 {
967 return tree_.lower_bound(key);
968 }
969
970 template<class K>
971 const_iterator lower_bound(
972 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
973 ) const
974 {
975 return tree_.lower_bound(key);
976 }
977
978 iterator upper_bound(const key_type& key)
979 {
980 return tree_.upper_bound(key);
981 }
982
983 const_iterator upper_bound(const key_type& key) const
984 {
985 return tree_.upper_bound(key);
986 }
987
988 template<class K>
989 iterator upper_bound(
990 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
991 )
992 {
993 return tree_.upper_bound(key);
994 }
995
996 template<class K>
997 const_iterator upper_bound(
998 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
999 ) const
1000 {
1001 return tree_.upper_bound(key);
1002 }
1003
1004 pair<iterator, iterator> equal_range(const key_type& key)
1005 {
1006 return tree_.equal_range(key);
1007 }
1008
1009 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
1010 {
1011 return tree_.equal_range(key);
1012 }
1013
1014 template<class K>
1015 pair<iterator, iterator> equal_range(
1016 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
1017 )
1018 {
1019 return tree_.equal_range(key);
1020 }
1021
1022 template<class K>
1023 pair<const_iterator, const_iterator> equal_range(
1024 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
1025 ) const
1026 {
1027 return tree_.equal_range(key);
1028 }
1029
1030 private:
1031 using tree_type = aux::rbtree<
1032 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
1033 key_compare, allocator_type, size_type,
1034 iterator, const_iterator,
1035 aux::rbtree_multi_policy
1036 >;
1037
1038 tree_type tree_;
1039 allocator_type allocator_;
1040
1041 template<class K, class C, class A>
1042 friend bool operator==(const multimap<K, C, A>&,
1043 const multimap<K, C, A>&);
1044 };
1045
1046 template<class Key, class Compare, class Allocator>
1047 bool operator==(const multimap<Key, Compare, Allocator>& lhs,
1048 const multimap<Key, Compare, Allocator>& rhs)
1049 {
1050 return lhs.tree_.is_eq_to(rhs.tree_);
1051 }
1052
1053 template<class Key, class Compare, class Allocator>
1054 bool operator<(const multimap<Key, Compare, Allocator>& lhs,
1055 const multimap<Key, Compare, Allocator>& rhs)
1056 {
1057 return lexicographical_compare(
1058 lhs.begin(), lhs.end(),
1059 rhs.begin(), rhs.end(),
1060 lhs.value_comp()
1061 );
1062 }
1063
1064 template<class Key, class Compare, class Allocator>
1065 bool operator!=(const multimap<Key, Compare, Allocator>& lhs,
1066 const multimap<Key, Compare, Allocator>& rhs)
1067 {
1068 return !(lhs == rhs);
1069 }
1070
1071 template<class Key, class Compare, class Allocator>
1072 bool operator>(const multimap<Key, Compare, Allocator>& lhs,
1073 const multimap<Key, Compare, Allocator>& rhs)
1074 {
1075 return rhs < lhs;
1076 }
1077
1078 template<class Key, class Compare, class Allocator>
1079 bool operator>=(const multimap<Key, Compare, Allocator>& lhs,
1080 const multimap<Key, Compare, Allocator>& rhs)
1081 {
1082 return !(lhs < rhs);
1083 }
1084
1085 template<class Key, class Compare, class Allocator>
1086 bool operator<=(const multimap<Key, Compare, Allocator>& lhs,
1087 const multimap<Key, Compare, Allocator>& rhs)
1088 {
1089 return !(rhs < lhs);
1090 }
1091}
1092
1093#endif
Note: See TracBrowser for help on using the repository browser.