Embedded Template Library 1.0
Loading...
Searching...
No Matches
multimap.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2014 John Wellbelove, rlindeman
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_MULTIMAP_INCLUDED
32#define ETL_MULTIMAP_INCLUDED
33
34#include "platform.h"
35#include "algorithm.h"
36#include "debug_count.h"
37#include "error_handler.h"
38#include "exception.h"
39#include "functional.h"
40#include "initializer_list.h"
41#include "iterator.h"
42#include "nth_type.h"
43#include "nullptr.h"
44#include "parameter_type.h"
45#include "placement_new.h"
46#include "pool.h"
47#include "type_traits.h"
48#include "utility.h"
49
50#include <stddef.h>
51
53#include "private/minmax_push.h"
54
55//*****************************************************************************
58//*****************************************************************************
59
60namespace etl
61{
62 //***************************************************************************
65 //***************************************************************************
66 class multimap_exception : public etl::exception
67 {
68 public:
69
70 multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
71 : exception(reason_, file_name_, line_number_)
72 {
73 }
74 };
75
76 //***************************************************************************
79 //***************************************************************************
80 class multimap_full : public etl::multimap_exception
81 {
82 public:
83
84 multimap_full(string_type file_name_, numeric_type line_number_)
85 : etl::multimap_exception(ETL_ERROR_TEXT("multimap:full", ETL_MULTIMAP_FILE_ID"A"), file_name_, line_number_)
86 {
87 }
88 };
89
90 //***************************************************************************
93 //***************************************************************************
94 class multimap_out_of_bounds : public etl::multimap_exception
95 {
96 public:
97
98 multimap_out_of_bounds(string_type file_name_, numeric_type line_number_)
99 : etl::multimap_exception(ETL_ERROR_TEXT("multimap:bounds", ETL_MULTIMAP_FILE_ID"B"), file_name_, line_number_)
100 {
101 }
102 };
103
104 //***************************************************************************
107 //***************************************************************************
108 class multimap_iterator : public etl::multimap_exception
109 {
110 public:
111
112 multimap_iterator(string_type file_name_, numeric_type line_number_)
113 : etl::multimap_exception(ETL_ERROR_TEXT("multimap:iterator", ETL_MULTIMAP_FILE_ID"C"), file_name_, line_number_)
114 {
115 }
116 };
117
118 //***************************************************************************
121 //***************************************************************************
123 {
124 public:
125
126 typedef size_t size_type;
127
128 //*************************************************************************
130 //*************************************************************************
132 {
133 return current_size;
134 }
135
136 //*************************************************************************
138 //*************************************************************************
140 {
141 return CAPACITY;
142 }
143
144 //*************************************************************************
146 //*************************************************************************
147 bool empty() const
148 {
149 return current_size == 0;
150 }
151
152 //*************************************************************************
154 //*************************************************************************
155 bool full() const
156 {
157 return current_size == CAPACITY;
158 }
159
160 //*************************************************************************
163 //*************************************************************************
165 {
166 return CAPACITY;
167 }
168
169 //*************************************************************************
172 //*************************************************************************
173 size_t available() const
174 {
175 return max_size() - size();
176 }
177
178 protected:
179
180 enum
181 {
182 kLeft,
183 kRight,
184 kNeither
185 };
186
187 //*************************************************************************
189 //*************************************************************************
190 struct Node
191 {
192 //***********************************************************************
194 //***********************************************************************
196 : parent(ETL_NULLPTR)
197 , weight((uint_least8_t)kNeither)
198 , dir((uint_least8_t)kNeither)
199 {
200 children[0] = ETL_NULLPTR;
201 children[1] = ETL_NULLPTR;
202 }
203
204 //***********************************************************************
206 //***********************************************************************
208 {
209 weight = (uint_least8_t)kNeither;
210 dir = (uint_least8_t)kNeither;
211 parent = ETL_NULLPTR;
212 children[0] = ETL_NULLPTR;
213 children[1] = ETL_NULLPTR;
214 }
215
216 Node* parent;
217 Node* children[2];
218 uint_least8_t weight;
219 uint_least8_t dir;
220 };
221
222 //*************************************************************************
224 //*************************************************************************
226 : current_size(0)
227 , CAPACITY(max_size_)
228 , root_node(ETL_NULLPTR)
229 {
230 }
231
232 //*************************************************************************
234 //*************************************************************************
236
237 //*************************************************************************
239 //*************************************************************************
240 void balance_node(Node*& critical_node)
241 {
242 // Step 1: Update weights for all children of the critical node up to the
243 // newly inserted node. This step is costly (in terms of traversing nodes
244 // multiple times during insertion) but doesn't require as much recursion
245 Node* weight_node = critical_node->children[critical_node->dir];
246 while (weight_node)
247 {
248 // Keep going until we reach a terminal node (dir == (uint_least8_t)
249 // kNeither)
250 if ((uint_least8_t)kNeither != weight_node->dir)
251 {
252 // Does this insert balance the previous weight factor value?
253 if (weight_node->weight == 1 - weight_node->dir)
254 {
255 weight_node->weight = (uint_least8_t)kNeither;
256 }
257 else
258 {
259 weight_node->weight = weight_node->dir;
260 }
261
262 // Update weight factor node to point to next node
263 weight_node = weight_node->children[weight_node->dir];
264 }
265 else
266 {
267 // Stop loop, terminal node found
268 break;
269 }
270 } // while(weight_node)
271
272 // Step 2: Update weight for critical_node or rotate tree to balance node
273 if ((uint_least8_t)kNeither == critical_node->weight)
274 {
275 critical_node->weight = critical_node->dir;
276 }
277 // If direction is different than weight, then it will now be balanced
278 else if (critical_node->dir != critical_node->weight)
279 {
280 critical_node->weight = (uint_least8_t)kNeither;
281 }
282 // Rotate is required to balance the tree at the critical node
283 else
284 {
285 // If critical node matches child node direction then perform a two
286 // node rotate in the direction of the critical node
287 if (critical_node->children[critical_node->dir] != ETL_NULLPTR) ETL_UNLIKELY
288 {
289 if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
290 {
291 rotate_2node(critical_node, critical_node->dir);
292 }
293 // Otherwise perform a three node rotation in the direction of the
294 // critical node
295 else
296 {
297 if (critical_node->children[critical_node->dir]->children[1 - critical_node->dir] != ETL_NULLPTR) ETL_UNLIKELY
298 {
299 rotate_3node(critical_node, critical_node->dir, critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
300 }
301 }
302 }
303 }
304 }
305
306 //*************************************************************************
308 //*************************************************************************
309 void rotate_2node(Node*& position, uint_least8_t dir)
310 {
311 // A C A B
312 // B C -> A E OR B C -> D A
313 // D E B D D E E C
314 // C (new position) becomes the root
315 // A (position) takes ownership of D as its children[kRight] child
316 // C (new position) takes ownership of A as its left child
317 // OR
318 // B (new position) becomes the root
319 // A (position) takes ownership of E as its left child
320 // B (new position) takes ownership of A as its right child
321
322 // Capture new root (either B or C depending on dir) and its parent
323 Node* new_root = position->children[dir];
324
325 // Replace position's previous child with new root's other child
326 position->children[dir] = new_root->children[1 - dir];
327 // Update new root's other child parent pointer
328 if (position->children[dir])
329 {
330 position->children[dir]->parent = position;
331 }
332
333 // New root's parent becomes current position's parent
334 new_root->parent = position->parent;
335 new_root->children[1 - dir] = position;
336 new_root->dir = 1 - dir;
337
338 // Clear weight factor from current position
339 position->weight = (uint_least8_t)kNeither;
340 // Position's parent becomes new_root
341 position->parent = new_root;
342 position = new_root;
343 // Clear weight factor from new root
344 position->weight = (uint_least8_t)kNeither;
345 }
346
347 //*************************************************************************
349 //*************************************************************************
350 void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
351 {
352 // --A-- --E-- --A-- --D--
353 // _B_ C -> B A OR B _C_ -> A C
354 // D E D F G C D E B F G E
355 // F G F G
356 // E (new position) becomes the root
357 // B (position) takes ownership of F as its left child
358 // A takes ownership of G as its right child
359 // OR
360 // D (new position) becomes the root
361 // A (position) takes ownership of F as its right child
362 // C takes ownership of G as its left child
363
364 // Capture new root (either E or D depending on dir)
365 Node* new_root = position->children[dir]->children[1 - dir];
366 // Set weight factor for B or C based on F or G existing and being a
367 // different than dir
368 position->children[dir]->weight = third != (uint_least8_t)kNeither && third != dir ? dir : (uint_least8_t)kNeither;
369
370 // Detach new root from its tree (replace with new roots child)
371 position->children[dir]->children[1 - dir] = new_root->children[dir];
372 // Update new roots child parent pointer
373 if (new_root->children[dir])
374 {
375 new_root->children[dir]->parent = position->children[dir];
376 }
377
378 // Attach current left tree to new root and update its parent
379 new_root->children[dir] = position->children[dir];
380 position->children[dir]->parent = new_root;
381
382 // Set weight factor for A based on F or G
383 position->weight = third != (uint_least8_t)kNeither && third == dir ? 1 - dir : (uint_least8_t)kNeither;
384
385 // Move new root's right tree to current roots left tree
386 position->children[dir] = new_root->children[1 - dir];
387 if (new_root->children[1 - dir])
388 {
389 new_root->children[1 - dir]->parent = position;
390 }
391
392 // Attach current root to new roots right tree and assume its parent
393 new_root->parent = position->parent;
394 new_root->children[1 - dir] = position;
395 new_root->dir = 1 - dir;
396
397 // Update current position's parent and replace with new root
398 position->parent = new_root;
399 position = new_root;
400 // Clear weight factor for new current position
401 position->weight = (uint_least8_t)kNeither;
402 }
403
404 //*************************************************************************
406 //*************************************************************************
407 void next_node(Node*& position) const
408 {
409 if (position)
410 {
411 // Is there a tree on the right? then find the minimum of that tree
412 if (position->children[(uint_least8_t)kRight])
413 {
414 // Return minimum node found
415 position = find_limit_node(position->children[(uint_least8_t)kRight], kLeft);
416 }
417 // Otherwise find the parent of this node
418 else
419 {
420 // Start with current position as parent
421 Node* parent = position;
422 do {
423 // Update current position as previous parent
424 position = parent;
425 // Find parent of current position
426 parent = position->parent; // find_parent_node(root_node, position);
427 // Repeat while previous position was on
428 // right side of parent tree
429 } while (parent && parent->children[(uint_least8_t)kRight] == position);
430
431 // Set parent node as the next position
432 position = parent;
433 }
434 }
435 }
436
437 //*************************************************************************
439 //*************************************************************************
440 void next_node(const Node*& position) const
441 {
442 if (position)
443 {
444 // Is there a tree on the right? then find the minimum of that tree
445 if (position->children[(uint_least8_t)kRight])
446 {
447 // Return minimum node found
448 position = find_limit_node(position->children[(uint_least8_t)kRight], kLeft);
449 }
450 // Otherwise find the parent of this node
451 else
452 {
453 // Start with current position as parent
454 const Node* parent = position;
455 do {
456 // Update current position as previous parent
457 position = parent;
458 // Find parent of current position
459 parent = position->parent;
460 // Repeat while previous position was on right side of parent tree
461 } while (parent && parent->children[(uint_least8_t)kRight] == position);
462
463 // Set parent node as the next position
464 position = parent;
465 }
466 }
467 }
468
469 //*************************************************************************
471 //*************************************************************************
472 void prev_node(Node*& position) const
473 {
474 // If starting at the terminal end, the previous node is the maximum node
475 // from the root
476 if (!position)
477 {
478 position = find_limit_node(root_node, kRight);
479 }
480 else
481 {
482 // Is there a tree on the left? then find the maximum of that tree
483 if (position->children[(uint_least8_t)kLeft])
484 {
485 // Return maximum node found
486 position = find_limit_node(position->children[(uint_least8_t)kLeft], kRight);
487 }
488 // Otherwise find the parent of this node
489 else
490 {
491 // Start with current position as parent
492 Node* parent = position;
493 do {
494 // Update current position as previous parent
495 position = parent;
496 // Find parent of current position
497 parent = position->parent;
498 // Repeat while previous position was on left side of parent tree
499 } while (parent && parent->children[(uint_least8_t)kLeft] == position);
500
501 // Set parent node as the next position
502 position = parent;
503 }
504 }
505 }
506
507 //*************************************************************************
509 //*************************************************************************
510 void prev_node(const Node*& position) const
511 {
512 // If starting at the terminal end, the previous node is the maximum node
513 // from the root
514 if (!position)
515 {
516 position = find_limit_node(root_node, kRight);
517 }
518 else
519 {
520 // Is there a tree on the left? then find the maximum of that tree
521 if (position->children[(uint_least8_t)kLeft])
522 {
523 // Return maximum node found
524 position = find_limit_node(position->children[(uint_least8_t)kLeft], kRight);
525 }
526 // Otherwise find the parent of this node
527 else
528 {
529 // Start with current position as parent
530 const Node* parent = position;
531 do {
532 // Update current position as previous parent
533 position = parent;
534 // Find parent of current position
535 parent = position->parent;
536 // Repeat while previous position was on left side of parent tree
537 } while (parent && parent->children[(uint_least8_t)kLeft] == position);
538
539 // Set parent node as the next position
540 position = parent;
541 }
542 }
543 }
544
545 //*************************************************************************
548 //*************************************************************************
549 Node* find_limit_node(Node* position, const int8_t dir) const
550 {
551 // Something at this position and in the direction specified? keep going
552 Node* limit_node = position;
553 while (limit_node && limit_node->children[dir])
554 {
555 limit_node = limit_node->children[dir];
556 }
557
558 // Return the limit node position found
559 return limit_node;
560 }
561
562 //*************************************************************************
564 //*************************************************************************
565 void attach_node(Node* parent, Node*& position, Node& node)
566 {
567 // Mark new node as leaf on attach to tree at position provided
568 node.mark_as_leaf();
569
570 // Keep track of this node's parent
571 node.parent = parent;
572
573 // Add the node here
574 position = &node;
575
576 // One more.
577 ++current_size;
578 }
579
580 //*************************************************************************
582 //*************************************************************************
583 void detach_node(Node*& position, Node*& replacement)
584 {
585 // Make temporary copy of actual nodes involved because we might lose
586 // their references in the process (e.g. position is the same as
587 // replacement or replacement is a child of position)
588 Node* detached = position;
589 Node* swap = replacement;
590
591 // Update current position to point to swap (replacement) node first
592 position = swap;
593
594 // Update replacement node to point to child in opposite direction
595 // otherwise we might lose the other child of the swap node
596 replacement = swap->children[1 - swap->dir];
597
598 if (replacement != ETL_NULLPTR)
599 {
600 replacement->parent = swap->parent;
601 }
602
603 // Point swap node to detached node's parent, children and weight
604 swap->parent = detached->parent;
605 swap->children[(uint_least8_t)kLeft] = detached->children[(uint_least8_t)kLeft];
606 swap->children[(uint_least8_t)kRight] = detached->children[(uint_least8_t)kRight];
607 if (swap->children[(uint_least8_t)kLeft])
608 {
609 swap->children[(uint_least8_t)kLeft]->parent = swap;
610 }
611 if (swap->children[(uint_least8_t)kRight])
612 {
613 swap->children[(uint_least8_t)kRight]->parent = swap;
614 }
615 swap->weight = detached->weight;
616 }
617
621 ETL_DECLARE_DEBUG_COUNT;
622 };
623
624 //***************************************************************************
627 //***************************************************************************
628 template <typename TKey, typename TMapped, typename TKeyCompare = etl::less<TKey> >
630 {
631 public:
632
633 typedef ETL_OR_STD::pair<const TKey, TMapped> value_type;
634 typedef const TKey key_type;
635 typedef TMapped mapped_type;
636 typedef TKeyCompare key_compare;
637 typedef value_type& reference;
638 typedef const value_type& const_reference;
639#if ETL_USING_CPP11
640 typedef value_type&& rvalue_reference;
641#endif
642 typedef value_type* pointer;
643 typedef const value_type* const_pointer;
644 typedef size_t size_type;
645
646 typedef const key_type& const_key_reference;
647#if ETL_USING_CPP11
648 typedef key_type&& rvalue_key_reference;
649#endif
650
652 {
653 public:
654
655 bool operator()(const_reference lhs, const_reference rhs) const
656 {
657 return (kcompare(lhs.first, rhs.first));
658 }
659
660 private:
661
662 key_compare kcompare;
663 };
664
665 protected:
666
667 //*************************************************************************
669 //*************************************************************************
670 struct Data_Node : public Node
671 {
672 explicit Data_Node(value_type value_)
673 : value(value_)
674 {
675 }
676
677 value_type value;
678 };
679
680 //*************************************************************************
682 //*************************************************************************
683 bool node_comp(const Data_Node& node1, const Data_Node& node2) const
684 {
685 return kcompare(node1.value.first, node2.value.first);
686 }
687
688 bool node_comp(const Data_Node& node, const_key_reference key) const
689 {
690 return kcompare(node.value.first, key);
691 }
692
693 bool node_comp(const_key_reference key, const Data_Node& node) const
694 {
695 return kcompare(key, node.value.first);
696 }
697
698#if ETL_USING_CPP11
699 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
700 bool node_comp(const Data_Node& node, const K& key) const
701 {
702 return kcompare(node.value.first, key);
703 }
704
705 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
706 bool node_comp(const K& key, const Data_Node& node) const
707 {
708 return kcompare(key, node.value.first);
709 }
710#endif
711
712 private:
713
715 ipool* p_node_pool;
716
717 key_compare kcompare;
718 value_compare vcompare;
719
720 //*************************************************************************
722 //*************************************************************************
723 static Data_Node* data_cast(Node* p_node)
724 {
725 return static_cast<Data_Node*>(p_node);
726 }
727
728 //*************************************************************************
730 //*************************************************************************
731 static Data_Node& data_cast(Node& node)
732 {
733 return static_cast<Data_Node&>(node);
734 }
735
736 //*************************************************************************
738 //*************************************************************************
739 static const Data_Node* data_cast(const Node* p_node)
740 {
741 return static_cast<const Data_Node*>(p_node);
742 }
743
744 //*************************************************************************
746 //*************************************************************************
747 static const Data_Node& data_cast(const Node& node)
748 {
749 return static_cast<const Data_Node&>(node);
750 }
751
752 public:
753
754 //*************************************************************************
756 //*************************************************************************
757 class iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, value_type>
758 {
759 public:
760
761 friend class imultimap;
762 friend class const_iterator;
763
764 iterator()
765 : p_multimap(ETL_NULLPTR)
766 , p_node(ETL_NULLPTR)
767 {
768 }
769
770 iterator(imultimap& multimap)
771 : p_multimap(&multimap)
772 , p_node(ETL_NULLPTR)
773 {
774 }
775
776 iterator(imultimap& multimap, Node* node)
777 : p_multimap(&multimap)
778 , p_node(node)
779 {
780 }
781
782 iterator(const iterator& other)
783 : p_multimap(other.p_multimap)
784 , p_node(other.p_node)
785 {
786 }
787
788 ~iterator() {}
789
790 iterator& operator++()
791 {
792 p_multimap->next_node(p_node);
793 return *this;
794 }
795
796 iterator operator++(int)
797 {
798 iterator temp(*this);
799 p_multimap->next_node(p_node);
800 return temp;
801 }
802
803 iterator& operator--()
804 {
805 p_multimap->prev_node(p_node);
806 return *this;
807 }
808
809 iterator operator--(int)
810 {
811 iterator temp(*this);
812 p_multimap->prev_node(p_node);
813 return temp;
814 }
815
816 iterator& operator=(const iterator& other)
817 {
818 p_multimap = other.p_multimap;
819 p_node = other.p_node;
820 return *this;
821 }
822
823 reference operator*() const
824 {
825 return imultimap::data_cast(p_node)->value;
826 }
827
828 pointer operator&() const
829 {
830 return &(imultimap::data_cast(p_node)->value);
831 }
832
833 pointer operator->() const
834 {
835 return &(imultimap::data_cast(p_node)->value);
836 }
837
838 friend bool operator==(const iterator& lhs, const iterator& rhs)
839 {
840 return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
841 }
842
843 friend bool operator!=(const iterator& lhs, const iterator& rhs)
844 {
845 return !(lhs == rhs);
846 }
847
848 private:
849
850 // Pointer to multimap associated with this iterator
851 imultimap* p_multimap;
852
853 // Pointer to the current node for this iterator
854 Node* p_node;
855 };
856 friend class iterator;
857
858 //*************************************************************************
860 //*************************************************************************
861 class const_iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, const value_type>
862 {
863 public:
864
865 friend class imultimap;
866
867 const_iterator()
868 : p_multimap(ETL_NULLPTR)
869 , p_node(ETL_NULLPTR)
870 {
871 }
872
873 const_iterator(const imultimap& multimap)
874 : p_multimap(&multimap)
875 , p_node(ETL_NULLPTR)
876 {
877 }
878
879 const_iterator(const imultimap& multimap, const Node* node)
880 : p_multimap(&multimap)
881 , p_node(node)
882 {
883 }
884
885 const_iterator(const typename imultimap::iterator& other)
886 : p_multimap(other.p_multimap)
887 , p_node(other.p_node)
888 {
889 }
890
891 const_iterator(const const_iterator& other)
892 : p_multimap(other.p_multimap)
893 , p_node(other.p_node)
894 {
895 }
896
897 ~const_iterator() {}
898
899 const_iterator& operator++()
900 {
901 p_multimap->next_node(p_node);
902 return *this;
903 }
904
905 const_iterator operator++(int)
906 {
907 const_iterator temp(*this);
908 p_multimap->next_node(p_node);
909 return temp;
910 }
911
912 const_iterator& operator--()
913 {
914 p_multimap->prev_node(p_node);
915 return *this;
916 }
917
918 const_iterator operator--(int)
919 {
920 const_iterator temp(*this);
921 p_multimap->prev_node(p_node);
922 return temp;
923 }
924
925 const_iterator& operator=(const const_iterator& other)
926 {
927 p_multimap = other.p_multimap;
928 p_node = other.p_node;
929 return *this;
930 }
931
932 const_reference operator*() const
933 {
934 return imultimap::data_cast(p_node)->value;
935 }
936
937 const_pointer operator&() const
938 {
939 return imultimap::data_cast(p_node)->value;
940 }
941
942 const_pointer operator->() const
943 {
944 return &(imultimap::data_cast(p_node)->value);
945 }
946
947 friend bool operator==(const const_iterator& lhs, const const_iterator& rhs)
948 {
949 return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
950 }
951
952 friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs)
953 {
954 return !(lhs == rhs);
955 }
956
957 private:
958
959 // Convert to an iterator.
960 imultimap::iterator to_iterator() const
961 {
962 return imultimap::iterator(const_cast<imultimap&>(*p_multimap), const_cast<Node*>(p_node));
963 }
964
965 // Pointer to multimap associated with this iterator
966 const imultimap* p_multimap;
967
968 // Pointer to the current node for this iterator
969 const Node* p_node;
970 };
971 friend class const_iterator;
972
973 typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
974
975 typedef ETL_OR_STD::reverse_iterator<iterator> reverse_iterator;
976 typedef ETL_OR_STD::reverse_iterator<const_iterator> const_reverse_iterator;
977
978 //*************************************************************************
980 //*************************************************************************
982 {
983 return iterator(*this, find_limit_node(root_node, kLeft));
984 }
985
986 //*************************************************************************
988 //*************************************************************************
990 {
991 return const_iterator(*this, find_limit_node(root_node, kLeft));
992 }
993
994 //*************************************************************************
996 //*************************************************************************
998 {
999 return iterator(*this);
1000 }
1001
1002 //*************************************************************************
1004 //*************************************************************************
1006 {
1007 return const_iterator(*this);
1008 }
1009
1010 //*************************************************************************
1012 //*************************************************************************
1014 {
1015 return const_iterator(*this, find_limit_node(root_node, kLeft));
1016 }
1017
1018 //*************************************************************************
1020 //*************************************************************************
1022 {
1023 return const_iterator(*this);
1024 }
1025
1026 //*************************************************************************
1028 //*************************************************************************
1029 reverse_iterator rbegin()
1030 {
1031 return reverse_iterator(iterator(*this));
1032 }
1033
1034 //*************************************************************************
1036 //*************************************************************************
1037 const_reverse_iterator rbegin() const
1038 {
1039 return const_reverse_iterator(const_iterator(*this));
1040 }
1041
1042 //*************************************************************************
1044 //*************************************************************************
1045 reverse_iterator rend()
1046 {
1047 return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
1048 }
1049
1050 //*************************************************************************
1052 //*************************************************************************
1053 const_reverse_iterator rend() const
1054 {
1055 return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
1056 }
1057
1058 //*************************************************************************
1060 //*************************************************************************
1061 const_reverse_iterator crbegin() const
1062 {
1063 return const_reverse_iterator(const_iterator(*this));
1064 }
1065
1066 //*************************************************************************
1068 //*************************************************************************
1069 const_reverse_iterator crend() const
1070 {
1071 return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
1072 }
1073
1074 //*********************************************************************
1081 //*********************************************************************
1082 template <typename TIterator>
1083 void assign(TIterator first, TIterator last)
1084 {
1085 initialise();
1086 insert(first, last);
1087 }
1088
1089 //*************************************************************************
1091 //*************************************************************************
1092 void clear()
1093 {
1094 initialise();
1095 }
1096
1097 //*********************************************************************
1101 //*********************************************************************
1102 size_type count(const_key_reference key) const
1103 {
1104 return count_nodes(key);
1105 }
1106
1107#if ETL_USING_CPP11
1108 //*********************************************************************
1109 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1110 size_type count(const K& key) const
1111 {
1112 return count_nodes(key);
1113 }
1114#endif
1115
1116 //*************************************************************************
1119 //*************************************************************************
1120 ETL_OR_STD::pair<iterator, iterator> equal_range(const_key_reference key)
1121 {
1122 return ETL_OR_STD::make_pair<iterator, iterator>(iterator(*this, find_lower_node(root_node, key)),
1123 iterator(*this, find_upper_node(root_node, key)));
1124 }
1125
1126#if ETL_USING_CPP11
1127 //*************************************************************************
1128 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1129 ETL_OR_STD::pair<iterator, iterator> equal_range(const K& key)
1130 {
1131 return ETL_OR_STD::make_pair<iterator, iterator>(iterator(*this, find_lower_node(root_node, key)),
1132 iterator(*this, find_upper_node(root_node, key)));
1133 }
1134#endif
1135
1136 //*************************************************************************
1139 //*************************************************************************
1140 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const_key_reference key) const
1141 {
1142 return ETL_OR_STD::make_pair<const_iterator, const_iterator>(const_iterator(*this, find_lower_node(root_node, key)),
1143 const_iterator(*this, find_upper_node(root_node, key)));
1144 }
1145
1146#if ETL_USING_CPP11
1147 //*************************************************************************
1148 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1149 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const K& key) const
1150 {
1151 return ETL_OR_STD::make_pair<const_iterator, const_iterator>(const_iterator(*this, find_lower_node(root_node, key)),
1152 const_iterator(*this, find_upper_node(root_node, key)));
1153 }
1154#endif
1155
1156 //*************************************************************************
1158 //*************************************************************************
1160 {
1161 // Remove the node by its node specified in iterator position
1162 return erase(const_iterator(position));
1163 }
1164
1165 //*************************************************************************
1167 //*************************************************************************
1169 {
1170 // Cast const away from node to be removed. This is necessary because the
1171 // STL definition of this method requires we provide the next node in the
1172 // sequence as an iterator.
1173 Node* node = const_cast<Node*>(position.p_node);
1174 iterator next(*this, node);
1175 ++next;
1176
1177 // Remove the non-const node provided
1178 remove_node(node);
1179
1180 return next;
1181 }
1182
1183 //*************************************************************************
1184 // Erase the key specified.
1185 //*************************************************************************
1186 size_type erase(const_key_reference key)
1187 {
1188 // Number of nodes removed
1189 size_type d = 0;
1190 const_iterator lower(*this, find_lower_node(root_node, key));
1191 const_iterator upper(*this, find_upper_node(root_node, key));
1192 while (lower != upper)
1193 {
1194 // Increment count for each node removed
1195 ++d;
1196 // Remove node using the other erase method
1197 lower = erase(lower);
1198 }
1199
1200 // Return the total count erased
1201 return d;
1202 }
1203
1204 //*************************************************************************
1205#if ETL_USING_CPP11
1206 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1207 size_type erase(K&& key)
1208 {
1209 // Number of nodes removed
1210 size_type d = 0;
1211 const_iterator lower(*this, find_lower_node(root_node, etl::forward<K>(key)));
1212 const_iterator upper(*this, find_upper_node(root_node, etl::forward<K>(key)));
1213 while (lower != upper)
1214 {
1215 // Increment count for each node removed
1216 ++d;
1217 // Remove node using the other erase method
1218 lower = erase(lower);
1219 }
1220
1221 // Return the total count erased
1222 return d;
1223 }
1224#endif
1225
1226 //*************************************************************************
1228 //*************************************************************************
1230 {
1231 while (first != last)
1232 {
1233 first = erase(first);
1234 }
1235
1236 return last.to_iterator();
1237 }
1238
1239 //*********************************************************************
1243 //*********************************************************************
1244 iterator find(const_key_reference key)
1245 {
1246 return iterator(*this, find_node(root_node, key));
1247 }
1248
1249#if ETL_USING_CPP11
1250 //*********************************************************************
1251 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1252 iterator find(const K& k)
1253 {
1254 return iterator(*this, find_node(root_node, k));
1255 }
1256#endif
1257
1258 //*********************************************************************
1262 //*********************************************************************
1263 const_iterator find(const_key_reference key) const
1264 {
1265 return const_iterator(*this, find_node(root_node, key));
1266 }
1267
1268#if ETL_USING_CPP11
1269 //*********************************************************************
1270 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1271 const_iterator find(const K& k) const
1272 {
1273 return const_iterator(*this, find_node(root_node, k));
1274 }
1275#endif
1276
1277 //*********************************************************************
1282 //*********************************************************************
1283 iterator insert(const_reference value)
1284 {
1285 // Default to no inserted node
1286 Node* inserted_node = ETL_NULLPTR;
1287
1288 ETL_ASSERT(!full(), ETL_ERROR(multimap_full));
1289
1290 // Get next available free node
1291 Data_Node& node = allocate_data_node(value);
1292
1293 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1294 inserted_node = insert_node(root_node, node);
1295
1296 // Insert node into tree and return iterator to new node location in tree
1297 return iterator(*this, inserted_node);
1298 }
1299
1300#if ETL_USING_CPP11
1301 //*********************************************************************
1306 //*********************************************************************
1307 iterator insert(rvalue_reference value)
1308 {
1309 // Default to no inserted node
1310 Node* inserted_node = ETL_NULLPTR;
1311
1312 ETL_ASSERT(!full(), ETL_ERROR(multimap_full));
1313
1314 // Get next available free node
1315 Data_Node& node = allocate_data_node(etl::move(value));
1316
1317 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1318 inserted_node = insert_node(root_node, node);
1319
1320 // Insert node into tree and return iterator to new node location in tree
1321 return iterator(*this, inserted_node);
1322 }
1323#endif
1324
1325 //*********************************************************************
1331 //*********************************************************************
1332 iterator insert(const_iterator /*position*/, const_reference value)
1333 {
1334 // Ignore position provided and just do a normal insert
1335 return insert(value);
1336 }
1337
1338#if ETL_USING_CPP11
1339 //*********************************************************************
1345 //*********************************************************************
1346 iterator insert(const_iterator /*position*/, rvalue_reference value)
1347 {
1348 // Ignore position provided and just do a normal insert
1349 return insert(etl::move(value));
1350 }
1351#endif
1352
1353 //*********************************************************************
1360 //*********************************************************************
1361 template <class TIterator>
1362 void insert(TIterator first, TIterator last)
1363 {
1364 while (first != last)
1365 {
1366 insert(*first);
1367 ++first;
1368 }
1369 }
1370
1371 //*********************************************************************
1373 //*********************************************************************
1374 iterator emplace(const_reference value)
1375 {
1376 return insert(value);
1377 }
1378
1379#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT
1380 //*********************************************************************
1383 //*********************************************************************
1384 template <typename... Args>
1385 iterator emplace(Args&&... args)
1386 {
1387 ETL_ASSERT(!full(), ETL_ERROR(multimap_full));
1388
1389 // Get next available free node
1390 Data_Node& node = allocate_data_node_from_args(etl::forward<Args>(args)...);
1391
1392 // Obtain the inserted node
1393 Node* inserted_node = insert_node(root_node, node);
1394
1395 // Return iterator to new node location in tree
1396 return iterator(*this, inserted_node);
1397 }
1398#endif
1399
1400 //*********************************************************************
1405 //*********************************************************************
1406 iterator lower_bound(const_key_reference key)
1407 {
1408 return iterator(*this, find_lower_node(root_node, key));
1409 }
1410
1411#if ETL_USING_CPP11
1412 //*********************************************************************
1413 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1414 iterator lower_bound(const K& key)
1415 {
1416 return iterator(*this, find_lower_node(root_node, key));
1417 }
1418#endif
1419
1420 //*********************************************************************
1425 //*********************************************************************
1426 const_iterator lower_bound(const_key_reference key) const
1427 {
1428 return const_iterator(*this, find_lower_node(root_node, key));
1429 }
1430
1431#if ETL_USING_CPP11
1432 //*********************************************************************
1433 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1434 const_iterator lower_bound(const K& key) const
1435 {
1436 return const_iterator(*this, find_lower_node(root_node, key));
1437 }
1438#endif
1439
1440 //*********************************************************************
1445 //*********************************************************************
1446 iterator upper_bound(const_key_reference key)
1447 {
1448 return iterator(*this, find_upper_node(root_node, key));
1449 }
1450
1451#if ETL_USING_CPP11
1452 //*********************************************************************
1453 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1454 iterator upper_bound(const K& key)
1455 {
1456 return iterator(*this, find_upper_node(root_node, key));
1457 }
1458#endif
1459
1460 //*********************************************************************
1465 //*********************************************************************
1466 const_iterator upper_bound(const_key_reference key) const
1467 {
1468 return const_iterator(*this, find_upper_node(root_node, key));
1469 }
1470
1471#if ETL_USING_CPP11
1472 //*********************************************************************
1473 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1474 const_iterator upper_bound(const K& key) const
1475 {
1476 return const_iterator(*this, find_upper_node(root_node, key));
1477 }
1478#endif
1479
1480 //*************************************************************************
1482 //*************************************************************************
1484 {
1485 // Skip if doing self assignment
1486 if (this != &rhs)
1487 {
1488 assign(rhs.cbegin(), rhs.cend());
1489 }
1490
1491 return *this;
1492 }
1493
1494#if ETL_USING_CPP11
1495 //*************************************************************************
1497 //*************************************************************************
1499 {
1500 // Skip if doing self assignment
1501 if (this != &rhs)
1502 {
1503 this->clear();
1504
1505 iterator from = rhs.begin();
1506
1507 while (from != rhs.end())
1508 {
1509 this->insert(etl::move(*from));
1510 ++from;
1511 }
1512 }
1513
1514 return *this;
1515 }
1516#endif
1517
1518 //*************************************************************************
1520 //*************************************************************************
1521 key_compare key_comp() const
1522 {
1523 return kcompare;
1524 }
1525
1526 //*************************************************************************
1528 //*************************************************************************
1530 {
1531 return vcompare;
1532 }
1533
1534 //*************************************************************************
1536 //*************************************************************************
1537 bool contains(const TKey& key) const
1538 {
1539 return find(key) != end();
1540 }
1541
1542#if ETL_USING_CPP11
1543 //*************************************************************************
1544 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1545 bool contains(const K& k) const
1546 {
1547 return find(k) != end();
1548 }
1549#endif
1550
1551 protected:
1552
1553 //*************************************************************************
1555 //*************************************************************************
1556 imultimap(etl::ipool& node_pool, size_t max_size_)
1557 : multimap_base(max_size_)
1558 , p_node_pool(&node_pool)
1559 {
1560 }
1561
1562 //*************************************************************************
1564 //*************************************************************************
1566 {
1567 const_iterator item = begin();
1568
1569 while (item != end())
1570 {
1571 item = erase(item);
1572 }
1573 }
1574
1575 private:
1576
1577 //*************************************************************************
1579 //*************************************************************************
1580 Data_Node& allocate_data_node(const_reference value)
1581 {
1582 Data_Node* node = allocate_data_node();
1583 ::new (&node->value) const value_type(value);
1584 ETL_INCREMENT_DEBUG_COUNT;
1585 return *node;
1586 }
1587
1588#if ETL_USING_CPP11
1589 //*************************************************************************
1591 //*************************************************************************
1592 Data_Node& allocate_data_node(rvalue_reference value)
1593 {
1594 Data_Node* node = allocate_data_node();
1595 ::new (&node->value) const value_type(etl::move(value));
1596 ETL_INCREMENT_DEBUG_COUNT;
1597 return *node;
1598 }
1599
1600 #if ETL_NOT_USING_STLPORT
1601 //*************************************************************************
1603 //*************************************************************************
1604 template <typename... Args>
1605 Data_Node& allocate_data_node_from_args(Args&&... args)
1606 {
1607 Data_Node* node = allocate_data_node();
1608 ::new (&node->value) const value_type(etl::forward<Args>(args)...);
1609 ETL_INCREMENT_DEBUG_COUNT;
1610 return *node;
1611 }
1612 #endif
1613
1614#endif
1615
1616 //*************************************************************************
1618 //*************************************************************************
1619 Data_Node* allocate_data_node()
1620 {
1621 Data_Node* (etl::ipool::*func)() = &etl::ipool::allocate<Data_Node>;
1622 return (p_node_pool->*func)();
1623 }
1624
1625 //*************************************************************************
1627 //*************************************************************************
1628 void destroy_data_node(Data_Node& node)
1629 {
1630 node.value.~value_type();
1631 p_node_pool->release(&node);
1632 ETL_DECREMENT_DEBUG_COUNT;
1633 }
1634
1635 //*************************************************************************
1637 //*************************************************************************
1638 size_type count_nodes(const_key_reference key) const
1639 {
1640 // Number of nodes that match the key provided result
1641 size_type result = 0;
1642
1643 // Find lower and upper nodes for the key provided
1644 const Node* lower = find_lower_node(root_node, key);
1645 const Node* upper = find_upper_node(root_node, key);
1646
1647 // Loop from lower node to upper node and find nodes that match
1648 while (lower != upper)
1649 {
1650 // Downcast found to Data_Node class for comparison and other operations
1651 const Data_Node& data_node = imultimap::data_cast(*lower);
1652
1653 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1654 {
1655 // This node matches the key provided
1656 ++result;
1657 }
1658
1659 // Move on to the next node
1660 next_node(lower);
1661 }
1662
1663 // Return the number of nodes that match
1664 return result;
1665 }
1666
1667#if ETL_USING_CPP11
1668 //*************************************************************************
1669 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1670 size_type count_nodes(const K& key) const
1671 {
1672 // Number of nodes that match the key provided result
1673 size_type result = 0;
1674
1675 // Find lower and upper nodes for the key provided
1676 const Node* lower = find_lower_node(root_node, key);
1677 const Node* upper = find_upper_node(root_node, key);
1678
1679 // Loop from lower node to upper node and find nodes that match
1680 while (lower != upper)
1681 {
1682 // Downcast found to Data_Node class for comparison and other operations
1683 const Data_Node& data_node = imultimap::data_cast(*lower);
1684
1685 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1686 {
1687 // This node matches the key provided
1688 ++result;
1689 }
1690
1691 // Move on to the next node
1692 next_node(lower);
1693 }
1694
1695 // Return the number of nodes that match
1696 return result;
1697 }
1698#endif
1699
1700 //*************************************************************************
1702 //*************************************************************************
1703 Node* find_node(Node* position, const_key_reference key)
1704 {
1705 Node* found = ETL_NULLPTR;
1706 while (position)
1707 {
1708 // Downcast found to Data_Node class for comparison and other operations
1709 Data_Node& data_node = imultimap::data_cast(*position);
1710 // Compare the node value to the current position value
1711 if (node_comp(key, data_node))
1712 {
1713 // Keep searching for the node on the left
1714 position = position->children[(uint_least8_t)kLeft];
1715 }
1716 else if (node_comp(data_node, key))
1717 {
1718 // Keep searching for the node on the right
1719 position = position->children[(uint_least8_t)kRight];
1720 }
1721 else
1722 {
1723 // We found one, keep looking for more on the left
1724 found = position;
1725 position = position->children[(uint_least8_t)kLeft];
1726 }
1727 }
1728
1729 // Return the node found (might be ETL_NULLPTR)
1730 return found;
1731 }
1732
1733#if ETL_USING_CPP11
1734 //*************************************************************************
1735 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1736 Node* find_node(Node* position, const K& key)
1737 {
1738 Node* found = ETL_NULLPTR;
1739 while (position)
1740 {
1741 // Downcast found to Data_Node class for comparison and other operations
1742 Data_Node& data_node = imultimap::data_cast(*position);
1743 // Compare the node value to the current position value
1744 if (node_comp(key, data_node))
1745 {
1746 // Keep searching for the node on the left
1747 position = position->children[(uint_least8_t)kLeft];
1748 }
1749 else if (node_comp(data_node, key))
1750 {
1751 // Keep searching for the node on the right
1752 position = position->children[(uint_least8_t)kRight];
1753 }
1754 else
1755 {
1756 // We found one, keep looking for more on the left
1757 found = position;
1758 position = position->children[(uint_least8_t)kLeft];
1759 }
1760 }
1761
1762 // Return the node found (might be ETL_NULLPTR)
1763 return found;
1764 }
1765#endif
1766
1767 //*************************************************************************
1769 //*************************************************************************
1770 const Node* find_node(const Node* position, const_key_reference key) const
1771 {
1772 const Node* found = ETL_NULLPTR;
1773 while (position)
1774 {
1775 // Downcast found to Data_Node class for comparison and other operations
1776 const Data_Node& data_node = imultimap::data_cast(*position);
1777 // Compare the node value to the current position value
1778 if (node_comp(key, data_node))
1779 {
1780 // Keep searching for the node on the left
1781 position = position->children[(uint_least8_t)kLeft];
1782 }
1783 else if (node_comp(data_node, key))
1784 {
1785 // Keep searching for the node on the right
1786 position = position->children[(uint_least8_t)kRight];
1787 }
1788 else
1789 {
1790 // We found one, keep looking for more on the left
1791 found = position;
1792 position = position->children[(uint_least8_t)kLeft];
1793 }
1794 }
1795
1796 // Return the node found (might be ETL_NULLPTR)
1797 return found;
1798 }
1799
1800#if ETL_USING_CPP11
1801 //*************************************************************************
1803 //*************************************************************************
1804 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1805 const Node* find_node(const Node* position, const K& key) const
1806 {
1807 const Node* found = ETL_NULLPTR;
1808 while (position)
1809 {
1810 // Downcast found to Data_Node class for comparison and other operations
1811 const Data_Node& data_node = imultimap::data_cast(*position);
1812 // Compare the node value to the current position value
1813 if (node_comp(key, data_node))
1814 {
1815 // Keep searching for the node on the left
1816 position = position->children[(uint_least8_t)kLeft];
1817 }
1818 else if (node_comp(data_node, key))
1819 {
1820 // Keep searching for the node on the right
1821 position = position->children[(uint_least8_t)kRight];
1822 }
1823 else
1824 {
1825 // We found one, keep looking for more on the left
1826 found = position;
1827 position = position->children[(uint_least8_t)kLeft];
1828 }
1829 }
1830
1831 // Return the node found (might be ETL_NULLPTR)
1832 return found;
1833 }
1834#endif
1835
1836 //*************************************************************************
1838 //*************************************************************************
1839 Node* find_lower_node(Node* position, const_key_reference key) const
1840 {
1841 // Something at this position? keep going
1842 Node* lower_node = ETL_NULLPTR;
1843 while (position)
1844 {
1845 // Downcast lower node to Data_Node reference for key comparisons
1846 Data_Node& data_node = imultimap::data_cast(*position);
1847 // Compare the key value to the current lower node key value
1848 if (node_comp(key, data_node))
1849 {
1850 lower_node = position;
1851 if (position->children[(uint_least8_t)kLeft])
1852 {
1853 position = position->children[(uint_least8_t)kLeft];
1854 }
1855 else
1856 {
1857 // Found lowest node
1858 break;
1859 }
1860 }
1861 else if (node_comp(data_node, key))
1862 {
1863 position = position->children[(uint_least8_t)kRight];
1864 }
1865 else
1866 {
1867 // Make note of current position, but keep looking to left for more
1868 lower_node = position;
1869 position = position->children[(uint_least8_t)kLeft];
1870 }
1871 }
1872
1873 // Return the lower_node position found
1874 return lower_node;
1875 }
1876
1877#if ETL_USING_CPP11
1878 //*************************************************************************
1879 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1880 Node* find_lower_node(Node* position, const K& key) const
1881 {
1882 // Something at this position? keep going
1883 Node* lower_node = ETL_NULLPTR;
1884 while (position)
1885 {
1886 // Downcast lower node to Data_Node reference for key comparisons
1887 Data_Node& data_node = imultimap::data_cast(*position);
1888 // Compare the key value to the current lower node key value
1889 if (node_comp(key, data_node))
1890 {
1891 lower_node = position;
1892 if (position->children[(uint_least8_t)kLeft])
1893 {
1894 position = position->children[(uint_least8_t)kLeft];
1895 }
1896 else
1897 {
1898 // Found lowest node
1899 break;
1900 }
1901 }
1902 else if (node_comp(data_node, key))
1903 {
1904 position = position->children[(uint_least8_t)kRight];
1905 }
1906 else
1907 {
1908 // Make note of current position, but keep looking to left for more
1909 lower_node = position;
1910 position = position->children[(uint_least8_t)kLeft];
1911 }
1912 }
1913
1914 // Return the lower_node position found
1915 return lower_node;
1916 }
1917#endif
1918
1919 //*************************************************************************
1921 //*************************************************************************
1922 Node* find_upper_node(Node* position, const_key_reference key) const
1923 {
1924 // Keep track of parent of last upper node
1925 Node* upper_node = ETL_NULLPTR;
1926 // Has an equal node been found? start with no
1927 bool found = false;
1928 while (position)
1929 {
1930 // Downcast position to Data_Node reference for key comparisons
1931 Data_Node& data_node = imultimap::data_cast(*position);
1932 // Compare the key value to the current upper node key value
1933 if (node_comp(data_node, key))
1934 {
1935 position = position->children[(uint_least8_t)kRight];
1936 }
1937 else if (node_comp(key, data_node))
1938 {
1939 upper_node = position;
1940 // If a node equal to key hasn't been found go left
1941 if (!found && position->children[(uint_least8_t)kLeft])
1942 {
1943 position = position->children[(uint_least8_t)kLeft];
1944 }
1945 else
1946 {
1947 break;
1948 }
1949 }
1950 else
1951 {
1952 // We found an equal item, break on next bigger item
1953 found = true;
1954 next_node(position);
1955 }
1956 }
1957
1958 // Return the upper node position found (might be ETL_NULLPTR)
1959 return upper_node;
1960 }
1961
1962#if ETL_USING_CPP11
1963 //*************************************************************************
1964 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1965 Node* find_upper_node(Node* position, const K& key) const
1966 {
1967 // Keep track of parent of last upper node
1968 Node* upper_node = ETL_NULLPTR;
1969 // Has an equal node been found? start with no
1970 bool found = false;
1971 while (position)
1972 {
1973 // Downcast position to Data_Node reference for key comparisons
1974 Data_Node& data_node = imultimap::data_cast(*position);
1975 // Compare the key value to the current upper node key value
1976 if (node_comp(data_node, key))
1977 {
1978 position = position->children[(uint_least8_t)kRight];
1979 }
1980 else if (node_comp(key, data_node))
1981 {
1982 upper_node = position;
1983 // If a node equal to key hasn't been found go left
1984 if (!found && position->children[(uint_least8_t)kLeft])
1985 {
1986 position = position->children[(uint_least8_t)kLeft];
1987 }
1988 else
1989 {
1990 break;
1991 }
1992 }
1993 else
1994 {
1995 // We found an equal item, break on next bigger item
1996 found = true;
1997 next_node(position);
1998 }
1999 }
2000
2001 // Return the upper node position found (might be ETL_NULLPTR)
2002 return upper_node;
2003 }
2004#endif
2005
2006 //*************************************************************************
2008 //*************************************************************************
2009 Node* insert_node(Node*& position, Data_Node& node)
2010 {
2011 // Find the location where the node belongs
2012 Node* found = position;
2013
2014 // Was position provided not empty? then find where the node belongs
2015 if (position)
2016 {
2017 // Find the critical parent node (default to ETL_NULLPTR)
2018 Node* critical_parent_node = ETL_NULLPTR;
2019 Node* critical_node = root_node;
2020
2021 while (found)
2022 {
2023 // Search for critical weight node (all nodes whose weight factor
2024 // is set to (uint_least8_t) kNeither (balanced)
2025 if ((uint_least8_t)kNeither != found->weight)
2026 {
2027 critical_node = found;
2028 }
2029
2030 // Downcast found to Data_Node class for comparison and other
2031 // operations
2032 Data_Node& found_data_node = imultimap::data_cast(*found);
2033
2034 // Is the node provided to the left of the current position?
2035 if (node_comp(node, found_data_node))
2036 {
2037 // Update direction taken to insert new node in parent node
2038 found->dir = (uint_least8_t)kLeft;
2039 }
2040 // Is the node provided to the right of the current position?
2041 else if (node_comp(found_data_node, node))
2042 {
2043 // Update direction taken to insert new node in parent node
2044 found->dir = (uint_least8_t)kRight;
2045 }
2046 else
2047 {
2048 // Update direction taken to insert new node in parent (and
2049 // duplicate) node to the right.
2050 found->dir = (uint_least8_t)kRight;
2051 }
2052
2053 // Is there a child of this parent node?
2054 if (found->children[found->dir])
2055 {
2056 // Will this node be the parent of the next critical node whose
2057 // weight factor is set to (uint_least8_t) kNeither (balanced)?
2058 if ((uint_least8_t)kNeither != found->children[found->dir]->weight)
2059 {
2060 critical_parent_node = found;
2061 }
2062
2063 // Keep looking for empty spot to insert new node
2064 found = found->children[found->dir];
2065 }
2066 else
2067 {
2068 // Attach node as a child of the parent node found
2069 attach_node(found, found->children[found->dir], node);
2070
2071 // Return newly added node
2072 found = found->children[found->dir];
2073
2074 // Exit loop
2075 break;
2076 }
2077 }
2078
2079 // Was a critical node found that should be checked for balance?
2080 if (critical_node)
2081 {
2082 if (critical_parent_node == ETL_NULLPTR && critical_node == root_node)
2083 {
2085 }
2086 else if (critical_parent_node == ETL_NULLPTR && critical_node == position)
2087 {
2088 balance_node(position);
2089 }
2090 else
2091 {
2092 if (critical_parent_node != ETL_NULLPTR)
2093 {
2094 balance_node(critical_parent_node->children[critical_parent_node->dir]);
2095 }
2096 }
2097 }
2098 }
2099 else
2100 {
2101 // Attach node to current position (which is assumed to be root)
2102 attach_node(ETL_NULLPTR, position, node);
2103
2104 // Return newly added node at current position
2105 found = position;
2106 }
2107
2108 // Return the node found (might be ETL_NULLPTR)
2109 return found;
2110 }
2111
2112 //*************************************************************************
2115 //*************************************************************************
2116 void remove_node(Node* node)
2117 {
2118 // If valid found node was provided then proceed with steps 1 through 5
2119 if (node)
2120 {
2121 // Downcast found node provided to Data_Node class
2122 Data_Node& data_node = imultimap::data_cast(*node);
2123
2124 // Keep track of node as found node
2125 Node* found = node;
2126
2127 // Step 1: Mark path from node provided back to the root node using the
2128 // internal temporary dir member value and using the parent pointer.
2129 // This will allow us to avoid recursion in finding the node in a tree
2130 // that might contain duplicate keys to be found.
2131 while (node)
2132 {
2133 if (node->parent)
2134 {
2135 // Which direction does parent use to get to this node?
2136 node->parent->dir = node->parent->children[(uint_least8_t)kLeft] == node ? (uint_least8_t)kLeft : (uint_least8_t)kRight;
2137
2138 // Make this nodes parent the next node
2139 node = node->parent;
2140 }
2141 else
2142 {
2143 // Root node found - break loop
2144 break;
2145 }
2146 }
2147
2148 // Step 2: Follow the path provided above until we reach the node
2149 // provided and look for the balance node to start rebalancing the tree
2150 // from (up to the replacement node that will be found in step 3)
2151 Node* balance = root_node;
2152 while (node)
2153 {
2154 // Did we reach the node provided originally (found) then go to step 3
2155 if (node == found)
2156 {
2157 // Update the direction towards a replacement node at the found node
2158 node->dir = node->children[(uint_least8_t)kLeft] ? (uint_least8_t)kLeft : (uint_least8_t)kRight;
2159
2160 // Exit loop and proceed with step 3
2161 break;
2162 }
2163 else
2164 {
2165 // If this nodes weight is (uint_least8_t) kNeither or we are taking
2166 // the shorter path to the next node and our sibling (on longer
2167 // path) is balanced then we need to update the balance node to this
2168 // node but all our ancestors will not require rebalancing
2169 if ((node->weight == (uint_least8_t)kNeither)
2170 || (node->weight == (1 - node->dir) && node->children[1 - node->dir]->weight == (uint_least8_t)kNeither))
2171 {
2172 // Update balance node to this node
2173 balance = node;
2174 }
2175
2176 // Keep searching for found in the direction provided in step 1
2177 node = node->children[node->dir];
2178 }
2179 }
2180 // The value for node should not be ETL_NULLPTR at this point otherwise
2181 // step 1 failed to provide the correct path to found. Step 5 will fail
2182 // (probably subtly) if node should be ETL_NULLPTR at this point
2183
2184 // Step 3: Find the node (node should be equal to found at this point)
2185 // to replace found with (might end up equal to found) while also
2186 // continuing to update balance the same as in step 2 above.
2187 while (node)
2188 {
2189 // Replacement node found if its missing a child in the replace->dir
2190 // value set at the end of step 2 above
2191 if (node->children[node->dir] == ETL_NULLPTR)
2192 {
2193 // Exit loop once node to replace found is determined
2194 break;
2195 }
2196
2197 // If this nodes weight is (uint_least8_t) kNeither or we are taking
2198 // the shorter path to the next node and our sibling (on longer path)
2199 // is balanced then we need to update the balance node to this node
2200 // but all our ancestors will not require rebalancing
2201 if ((node->weight == (uint_least8_t)kNeither)
2202 || (node->weight == (1 - node->dir) && node->children[1 - node->dir]->weight == (uint_least8_t)kNeither))
2203 {
2204 // Update balance node to this node
2205 balance = node;
2206 }
2207
2208 // Keep searching for replacement node in the direction specified
2209 // above
2210 node = node->children[node->dir];
2211
2212 // Downcast node to Data_Node class for comparison operations
2213 Data_Node& replace_data_node = imultimap::data_cast(*node);
2214
2215 // Compare the key provided to the replace data node key
2216 if (node_comp(data_node, replace_data_node))
2217 {
2218 // Update the direction to the replace node
2219 node->dir = (uint_least8_t)kLeft;
2220 }
2221 else if (node_comp(replace_data_node, data_node))
2222 {
2223 // Update the direction to the replace node
2224 node->dir = (uint_least8_t)kRight;
2225 }
2226 else
2227 {
2228 // Update the direction to the replace node
2229 node->dir = 1 - found->dir;
2230 }
2231 } // while(node)
2232
2233 // Step 4: Update weights from balance to parent of node determined
2234 // in step 3 above rotating (2 or 3 node rotations) as needed.
2235 while (balance)
2236 {
2237 // Break when balance node reaches the parent of replacement node
2238 if (balance->children[balance->dir] == ETL_NULLPTR)
2239 {
2240 break;
2241 }
2242
2243 // If balance node is balanced already ((uint_least8_t) kNeither) then
2244 // just imbalance the node in the opposite direction of the node being
2245 // removed
2246 if (balance->weight == (uint_least8_t)kNeither)
2247 {
2248 balance->weight = 1 - balance->dir;
2249 }
2250 // If balance node is imbalanced in the opposite direction of the
2251 // node being removed then the node now becomes balanced
2252 else if (balance->weight == balance->dir)
2253 {
2254 balance->weight = (uint_least8_t)kNeither;
2255 }
2256 // Otherwise a rotation is required at this node
2257 else
2258 {
2259 int weight = balance->children[1 - balance->dir]->weight;
2260 // Perform a 3 node rotation if weight is same as balance->dir
2261 if (weight == balance->dir)
2262 {
2263 // Is the root node being rebalanced (no parent)
2264 if (balance->parent == ETL_NULLPTR)
2265 {
2266 rotate_3node(root_node, 1 - balance->dir, balance->children[1 - balance->dir]->children[balance->dir]->weight);
2267 }
2268 else
2269 {
2270 rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
2271 balance->children[1 - balance->dir]->children[balance->dir]->weight);
2272 }
2273 }
2274 // Already balanced, rebalance and make it heavy in opposite
2275 // direction of the node being removed
2276 else if (weight == (uint_least8_t)kNeither)
2277 {
2278 // Is the root node being rebalanced (no parent)
2279 if (balance->parent == ETL_NULLPTR)
2280 {
2281 rotate_2node(root_node, 1 - balance->dir);
2282 root_node->weight = balance->dir;
2283 }
2284 else
2285 {
2286 // Balance parent might change during rotate, keep local copy
2287 // to old parent so its weight can be updated after the 2 node
2288 // rotate is completed
2289 Node* old_parent = balance->parent;
2290 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2291 old_parent->children[old_parent->dir]->weight = balance->dir;
2292 }
2293 // Update balance node weight in opposite direction of node
2294 // removed
2295 balance->weight = 1 - balance->dir;
2296 }
2297 // Rebalance and leave it balanced
2298 else
2299 {
2300 // Is the root node being rebalanced (no parent)
2301 if (balance->parent == ETL_NULLPTR)
2302 {
2303 rotate_2node(root_node, 1 - balance->dir);
2304 }
2305 else
2306 {
2307 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2308 }
2309 }
2310 }
2311
2312 // Next balance node to consider
2313 balance = balance->children[balance->dir];
2314 } // while(balance)
2315
2316 // Step 5: Swap found with node (replacement)
2317 if (found->parent)
2318 {
2319 // Handle traditional case
2320 detach_node(found->parent->children[found->parent->dir], node->parent->children[node->parent->dir]);
2321 }
2322 // Handle root node removal
2323 else
2324 {
2325 // Valid replacement node for root node being removed?
2326 if (node->parent)
2327 {
2328 detach_node(root_node, node->parent->children[node->parent->dir]);
2329 }
2330 else
2331 {
2332 // Found node and replacement node are both root node
2334 }
2335 }
2336
2337 // One less.
2338 --current_size;
2339
2340 // Destroy the node detached above
2341 destroy_data_node(data_node);
2342 } // if(found)
2343 }
2344
2345 // Disable copy construction.
2346 imultimap(const imultimap&);
2347
2348 //*************************************************************************
2350 //*************************************************************************
2351#if defined(ETL_POLYMORPHIC_MULTIMAP) || defined(ETL_POLYMORPHIC_CONTAINERS)
2352
2353 public:
2354
2355 virtual ~imultimap() {}
2356#else
2357
2358 protected:
2359
2361#endif
2362 };
2363
2364 //*************************************************************************
2366 //*************************************************************************
2367 template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = etl::less<TKey> >
2368 class multimap : public etl::imultimap<TKey, TValue, TCompare>
2369 {
2370 public:
2371
2372 static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_;
2373
2374 //*************************************************************************
2376 //*************************************************************************
2378 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2379 {
2380 this->initialise();
2381 }
2382
2383 //*************************************************************************
2385 //*************************************************************************
2386 multimap(const multimap& other)
2387 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2388 {
2389 if (this != &other)
2390 {
2391 this->assign(other.cbegin(), other.cend());
2392 }
2393 }
2394
2395#if ETL_USING_CPP11
2396 //*************************************************************************
2398 //*************************************************************************
2399 multimap(multimap&& other)
2400 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2401 {
2402 if (this != &other)
2403 {
2404 typename etl::imultimap<TKey, TValue, TCompare>::iterator from = other.begin();
2405
2406 while (from != other.end())
2407 {
2409 ++temp;
2410
2411 this->insert(etl::move(*from));
2412 from = temp;
2413 }
2414 }
2415 }
2416#endif
2417
2418 //*************************************************************************
2423 //*************************************************************************
2424 template <typename TIterator>
2425 multimap(TIterator first, TIterator last)
2426 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2427 {
2428 this->assign(first, last);
2429 }
2430
2431#if ETL_HAS_INITIALIZER_LIST
2432 //*************************************************************************
2434 //*************************************************************************
2435 multimap(std::initializer_list< typename etl::imultimap<TKey, TValue, TCompare>::value_type> init)
2436 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2437 {
2438 this->assign(init.begin(), init.end());
2439 }
2440#endif
2441
2442 //*************************************************************************
2444 //*************************************************************************
2446 {
2447 this->initialise();
2448 }
2449
2450 //*************************************************************************
2452 //*************************************************************************
2454 {
2455 // Skip if doing self assignment
2456 if (this != &rhs)
2457 {
2458 this->assign(rhs.cbegin(), rhs.cend());
2459 }
2460
2461 return *this;
2462 }
2463
2464#if ETL_USING_CPP11
2465 //*************************************************************************
2467 //*************************************************************************
2468 multimap& operator=(multimap&& rhs)
2469 {
2470 if (this != &rhs)
2471 {
2472 typename etl::imultimap<TKey, TValue, TCompare>::iterator from = rhs.begin();
2473
2474 while (from != rhs.end())
2475 {
2477 ++temp;
2478
2479 this->insert(etl::move(*from));
2480 from = temp;
2481 }
2482 }
2483
2484 return *this;
2485 }
2486#endif
2487
2488 private:
2489
2491 etl::pool<typename etl::imultimap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool;
2492 };
2493
2494 template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare>
2495 ETL_CONSTANT size_t multimap<TKey, TValue, MAX_SIZE_, TCompare>::MAX_SIZE;
2496
2497 //*************************************************************************
2499 //*************************************************************************
2500#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
2501 template <typename... TPairs>
2502 multimap(TPairs...)
2503 -> multimap<typename etl::nth_type_t<0, TPairs...>::first_type, typename etl::nth_type_t<0, TPairs...>::second_type, sizeof...(TPairs)>;
2504#endif
2505
2506 //*************************************************************************
2508 //*************************************************************************
2509#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
2510 template <typename TKey, typename TMapped, typename TKeyCompare = etl::less<TKey>, typename... TPairs>
2511 constexpr auto make_multimap(TPairs&&... pairs) -> etl::multimap<TKey, TMapped, sizeof...(TPairs), TKeyCompare>
2512 {
2513 return {etl::forward<TPairs>(pairs)...};
2514 }
2515#endif
2516
2517 //***************************************************************************
2523 //***************************************************************************
2524 template <typename TKey, typename TMapped, typename TKeyCompare>
2526 {
2527 return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
2528 }
2529
2530 //***************************************************************************
2536 //***************************************************************************
2537 template <typename TKey, typename TMapped, typename TKeyCompare>
2539 {
2540 return !(lhs == rhs);
2541 }
2542
2543 //*************************************************************************
2549 //*************************************************************************
2550 template <typename TKey, typename TMapped, typename TKeyCompare>
2552 {
2553 return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), lhs.value_comp());
2554 }
2555
2556 //*************************************************************************
2562 //*************************************************************************
2563 template <typename TKey, typename TMapped, typename TKeyCompare>
2565 {
2566 return (rhs < lhs);
2567 }
2568
2569 //*************************************************************************
2576 //*************************************************************************
2577 template <typename TKey, typename TMapped, typename TKeyCompare>
2579 {
2580 return !(lhs > rhs);
2581 }
2582
2583 //*************************************************************************
2589 //*************************************************************************
2590 template <typename TKey, typename TMapped, typename TKeyCompare>
2592 {
2593 return !(lhs < rhs);
2594 }
2595} // namespace etl
2596
2597#include "private/minmax_pop.h"
2598
2599#endif
const_iterator
Definition multimap.h:862
iterator.
Definition multimap.h:758
Definition multimap.h:652
A templated multimap implementation that uses a fixed size buffer.
Definition multimap.h:2369
multimap(TIterator first, TIterator last)
Definition multimap.h:2425
multimap & operator=(const multimap &rhs)
Assignment operator.
Definition multimap.h:2453
multimap()
Default constructor.
Definition multimap.h:2377
~multimap()
Destructor.
Definition multimap.h:2445
multimap(const multimap &other)
Copy constructor.
Definition multimap.h:2386
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
ETL_EXCEPTION_CONSTEXPR exception(string_type reason_, string_type, numeric_type)
Constructor.
Definition exception.h:81
Definition exception.h:59
void assign(TIterator first, TIterator last)
Definition multimap.h:1083
bool contains(const TKey &key) const
Check if the map contains the key.
Definition multimap.h:1537
iterator find(const_key_reference key)
Definition multimap.h:1244
void attach_node(Node *parent, Node *&position, Node &node)
Attach the provided node to the position provided.
Definition multimap.h:565
reverse_iterator rend()
Gets the reverse end of the list.
Definition multimap.h:1045
reverse_iterator rbegin()
Gets the reverse beginning of the list.
Definition multimap.h:1029
size_type size() const
Gets the size of the map.
Definition multimap.h:131
size_type current_size
The number of the used nodes.
Definition multimap.h:618
void next_node(const Node *&position) const
Find the next node in sequence from the node provided.
Definition multimap.h:440
iterator lower_bound(const_key_reference key)
Definition multimap.h:1406
const_reverse_iterator rbegin() const
Gets the reverse beginning of the list.
Definition multimap.h:1037
const_iterator upper_bound(const_key_reference key) const
Definition multimap.h:1466
multimap_base(size_type max_size_)
The constructor that is called from derived classes.
Definition multimap.h:225
const_iterator find(const_key_reference key) const
Definition multimap.h:1263
imultimap & operator=(const imultimap &rhs)
Assignment operator.
Definition multimap.h:1483
iterator insert(const_reference value)
Definition multimap.h:1283
bool node_comp(const Data_Node &node1, const Data_Node &node2) const
How to compare node elements.
Definition multimap.h:683
iterator erase(const_iterator first, const_iterator last)
Erases a range of elements.
Definition multimap.h:1229
ETL_OR_STD::pair< iterator, iterator > equal_range(const_key_reference key)
Definition multimap.h:1120
~multimap_base()
The constructor that is called from derived classes.
Definition multimap.h:235
void prev_node(const Node *&position) const
Find the previous node in sequence from the node provided.
Definition multimap.h:510
size_t available() const
Definition multimap.h:173
iterator end()
Gets the end of the multimap.
Definition multimap.h:997
void clear()
Clears the multimap.
Definition multimap.h:1092
void rotate_2node(Node *&position, uint_least8_t dir)
Rotate two nodes at the position provided the to balance the tree.
Definition multimap.h:309
iterator erase(iterator position)
Erases the value at the specified position.
Definition multimap.h:1159
const size_type CAPACITY
The maximum size of the map.
Definition multimap.h:619
void detach_node(Node *&position, Node *&replacement)
Detach the node at the position provided.
Definition multimap.h:583
const_reverse_iterator rend() const
Gets the reverse end of the list.
Definition multimap.h:1053
const_iterator end() const
Gets the end of the multimap.
Definition multimap.h:1005
key_compare key_comp() const
How to compare two key elements.
Definition multimap.h:1521
const_iterator cend() const
Gets the end of the multimap.
Definition multimap.h:1021
iterator insert(const_iterator, const_reference value)
Definition multimap.h:1332
bool empty() const
Checks to see if the map is empty.
Definition multimap.h:147
void next_node(Node *&position) const
Find the next node in sequence from the node provided.
Definition multimap.h:407
size_type capacity() const
Definition multimap.h:164
void prev_node(Node *&position) const
Find the previous node in sequence from the node provided.
Definition multimap.h:472
Node * root_node
The node that acts as the multimap root.
Definition multimap.h:620
size_t size_type
The type used for determining the size of map.
Definition multimap.h:126
const_reverse_iterator crbegin() const
Gets the reverse beginning of the list.
Definition multimap.h:1061
iterator begin()
Gets the beginning of the multimap.
Definition multimap.h:981
iterator emplace(const_reference value)
Emplaces a value to the multimap.
Definition multimap.h:1374
void insert(TIterator first, TIterator last)
Definition multimap.h:1362
const_iterator lower_bound(const_key_reference key) const
Definition multimap.h:1426
size_type max_size() const
Gets the maximum possible size of the map.
Definition multimap.h:139
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(const_key_reference key) const
Definition multimap.h:1140
const_iterator cbegin() const
Gets the beginning of the multimap.
Definition multimap.h:1013
iterator upper_bound(const_key_reference key)
Definition multimap.h:1446
size_type count(const_key_reference key) const
Definition multimap.h:1102
const_reverse_iterator crend() const
Gets the reverse end of the list.
Definition multimap.h:1069
void initialise()
Initialise the multimap.
Definition multimap.h:1565
imultimap(etl::ipool &node_pool, size_t max_size_)
Constructor.
Definition multimap.h:1556
value_compare value_comp() const
How to compare two value elements.
Definition multimap.h:1529
void rotate_3node(Node *&position, uint_least8_t dir, uint_least8_t third)
Rotate three nodes at the position provided the to balance the tree.
Definition multimap.h:350
Node * find_limit_node(Node *position, const int8_t dir) const
Definition multimap.h:549
const_iterator begin() const
Gets the beginning of the multimap.
Definition multimap.h:989
bool full() const
Checks to see if the map is full.
Definition multimap.h:155
~imultimap()
Destructor.
Definition multimap.h:2360
iterator erase(const_iterator position)
Erases the value at the specified position.
Definition multimap.h:1168
void balance_node(Node *&critical_node)
Balance the critical node at the position provided as needed.
Definition multimap.h:240
Definition multimap.h:630
Definition multimap.h:123
Definition multimap.h:67
Definition multimap.h:81
T * allocate()
Definition ipool.h:334
Definition ipool.h:110
Definition absolute.h:40
ETL_CONSTEXPR14 void swap(etl::typed_storage_ext< T > &lhs, etl::typed_storage_ext< T > &rhs) ETL_NOEXCEPT
Swap two etl::typed_storage_ext.
Definition alignment.h:856
ETL_CONSTEXPR14 bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1078
bool operator>(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1130
bool operator>=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1144
ETL_CONSTEXPR14 bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1090
bool operator<(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1103
bool operator<=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1117
The data node element in the multimap.
Definition multimap.h:671
iterator
Definition iterator.h:482
The node element in the multimap.
Definition multimap.h:191
Node()
Constructor.
Definition multimap.h:195
void mark_as_leaf()
Marks the node as a leaf.
Definition multimap.h:207
ETL_CONSTEXPR14 bool operator==(const etl::to_arithmetic_result< T > &lhs, const etl::to_arithmetic_result< T > &rhs)
Equality test for etl::to_arithmetic_result.
Definition to_arithmetic.h:903
ETL_CONSTEXPR14 bool operator!=(const etl::to_arithmetic_result< T > &lhs, const etl::to_arithmetic_result< T > &rhs)
Inequality test for etl::to_arithmetic_result.
Definition to_arithmetic.h:937