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 //*********************************************************************
1376 //*********************************************************************
1377 iterator lower_bound(const_key_reference key)
1378 {
1379 return iterator(*this, find_lower_node(root_node, key));
1380 }
1381
1382#if ETL_USING_CPP11
1383 //*********************************************************************
1384 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1385 iterator lower_bound(const K& key)
1386 {
1387 return iterator(*this, find_lower_node(root_node, key));
1388 }
1389#endif
1390
1391 //*********************************************************************
1396 //*********************************************************************
1397 const_iterator lower_bound(const_key_reference key) const
1398 {
1399 return const_iterator(*this, find_lower_node(root_node, key));
1400 }
1401
1402#if ETL_USING_CPP11
1403 //*********************************************************************
1404 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1405 const_iterator lower_bound(const K& key) const
1406 {
1407 return const_iterator(*this, find_lower_node(root_node, key));
1408 }
1409#endif
1410
1411 //*********************************************************************
1416 //*********************************************************************
1417 iterator upper_bound(const_key_reference key)
1418 {
1419 return iterator(*this, find_upper_node(root_node, key));
1420 }
1421
1422#if ETL_USING_CPP11
1423 //*********************************************************************
1424 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1425 iterator upper_bound(const K& key)
1426 {
1427 return iterator(*this, find_upper_node(root_node, key));
1428 }
1429#endif
1430
1431 //*********************************************************************
1436 //*********************************************************************
1437 const_iterator upper_bound(const_key_reference key) const
1438 {
1439 return const_iterator(*this, find_upper_node(root_node, key));
1440 }
1441
1442#if ETL_USING_CPP11
1443 //*********************************************************************
1444 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1445 const_iterator upper_bound(const K& key) const
1446 {
1447 return const_iterator(*this, find_upper_node(root_node, key));
1448 }
1449#endif
1450
1451 //*************************************************************************
1453 //*************************************************************************
1455 {
1456 // Skip if doing self assignment
1457 if (this != &rhs)
1458 {
1459 assign(rhs.cbegin(), rhs.cend());
1460 }
1461
1462 return *this;
1463 }
1464
1465#if ETL_USING_CPP11
1466 //*************************************************************************
1468 //*************************************************************************
1470 {
1471 // Skip if doing self assignment
1472 if (this != &rhs)
1473 {
1474 this->clear();
1475
1476 iterator from = rhs.begin();
1477
1478 while (from != rhs.end())
1479 {
1480 this->insert(etl::move(*from));
1481 ++from;
1482 }
1483 }
1484
1485 return *this;
1486 }
1487#endif
1488
1489 //*************************************************************************
1491 //*************************************************************************
1492 key_compare key_comp() const
1493 {
1494 return kcompare;
1495 }
1496
1497 //*************************************************************************
1499 //*************************************************************************
1501 {
1502 return vcompare;
1503 }
1504
1505 //*************************************************************************
1507 //*************************************************************************
1508 bool contains(const TKey& key) const
1509 {
1510 return find(key) != end();
1511 }
1512
1513#if ETL_USING_CPP11
1514 //*************************************************************************
1515 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1516 bool contains(const K& k) const
1517 {
1518 return find(k) != end();
1519 }
1520#endif
1521
1522 protected:
1523
1524 //*************************************************************************
1526 //*************************************************************************
1527 imultimap(etl::ipool& node_pool, size_t max_size_)
1528 : multimap_base(max_size_)
1529 , p_node_pool(&node_pool)
1530 {
1531 }
1532
1533 //*************************************************************************
1535 //*************************************************************************
1537 {
1538 const_iterator item = begin();
1539
1540 while (item != end())
1541 {
1542 item = erase(item);
1543 }
1544 }
1545
1546 private:
1547
1548 //*************************************************************************
1550 //*************************************************************************
1551 Data_Node& allocate_data_node(const_reference value)
1552 {
1553 Data_Node* node = allocate_data_node();
1554 ::new (&node->value) const value_type(value);
1555 ETL_INCREMENT_DEBUG_COUNT;
1556 return *node;
1557 }
1558
1559#if ETL_USING_CPP11
1560 //*************************************************************************
1562 //*************************************************************************
1563 Data_Node& allocate_data_node(rvalue_reference value)
1564 {
1565 Data_Node* node = allocate_data_node();
1566 ::new (&node->value) const value_type(etl::move(value));
1567 ETL_INCREMENT_DEBUG_COUNT;
1568 return *node;
1569 }
1570#endif
1571
1572 //*************************************************************************
1574 //*************************************************************************
1575 Data_Node* allocate_data_node()
1576 {
1577 Data_Node* (etl::ipool::*func)() = &etl::ipool::allocate<Data_Node>;
1578 return (p_node_pool->*func)();
1579 }
1580
1581 //*************************************************************************
1583 //*************************************************************************
1584 void destroy_data_node(Data_Node& node)
1585 {
1586 node.value.~value_type();
1587 p_node_pool->release(&node);
1588 ETL_DECREMENT_DEBUG_COUNT;
1589 }
1590
1591 //*************************************************************************
1593 //*************************************************************************
1594 size_type count_nodes(const_key_reference key) const
1595 {
1596 // Number of nodes that match the key provided result
1597 size_type result = 0;
1598
1599 // Find lower and upper nodes for the key provided
1600 const Node* lower = find_lower_node(root_node, key);
1601 const Node* upper = find_upper_node(root_node, key);
1602
1603 // Loop from lower node to upper node and find nodes that match
1604 while (lower != upper)
1605 {
1606 // Downcast found to Data_Node class for comparison and other operations
1607 const Data_Node& data_node = imultimap::data_cast(*lower);
1608
1609 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1610 {
1611 // This node matches the key provided
1612 ++result;
1613 }
1614
1615 // Move on to the next node
1616 next_node(lower);
1617 }
1618
1619 // Return the number of nodes that match
1620 return result;
1621 }
1622
1623#if ETL_USING_CPP11
1624 //*************************************************************************
1625 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1626 size_type count_nodes(const K& key) const
1627 {
1628 // Number of nodes that match the key provided result
1629 size_type result = 0;
1630
1631 // Find lower and upper nodes for the key provided
1632 const Node* lower = find_lower_node(root_node, key);
1633 const Node* upper = find_upper_node(root_node, key);
1634
1635 // Loop from lower node to upper node and find nodes that match
1636 while (lower != upper)
1637 {
1638 // Downcast found to Data_Node class for comparison and other operations
1639 const Data_Node& data_node = imultimap::data_cast(*lower);
1640
1641 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1642 {
1643 // This node matches the key provided
1644 ++result;
1645 }
1646
1647 // Move on to the next node
1648 next_node(lower);
1649 }
1650
1651 // Return the number of nodes that match
1652 return result;
1653 }
1654#endif
1655
1656 //*************************************************************************
1658 //*************************************************************************
1659 Node* find_node(Node* position, const_key_reference key)
1660 {
1661 Node* found = ETL_NULLPTR;
1662 while (position)
1663 {
1664 // Downcast found to Data_Node class for comparison and other operations
1665 Data_Node& data_node = imultimap::data_cast(*position);
1666 // Compare the node value to the current position value
1667 if (node_comp(key, data_node))
1668 {
1669 // Keep searching for the node on the left
1670 position = position->children[(uint_least8_t)kLeft];
1671 }
1672 else if (node_comp(data_node, key))
1673 {
1674 // Keep searching for the node on the right
1675 position = position->children[(uint_least8_t)kRight];
1676 }
1677 else
1678 {
1679 // We found one, keep looking for more on the left
1680 found = position;
1681 position = position->children[(uint_least8_t)kLeft];
1682 }
1683 }
1684
1685 // Return the node found (might be ETL_NULLPTR)
1686 return found;
1687 }
1688
1689#if ETL_USING_CPP11
1690 //*************************************************************************
1691 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1692 Node* find_node(Node* position, const K& key)
1693 {
1694 Node* found = ETL_NULLPTR;
1695 while (position)
1696 {
1697 // Downcast found to Data_Node class for comparison and other operations
1698 Data_Node& data_node = imultimap::data_cast(*position);
1699 // Compare the node value to the current position value
1700 if (node_comp(key, data_node))
1701 {
1702 // Keep searching for the node on the left
1703 position = position->children[(uint_least8_t)kLeft];
1704 }
1705 else if (node_comp(data_node, key))
1706 {
1707 // Keep searching for the node on the right
1708 position = position->children[(uint_least8_t)kRight];
1709 }
1710 else
1711 {
1712 // We found one, keep looking for more on the left
1713 found = position;
1714 position = position->children[(uint_least8_t)kLeft];
1715 }
1716 }
1717
1718 // Return the node found (might be ETL_NULLPTR)
1719 return found;
1720 }
1721#endif
1722
1723 //*************************************************************************
1725 //*************************************************************************
1726 const Node* find_node(const Node* position, const_key_reference key) const
1727 {
1728 const Node* found = ETL_NULLPTR;
1729 while (position)
1730 {
1731 // Downcast found to Data_Node class for comparison and other operations
1732 const Data_Node& data_node = imultimap::data_cast(*position);
1733 // Compare the node value to the current position value
1734 if (node_comp(key, data_node))
1735 {
1736 // Keep searching for the node on the left
1737 position = position->children[(uint_least8_t)kLeft];
1738 }
1739 else if (node_comp(data_node, key))
1740 {
1741 // Keep searching for the node on the right
1742 position = position->children[(uint_least8_t)kRight];
1743 }
1744 else
1745 {
1746 // We found one, keep looking for more on the left
1747 found = position;
1748 position = position->children[(uint_least8_t)kLeft];
1749 }
1750 }
1751
1752 // Return the node found (might be ETL_NULLPTR)
1753 return found;
1754 }
1755
1756#if ETL_USING_CPP11
1757 //*************************************************************************
1759 //*************************************************************************
1760 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1761 const Node* find_node(const Node* position, const K& key) const
1762 {
1763 const Node* found = ETL_NULLPTR;
1764 while (position)
1765 {
1766 // Downcast found to Data_Node class for comparison and other operations
1767 const Data_Node& data_node = imultimap::data_cast(*position);
1768 // Compare the node value to the current position value
1769 if (node_comp(key, data_node))
1770 {
1771 // Keep searching for the node on the left
1772 position = position->children[(uint_least8_t)kLeft];
1773 }
1774 else if (node_comp(data_node, key))
1775 {
1776 // Keep searching for the node on the right
1777 position = position->children[(uint_least8_t)kRight];
1778 }
1779 else
1780 {
1781 // We found one, keep looking for more on the left
1782 found = position;
1783 position = position->children[(uint_least8_t)kLeft];
1784 }
1785 }
1786
1787 // Return the node found (might be ETL_NULLPTR)
1788 return found;
1789 }
1790#endif
1791
1792 //*************************************************************************
1794 //*************************************************************************
1795 Node* find_lower_node(Node* position, const_key_reference key) const
1796 {
1797 // Something at this position? keep going
1798 Node* lower_node = ETL_NULLPTR;
1799 while (position)
1800 {
1801 // Downcast lower node to Data_Node reference for key comparisons
1802 Data_Node& data_node = imultimap::data_cast(*position);
1803 // Compare the key value to the current lower node key value
1804 if (node_comp(key, data_node))
1805 {
1806 lower_node = position;
1807 if (position->children[(uint_least8_t)kLeft])
1808 {
1809 position = position->children[(uint_least8_t)kLeft];
1810 }
1811 else
1812 {
1813 // Found lowest node
1814 break;
1815 }
1816 }
1817 else if (node_comp(data_node, key))
1818 {
1819 position = position->children[(uint_least8_t)kRight];
1820 }
1821 else
1822 {
1823 // Make note of current position, but keep looking to left for more
1824 lower_node = position;
1825 position = position->children[(uint_least8_t)kLeft];
1826 }
1827 }
1828
1829 // Return the lower_node position found
1830 return lower_node;
1831 }
1832
1833#if ETL_USING_CPP11
1834 //*************************************************************************
1835 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1836 Node* find_lower_node(Node* position, const K& key) const
1837 {
1838 // Something at this position? keep going
1839 Node* lower_node = ETL_NULLPTR;
1840 while (position)
1841 {
1842 // Downcast lower node to Data_Node reference for key comparisons
1843 Data_Node& data_node = imultimap::data_cast(*position);
1844 // Compare the key value to the current lower node key value
1845 if (node_comp(key, data_node))
1846 {
1847 lower_node = position;
1848 if (position->children[(uint_least8_t)kLeft])
1849 {
1850 position = position->children[(uint_least8_t)kLeft];
1851 }
1852 else
1853 {
1854 // Found lowest node
1855 break;
1856 }
1857 }
1858 else if (node_comp(data_node, key))
1859 {
1860 position = position->children[(uint_least8_t)kRight];
1861 }
1862 else
1863 {
1864 // Make note of current position, but keep looking to left for more
1865 lower_node = position;
1866 position = position->children[(uint_least8_t)kLeft];
1867 }
1868 }
1869
1870 // Return the lower_node position found
1871 return lower_node;
1872 }
1873#endif
1874
1875 //*************************************************************************
1877 //*************************************************************************
1878 Node* find_upper_node(Node* position, const_key_reference key) const
1879 {
1880 // Keep track of parent of last upper node
1881 Node* upper_node = ETL_NULLPTR;
1882 // Has an equal node been found? start with no
1883 bool found = false;
1884 while (position)
1885 {
1886 // Downcast position to Data_Node reference for key comparisons
1887 Data_Node& data_node = imultimap::data_cast(*position);
1888 // Compare the key value to the current upper node key value
1889 if (node_comp(data_node, key))
1890 {
1891 position = position->children[(uint_least8_t)kRight];
1892 }
1893 else if (node_comp(key, data_node))
1894 {
1895 upper_node = position;
1896 // If a node equal to key hasn't been found go left
1897 if (!found && position->children[(uint_least8_t)kLeft])
1898 {
1899 position = position->children[(uint_least8_t)kLeft];
1900 }
1901 else
1902 {
1903 break;
1904 }
1905 }
1906 else
1907 {
1908 // We found an equal item, break on next bigger item
1909 found = true;
1910 next_node(position);
1911 }
1912 }
1913
1914 // Return the upper node position found (might be ETL_NULLPTR)
1915 return upper_node;
1916 }
1917
1918#if ETL_USING_CPP11
1919 //*************************************************************************
1920 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1921 Node* find_upper_node(Node* position, const K& key) const
1922 {
1923 // Keep track of parent of last upper node
1924 Node* upper_node = ETL_NULLPTR;
1925 // Has an equal node been found? start with no
1926 bool found = false;
1927 while (position)
1928 {
1929 // Downcast position to Data_Node reference for key comparisons
1930 Data_Node& data_node = imultimap::data_cast(*position);
1931 // Compare the key value to the current upper node key value
1932 if (node_comp(data_node, key))
1933 {
1934 position = position->children[(uint_least8_t)kRight];
1935 }
1936 else if (node_comp(key, data_node))
1937 {
1938 upper_node = position;
1939 // If a node equal to key hasn't been found go left
1940 if (!found && position->children[(uint_least8_t)kLeft])
1941 {
1942 position = position->children[(uint_least8_t)kLeft];
1943 }
1944 else
1945 {
1946 break;
1947 }
1948 }
1949 else
1950 {
1951 // We found an equal item, break on next bigger item
1952 found = true;
1953 next_node(position);
1954 }
1955 }
1956
1957 // Return the upper node position found (might be ETL_NULLPTR)
1958 return upper_node;
1959 }
1960#endif
1961
1962 //*************************************************************************
1964 //*************************************************************************
1965 Node* insert_node(Node*& position, Data_Node& node)
1966 {
1967 // Find the location where the node belongs
1968 Node* found = position;
1969
1970 // Was position provided not empty? then find where the node belongs
1971 if (position)
1972 {
1973 // Find the critical parent node (default to ETL_NULLPTR)
1974 Node* critical_parent_node = ETL_NULLPTR;
1975 Node* critical_node = root_node;
1976
1977 while (found)
1978 {
1979 // Search for critical weight node (all nodes whose weight factor
1980 // is set to (uint_least8_t) kNeither (balanced)
1981 if ((uint_least8_t)kNeither != found->weight)
1982 {
1983 critical_node = found;
1984 }
1985
1986 // Downcast found to Data_Node class for comparison and other
1987 // operations
1988 Data_Node& found_data_node = imultimap::data_cast(*found);
1989
1990 // Is the node provided to the left of the current position?
1991 if (node_comp(node, found_data_node))
1992 {
1993 // Update direction taken to insert new node in parent node
1994 found->dir = (uint_least8_t)kLeft;
1995 }
1996 // Is the node provided to the right of the current position?
1997 else if (node_comp(found_data_node, node))
1998 {
1999 // Update direction taken to insert new node in parent node
2000 found->dir = (uint_least8_t)kRight;
2001 }
2002 else
2003 {
2004 // Update direction taken to insert new node in parent (and
2005 // duplicate) node to the right.
2006 found->dir = (uint_least8_t)kRight;
2007 }
2008
2009 // Is there a child of this parent node?
2010 if (found->children[found->dir])
2011 {
2012 // Will this node be the parent of the next critical node whose
2013 // weight factor is set to (uint_least8_t) kNeither (balanced)?
2014 if ((uint_least8_t)kNeither != found->children[found->dir]->weight)
2015 {
2016 critical_parent_node = found;
2017 }
2018
2019 // Keep looking for empty spot to insert new node
2020 found = found->children[found->dir];
2021 }
2022 else
2023 {
2024 // Attach node as a child of the parent node found
2025 attach_node(found, found->children[found->dir], node);
2026
2027 // Return newly added node
2028 found = found->children[found->dir];
2029
2030 // Exit loop
2031 break;
2032 }
2033 }
2034
2035 // Was a critical node found that should be checked for balance?
2036 if (critical_node)
2037 {
2038 if (critical_parent_node == ETL_NULLPTR && critical_node == root_node)
2039 {
2041 }
2042 else if (critical_parent_node == ETL_NULLPTR && critical_node == position)
2043 {
2044 balance_node(position);
2045 }
2046 else
2047 {
2048 if (critical_parent_node != ETL_NULLPTR)
2049 {
2050 balance_node(critical_parent_node->children[critical_parent_node->dir]);
2051 }
2052 }
2053 }
2054 }
2055 else
2056 {
2057 // Attach node to current position (which is assumed to be root)
2058 attach_node(ETL_NULLPTR, position, node);
2059
2060 // Return newly added node at current position
2061 found = position;
2062 }
2063
2064 // Return the node found (might be ETL_NULLPTR)
2065 return found;
2066 }
2067
2068 //*************************************************************************
2071 //*************************************************************************
2072 void remove_node(Node* node)
2073 {
2074 // If valid found node was provided then proceed with steps 1 through 5
2075 if (node)
2076 {
2077 // Downcast found node provided to Data_Node class
2078 Data_Node& data_node = imultimap::data_cast(*node);
2079
2080 // Keep track of node as found node
2081 Node* found = node;
2082
2083 // Step 1: Mark path from node provided back to the root node using the
2084 // internal temporary dir member value and using the parent pointer.
2085 // This will allow us to avoid recursion in finding the node in a tree
2086 // that might contain duplicate keys to be found.
2087 while (node)
2088 {
2089 if (node->parent)
2090 {
2091 // Which direction does parent use to get to this node?
2092 node->parent->dir = node->parent->children[(uint_least8_t)kLeft] == node ? (uint_least8_t)kLeft : (uint_least8_t)kRight;
2093
2094 // Make this nodes parent the next node
2095 node = node->parent;
2096 }
2097 else
2098 {
2099 // Root node found - break loop
2100 break;
2101 }
2102 }
2103
2104 // Step 2: Follow the path provided above until we reach the node
2105 // provided and look for the balance node to start rebalancing the tree
2106 // from (up to the replacement node that will be found in step 3)
2107 Node* balance = root_node;
2108 while (node)
2109 {
2110 // Did we reach the node provided originally (found) then go to step 3
2111 if (node == found)
2112 {
2113 // Update the direction towards a replacement node at the found node
2114 node->dir = node->children[(uint_least8_t)kLeft] ? (uint_least8_t)kLeft : (uint_least8_t)kRight;
2115
2116 // Exit loop and proceed with step 3
2117 break;
2118 }
2119 else
2120 {
2121 // If this nodes weight is (uint_least8_t) kNeither or we are taking
2122 // the shorter path to the next node and our sibling (on longer
2123 // path) is balanced then we need to update the balance node to this
2124 // node but all our ancestors will not require rebalancing
2125 if ((node->weight == (uint_least8_t)kNeither)
2126 || (node->weight == (1 - node->dir) && node->children[1 - node->dir]->weight == (uint_least8_t)kNeither))
2127 {
2128 // Update balance node to this node
2129 balance = node;
2130 }
2131
2132 // Keep searching for found in the direction provided in step 1
2133 node = node->children[node->dir];
2134 }
2135 }
2136 // The value for node should not be ETL_NULLPTR at this point otherwise
2137 // step 1 failed to provide the correct path to found. Step 5 will fail
2138 // (probably subtly) if node should be ETL_NULLPTR at this point
2139
2140 // Step 3: Find the node (node should be equal to found at this point)
2141 // to replace found with (might end up equal to found) while also
2142 // continuing to update balance the same as in step 2 above.
2143 while (node)
2144 {
2145 // Replacement node found if its missing a child in the replace->dir
2146 // value set at the end of step 2 above
2147 if (node->children[node->dir] == ETL_NULLPTR)
2148 {
2149 // Exit loop once node to replace found is determined
2150 break;
2151 }
2152
2153 // If this nodes weight is (uint_least8_t) kNeither or we are taking
2154 // the shorter path to the next node and our sibling (on longer path)
2155 // is balanced then we need to update the balance node to this node
2156 // but all our ancestors will not require rebalancing
2157 if ((node->weight == (uint_least8_t)kNeither)
2158 || (node->weight == (1 - node->dir) && 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
2165 // above
2166 node = node->children[node->dir];
2167
2168 // Downcast node to Data_Node class for comparison operations
2169 Data_Node& replace_data_node = imultimap::data_cast(*node);
2170
2171 // Compare the key provided to the replace data node key
2172 if (node_comp(data_node, replace_data_node))
2173 {
2174 // Update the direction to the replace node
2175 node->dir = (uint_least8_t)kLeft;
2176 }
2177 else if (node_comp(replace_data_node, data_node))
2178 {
2179 // Update the direction to the replace node
2180 node->dir = (uint_least8_t)kRight;
2181 }
2182 else
2183 {
2184 // Update the direction to the replace node
2185 node->dir = 1 - found->dir;
2186 }
2187 } // while(node)
2188
2189 // Step 4: Update weights from balance to parent of node determined
2190 // in step 3 above rotating (2 or 3 node rotations) as needed.
2191 while (balance)
2192 {
2193 // Break when balance node reaches the parent of replacement node
2194 if (balance->children[balance->dir] == ETL_NULLPTR)
2195 {
2196 break;
2197 }
2198
2199 // If balance node is balanced already ((uint_least8_t) kNeither) then
2200 // just imbalance the node in the opposite direction of the node being
2201 // removed
2202 if (balance->weight == (uint_least8_t)kNeither)
2203 {
2204 balance->weight = 1 - balance->dir;
2205 }
2206 // If balance node is imbalanced in the opposite direction of the
2207 // node being removed then the node now becomes balanced
2208 else if (balance->weight == balance->dir)
2209 {
2210 balance->weight = (uint_least8_t)kNeither;
2211 }
2212 // Otherwise a rotation is required at this node
2213 else
2214 {
2215 int weight = balance->children[1 - balance->dir]->weight;
2216 // Perform a 3 node rotation if weight is same as balance->dir
2217 if (weight == balance->dir)
2218 {
2219 // Is the root node being rebalanced (no parent)
2220 if (balance->parent == ETL_NULLPTR)
2221 {
2222 rotate_3node(root_node, 1 - balance->dir, balance->children[1 - balance->dir]->children[balance->dir]->weight);
2223 }
2224 else
2225 {
2226 rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
2227 balance->children[1 - balance->dir]->children[balance->dir]->weight);
2228 }
2229 }
2230 // Already balanced, rebalance and make it heavy in opposite
2231 // direction of the node being removed
2232 else if (weight == (uint_least8_t)kNeither)
2233 {
2234 // Is the root node being rebalanced (no parent)
2235 if (balance->parent == ETL_NULLPTR)
2236 {
2237 rotate_2node(root_node, 1 - balance->dir);
2238 root_node->weight = balance->dir;
2239 }
2240 else
2241 {
2242 // Balance parent might change during rotate, keep local copy
2243 // to old parent so its weight can be updated after the 2 node
2244 // rotate is completed
2245 Node* old_parent = balance->parent;
2246 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2247 old_parent->children[old_parent->dir]->weight = balance->dir;
2248 }
2249 // Update balance node weight in opposite direction of node
2250 // removed
2251 balance->weight = 1 - balance->dir;
2252 }
2253 // Rebalance and leave it balanced
2254 else
2255 {
2256 // Is the root node being rebalanced (no parent)
2257 if (balance->parent == ETL_NULLPTR)
2258 {
2259 rotate_2node(root_node, 1 - balance->dir);
2260 }
2261 else
2262 {
2263 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2264 }
2265 }
2266 }
2267
2268 // Next balance node to consider
2269 balance = balance->children[balance->dir];
2270 } // while(balance)
2271
2272 // Step 5: Swap found with node (replacement)
2273 if (found->parent)
2274 {
2275 // Handle traditional case
2276 detach_node(found->parent->children[found->parent->dir], node->parent->children[node->parent->dir]);
2277 }
2278 // Handle root node removal
2279 else
2280 {
2281 // Valid replacement node for root node being removed?
2282 if (node->parent)
2283 {
2284 detach_node(root_node, node->parent->children[node->parent->dir]);
2285 }
2286 else
2287 {
2288 // Found node and replacement node are both root node
2290 }
2291 }
2292
2293 // One less.
2294 --current_size;
2295
2296 // Destroy the node detached above
2297 destroy_data_node(data_node);
2298 } // if(found)
2299 }
2300
2301 // Disable copy construction.
2302 imultimap(const imultimap&);
2303
2304 //*************************************************************************
2306 //*************************************************************************
2307#if defined(ETL_POLYMORPHIC_MULTIMAP) || defined(ETL_POLYMORPHIC_CONTAINERS)
2308
2309 public:
2310
2311 virtual ~imultimap() {}
2312#else
2313
2314 protected:
2315
2317#endif
2318 };
2319
2320 //*************************************************************************
2322 //*************************************************************************
2323 template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = etl::less<TKey> >
2324 class multimap : public etl::imultimap<TKey, TValue, TCompare>
2325 {
2326 public:
2327
2328 static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_;
2329
2330 //*************************************************************************
2332 //*************************************************************************
2334 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2335 {
2336 this->initialise();
2337 }
2338
2339 //*************************************************************************
2341 //*************************************************************************
2342 multimap(const multimap& other)
2343 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2344 {
2345 if (this != &other)
2346 {
2347 this->assign(other.cbegin(), other.cend());
2348 }
2349 }
2350
2351#if ETL_USING_CPP11
2352 //*************************************************************************
2354 //*************************************************************************
2355 multimap(multimap&& other)
2356 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2357 {
2358 if (this != &other)
2359 {
2360 typename etl::imultimap<TKey, TValue, TCompare>::iterator from = other.begin();
2361
2362 while (from != other.end())
2363 {
2365 ++temp;
2366
2367 this->insert(etl::move(*from));
2368 from = temp;
2369 }
2370 }
2371 }
2372#endif
2373
2374 //*************************************************************************
2379 //*************************************************************************
2380 template <typename TIterator>
2381 multimap(TIterator first, TIterator last)
2382 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2383 {
2384 this->assign(first, last);
2385 }
2386
2387#if ETL_HAS_INITIALIZER_LIST
2388 //*************************************************************************
2390 //*************************************************************************
2391 multimap(std::initializer_list< typename etl::imultimap<TKey, TValue, TCompare>::value_type> init)
2392 : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2393 {
2394 this->assign(init.begin(), init.end());
2395 }
2396#endif
2397
2398 //*************************************************************************
2400 //*************************************************************************
2402 {
2403 this->initialise();
2404 }
2405
2406 //*************************************************************************
2408 //*************************************************************************
2410 {
2411 // Skip if doing self assignment
2412 if (this != &rhs)
2413 {
2414 this->assign(rhs.cbegin(), rhs.cend());
2415 }
2416
2417 return *this;
2418 }
2419
2420#if ETL_USING_CPP11
2421 //*************************************************************************
2423 //*************************************************************************
2424 multimap& operator=(multimap&& rhs)
2425 {
2426 if (this != &rhs)
2427 {
2428 typename etl::imultimap<TKey, TValue, TCompare>::iterator from = rhs.begin();
2429
2430 while (from != rhs.end())
2431 {
2433 ++temp;
2434
2435 this->insert(etl::move(*from));
2436 from = temp;
2437 }
2438 }
2439
2440 return *this;
2441 }
2442#endif
2443
2444 private:
2445
2447 etl::pool<typename etl::imultimap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool;
2448 };
2449
2450 template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare>
2451 ETL_CONSTANT size_t multimap<TKey, TValue, MAX_SIZE_, TCompare>::MAX_SIZE;
2452
2453 //*************************************************************************
2455 //*************************************************************************
2456#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
2457 template <typename... TPairs>
2458 multimap(TPairs...)
2459 -> multimap<typename etl::nth_type_t<0, TPairs...>::first_type, typename etl::nth_type_t<0, TPairs...>::second_type, 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(), rhs.begin(), rhs.end(), lhs.value_comp());
2510 }
2511
2512 //*************************************************************************
2518 //*************************************************************************
2519 template <typename TKey, typename TMapped, typename TKeyCompare>
2521 {
2522 return (rhs < lhs);
2523 }
2524
2525 //*************************************************************************
2532 //*************************************************************************
2533 template <typename TKey, typename TMapped, typename TKeyCompare>
2535 {
2536 return !(lhs > rhs);
2537 }
2538
2539 //*************************************************************************
2545 //*************************************************************************
2546 template <typename TKey, typename TMapped, typename TKeyCompare>
2548 {
2549 return !(lhs < rhs);
2550 }
2551} // namespace etl
2552
2553#include "private/minmax_pop.h"
2554
2555#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:2325
multimap(TIterator first, TIterator last)
Definition multimap.h:2381
multimap & operator=(const multimap &rhs)
Assignment operator.
Definition multimap.h:2409
multimap()
Default constructor.
Definition multimap.h:2333
~multimap()
Destructor.
Definition multimap.h:2401
multimap(const multimap &other)
Copy constructor.
Definition multimap.h:2342
ETL_CONSTEXPR14 bool operator!=(const etl::bitset< Active_Bits, TElement > &lhs, const etl::bitset< Active_Bits, TElement > &rhs) ETL_NOEXCEPT
Definition bitset_new.h:2529
#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:1508
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:1377
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:1437
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:1454
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:1492
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
void insert(TIterator first, TIterator last)
Definition multimap.h:1362
const_iterator lower_bound(const_key_reference key) const
Definition multimap.h:1397
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:1417
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:1536
imultimap(etl::ipool &node_pool, size_t max_size_)
Constructor.
Definition multimap.h:1527
value_compare value_comp() const
How to compare two value elements.
Definition multimap.h:1500
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:2316
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:333
Definition ipool.h:109
bitset_ext
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:1081
bool operator>(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1133
bool operator>=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1147
ETL_CONSTEXPR14 bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1093
bool operator<(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1106
bool operator<=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1120
The data node element in the multimap.
Definition multimap.h:671
iterator
Definition iterator.h:424
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