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