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