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

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

cpp: added multimap and a WIP version of map that still needs map specific functions like index access, insert_or_assign etc

  • Property mode set to 100644
File size: 31.5 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 // 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 {
527 // TODO: need lexicographical_compare
528 return false;
529 }
530
531 template<class Key, class Compare, class Allocator>
532 bool operator!=(const map<Key, Compare, Allocator>& lhs,
533 const map<Key, Compare, Allocator>& rhs)
534 {
535 return !(lhs == rhs);
536 }
537
538 template<class Key, class Compare, class Allocator>
539 bool operator>(const map<Key, Compare, Allocator>& lhs,
540 const map<Key, Compare, Allocator>& rhs)
541 {
542 // TODO: need lexicographical_compare
543 return false;
544 }
545
546 template<class Key, class Compare, class Allocator>
547 bool operator>=(const map<Key, Compare, Allocator>& lhs,
548 const map<Key, Compare, Allocator>& rhs)
549 {
550 // TODO: need lexicographical_compare
551 return false;
552 }
553
554 template<class Key, class Compare, class Allocator>
555 bool operator<=(const map<Key, Compare, Allocator>& lhs,
556 const map<Key, Compare, Allocator>& rhs)
557 {
558 // TODO: need lexicographical_compare
559 return false;
560 }
561 /**
562 * 23.4.5, class template multimap:
563 */
564
565 template<
566 class Key, class Value,
567 class Compare = less<Key>,
568 class Alloc = allocator<pair<const Key, Value>>
569 >
570 class multimap
571 {
572 public:
573 using key_type = Key;
574 using mapped_type = Value;
575 using value_type = pair<const key_type, mapped_type>;
576 using key_compare = Compare;
577 using allocator_type = Alloc;
578 using pointer = typename allocator_traits<allocator_type>::pointer;
579 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
580 using reference = value_type&;
581 using const_reference = const value_type&;
582 using size_type = size_t;
583 using difference_type = ptrdiff_t;
584
585 class value_compare
586 {
587 friend class multimap;
588
589 protected:
590 key_compare comp;
591
592 value_compare(key_compare c)
593 : comp{c}
594 { /* DUMMY BODY */ }
595
596 public:
597 using result_type = bool;
598 using first_argument_type = value_type;
599 using second_argument_type = value_type;
600
601 bool operator()(const value_type& lhs, const value_type& rhs) const
602 {
603 return comp(lhs.first, rhs.first);
604 }
605 };
606
607 using iterator = aux::rbtree_iterator<
608 value_type, reference, pointer, size_type
609 >;
610 using const_iterator = aux::rbtree_const_iterator<
611 value_type, const_reference, const_pointer, size_type
612 >;
613
614 using reverse_iterator = std::reverse_iterator<iterator>;
615 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
616
617 multimap()
618 : multimap{key_compare{}}
619 { /* DUMMY BODY */ }
620
621 explicit multimap(const key_compare& comp,
622 const allocator_type& alloc = allocator_type{})
623 : tree_{comp}, allocator_{alloc}
624 { /* DUMMY BODY */ }
625
626 template<class InputIterator>
627 multimap(InputIterator first, InputIterator last,
628 const key_compare& comp = key_compare{},
629 const allocator_type& alloc = allocator_type{})
630 : multimap{comp, alloc}
631 {
632 insert(first, last);
633 }
634
635 multimap(const multimap& other)
636 : multimap{other, other.allocator_}
637 { /* DUMMY BODY */ }
638
639 multimap(multimap&& other)
640 : tree_{move(other.tree_)}, allocator_{move(other.allocator_)}
641 { /* DUMMY BODY */ }
642
643 explicit multimap(const allocator_type& alloc)
644 : tree_{}, allocator_{alloc}
645 { /* DUMMY BODY */ }
646
647 multimap(const multimap& other, const allocator_type& alloc)
648 : tree_{other.tree_}, allocator_{alloc}
649 { /* DUMMY BODY */ }
650
651 multimap(multimap&& other, const allocator_type& alloc)
652 : tree_{move(other.tree_)}, allocator_{alloc}
653 { /* DUMMY BODY */ }
654
655 multimap(initializer_list<value_type> init,
656 const key_compare& comp = key_compare{},
657 const allocator_type& alloc = allocator_type{})
658 : multimap{comp, alloc}
659 {
660 insert(init.begin(), init.end());
661 }
662
663 template<class InputIterator>
664 multimap(InputIterator first, InputIterator last,
665 const allocator_type& alloc)
666 : multimap{first, last, key_compare{}, alloc}
667 { /* DUMMY BODY */ }
668
669 multimap(initializer_list<value_type> init,
670 const allocator_type& alloc)
671 : multimap{init, key_compare{}, alloc}
672 { /* DUMMY BODY */ }
673
674 ~multimap()
675 { /* DUMMY BODY */ }
676
677 multimap& operator=(const multimap& other)
678 {
679 tree_ = other.tree_;
680 allocator_ = other.allocator_;
681
682 return *this;
683 }
684
685 multimap& operator=(multimap&& other)
686 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
687 is_nothrow_move_assignable<key_compare>::value)
688 {
689 tree_ = move(other.tree_);
690 allocator_ = move(other.allocator_);
691
692 return *this;
693 }
694
695 multimap& operator=(initializer_list<value_type>& init)
696 {
697 tree_.clear();
698
699 insert(init.begin(), init.end());
700
701 return *this;
702 }
703
704 allocator_type get_allocator() const noexcept
705 {
706 return allocator_;
707 }
708
709 iterator begin() noexcept
710 {
711 return tree_.begin();
712 }
713
714 const_iterator begin() const noexcept
715 {
716 return tree_.begin();
717 }
718
719 iterator end() noexcept
720 {
721 return tree_.end();
722 }
723
724 const_iterator end() const noexcept
725 {
726 return tree_.end();
727 }
728
729 reverse_iterator rbegin() noexcept
730 {
731 return tree_.rbegin();
732 }
733
734 const_reverse_iterator rbegin() const noexcept
735 {
736 return tree_.rbegin();
737 }
738
739 reverse_iterator rend() noexcept
740 {
741 return tree_.rend();
742 }
743
744 const_reverse_iterator rend() const noexcept
745 {
746 return tree_.rend();
747 }
748
749 const_iterator cbegin() const noexcept
750 {
751 return tree_.cbegin();
752 }
753
754 const_iterator cend() const noexcept
755 {
756 return tree_.cend();
757 }
758
759 const_reverse_iterator crbegin() const noexcept
760 {
761 return tree_.crbegin();
762 }
763
764 const_reverse_iterator crend() const noexcept
765 {
766 return tree_.crend();
767 }
768
769 bool empty() const noexcept
770 {
771 return tree_.empty();
772 }
773
774 size_type size() const noexcept
775 {
776 return tree_.size();
777 }
778
779 size_type max_size() const noexcept
780 {
781 return tree_.max_size(allocator_);
782 }
783
784 template<class... Args>
785 iterator emplace(Args&&... args)
786 {
787 return tree_.emplace(forward<Args>(args)...);
788 }
789
790 template<class... Args>
791 iterator emplace_hint(const_iterator, Args&&... args)
792 {
793 return emplace(forward<Args>(args)...);
794 }
795
796 iterator insert(const value_type& val)
797 {
798 return tree_.insert(val);
799 }
800
801 iterator insert(value_type&& val)
802 {
803 return tree_.insert(forward<value_type>(val));
804 }
805
806 template<class T>
807 iterator insert(
808 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val
809 )
810 {
811 return emplace(forward<T>(val));
812 }
813
814 iterator insert(const_iterator, const value_type& val)
815 {
816 return insert(val);
817 }
818
819 iterator insert(const_iterator, value_type&& val)
820 {
821 return insert(forward<value_type>(val));
822 }
823
824 template<class T>
825 iterator insert(
826 const_iterator hint,
827 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val
828 )
829 {
830 return emplace_hint(hint, forward<T>(val));
831 }
832
833 template<class InputIterator>
834 void insert(InputIterator first, InputIterator last)
835 {
836 while (first != last)
837 insert(*first++);
838 }
839
840 void insert(initializer_list<value_type> init)
841 {
842 insert(init.begin(), init.end());
843 }
844
845 iterator erase(const_iterator position)
846 {
847 return tree_.erase(position);
848 }
849
850 size_type erase(const key_type& key)
851 {
852 return tree_.erase(key);
853 }
854
855 iterator erase(const_iterator first, const_iterator last)
856 {
857 while (first != last)
858 first = erase(first);
859
860 return iterator{
861 first.node(), first.end()
862 };
863 }
864
865 void swap(multimap& other)
866 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
867 noexcept(std::swap(declval<key_compare>(), declval<key_compare>())))
868 {
869 tree_.swap(other.tree_);
870 std::swap(allocator_, other.allocator_);
871 }
872
873 void clear() noexcept
874 {
875 tree_.clear();
876 }
877
878 key_compare key_comp() const
879 {
880 return tree_.key_comp();
881 }
882
883 value_compare value_comp() const
884 {
885 return value_compare{tree_.key_comp()};
886 }
887
888 iterator find(const key_type& key)
889 {
890 return tree_.find(key);
891 }
892
893 const_iterator find(const key_type& key) const
894 {
895 return tree_.find(key);
896 }
897
898 template<class K>
899 iterator find(
900 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
901 )
902 {
903 return tree_.find(key);
904 }
905
906 template<class K>
907 const_iterator find(
908 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
909 ) const
910 {
911 return tree_.find(key);
912 }
913
914 size_type count(const key_type& key) const
915 {
916 return tree_.count(key);
917 }
918
919 template<class K>
920 size_type count(
921 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
922 ) const
923 {
924 return tree_.count(key);
925 }
926
927 iterator lower_bound(const key_type& key)
928 {
929 return tree_.lower_bound(key);
930 }
931
932 const_iterator lower_bound(const key_type& key) const
933 {
934 return tree_.lower_bound(key);
935 }
936
937 template<class K>
938 iterator lower_bound(
939 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
940 )
941 {
942 return tree_.lower_bound(key);
943 }
944
945 template<class K>
946 const_iterator lower_bound(
947 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
948 ) const
949 {
950 return tree_.lower_bound(key);
951 }
952
953 iterator upper_bound(const key_type& key)
954 {
955 return tree_.upper_bound(key);
956 }
957
958 const_iterator upper_bound(const key_type& key) const
959 {
960 return tree_.upper_bound(key);
961 }
962
963 template<class K>
964 iterator upper_bound(
965 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
966 )
967 {
968 return tree_.upper_bound(key);
969 }
970
971 template<class K>
972 const_iterator upper_bound(
973 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
974 ) const
975 {
976 return tree_.upper_bound(key);
977 }
978
979 pair<iterator, iterator> equal_range(const key_type& key)
980 {
981 return tree_.equal_range(key);
982 }
983
984 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
985 {
986 return tree_.equal_range(key);
987 }
988
989 template<class K>
990 pair<iterator, iterator> equal_range(
991 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
992 )
993 {
994 return tree_.equal_range(key);
995 }
996
997 template<class K>
998 pair<const_iterator, const_iterator> equal_range(
999 enable_if_t<aux::is_transparent_v<key_compare>, const K&> key
1000 ) const
1001 {
1002 return tree_.equal_range(key);
1003 }
1004
1005 private:
1006 using tree_type = aux::rbtree<
1007 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
1008 key_compare, allocator_type, size_type,
1009 iterator, const_iterator,
1010 aux::rbtree_multi_policy
1011 >;
1012
1013 tree_type tree_;
1014 allocator_type allocator_;
1015
1016 template<class K, class C, class A>
1017 friend bool operator==(const multimap<K, C, A>&,
1018 const multimap<K, C, A>&);
1019 };
1020
1021 template<class Key, class Compare, class Allocator>
1022 bool operator==(const multimap<Key, Compare, Allocator>& lhs,
1023 const multimap<Key, Compare, Allocator>& rhs)
1024 {
1025 return lhs.tree_.is_eq_to(rhs.tree_);
1026 }
1027
1028 template<class Key, class Compare, class Allocator>
1029 bool operator<(const multimap<Key, Compare, Allocator>& lhs,
1030 const multimap<Key, Compare, Allocator>& rhs)
1031 {
1032 // TODO: need lexicographical_compare
1033 return false;
1034 }
1035
1036 template<class Key, class Compare, class Allocator>
1037 bool operator!=(const multimap<Key, Compare, Allocator>& lhs,
1038 const multimap<Key, Compare, Allocator>& rhs)
1039 {
1040 return !(lhs == rhs);
1041 }
1042
1043 template<class Key, class Compare, class Allocator>
1044 bool operator>(const multimap<Key, Compare, Allocator>& lhs,
1045 const multimap<Key, Compare, Allocator>& rhs)
1046 {
1047 // TODO: need lexicographical_compare
1048 return false;
1049 }
1050
1051 template<class Key, class Compare, class Allocator>
1052 bool operator>=(const multimap<Key, Compare, Allocator>& lhs,
1053 const multimap<Key, Compare, Allocator>& rhs)
1054 {
1055 // TODO: need lexicographical_compare
1056 return false;
1057 }
1058
1059 template<class Key, class Compare, class Allocator>
1060 bool operator<=(const multimap<Key, Compare, Allocator>& lhs,
1061 const multimap<Key, Compare, Allocator>& rhs)
1062 {
1063 // TODO: need lexicographical_compare
1064 return false;
1065 }
1066}
1067
1068#endif
Note: See TracBrowser for help on using the repository browser.