Embedded Template Library 1.0
Loading...
Searching...
No Matches
map.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) 2021 John Wellbelove
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_MAP_INCLUDED
32#define ETL_MAP_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//*****************************************************************************
59//*****************************************************************************
60
61namespace etl
62{
63 //***************************************************************************
66 //***************************************************************************
67 class map_exception : public etl::exception
68 {
69 public:
70
71 map_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 map_full : public etl::map_exception
82 {
83 public:
84
85 map_full(string_type file_name_, numeric_type line_number_)
86 : etl::map_exception(ETL_ERROR_TEXT("map:full", ETL_MAP_FILE_ID"A"), file_name_, line_number_)
87 {
88 }
89 };
90
91 //***************************************************************************
94 //***************************************************************************
95 class map_out_of_bounds : public etl::map_exception
96 {
97 public:
98
99 map_out_of_bounds(string_type file_name_, numeric_type line_number_)
100 : etl::map_exception(ETL_ERROR_TEXT("map:bounds", ETL_MAP_FILE_ID"B"), file_name_, line_number_)
101 {
102 }
103 };
104
105 //***************************************************************************
108 //***************************************************************************
109 class map_iterator : public etl::map_exception
110 {
111 public:
112
113 map_iterator(string_type file_name_, numeric_type line_number_)
114 : etl::map_exception(ETL_ERROR_TEXT("map:iterator", ETL_MAP_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 = 0,
184 kRight = 1,
185 kNeither = 2
186 };
187
188 //*************************************************************************
190 //*************************************************************************
191 struct Node
192 {
193 //***********************************************************************
195 //***********************************************************************
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 ~Node() {}
205
206 //***********************************************************************
208 //***********************************************************************
210 {
211 weight = uint_least8_t(kNeither);
212 dir = uint_least8_t(kNeither);
213 children[0] = ETL_NULLPTR;
214 children[1] = ETL_NULLPTR;
215 }
216
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
233 //*************************************************************************
235 //*************************************************************************
237
238 //*************************************************************************
240 //*************************************************************************
241 void balance_node(Node*& critical_node)
242 {
243 // Step 1: Update weights for all children of the critical node up to the
244 // newly inserted node. This step is costly (in terms of traversing nodes
245 // multiple times during insertion) but doesn't require as much recursion
246 Node* weight_node = critical_node->children[critical_node->dir];
247 while (weight_node)
248 {
249 // Keep going until we reach a terminal node (dir == 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 // Check for nullptr before dereferencing to avoid C28182 warning
288 if (critical_node->children[critical_node->dir] != ETL_NULLPTR) ETL_UNLIKELY
289 {
290 if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
291 {
292 rotate_2node(critical_node, critical_node->dir);
293 }
294 // Otherwise perform a three node rotation in the direction of the
295 // critical node
296 else
297 {
298 if (critical_node->children[critical_node->dir]->children[1 - critical_node->dir] != ETL_NULLPTR) ETL_UNLIKELY
299 {
300 rotate_3node(critical_node, critical_node->dir, critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
301 }
302 }
303 }
304 }
305 }
306
307 //*************************************************************************
309 //*************************************************************************
310 void rotate_2node(Node*& position, uint_least8_t dir)
311 {
312 // A C A B
313 // B C -> A E OR B C -> D A
314 // D E B D D E E C
315 // C (new position) becomes the root
316 // A (position) takes ownership of D as its children[kRight] child
317 // C (new position) takes ownership of A as its left child
318 // OR
319 // B (new position) becomes the root
320 // A (position) takes ownership of E as its left child
321 // B (new position) takes ownership of A as its right child
322
323 // Capture new root
324 Node* new_root = position->children[dir];
325 // Replace position's previous child with new root's other child
326 position->children[dir] = new_root->children[1 - dir];
327 // New root now becomes parent of current position
328 new_root->children[1 - dir] = position;
329 // Clear weight factor from current position
330 position->weight = uint_least8_t(kNeither);
331 // Newly detached right now becomes current position
332 position = new_root;
333 // Clear weight factor from new root
334 position->weight = uint_least8_t(kNeither);
335 }
336
337 //*************************************************************************
339 //*************************************************************************
340 void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
341 {
342 // --A-- --E-- --A-- --D--
343 // _B_ C -> B A OR B _C_ -> A C
344 // D E D F G C D E B F G E
345 // F G F G
346 // E (new position) becomes the root
347 // B (position) takes ownership of F as its left child
348 // A takes ownership of G as its right child
349 // OR
350 // D (new position) becomes the root
351 // A (position) takes ownership of F as its right child
352 // C takes ownership of G as its left child
353
354 // Capture new root (either E or D depending on dir)
355 Node* new_root = position->children[dir]->children[1 - dir];
356 // Set weight factor for B or C based on F or G existing and being a
357 // different than dir
358 position->children[dir]->weight = third != uint_least8_t(kNeither) && third != dir ? dir : uint_least8_t(kNeither);
359
360 // Detach new root from its tree (replace with new roots child)
361 position->children[dir]->children[1 - dir] = new_root->children[dir];
362 // Attach current left tree to new root
363 new_root->children[dir] = position->children[dir];
364 // Set weight factor for A based on F or G
365 position->weight = third != uint_least8_t(kNeither) && third == dir ? 1 - dir : uint_least8_t(kNeither);
366
367 // Move new root's right tree to current roots left tree
368 position->children[dir] = new_root->children[1 - dir];
369 // Attach current root to new roots right tree
370 new_root->children[1 - dir] = position;
371 // Replace current position with new root
372 position = new_root;
373 // Clear weight factor for new current position
374 position->weight = uint_least8_t(kNeither);
375 }
376
377 //*************************************************************************
380 //*************************************************************************
381 Node* find_limit_node(Node* position, const int8_t dir) const
382 {
383 // Something at this position and in the direction specified? keep going
384 Node* limit_node = position;
385 while (limit_node && limit_node->children[dir])
386 {
387 limit_node = limit_node->children[dir];
388 }
389
390 // Return the limit node position found
391 return limit_node;
392 }
393
394 //*************************************************************************
397 //*************************************************************************
398 const Node* find_limit_node(const Node* position, const int8_t dir) const
399 {
400 // Something at this position and in the direction specified? keep going
401 const Node* limit_node = position;
402 while (limit_node && limit_node->children[dir])
403 {
404 limit_node = limit_node->children[dir];
405 }
406
407 // Return the limit node position found
408 return limit_node;
409 }
410
411 //*************************************************************************
413 //*************************************************************************
414 void attach_node(Node*& position, Node& node)
415 {
416 // Mark new node as leaf on attach to tree at position provided
417 node.mark_as_leaf();
418
419 // Add the node here
420 position = &node;
421
422 // One more.
423 ++current_size;
424 }
425
426 //*************************************************************************
428 //*************************************************************************
429 void detach_node(Node*& position, Node*& replacement)
430 {
431 // Make temporary copy of actual nodes involved because we might lose
432 // their references in the process (e.g. position is the same as
433 // replacement or replacement is a child of position)
434 Node* detached = position;
435 Node* swap = replacement;
436
437 // Update current position to point to swap (replacement) node first
438 position = swap;
439
440 // Update replacement node to point to child in opposite direction
441 // otherwise we might lose the other child of the swap node
442 replacement = swap->children[1 - swap->dir];
443
444 // Point swap node to detached node's children and weight
445 swap->children[kLeft] = detached->children[kLeft];
446 swap->children[kRight] = detached->children[kRight];
447 swap->weight = detached->weight;
448 }
449
453 ETL_DECLARE_DEBUG_COUNT;
454 };
455
456 //***************************************************************************
459 //***************************************************************************
460 template <typename TKey, typename TMapped, typename TKeyCompare = etl::less<TKey> >
461 class imap : public etl::map_base
462 {
463 public:
464
465 typedef TKey key_type;
466 typedef ETL_OR_STD::pair<const TKey, TMapped> value_type;
467 typedef TMapped mapped_type;
468 typedef TKeyCompare key_compare;
469 typedef value_type& reference;
470 typedef const value_type& const_reference;
471#if ETL_USING_CPP11
472 typedef value_type&& rvalue_reference;
473#endif
474 typedef value_type* pointer;
475 typedef const value_type* const_pointer;
476 typedef size_t size_type;
477
479 typedef const key_type& const_key_reference;
480#if ETL_USING_CPP11
481 typedef key_type&& rvalue_key_reference;
482#endif
483 typedef mapped_type& mapped_reference;
484 typedef const mapped_type& const_mapped_reference;
485
487 {
488 public:
489
490 bool operator()(const_reference lhs, const_reference rhs) const
491 {
492 return (kcompare(lhs.first, rhs.first));
493 }
494
495 private:
496
497 key_compare kcompare;
498 };
499
500 protected:
501
502 //*************************************************************************
504 //*************************************************************************
505 struct Data_Node : public Node
506 {
507 explicit Data_Node(value_type value_)
508 : value(value_)
509 {
510 }
511
512 ~Data_Node() {}
513
514 value_type value;
515 };
516
517 //*************************************************************************
519 //*************************************************************************
520 bool node_comp(const Data_Node& node1, const Data_Node& node2) const
521 {
522 return kcompare(node1.value.first, node2.value.first);
523 }
524
525 bool node_comp(const Data_Node& node, const_key_reference key) const
526 {
527 return kcompare(node.value.first, key);
528 }
529
530 bool node_comp(const_key_reference key, const Data_Node& node) const
531 {
532 return kcompare(key, node.value.first);
533 }
534
535#if ETL_USING_CPP11
536 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
537 bool node_comp(const Data_Node& node, const K& key) const
538 {
539 return kcompare(node.value.first, key);
540 }
541
542 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
543 bool node_comp(const K& key, const Data_Node& node) const
544 {
545 return kcompare(key, node.value.first);
546 }
547#endif
548
549 private:
550
552 ipool* p_node_pool;
553
554 key_compare kcompare;
555 value_compare vcompare;
556
557 //*************************************************************************
559 //*************************************************************************
560 static Data_Node* data_cast(Node* p_node)
561 {
562 return static_cast<Data_Node*>(p_node);
563 }
564
565 //*************************************************************************
567 //*************************************************************************
568 static Data_Node& data_cast(Node& node)
569 {
570 return static_cast<Data_Node&>(node);
571 }
572
573 //*************************************************************************
575 //*************************************************************************
576 static const Data_Node* data_cast(const Node* p_node)
577 {
578 return static_cast<const Data_Node*>(p_node);
579 }
580
581 //*************************************************************************
583 //*************************************************************************
584 static const Data_Node& data_cast(const Node& node)
585 {
586 return static_cast<const Data_Node&>(node);
587 }
588
589 public:
590
591 //*************************************************************************
593 //*************************************************************************
594 class iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, value_type>
595 {
596 public:
597
598 friend class imap;
599 friend class const_iterator;
600
601 iterator()
602 : p_map(ETL_NULLPTR)
603 , p_node(ETL_NULLPTR)
604 {
605 }
606
607 iterator(imap& map)
608 : p_map(&map)
609 , p_node(ETL_NULLPTR)
610 {
611 }
612
613 iterator(imap& map, Node* node)
614 : p_map(&map)
615 , p_node(node)
616 {
617 }
618
619 iterator(const iterator& other)
620 : p_map(other.p_map)
621 , p_node(other.p_node)
622 {
623 }
624
625 ~iterator() {}
626
627 iterator& operator++()
628 {
629 p_map->next_node(p_node);
630 return *this;
631 }
632
633 iterator operator++(int)
634 {
635 iterator temp(*this);
636 p_map->next_node(p_node);
637 return temp;
638 }
639
640 iterator& operator--()
641 {
642 p_map->prev_node(p_node);
643 return *this;
644 }
645
646 iterator operator--(int)
647 {
648 iterator temp(*this);
649 p_map->prev_node(p_node);
650 return temp;
651 }
652
653 iterator& operator=(const iterator& other)
654 {
655 p_map = other.p_map;
656 p_node = other.p_node;
657 return *this;
658 }
659
660 reference operator*() const
661 {
662 return imap::data_cast(p_node)->value;
663 }
664
665 pointer operator&() const
666 {
667 return &(imap::data_cast(p_node)->value);
668 }
669
670 pointer operator->() const
671 {
672 return &(imap::data_cast(p_node)->value);
673 }
674
675 friend bool operator==(const iterator& lhs, const iterator& rhs)
676 {
677 return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node;
678 }
679
680 friend bool operator!=(const iterator& lhs, const iterator& rhs)
681 {
682 return !(lhs == rhs);
683 }
684
685 private:
686
687 // Pointer to map associated with this iterator
688 imap* p_map;
689
690 // Pointer to the current node for this iterator
691 Node* p_node;
692 };
693
694 friend class iterator;
695
696 //*************************************************************************
698 //*************************************************************************
699 class const_iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, const value_type>
700 {
701 public:
702
703 friend class imap;
704
705 const_iterator()
706 : p_map(ETL_NULLPTR)
707 , p_node(ETL_NULLPTR)
708 {
709 }
710
711 const_iterator(const imap& map)
712 : p_map(&map)
713 , p_node(ETL_NULLPTR)
714 {
715 }
716
717 const_iterator(const imap& map, const Node* node)
718 : p_map(&map)
719 , p_node(node)
720 {
721 }
722
723 const_iterator(const typename imap::iterator& other)
724 : p_map(other.p_map)
725 , p_node(other.p_node)
726 {
727 }
728
729 const_iterator(const const_iterator& other)
730 : p_map(other.p_map)
731 , p_node(other.p_node)
732 {
733 }
734
735 ~const_iterator() {}
736
737 const_iterator& operator++()
738 {
739 p_map->next_node(p_node);
740 return *this;
741 }
742
743 const_iterator operator++(int)
744 {
745 const_iterator temp(*this);
746 p_map->next_node(p_node);
747 return temp;
748 }
749
750 const_iterator& operator--()
751 {
752 p_map->prev_node(p_node);
753 return *this;
754 }
755
756 const_iterator operator--(int)
757 {
758 const_iterator temp(*this);
759 p_map->prev_node(p_node);
760 return temp;
761 }
762
763 const_iterator& operator=(const const_iterator& other)
764 {
765 p_map = other.p_map;
766 p_node = other.p_node;
767 return *this;
768 }
769
770 const_reference operator*() const
771 {
772 return imap::data_cast(p_node)->value;
773 }
774
775 const_pointer operator&() const
776 {
777 return imap::data_cast(p_node)->value;
778 }
779
780 const_pointer operator->() const
781 {
782 return &(imap::data_cast(p_node)->value);
783 }
784
785 friend bool operator==(const const_iterator& lhs, const const_iterator& rhs)
786 {
787 return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node;
788 }
789
790 friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs)
791 {
792 return !(lhs == rhs);
793 }
794
795 private:
796
797 // Convert to an iterator.
798 imap::iterator to_iterator() const
799 {
800 return imap::iterator(const_cast<imap&>(*p_map), const_cast<Node*>(p_node));
801 }
802
803 // Pointer to map associated with this iterator
804 const imap* p_map;
805
806 // Pointer to the current node for this iterator
807 const Node* p_node;
808 };
809
810 friend class const_iterator;
811
812 typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
813
814 typedef ETL_OR_STD::reverse_iterator<iterator> reverse_iterator;
815 typedef ETL_OR_STD::reverse_iterator<const_iterator> const_reverse_iterator;
816
817 //*************************************************************************
819 //*************************************************************************
821 {
822 return iterator(*this, find_limit_node(root_node, kLeft));
823 }
824
825 //*************************************************************************
827 //*************************************************************************
829 {
830 return const_iterator(*this, find_limit_node(root_node, kLeft));
831 }
832
833 //*************************************************************************
835 //*************************************************************************
837 {
838 return iterator(*this);
839 }
840
841 //*************************************************************************
843 //*************************************************************************
845 {
846 return const_iterator(*this);
847 }
848
849 //*************************************************************************
851 //*************************************************************************
853 {
854 return const_iterator(*this, find_limit_node(root_node, kLeft));
855 }
856
857 //*************************************************************************
859 //*************************************************************************
861 {
862 return const_iterator(*this);
863 }
864
865 //*************************************************************************
867 //*************************************************************************
868 reverse_iterator rbegin()
869 {
870 return reverse_iterator(iterator(*this));
871 }
872
873 //*************************************************************************
875 //*************************************************************************
876 const_reverse_iterator rbegin() const
877 {
878 return const_reverse_iterator(const_iterator(*this));
879 }
880
881 //*************************************************************************
883 //*************************************************************************
884 reverse_iterator rend()
885 {
886 return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
887 }
888
889 //*************************************************************************
891 //*************************************************************************
892 const_reverse_iterator rend() const
893 {
894 return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
895 }
896
897 //*************************************************************************
899 //*************************************************************************
900 const_reverse_iterator crbegin() const
901 {
902 return const_reverse_iterator(const_iterator(*this));
903 }
904
905 //*************************************************************************
907 //*************************************************************************
908 const_reverse_iterator crend() const
909 {
910 return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
911 }
912
913#if ETL_USING_CPP11
914 //*********************************************************************
918 //*********************************************************************
919 mapped_reference operator[](rvalue_key_reference key)
920 {
921 iterator i_element = find(etl::move(key));
922
923 if (!i_element.p_node)
924 {
925 // Default to no inserted node
926 Node* inserted_node = ETL_NULLPTR;
927
928 ETL_ASSERT(!full(), ETL_ERROR(map_full));
929
930 // Get next available free node
931 Data_Node& node = allocate_data_node_with_key(etl::move(key));
932
933 // Obtain the inserted node (might be ETL_NULLPTR if node was a
934 // duplicate)
935 inserted_node = insert_node(root_node, node);
936
937 // Insert node into tree and return iterator to new node location in
938 // tree
939 i_element = iterator(*this, inserted_node);
940 }
941
942 return i_element->second;
943 }
944#endif
945
946 //*********************************************************************
950 //*********************************************************************
951 mapped_reference operator[](const_key_reference key)
952 {
953 iterator i_element = find(key);
954
955 if (!i_element.p_node)
956 {
957 // Default to no inserted node
958 Node* inserted_node = ETL_NULLPTR;
959
960 ETL_ASSERT(!full(), ETL_ERROR(map_full));
961
962 // Get next available free node
963 Data_Node& node = allocate_data_node_with_key(key);
964
965 // Obtain the inserted node (might be ETL_NULLPTR if node was a
966 // duplicate)
967 inserted_node = insert_node(root_node, node);
968
969 // Insert node into tree and return iterator to new node location in
970 // tree
971 i_element = iterator(*this, inserted_node);
972 }
973
974 return i_element->second;
975 }
976
977 //*********************************************************************
983 //*********************************************************************
984 mapped_reference at(const_key_reference key)
985 {
986 iterator i_element = find(key);
987
988 ETL_ASSERT(i_element.p_node != ETL_NULLPTR, ETL_ERROR(map_out_of_bounds));
989
990 return i_element->second;
991 }
992
993#if ETL_USING_CPP11
994 //*********************************************************************
995 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
996 mapped_reference at(const K& key)
997 {
998 iterator i_element = find(key);
999
1000 ETL_ASSERT(i_element.p_node != ETL_NULLPTR, ETL_ERROR(map_out_of_bounds));
1001
1002 return i_element->second;
1003 }
1004#endif
1005
1006 //*********************************************************************
1012 //*********************************************************************
1013 const_mapped_reference at(const_key_reference key) const
1014 {
1015 const_iterator i_element = find(key);
1016
1017 ETL_ASSERT(i_element.p_node != ETL_NULLPTR, ETL_ERROR(map_out_of_bounds));
1018
1019 return i_element->second;
1020 }
1021
1022#if ETL_USING_CPP11
1023 //*********************************************************************
1024 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1025 const_mapped_reference at(const K& key) const
1026 {
1027 const_iterator i_element = find(key);
1028
1029 ETL_ASSERT(i_element.p_node != ETL_NULLPTR, ETL_ERROR(map_out_of_bounds));
1030
1031 return i_element->second;
1032 }
1033#endif
1034
1035 //*********************************************************************
1042 //*********************************************************************
1043 template <typename TIterator>
1044 void assign(TIterator first, TIterator last)
1045 {
1046 initialise();
1047 insert(first, last);
1048 }
1049
1050 //*************************************************************************
1052 //*************************************************************************
1053 void clear()
1054 {
1055 initialise();
1056 }
1057
1058 //*********************************************************************
1062 //*********************************************************************
1063 size_type count(const_key_reference key) const
1064 {
1065 return find_node(root_node, key) ? 1 : 0;
1066 }
1067
1068#if ETL_USING_CPP11
1069 //*********************************************************************
1070 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1071 size_type count(const K& key) const
1072 {
1073 return find_node(root_node, key) ? 1 : 0;
1074 }
1075#endif
1076
1077 //*************************************************************************
1080 //*************************************************************************
1081 ETL_OR_STD::pair<iterator, iterator> equal_range(const_key_reference key)
1082 {
1083 return ETL_OR_STD::make_pair<iterator, iterator>(iterator(*this, find_lower_node(root_node, key)),
1084 iterator(*this, find_upper_node(root_node, key)));
1085 }
1086
1087#if ETL_USING_CPP11
1088 //*************************************************************************
1089 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1090 ETL_OR_STD::pair<iterator, iterator> equal_range(const K& key)
1091 {
1092 return ETL_OR_STD::make_pair<iterator, iterator>(iterator(*this, find_lower_node(root_node, key)),
1093 iterator(*this, find_upper_node(root_node, key)));
1094 }
1095#endif
1096
1097 //*************************************************************************
1100 //*************************************************************************
1101 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const_key_reference key) const
1102 {
1103 return ETL_OR_STD::make_pair<const_iterator, const_iterator>(const_iterator(*this, find_lower_node(root_node, key)),
1104 const_iterator(*this, find_upper_node(root_node, 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 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const K& key) const
1111 {
1112 return ETL_OR_STD::make_pair<const_iterator, const_iterator>(const_iterator(*this, find_lower_node(root_node, key)),
1113 const_iterator(*this, find_upper_node(root_node, key)));
1114 }
1115#endif
1116
1117 //*************************************************************************
1119 //*************************************************************************
1121 {
1122 // Find the parent node to be removed
1123 Node*& reference_node = find_node(root_node, position.p_node);
1124 iterator next(*this, reference_node);
1125 ++next;
1126
1127 remove_node(root_node, (*position).first);
1128
1129 return next;
1130 }
1131
1132 //*************************************************************************
1133 // Erase the key specified.
1134 //*************************************************************************
1136 {
1137 // Return 1 if key value was found and removed
1138 return remove_node(root_node, key) ? 1 : 0;
1139 }
1140
1141 //*********************************************************************
1142#if ETL_USING_CPP11
1143 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1144 size_type erase(K&& key)
1145 {
1146 // Return 1 if key value was found and removed
1147 return remove_node(root_node, etl::forward<K>(key)) ? 1 : 0;
1148 }
1149#endif
1150
1151 //*************************************************************************
1153 //*************************************************************************
1155 {
1156 while (first != last)
1157 {
1158 first = erase(first);
1159 }
1160
1161 return last.to_iterator();
1162 }
1163
1164 //*********************************************************************
1168 //*********************************************************************
1170 {
1171 return iterator(*this, find_node(root_node, key));
1172 }
1173
1174#if ETL_USING_CPP11
1175 //*********************************************************************
1176 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1177 iterator find(const K& k)
1178 {
1179 return iterator(*this, find_node(root_node, k));
1180 }
1181#endif
1182
1183 //*********************************************************************
1187 //*********************************************************************
1189 {
1190 return const_iterator(*this, find_node(root_node, key));
1191 }
1192
1193#if ETL_USING_CPP11
1194 //*********************************************************************
1195 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1196 const_iterator find(const K& k) const
1197 {
1198 return const_iterator(*this, find_node(root_node, k));
1199 }
1200#endif
1201
1202 //*********************************************************************
1207 //*********************************************************************
1208 ETL_OR_STD::pair<iterator, bool> insert(const_reference value)
1209 {
1210 // Default to no inserted node
1211 Node* inserted_node = ETL_NULLPTR;
1212 bool inserted = false;
1213
1214 ETL_ASSERT(!full(), ETL_ERROR(map_full));
1215
1216 // Get next available free node
1217 Data_Node& node = allocate_data_node(value);
1218
1219 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1220 inserted_node = insert_node(root_node, node);
1221 inserted = inserted_node == &node;
1222
1223 // Insert node into tree and return iterator to new node location in tree
1224 return ETL_OR_STD::make_pair(iterator(*this, inserted_node), inserted);
1225 }
1226
1227#if ETL_USING_CPP11
1228 //*********************************************************************
1233 //*********************************************************************
1234 ETL_OR_STD::pair<iterator, bool> insert(rvalue_reference value)
1235 {
1236 // Default to no inserted node
1237 Node* inserted_node = ETL_NULLPTR;
1238 bool inserted = false;
1239
1240 ETL_ASSERT(!full(), ETL_ERROR(map_full));
1241
1242 // Get next available free node
1243 Data_Node& node = allocate_data_node(etl::move(value));
1244
1245 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1246 inserted_node = insert_node(root_node, node);
1247 inserted = inserted_node == &node;
1248
1249 // Insert node into tree and return iterator to new node location in tree
1250 return ETL_OR_STD::make_pair(iterator(*this, inserted_node), inserted);
1251 }
1252#endif
1253
1254 //*********************************************************************
1260 //*********************************************************************
1261 iterator insert(const_iterator /*position*/, const_reference value)
1262 {
1263 // Default to no inserted node
1264 Node* inserted_node = ETL_NULLPTR;
1265
1266 ETL_ASSERT(!full(), ETL_ERROR(map_full));
1267
1268 // Get next available free node
1269 Data_Node& node = allocate_data_node(value);
1270
1271 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1272 inserted_node = insert_node(root_node, node);
1273
1274 // Insert node into tree and return iterator to new node location in tree
1275 return iterator(*this, inserted_node);
1276 }
1277
1278#if ETL_USING_CPP11
1279 //*********************************************************************
1285 //*********************************************************************
1286 iterator insert(const_iterator /*position*/, rvalue_reference value)
1287 {
1288 // Default to no inserted node
1289 Node* inserted_node = ETL_NULLPTR;
1290
1291 ETL_ASSERT(!full(), ETL_ERROR(map_full));
1292
1293 // Get next available free node
1294 Data_Node& node = allocate_data_node(etl::move(value));
1295
1296 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1297 inserted_node = insert_node(root_node, node);
1298
1299 // Insert node into tree and return iterator to new node location in tree
1300 return iterator(*this, inserted_node);
1301 }
1302#endif
1303
1304 //*********************************************************************
1311 //*********************************************************************
1312 template <class TIterator>
1313 void insert(TIterator first, TIterator last)
1314 {
1315 while (first != last)
1316 {
1317 insert(*first);
1318 ++first;
1319 }
1320 }
1321
1322 //*********************************************************************
1327 //*********************************************************************
1329 {
1330 return iterator(*this, find_lower_node(root_node, key));
1331 }
1332
1333#if ETL_USING_CPP11
1334 //*********************************************************************
1335 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1336 iterator lower_bound(const K& key)
1337 {
1338 return iterator(*this, find_lower_node(root_node, key));
1339 }
1340#endif
1341
1342 //*********************************************************************
1347 //*********************************************************************
1349 {
1350 return const_iterator(*this, find_lower_node(root_node, key));
1351 }
1352
1353#if ETL_USING_CPP11
1354 //*********************************************************************
1355 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1356 const_iterator lower_bound(const K& key) const
1357 {
1358 return const_iterator(*this, find_lower_node(root_node, key));
1359 }
1360#endif
1361
1362 //*********************************************************************
1367 //*********************************************************************
1369 {
1370 return iterator(*this, find_upper_node(root_node, key));
1371 }
1372
1373#if ETL_USING_CPP11
1374 //*********************************************************************
1375 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1376 iterator upper_bound(const K& key)
1377 {
1378 return iterator(*this, find_upper_node(root_node, key));
1379 }
1380#endif
1381
1382 //*********************************************************************
1387 //*********************************************************************
1389 {
1390 return const_iterator(*this, find_upper_node(root_node, key));
1391 }
1392
1393#if ETL_USING_CPP11
1394 //*********************************************************************
1395 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1396 const_iterator upper_bound(const K& key) const
1397 {
1398 return const_iterator(*this, find_upper_node(root_node, key));
1399 }
1400#endif
1401
1402 //*************************************************************************
1404 //*************************************************************************
1405 imap& operator=(const imap& rhs)
1406 {
1407 // Skip if doing self assignment
1408 if (this != &rhs)
1409 {
1410 assign(rhs.cbegin(), rhs.cend());
1411 }
1412
1413 return *this;
1414 }
1415
1416#if ETL_USING_CPP11
1417 //*************************************************************************
1419 //*************************************************************************
1420 imap& operator=(imap&& rhs)
1421 {
1422 // Skip if doing self assignment
1423 if (this != &rhs)
1424 {
1425 this->clear();
1426
1427 typename etl::imap<TKey, TMapped, TKeyCompare>::iterator from = rhs.begin();
1428
1429 while (from != rhs.end())
1430 {
1431 this->insert(etl::move(*from));
1432 ++from;
1433 }
1434 }
1435
1436 return *this;
1437 }
1438#endif
1439
1440 //*************************************************************************
1442 //*************************************************************************
1443 key_compare key_comp() const
1444 {
1445 return kcompare;
1446 }
1447
1448 //*************************************************************************
1450 //*************************************************************************
1452 {
1453 return vcompare;
1454 }
1455
1456 //*************************************************************************
1458 //*************************************************************************
1459 bool contains(const TKey& key) const
1460 {
1461 return find(key) != end();
1462 }
1463
1464#if ETL_USING_CPP11
1465 //*************************************************************************
1466 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1467 bool contains(const K& k) const
1468 {
1469 return find(k) != end();
1470 }
1471#endif
1472
1473 protected:
1474
1475 //*************************************************************************
1477 //*************************************************************************
1478 imap(etl::ipool& node_pool, size_t max_size_)
1479 : etl::map_base(max_size_)
1480 , p_node_pool(&node_pool)
1481 {
1482 }
1483
1484 //*************************************************************************
1486 //*************************************************************************
1488 {
1489 const_iterator item = begin();
1490
1491 while (item != end())
1492 {
1493 item = erase(item);
1494 }
1495 }
1496
1497 private:
1498
1499 //*************************************************************************
1501 //*************************************************************************
1502 Data_Node& allocate_data_node(const_reference value)
1503 {
1504 Data_Node* node = allocate_data_node();
1505 ::new (&node->value) value_type(value);
1506 ETL_INCREMENT_DEBUG_COUNT;
1507 return *node;
1508 }
1509
1510 //*************************************************************************
1512 //*************************************************************************
1513 Data_Node& allocate_data_node_with_key(const_key_reference key)
1514 {
1515 Data_Node* node = allocate_data_node();
1516
1517 ::new ((void*)etl::addressof(node->value.first)) key_type(key);
1518 ::new ((void*)etl::addressof(node->value.second)) mapped_type();
1519 ETL_INCREMENT_DEBUG_COUNT;
1520 return *node;
1521 }
1522
1523#if ETL_USING_CPP11
1524 //*************************************************************************
1526 //*************************************************************************
1527 Data_Node& allocate_data_node(rvalue_reference value)
1528 {
1529 Data_Node* node = allocate_data_node();
1530 ::new (&node->value) value_type(etl::move(value));
1531 ETL_INCREMENT_DEBUG_COUNT;
1532 return *node;
1533 }
1534
1535 //*************************************************************************
1537 //*************************************************************************
1538 Data_Node& allocate_data_node_with_key(rvalue_key_reference key)
1539 {
1540 Data_Node* node = allocate_data_node();
1541
1542 ::new ((void*)etl::addressof(node->value.first)) key_type(etl::move(key));
1543 ::new ((void*)etl::addressof(node->value.second)) mapped_type();
1544 ETL_INCREMENT_DEBUG_COUNT;
1545 return *node;
1546 }
1547
1548#endif
1549
1550 //*************************************************************************
1552 //*************************************************************************
1553 Data_Node* allocate_data_node()
1554 {
1555 Data_Node* (etl::ipool::*func)() = &etl::ipool::allocate<Data_Node>;
1556 return (p_node_pool->*func)();
1557 }
1558
1559 //*************************************************************************
1561 //*************************************************************************
1562 void destroy_data_node(Data_Node& node)
1563 {
1564 node.value.~value_type();
1565 p_node_pool->release(&node);
1566 ETL_DECREMENT_DEBUG_COUNT;
1567 }
1568
1569 //*************************************************************************
1571 //*************************************************************************
1572 Node* find_node(Node* position, const_key_reference key)
1573 {
1574 Node* found = position;
1575 while (found)
1576 {
1577 // Downcast found to Data_Node class for comparison and other operations
1578 Data_Node& found_data_node = imap::data_cast(*found);
1579
1580 // Compare the node value to the current position value
1581 if (node_comp(key, found_data_node))
1582 {
1583 // Keep searching for the node on the left
1584 found = found->children[kLeft];
1585 }
1586 else if (node_comp(found_data_node, key))
1587 {
1588 // Keep searching for the node on the right
1589 found = found->children[kRight];
1590 }
1591 else
1592 {
1593 // Node that matches the key provided was found, exit loop
1594 break;
1595 }
1596 }
1597
1598 // Return the node found (might be ETL_NULLPTR)
1599 return found;
1600 }
1601
1602#if ETL_USING_CPP11
1603 //*********************************************************************
1604 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1605 Node* find_node(Node* position, const K& key)
1606 {
1607 Node* found = position;
1608 while (found)
1609 {
1610 // Downcast found to Data_Node class for comparison and other operations
1611 Data_Node& found_data_node = imap::data_cast(*found);
1612
1613 // Compare the node value to the current position value
1614 if (node_comp(key, found_data_node))
1615 {
1616 // Keep searching for the node on the left
1617 found = found->children[kLeft];
1618 }
1619 else if (node_comp(found_data_node, key))
1620 {
1621 // Keep searching for the node on the right
1622 found = found->children[kRight];
1623 }
1624 else
1625 {
1626 // Node that matches the key provided was found, exit loop
1627 break;
1628 }
1629 }
1630
1631 // Return the node found (might be ETL_NULLPTR)
1632 return found;
1633 }
1634#endif
1635
1636 //*************************************************************************
1638 //*************************************************************************
1639 const Node* find_node(const Node* position, const_key_reference key) const
1640 {
1641 const Node* found = position;
1642 while (found)
1643 {
1644 // Downcast found to Data_Node class for comparison and other operations
1645 const Data_Node& found_data_node = imap::data_cast(*found);
1646
1647 // Compare the node value to the current position value
1648 if (node_comp(key, found_data_node))
1649 {
1650 // Keep searching for the node on the left
1651 found = found->children[kLeft];
1652 }
1653 else if (node_comp(found_data_node, key))
1654 {
1655 // Keep searching for the node on the right
1656 found = found->children[kRight];
1657 }
1658 else
1659 {
1660 // Node that matches the key provided was found, exit loop
1661 break;
1662 }
1663 }
1664
1665 // Return the node found (might be ETL_NULLPTR)
1666 return found;
1667 }
1668
1669#if ETL_USING_CPP11
1670 //*********************************************************************
1671 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1672 const Node* find_node(const Node* position, const K& key) const
1673 {
1674 const Node* found = position;
1675 while (found)
1676 {
1677 // Downcast found to Data_Node class for comparison and other operations
1678 const Data_Node& found_data_node = imap::data_cast(*found);
1679
1680 // Compare the node value to the current position value
1681 if (node_comp(key, found_data_node))
1682 {
1683 // Keep searching for the node on the left
1684 found = found->children[kLeft];
1685 }
1686 else if (node_comp(found_data_node, key))
1687 {
1688 // Keep searching for the node on the right
1689 found = found->children[kRight];
1690 }
1691 else
1692 {
1693 // Node that matches the key provided was found, exit loop
1694 break;
1695 }
1696 }
1697
1698 // Return the node found (might be ETL_NULLPTR)
1699 return found;
1700 }
1701#endif
1702
1703 //*************************************************************************
1705 //*************************************************************************
1706 Node*& find_node(Node*& position, const Node* node)
1707 {
1708 Node* found = position;
1709 while (found)
1710 {
1711 if (found->children[kLeft] == node)
1712 {
1713 return found->children[kLeft];
1714 }
1715 else if (found->children[kRight] == node)
1716 {
1717 return found->children[kRight];
1718 }
1719 else
1720 {
1721 // Downcast found to Data_Node class for comparison and other
1722 // operations
1723 Data_Node& found_data_node = imap::data_cast(*found);
1724 const Data_Node& data_node = imap::data_cast(*node);
1725
1726 // Compare the node value to the current position value
1727 if (node_comp(data_node, found_data_node))
1728 {
1729 // Keep searching for the node on the left
1730 found = found->children[kLeft];
1731 }
1732 else if (node_comp(found_data_node, data_node))
1733 {
1734 // Keep searching for the node on the right
1735 found = found->children[kRight];
1736 }
1737 else
1738 {
1739 // Return position provided (it matches the node)
1740 return position;
1741 }
1742 }
1743 }
1744
1745 // Return root node if nothing was found
1746 return root_node;
1747 }
1748
1749 //*************************************************************************
1752 //*************************************************************************
1753 Node* find_parent_node(Node* position, const Node* node)
1754 {
1755 // Default to no parent node found
1756 Node* found = ETL_NULLPTR;
1757
1758 // If the position provided is the same as the node then there is no
1759 // parent
1760 if (position && node && position != node)
1761 {
1762 while (position)
1763 {
1764 // Is this position not the parent of the node we are looking for?
1765 if (position->children[kLeft] != node && position->children[kRight] != node)
1766 {
1767 // Downcast node and position to Data_Node references for key
1768 // comparisons
1769 const Data_Node& node_data_node = imap::data_cast(*node);
1770 Data_Node& position_data_node = imap::data_cast(*position);
1771 // Compare the node value to the current position value
1772 if (node_comp(node_data_node, position_data_node))
1773 {
1774 // Keep looking for parent on the left
1775 position = position->children[kLeft];
1776 }
1777 else if (node_comp(position_data_node, node_data_node))
1778 {
1779 // Keep looking for parent on the right
1780 position = position->children[kRight];
1781 }
1782 }
1783 else
1784 {
1785 // Return the current position as the parent node found
1786 found = position;
1787
1788 // Parent node found, exit loop
1789 break;
1790 }
1791 }
1792 }
1793
1794 // Return the parent node found (might be ETL_NULLPTR)
1795 return found;
1796 }
1797
1798 //*************************************************************************
1801 //*************************************************************************
1802 const Node* find_parent_node(const Node* position, const Node* node) const
1803 {
1804 // Default to no parent node found
1805 const Node* found = ETL_NULLPTR;
1806
1807 // If the position provided is the same as the node then there is no
1808 // parent
1809 if (position && node && position != node)
1810 {
1811 while (position)
1812 {
1813 // Is this position not the parent of the node we are looking for?
1814 if (position->children[kLeft] != node && position->children[kRight] != node)
1815 {
1816 // Downcast node and position to Data_Node references for key
1817 // comparisons
1818 const Data_Node& node_data_node = imap::data_cast(*node);
1819 const Data_Node& position_data_node = imap::data_cast(*position);
1820 // Compare the node value to the current position value
1821 if (node_comp(node_data_node, position_data_node))
1822 {
1823 // Keep looking for parent on the left
1824 position = position->children[kLeft];
1825 }
1826 else if (node_comp(position_data_node, node_data_node))
1827 {
1828 // Keep looking for parent on the right
1829 position = position->children[kRight];
1830 }
1831 }
1832 else
1833 {
1834 // Return the current position as the parent node found
1835 found = position;
1836
1837 // Parent node found, exit loop
1838 break;
1839 }
1840 }
1841 }
1842
1843 // Return the parent node found (might be ETL_NULLPTR)
1844 return found;
1845 }
1846
1847 //*************************************************************************
1849 //*************************************************************************
1850 Node* find_lower_node(Node* position, const_key_reference key) const
1851 {
1852 // Something at this position? keep going
1853 Node* lower_node = ETL_NULLPTR;
1854 while (position)
1855 {
1856 // Downcast lower node to Data_Node reference for key comparisons
1857 Data_Node& data_node = imap::data_cast(*position);
1858 // Compare the key value to the current lower node key value
1859 if (node_comp(key, data_node))
1860 {
1861 lower_node = position;
1862 if (position->children[kLeft])
1863 {
1864 position = position->children[kLeft];
1865 }
1866 else
1867 {
1868 // Found lowest node
1869 break;
1870 }
1871 }
1872 else if (node_comp(data_node, key))
1873 {
1874 position = position->children[kRight];
1875 }
1876 else
1877 {
1878 // Make note of current position, but keep looking to left for more
1879 lower_node = position;
1880 position = position->children[kLeft];
1881 }
1882 }
1883
1884 // Return the lower_node position found
1885 return lower_node;
1886 }
1887
1888#if ETL_USING_CPP11
1889 //*************************************************************************
1890 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1891 Node* find_lower_node(Node* position, const K& key) const
1892 {
1893 // Something at this position? keep going
1894 Node* lower_node = ETL_NULLPTR;
1895 while (position)
1896 {
1897 // Downcast lower node to Data_Node reference for key comparisons
1898 Data_Node& data_node = imap::data_cast(*position);
1899 // Compare the key value to the current lower node key value
1900 if (node_comp(key, data_node))
1901 {
1902 lower_node = position;
1903 if (position->children[kLeft])
1904 {
1905 position = position->children[kLeft];
1906 }
1907 else
1908 {
1909 // Found lowest node
1910 break;
1911 }
1912 }
1913 else if (node_comp(data_node, key))
1914 {
1915 position = position->children[kRight];
1916 }
1917 else
1918 {
1919 // Make note of current position, but keep looking to left for more
1920 lower_node = position;
1921 position = position->children[kLeft];
1922 }
1923 }
1924
1925 // Return the lower_node position found
1926 return lower_node;
1927 }
1928#endif
1929
1930 //*************************************************************************
1932 //*************************************************************************
1933 Node* find_upper_node(Node* position, const_key_reference key) const
1934 {
1935 // Keep track of parent of last upper node
1936 Node* upper_node = ETL_NULLPTR;
1937 // Start with position provided
1938 Node* node = position;
1939 while (node)
1940 {
1941 // Downcast position to Data_Node reference for key comparisons
1942 Data_Node& data_node = imap::data_cast(*node);
1943 // Compare the key value to the current upper node key value
1944 if (node_comp(key, data_node))
1945 {
1946 upper_node = node;
1947 node = node->children[kLeft];
1948 }
1949 else if (node_comp(data_node, key))
1950 {
1951 node = node->children[kRight];
1952 }
1953 else if (node->children[kRight])
1954 {
1955 upper_node = find_limit_node(node->children[kRight], kLeft);
1956 break;
1957 }
1958 else
1959 {
1960 break;
1961 }
1962 }
1963
1964 // Return the upper node position found (might be ETL_NULLPTR)
1965 return upper_node;
1966 }
1967
1968#if ETL_USING_CPP11
1969 //*************************************************************************
1970 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1971 Node* find_upper_node(Node* position, const K& key) const
1972 {
1973 // Keep track of parent of last upper node
1974 Node* upper_node = ETL_NULLPTR;
1975 // Start with position provided
1976 Node* node = position;
1977 while (node)
1978 {
1979 // Downcast position to Data_Node reference for key comparisons
1980 Data_Node& data_node = imap::data_cast(*node);
1981 // Compare the key value to the current upper node key value
1982 if (node_comp(key, data_node))
1983 {
1984 upper_node = node;
1985 node = node->children[kLeft];
1986 }
1987 else if (node_comp(data_node, key))
1988 {
1989 node = node->children[kRight];
1990 }
1991 else if (node->children[kRight])
1992 {
1993 upper_node = find_limit_node(node->children[kRight], kLeft);
1994 break;
1995 }
1996 else
1997 {
1998 break;
1999 }
2000 }
2001
2002 // Return the upper node position found (might be ETL_NULLPTR)
2003 return upper_node;
2004 }
2005#endif
2006
2007 //*************************************************************************
2009 //*************************************************************************
2010 Node* insert_node(Node*& position, Data_Node& node)
2011 {
2012 // Find the location where the node belongs
2013 Node* found = position;
2014
2015 // Was position provided not empty? then find where the node belongs
2016 if (position)
2017 {
2018 // Find the critical parent node (default to ETL_NULLPTR)
2019 Node* critical_parent_node = ETL_NULLPTR;
2020 Node* critical_node = root_node;
2021
2022 while (found)
2023 {
2024 // Search for critical weight node (all nodes whose weight factor
2025 // is set to kNeither (balanced)
2026 if (kNeither != found->weight)
2027 {
2028 critical_node = found;
2029 }
2030
2031 // Downcast found to Data_Node class for comparison and other
2032 // operations
2033 Data_Node& found_data_node = imap::data_cast(*found);
2034
2035 // Is the node provided to the left of the current position?
2036 if (node_comp(node, found_data_node))
2037 {
2038 // Update direction taken to insert new node in parent node
2039 found->dir = kLeft;
2040 }
2041 // Is the node provided to the right of the current position?
2042 else if (node_comp(found_data_node, node))
2043 {
2044 // Update direction taken to insert new node in parent node
2045 found->dir = kRight;
2046 }
2047 else
2048 {
2049 // Update direction taken to insert new node in parent node
2050 found->dir = kNeither;
2051
2052 // Clear critical node value to skip weight step below
2053 critical_node = ETL_NULLPTR;
2054
2055 // Destroy the node provided (its a duplicate)
2056 destroy_data_node(node);
2057
2058 // Exit loop, duplicate node found
2059 break;
2060 }
2061
2062 // Is there a child of this parent node?
2063 if (found->children[found->dir])
2064 {
2065 // Will this node be the parent of the next critical node whose
2066 // weight factor is set to kNeither (balanced)?
2067 if (kNeither != found->children[found->dir]->weight)
2068 {
2069 critical_parent_node = found;
2070 }
2071
2072 // Keep looking for empty spot to insert new node
2073 found = found->children[found->dir];
2074 }
2075 else
2076 {
2077 // Attach node to right
2078 attach_node(found->children[found->dir], node);
2079
2080 // Return newly added node
2081 found = found->children[found->dir];
2082
2083 // Exit loop
2084 break;
2085 }
2086 }
2087
2088 // Was a critical node found that should be checked for balance?
2089 if (critical_node)
2090 {
2091 if (critical_parent_node == ETL_NULLPTR && critical_node == root_node)
2092 {
2094 }
2095 else if (critical_parent_node == ETL_NULLPTR && critical_node == position)
2096 {
2097 balance_node(position);
2098 }
2099 else
2100 {
2101 if (critical_parent_node != ETL_NULLPTR)
2102 {
2103 balance_node(critical_parent_node->children[critical_parent_node->dir]);
2104 }
2105 }
2106 }
2107 }
2108 else
2109 {
2110 // Attach node to current position
2111 attach_node(position, node);
2112
2113 // Return newly added node at current position
2114 found = position;
2115 }
2116
2117 // Return the node found (might be ETL_NULLPTR)
2118 return found;
2119 }
2120
2121 //*************************************************************************
2123 //*************************************************************************
2124 void next_node(Node*& position)
2125 {
2126 if (position)
2127 {
2128 // Is there a tree on the right? then find the minimum of that tree
2129 if (position->children[kRight])
2130 {
2131 // Return minimum node found
2132 position = find_limit_node(position->children[kRight], kLeft);
2133 }
2134 // Otherwise find the parent of this node
2135 else
2136 {
2137 // Start with current position as parent
2138 Node* parent = position;
2139 do {
2140 // Update current position as previous parent
2141 position = parent;
2142 // Find parent of current position
2143 parent = find_parent_node(root_node, position);
2144 // Repeat while previous position was on right side of parent tree
2145 } while (parent && parent->children[kRight] == position);
2146
2147 // Set parent node as the next position
2148 position = parent;
2149 }
2150 }
2151 }
2152
2153 //*************************************************************************
2155 //*************************************************************************
2156 void next_node(const Node*& position) const
2157 {
2158 if (position)
2159 {
2160 // Is there a tree on the right? then find the minimum of that tree
2161 if (position->children[kRight])
2162 {
2163 // Return minimum node found
2164 position = find_limit_node(position->children[kRight], kLeft);
2165 }
2166 // Otherwise find the parent of this node
2167 else
2168 {
2169 // Start with current position as parent
2170 const Node* parent = position;
2171 do {
2172 // Update current position as previous parent
2173 position = parent;
2174 // Find parent of current position
2175 parent = find_parent_node(root_node, position);
2176 // Repeat while previous position was on right side of parent tree
2177 } while (parent && parent->children[kRight] == position);
2178
2179 // Set parent node as the next position
2180 position = parent;
2181 }
2182 }
2183 }
2184
2185 //*************************************************************************
2187 //*************************************************************************
2188 void prev_node(Node*& position)
2189 {
2190 // If starting at the terminal end, the previous node is the maximum node
2191 // from the root
2192 if (!position)
2193 {
2194 position = find_limit_node(root_node, kRight);
2195 }
2196 else
2197 {
2198 // Is there a tree on the left? then find the maximum of that tree
2199 if (position->children[kLeft])
2200 {
2201 // Return maximum node found
2202 position = find_limit_node(position->children[kLeft], kRight);
2203 }
2204 // Otherwise find the parent of this node
2205 else
2206 {
2207 // Start with current position as parent
2208 Node* parent = position;
2209 do {
2210 // Update current position as previous parent
2211 position = parent;
2212 // Find parent of current position
2213 parent = find_parent_node(root_node, position);
2214 // Repeat while previous position was on left side of parent tree
2215 } while (parent && parent->children[kLeft] == position);
2216
2217 // Set parent node as the next position
2218 position = parent;
2219 }
2220 }
2221 }
2222
2223 //*************************************************************************
2225 //*************************************************************************
2226 void prev_node(const Node*& position) const
2227 {
2228 // If starting at the terminal end, the previous node is the maximum node
2229 // from the root
2230 if (!position)
2231 {
2232 position = find_limit_node(root_node, kRight);
2233 }
2234 else
2235 {
2236 // Is there a tree on the left? then find the maximum of that tree
2237 if (position->children[kLeft])
2238 {
2239 // Return maximum node found
2240 position = find_limit_node(position->children[kLeft], kRight);
2241 }
2242 // Otherwise find the parent of this node
2243 else
2244 {
2245 // Start with current position as parent
2246 const Node* parent = position;
2247 do {
2248 // Update current position as previous parent
2249 position = parent;
2250 // Find parent of current position
2251 parent = find_parent_node(root_node, position);
2252 // Repeat while previous position was on left side of parent tree
2253 } while (parent && parent->children[kLeft] == position);
2254
2255 // Set parent node as the next position
2256 position = parent;
2257 }
2258 }
2259 }
2260
2261 //*************************************************************************
2264 //*************************************************************************
2265 Node* remove_node(Node*& position, const_key_reference key)
2266 {
2267 // Step 1: Find the target node that matches the key provided, the
2268 // replacement node (might be the same as target node), and the critical
2269 // node to start rebalancing the tree from (up to the replacement node)
2270 Node* found_parent = ETL_NULLPTR;
2271 Node* found = ETL_NULLPTR;
2272 Node* replace_parent = ETL_NULLPTR;
2273 Node* replace = position;
2274 Node* balance_parent = ETL_NULLPTR;
2275 Node* balance = root_node;
2276 while (replace)
2277 {
2278 // Downcast found to Data_Node class for comparison and other operations
2279 Data_Node& replace_data_node = imap::data_cast(*replace);
2280
2281 // Compare the key provided to the replace data node key
2282 if (node_comp(key, replace_data_node))
2283 {
2284 // Update the direction to the target/replace node
2285 replace->dir = kLeft;
2286 }
2287 else if (node_comp(replace_data_node, key))
2288 {
2289 // Update the direction to the target/replace node
2290 replace->dir = kRight;
2291 }
2292 else
2293 {
2294 // Update the direction to the replace node (target node found here)
2295 replace->dir = replace->children[kLeft] ? kLeft : kRight;
2296
2297 // Note the target node was found (and its parent)
2298 found_parent = replace_parent;
2299 found = replace;
2300 }
2301 // Replacement node found if its missing a child in the replace->dir
2302 // value set above
2303 if (replace->children[replace->dir] == ETL_NULLPTR)
2304 {
2305 // Exit loop once replace node is found (target might not have been)
2306 break;
2307 }
2308
2309 // If replacement node weight is kNeither or we are taking the shorter
2310 // path of replacement node and our sibling (on longer path) is
2311 // balanced then we need to update the balance node to match this
2312 // replacement node but all our ancestors will not require rebalancing
2313 if ((replace->weight == kNeither) || (replace->weight == (1 - replace->dir) && replace->children[1 - replace->dir]->weight == kNeither))
2314 {
2315 // Update balance node (and its parent) to replacement node
2316 balance_parent = replace_parent;
2317 balance = replace;
2318 }
2319
2320 // Keep searching for the replacement node
2321 replace_parent = replace;
2322 replace = replace->children[replace->dir];
2323 }
2324
2325 // If target node was found, proceed with rebalancing and replacement
2326 if (found)
2327 {
2328 // Step 2: Update weights from critical node to replacement parent node
2329 while (balance)
2330 {
2331 if (balance->children[balance->dir] == ETL_NULLPTR)
2332 {
2333 break;
2334 }
2335
2336 if (balance->weight == kNeither)
2337 {
2338 balance->weight = 1 - balance->dir;
2339 }
2340 else if (balance->weight == balance->dir)
2341 {
2342 balance->weight = kNeither;
2343 }
2344 else
2345 {
2346 int weight = balance->children[1 - balance->dir]->weight;
2347 // Perform a 3 node rotation if weight is same as balance->dir
2348 if (weight == balance->dir)
2349 {
2350 // Is the root node being rebalanced (no parent)
2351 if (balance_parent == ETL_NULLPTR)
2352 {
2353 rotate_3node(root_node, 1 - balance->dir, balance->children[1 - balance->dir]->children[balance->dir]->weight);
2354 }
2355 else
2356 {
2357 rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir,
2358 balance->children[1 - balance->dir]->children[balance->dir]->weight);
2359 }
2360 }
2361 // Already balanced, rebalance and make it heavy in opposite
2362 // direction of the node being removed
2363 else if (weight == kNeither)
2364 {
2365 // Is the root node being rebalanced (no parent)
2366 if (balance_parent == ETL_NULLPTR)
2367 {
2368 rotate_2node(root_node, 1 - balance->dir);
2369 root_node->weight = balance->dir;
2370 }
2371 else
2372 {
2373 rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
2374 balance_parent->children[balance_parent->dir]->weight = balance->dir;
2375 }
2376 // Update balance node weight in opposite direction of node
2377 // removed
2378 balance->weight = 1 - balance->dir;
2379 }
2380 // Rebalance and leave it balanced
2381 else
2382 {
2383 // Is the root node being rebalanced (no parent)
2384 if (balance_parent == ETL_NULLPTR)
2385 {
2386 rotate_2node(root_node, 1 - balance->dir);
2387 }
2388 else
2389 {
2390 rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
2391 }
2392 }
2393
2394 // Is balance node the same as the target node found? then update
2395 // its parent after the rotation performed above
2396 if (balance == found)
2397 {
2398 if (balance_parent)
2399 {
2400 found_parent = balance_parent->children[balance_parent->dir];
2401 // Update dir since it is likely stale
2402 found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight;
2403 }
2404 else
2405 {
2406 found_parent = root_node;
2407 root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight;
2408 }
2409 }
2410 }
2411
2412 // Next balance node to consider
2413 balance_parent = balance;
2414 balance = balance->children[balance->dir];
2415 } // while(balance)
2416
2417 // Step 3: Swap found node with replacement node
2418 if (found_parent)
2419 {
2420 // Handle traditional case
2421 detach_node(found_parent->children[found_parent->dir], replace_parent->children[replace_parent->dir]);
2422 }
2423 // Handle root node removal
2424 else
2425 {
2426 // Valid replacement node for root node being removed?
2427 if (replace_parent)
2428 {
2429 detach_node(root_node, replace_parent->children[replace_parent->dir]);
2430 }
2431 else
2432 {
2433 // Target node and replacement node are both root node
2435 }
2436 }
2437
2438 // Downcast found into data node
2439 Data_Node& found_data_node = imap::data_cast(*found);
2440
2441 // One less.
2442 --current_size;
2443
2444 // Destroy the node removed
2445 destroy_data_node(found_data_node);
2446 } // if(found)
2447
2448 // Return node found (might be ETL_NULLPTR)
2449 return found;
2450 }
2451
2452#if ETL_USING_CPP11
2453 //*************************************************************************
2456 //*************************************************************************
2457 template <typename K, typename KC = TKeyCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
2458 Node* remove_node(Node*& position, const K& key)
2459 {
2460 // Step 1: Find the target node that matches the key provided, the
2461 // replacement node (might be the same as target node), and the critical
2462 // node to start rebalancing the tree from (up to the replacement node)
2463 Node* found_parent = ETL_NULLPTR;
2464 Node* found = ETL_NULLPTR;
2465 Node* replace_parent = ETL_NULLPTR;
2466 Node* replace = position;
2467 Node* balance_parent = ETL_NULLPTR;
2468 Node* balance = root_node;
2469 while (replace)
2470 {
2471 // Downcast found to Data_Node class for comparison and other operations
2472 Data_Node& replace_data_node = imap::data_cast(*replace);
2473
2474 // Compare the key provided to the replace data node key
2475 if (node_comp(key, replace_data_node))
2476 {
2477 // Update the direction to the target/replace node
2478 replace->dir = kLeft;
2479 }
2480 else if (node_comp(replace_data_node, key))
2481 {
2482 // Update the direction to the target/replace node
2483 replace->dir = kRight;
2484 }
2485 else
2486 {
2487 // Update the direction to the replace node (target node found here)
2488 replace->dir = replace->children[kLeft] ? kLeft : kRight;
2489
2490 // Note the target node was found (and its parent)
2491 found_parent = replace_parent;
2492 found = replace;
2493 }
2494 // Replacement node found if its missing a child in the replace->dir
2495 // value set above
2496 if (replace->children[replace->dir] == ETL_NULLPTR)
2497 {
2498 // Exit loop once replace node is found (target might not have been)
2499 break;
2500 }
2501
2502 // If replacement node weight is kNeither or we are taking the shorter
2503 // path of replacement node and our sibling (on longer path) is
2504 // balanced then we need to update the balance node to match this
2505 // replacement node but all our ancestors will not require rebalancing
2506 if ((replace->weight == kNeither) || (replace->weight == (1 - replace->dir) && replace->children[1 - replace->dir]->weight == kNeither))
2507 {
2508 // Update balance node (and its parent) to replacement node
2509 balance_parent = replace_parent;
2510 balance = replace;
2511 }
2512
2513 // Keep searching for the replacement node
2514 replace_parent = replace;
2515 replace = replace->children[replace->dir];
2516 }
2517
2518 // If target node was found, proceed with rebalancing and replacement
2519 if (found)
2520 {
2521 // Step 2: Update weights from critical node to replacement parent node
2522 while (balance)
2523 {
2524 if (balance->children[balance->dir] == ETL_NULLPTR)
2525 {
2526 break;
2527 }
2528
2529 if (balance->weight == kNeither)
2530 {
2531 balance->weight = 1 - balance->dir;
2532 }
2533 else if (balance->weight == balance->dir)
2534 {
2535 balance->weight = kNeither;
2536 }
2537 else
2538 {
2539 int weight = balance->children[1 - balance->dir]->weight;
2540 // Perform a 3 node rotation if weight is same as balance->dir
2541 if (weight == balance->dir)
2542 {
2543 // Is the root node being rebalanced (no parent)
2544 if (balance_parent == ETL_NULLPTR)
2545 {
2546 rotate_3node(root_node, 1 - balance->dir, balance->children[1 - balance->dir]->children[balance->dir]->weight);
2547 }
2548 else
2549 {
2550 rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir,
2551 balance->children[1 - balance->dir]->children[balance->dir]->weight);
2552 }
2553 }
2554 // Already balanced, rebalance and make it heavy in opposite
2555 // direction of the node being removed
2556 else if (weight == kNeither)
2557 {
2558 // Is the root node being rebalanced (no parent)
2559 if (balance_parent == ETL_NULLPTR)
2560 {
2561 rotate_2node(root_node, 1 - balance->dir);
2562 root_node->weight = balance->dir;
2563 }
2564 else
2565 {
2566 rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
2567 balance_parent->children[balance_parent->dir]->weight = balance->dir;
2568 }
2569 // Update balance node weight in opposite direction of node
2570 // removed
2571 balance->weight = 1 - balance->dir;
2572 }
2573 // Rebalance and leave it balanced
2574 else
2575 {
2576 // Is the root node being rebalanced (no parent)
2577 if (balance_parent == ETL_NULLPTR)
2578 {
2579 rotate_2node(root_node, 1 - balance->dir);
2580 }
2581 else
2582 {
2583 rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
2584 }
2585 }
2586
2587 // Is balance node the same as the target node found? then update
2588 // its parent after the rotation performed above
2589 if (balance == found)
2590 {
2591 if (balance_parent)
2592 {
2593 found_parent = balance_parent->children[balance_parent->dir];
2594 // Update dir since it is likely stale
2595 found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight;
2596 }
2597 else
2598 {
2599 found_parent = root_node;
2600 root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight;
2601 }
2602 }
2603 }
2604
2605 // Next balance node to consider
2606 balance_parent = balance;
2607 balance = balance->children[balance->dir];
2608 } // while(balance)
2609
2610 // Step 3: Swap found node with replacement node
2611 if (found_parent)
2612 {
2613 // Handle traditional case
2614 detach_node(found_parent->children[found_parent->dir], replace_parent->children[replace_parent->dir]);
2615 }
2616 // Handle root node removal
2617 else
2618 {
2619 // Valid replacement node for root node being removed?
2620 if (replace_parent)
2621 {
2622 detach_node(root_node, replace_parent->children[replace_parent->dir]);
2623 }
2624 else
2625 {
2626 // Target node and replacement node are both root node
2628 }
2629 }
2630
2631 // Downcast found into data node
2632 Data_Node& found_data_node = imap::data_cast(*found);
2633
2634 // One less.
2635 --current_size;
2636
2637 // Destroy the node removed
2638 destroy_data_node(found_data_node);
2639 } // if(found)
2640
2641 // Return node found (might be ETL_NULLPTR)
2642 return found;
2643 }
2644#endif
2645
2646 // Disable copy construction.
2647 imap(const imap&);
2648
2649 //*************************************************************************
2651 //*************************************************************************
2652#if defined(ETL_POLYMORPHIC_MAP) || defined(ETL_POLYMORPHIC_CONTAINERS)
2653
2654 public:
2655
2656 virtual ~imap() {}
2657#else
2658
2659 protected:
2660
2662#endif
2663 };
2664
2665 //*************************************************************************
2667 //*************************************************************************
2668 template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = etl::less<TKey> >
2669 class map : public etl::imap<TKey, TValue, TCompare>
2670 {
2671 public:
2672
2673 static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_;
2674
2675 //*************************************************************************
2677 //*************************************************************************
2679 : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2680 {
2681 this->initialise();
2682 }
2683
2684 //*************************************************************************
2686 //*************************************************************************
2687 map(const map& other)
2688 : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2689 {
2690 if (this != &other)
2691 {
2692 this->assign(other.cbegin(), other.cend());
2693 }
2694 }
2695
2696#if ETL_USING_CPP11
2697 //*************************************************************************
2699 //*************************************************************************
2700 map(map&& other)
2701 : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2702 {
2703 if (this != &other)
2704 {
2705 typename etl::imap<TKey, TValue, TCompare>::iterator from = other.begin();
2706
2707 while (from != other.end())
2708 {
2710 ++temp;
2711
2712 this->insert(etl::move(*from));
2713 from = temp;
2714 }
2715 }
2716 }
2717#endif
2718
2719 //*************************************************************************
2724 //*************************************************************************
2725 template <typename TIterator>
2726 map(TIterator first, TIterator last)
2727 : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2728 {
2729 this->assign(first, last);
2730 }
2731
2732#if ETL_HAS_INITIALIZER_LIST
2733 //*************************************************************************
2735 //*************************************************************************
2736 map(std::initializer_list< typename etl::imap<TKey, TValue, TCompare>::value_type> init)
2737 : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2738 {
2739 this->assign(init.begin(), init.end());
2740 }
2741#endif
2742
2743 //*************************************************************************
2745 //*************************************************************************
2747 {
2748 this->initialise();
2749 }
2750
2751 //*************************************************************************
2753 //*************************************************************************
2754 map& operator=(const map& rhs)
2755 {
2756 // Skip if doing self assignment
2757 if (this != &rhs)
2758 {
2759 this->assign(rhs.cbegin(), rhs.cend());
2760 }
2761
2762 return *this;
2763 }
2764
2765#if ETL_USING_CPP11
2766 //*************************************************************************
2768 //*************************************************************************
2769 map& operator=(map&& rhs)
2770 {
2771 // Skip if doing self assignment
2772 if (this != &rhs)
2773 {
2774 this->clear();
2775
2776 typename etl::imap<TKey, TValue, TCompare>::iterator from = rhs.begin();
2777
2778 while (from != rhs.end())
2779 {
2781 ++temp;
2782
2783 this->insert(etl::move(*from));
2784 from = temp;
2785 }
2786 }
2787
2788 return *this;
2789 }
2790#endif
2791
2792 private:
2793
2795 etl::pool<typename etl::imap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool;
2796 };
2797
2798 template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare>
2799 ETL_CONSTANT size_t map<TKey, TValue, MAX_SIZE_, TCompare>::MAX_SIZE;
2800
2801 //*************************************************************************
2803 //*************************************************************************
2804#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
2805 template <typename... TPairs>
2806 map(TPairs...) -> map<typename etl::nth_type_t<0, TPairs...>::first_type, typename etl::nth_type_t<0, TPairs...>::second_type, sizeof...(TPairs)>;
2807#endif
2808
2809 //*************************************************************************
2811 //*************************************************************************
2812#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
2813 template <typename TKey, typename TMapped, typename TKeyCompare = etl::less<TKey>, typename... TPairs>
2814 constexpr auto make_map(TPairs&&... pairs) -> etl::map<TKey, TMapped, sizeof...(TPairs), TKeyCompare>
2815 {
2816 return {etl::forward<TPairs>(pairs)...};
2817 }
2818#endif
2819
2820 //***************************************************************************
2826 //***************************************************************************
2827 template <typename TKey, typename TMapped, typename TKeyCompare>
2829 {
2830 return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
2831 }
2832
2833 //***************************************************************************
2839 //***************************************************************************
2840 template <typename TKey, typename TMapped, typename TKeyCompare>
2842 {
2843 return !(lhs == rhs);
2844 }
2845
2846 //*************************************************************************
2852 //*************************************************************************
2853 template <typename TKey, typename TMapped, typename TKeyCompare>
2855 {
2856 return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), lhs.value_comp());
2857 }
2858
2859 //*************************************************************************
2865 //*************************************************************************
2866 template <typename TKey, typename TMapped, typename TKeyCompare>
2868 {
2869 return (rhs < lhs);
2870 }
2871
2872 //*************************************************************************
2879 //*************************************************************************
2880 template <typename TKey, typename TMapped, typename TKeyCompare>
2882 {
2883 return !(lhs > rhs);
2884 }
2885
2886 //*************************************************************************
2892 //*************************************************************************
2893 template <typename TKey, typename TMapped, typename TKeyCompare>
2895 {
2896 return !(lhs < rhs);
2897 }
2898} // namespace etl
2899
2900#include "private/minmax_pop.h"
2901
2902#endif
const_iterator
Definition map.h:700
iterator.
Definition map.h:595
Definition map.h:487
A templated map implementation that uses a fixed size buffer.
Definition map.h:2670
map(const map &other)
Copy constructor.
Definition map.h:2687
map & operator=(const map &rhs)
Assignment operator.
Definition map.h:2754
~map()
Destructor.
Definition map.h:2746
map(TIterator first, TIterator last)
Definition map.h:2726
map()
Default constructor.
Definition map.h:2678
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
const_reverse_iterator crend() const
Gets the reverse end of the list.
Definition map.h:908
void detach_node(Node *&position, Node *&replacement)
Detach the node at the position provided.
Definition map.h:429
imap & operator=(const imap &rhs)
Assignment operator.
Definition map.h:1405
void rotate_2node(Node *&position, uint_least8_t dir)
Rotate two nodes at the position provided the to balance the tree.
Definition map.h:310
void clear()
Clears the map.
Definition map.h:1053
bool empty() const
Checks to see if the map is empty.
Definition map.h:148
bool full() const
Checks to see if the map is full.
Definition map.h:156
size_type count(const_key_reference key) const
Definition map.h:1063
const_iterator end() const
Gets the end of the map.
Definition map.h:844
iterator erase(const_iterator first, const_iterator last)
Erases a range of elements.
Definition map.h:1154
const size_type CAPACITY
The maximum size of the map.
Definition map.h:451
void initialise()
Initialise the map.
Definition map.h:1487
size_t size_type
The type used for determining the size of map.
Definition map.h:127
reverse_iterator rend()
Gets the reverse end of the list.
Definition map.h:884
void assign(TIterator first, TIterator last)
Definition map.h:1044
void insert(TIterator first, TIterator last)
Definition map.h:1313
map_base(size_type max_size_)
The constructor that is called from derived classes.
Definition map.h:225
mapped_reference at(const_key_reference key)
Definition map.h:984
key_compare key_comp() const
How to compare two key elements.
Definition map.h:1443
size_type capacity() const
Definition map.h:165
ETL_OR_STD::pair< iterator, iterator > equal_range(const_key_reference key)
Definition map.h:1081
~imap()
Destructor.
Definition map.h:2661
const_mapped_reference at(const_key_reference key) const
Definition map.h:1013
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(const_key_reference key) const
Definition map.h:1101
ETL_OR_STD::pair< iterator, bool > insert(const_reference value)
Definition map.h:1208
const_iterator cbegin() const
Gets the beginning of the map.
Definition map.h:852
const_reverse_iterator rbegin() const
Gets the reverse beginning of the list.
Definition map.h:876
Node * root_node
The node that acts as the map root.
Definition map.h:452
size_type size() const
Gets the size of the map.
Definition map.h:132
const_iterator cend() const
Gets the end of the map.
Definition map.h:860
size_type max_size() const
Gets the maximum possible size of the map.
Definition map.h:140
iterator find(const_key_reference key)
Definition map.h:1169
const_iterator upper_bound(const_key_reference key) const
Definition map.h:1388
const key_type & const_key_reference
Defines the parameter types.
Definition map.h:479
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 map.h:340
iterator upper_bound(const_key_reference key)
Definition map.h:1368
iterator lower_bound(const_key_reference key)
Definition map.h:1328
iterator begin()
Gets the beginning of the map.
Definition map.h:820
size_t available() const
Definition map.h:174
const_reverse_iterator crbegin() const
Gets the reverse beginning of the list.
Definition map.h:900
bool contains(const TKey &key) const
Check if the map contains the key.
Definition map.h:1459
iterator end()
Gets the end of the map.
Definition map.h:836
const_reverse_iterator rend() const
Gets the reverse end of the list.
Definition map.h:892
const_iterator lower_bound(const_key_reference key) const
Definition map.h:1348
reverse_iterator rbegin()
Gets the reverse beginning of the list.
Definition map.h:868
iterator erase(const_iterator position)
Erases the value at the specified position.
Definition map.h:1120
const Node * find_limit_node(const Node *position, const int8_t dir) const
Definition map.h:398
size_type current_size
The number of the used nodes.
Definition map.h:450
Node * find_limit_node(Node *position, const int8_t dir) const
Definition map.h:381
~map_base()
Destructor.
Definition map.h:236
const_iterator find(const_key_reference key) const
Definition map.h:1188
mapped_reference operator[](const_key_reference key)
Definition map.h:951
value_compare value_comp() const
How to compare two value elements.
Definition map.h:1451
imap(etl::ipool &node_pool, size_t max_size_)
Constructor.
Definition map.h:1478
void attach_node(Node *&position, Node &node)
Attach the provided node to the position provided.
Definition map.h:414
iterator insert(const_iterator, const_reference value)
Definition map.h:1261
const_iterator begin() const
Gets the beginning of the map.
Definition map.h:828
bool node_comp(const Data_Node &node1, const Data_Node &node2) const
How to compare node elements.
Definition map.h:520
void balance_node(Node *&critical_node)
Balance the critical node at the position provided as needed.
Definition map.h:241
Definition map.h:462
Definition map.h:124
Definition map.h:68
Definition map.h:82
Definition map.h:96
ETL_CONSTEXPR17 etl::enable_if<!etl::is_same< T, etl::nullptr_t >::value, T >::type * addressof(T &t)
Definition addressof.h:52
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 map.
Definition map.h:506
iterator
Definition iterator.h:424
The node element in the map.
Definition map.h:192
void mark_as_leaf()
Marks the node as a leaf.
Definition map.h:209
Node()
Constructor.
Definition map.h:196