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