Embedded Template Library  1.0
map.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2014 jwellbelove, rlindeman
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_MAP_INCLUDED
32 #define ETL_MAP_INCLUDED
33 
34 #include <stddef.h>
35 
36 #include "platform.h"
37 #include "algorithm.h"
38 #include "iterator.h"
39 #include "functional.h"
40 #include "container.h"
41 #include "pool.h"
42 #include "exception.h"
43 #include "error_handler.h"
44 #include "debug_count.h"
45 #include "nullptr.h"
46 #include "type_traits.h"
47 #include "parameter_type.h"
48 #include "iterator.h"
49 #include "utility.h"
50 #include "placement_new.h"
51 
52 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
53  #include <initializer_list>
54 #endif
55 
56 #include "private/minmax_push.h"
57 
58 #undef ETL_FILE
59 #define ETL_FILE "8"
60 
61 //*****************************************************************************
65 //*****************************************************************************
66 
67 namespace etl
68 {
69  //***************************************************************************
72  //***************************************************************************
74  {
75  public:
76 
77  map_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
78  : exception(reason_, file_name_, line_number_)
79  {
80  }
81  };
82 
83  //***************************************************************************
86  //***************************************************************************
88  {
89  public:
90 
91  map_full(string_type file_name_, numeric_type line_number_)
92  : etl::map_exception("map:full", file_name_, line_number_)
93  {
94  }
95  };
96 
97  //***************************************************************************
100  //***************************************************************************
102  {
103  public:
104 
105  map_out_of_bounds(string_type file_name_, numeric_type line_number_)
106  : etl::map_exception("map:bounds", file_name_, line_number_)
107  {
108  }
109  };
110 
111  //***************************************************************************
114  //***************************************************************************
116  {
117  public:
118 
119  map_iterator(string_type file_name_, numeric_type line_number_)
120  : etl::map_exception("map:iterator", file_name_, line_number_)
121  {
122  }
123  };
124 
125  //***************************************************************************
128  //***************************************************************************
129  class map_base
130  {
131  public:
132 
133  typedef size_t size_type;
134 
135  //*************************************************************************
137  //*************************************************************************
138  size_type size() const
139  {
140  return current_size;
141  }
142 
143  //*************************************************************************
145  //*************************************************************************
147  {
148  return CAPACITY;
149  }
150 
151  //*************************************************************************
153  //*************************************************************************
154  bool empty() const
155  {
156  return current_size == 0;
157  }
158 
159  //*************************************************************************
161  //*************************************************************************
162  bool full() const
163  {
164  return current_size == CAPACITY;
165  }
166 
167  //*************************************************************************
170  //*************************************************************************
172  {
173  return CAPACITY;
174  }
175 
176  //*************************************************************************
179  //*************************************************************************
180  size_t available() const
181  {
182  return max_size() - size();
183  }
184 
185  protected:
186 
187  enum
188  {
189  kLeft = 0,
190  kRight = 1,
191  kNeither = 2
192  };
193 
194  //*************************************************************************
196  //*************************************************************************
197  struct Node
198  {
199  //***********************************************************************
201  //***********************************************************************
202  Node() :
203  weight(uint_least8_t(kNeither)),
204  dir(uint_least8_t(kNeither))
205  {
206  }
207 
208  ~Node()
209  {
210 
211  }
212 
213  //***********************************************************************
215  //***********************************************************************
217  {
218  weight = uint_least8_t(kNeither);
219  dir = uint_least8_t(kNeither);
220  children[0] = ETL_NULLPTR;
221  children[1] = ETL_NULLPTR;
222  }
223 
224  Node* children[2];
225  uint_least8_t weight;
226  uint_least8_t dir;
227  };
228 
229  //*************************************************************************
231  //*************************************************************************
232  map_base(size_type max_size_)
233  : current_size(0)
234  , CAPACITY(max_size_)
235  , root_node(ETL_NULLPTR)
236 
237  {
238  }
239 
240  //*************************************************************************
242  //*************************************************************************
244  {
245  }
246 
247  //*************************************************************************
249  //*************************************************************************
250  void balance_node(Node*& critical_node)
251  {
252  // Step 1: Update weights for all children of the critical node up to the
253  // newly inserted node. This step is costly (in terms of traversing nodes
254  // multiple times during insertion) but doesn't require as much recursion
255  Node* weight_node = critical_node->children[critical_node->dir];
256  while (weight_node)
257  {
258  // Keep going until we reach a terminal node (dir == kNeither)
259  if (uint_least8_t(kNeither) != weight_node->dir)
260  {
261  // Does this insert balance the previous weight factor value?
262  if (weight_node->weight == 1 - weight_node->dir)
263  {
264  weight_node->weight = uint_least8_t(kNeither);
265  }
266  else
267  {
268  weight_node->weight = weight_node->dir;
269  }
270 
271  // Update weight factor node to point to next node
272  weight_node = weight_node->children[weight_node->dir];
273  }
274  else
275  {
276  // Stop loop, terminal node found
277  break;
278  }
279  } // while(weight_node)
280 
281  // Step 2: Update weight for critical_node or rotate tree to balance node
282  if (uint_least8_t(kNeither) == critical_node->weight)
283  {
284  critical_node->weight = critical_node->dir;
285  }
286  // If direction is different than weight, then it will now be balanced
287  else if (critical_node->dir != critical_node->weight)
288  {
289  critical_node->weight = uint_least8_t(kNeither);
290  }
291  // Rotate is required to balance the tree at the critical node
292  else
293  {
294  // If critical node matches child node direction then perform a two
295  // node rotate in the direction of the critical node
296  if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
297  {
298  rotate_2node(critical_node, critical_node->dir);
299  }
300  // Otherwise perform a three node rotation in the direction of the
301  // critical node
302  else
303  {
304  rotate_3node(critical_node, critical_node->dir,
305  critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
306  }
307  }
308  }
309 
310  //*************************************************************************
312  //*************************************************************************
313  void rotate_2node(Node*& position, uint_least8_t dir)
314  {
315  // A C A B
316  // B C -> A E OR B C -> D A
317  // D E B D D E E C
318  // C (new position) becomes the root
319  // A (position) takes ownership of D as its children[kRight] child
320  // C (new position) takes ownership of A as its left child
321  // OR
322  // B (new position) becomes the root
323  // A (position) takes ownership of E as its left child
324  // B (new position) takes ownership of A as its right child
325 
326  // Capture new root
327  Node* new_root = position->children[dir];
328  // Replace position's previous child with new root's other child
329  position->children[dir] = new_root->children[1 - dir];
330  // New root now becomes parent of current position
331  new_root->children[1 - dir] = position;
332  // Clear weight factor from current position
333  position->weight = uint_least8_t(kNeither);
334  // Newly detached right now becomes current position
335  position = new_root;
336  // Clear weight factor from new root
337  position->weight = uint_least8_t(kNeither);
338  }
339 
340  //*************************************************************************
342  //*************************************************************************
343  void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
344  {
345  // --A-- --E-- --A-- --D--
346  // _B_ C -> B A OR B _C_ -> A C
347  // D E D F G C D E B F G E
348  // F G F G
349  // E (new position) becomes the root
350  // B (position) takes ownership of F as its left child
351  // A takes ownership of G as its right child
352  // OR
353  // D (new position) becomes the root
354  // A (position) takes ownership of F as its right child
355  // C takes ownership of G as its left child
356 
357  // Capture new root (either E or D depending on dir)
358  Node* new_root = position->children[dir]->children[1 - dir];
359  // Set weight factor for B or C based on F or G existing and being a different than dir
360  position->children[dir]->weight = third != uint_least8_t(kNeither) && third != dir ? dir : uint_least8_t(kNeither);
361 
362  // Detach new root from its tree (replace with new roots child)
363  position->children[dir]->children[1 - dir] =
364  new_root->children[dir];
365  // Attach current left tree to new root
366  new_root->children[dir] = position->children[dir];
367  // Set weight factor for A based on F or G
368  position->weight = third != uint_least8_t(kNeither) && third == dir ? 1 - dir : uint_least8_t(kNeither);
369 
370  // Move new root's right tree to current roots left tree
371  position->children[dir] = new_root->children[1 - dir];
372  // Attach current root to new roots right tree
373  new_root->children[1 - dir] = position;
374  // Replace current position with new root
375  position = new_root;
376  // Clear weight factor for new current position
377  position->weight = uint_least8_t(kNeither);
378  }
379 
380  //*************************************************************************
383  //*************************************************************************
384  Node* find_limit_node(Node* position, const int8_t dir) const
385  {
386  // Something at this position and in the direction specified? keep going
387  Node* limit_node = position;
388  while (limit_node && limit_node->children[dir])
389  {
390  limit_node = limit_node->children[dir];
391  }
392 
393  // Return the limit node position found
394  return limit_node;
395  }
396 
397  //*************************************************************************
400  //*************************************************************************
401  const Node* find_limit_node(const Node* position, const int8_t dir) const
402  {
403  // Something at this position and in the direction specified? keep going
404  const Node* limit_node = position;
405  while (limit_node && limit_node->children[dir])
406  {
407  limit_node = limit_node->children[dir];
408  }
409 
410  // Return the limit node position found
411  return limit_node;
412  }
413 
414  //*************************************************************************
416  //*************************************************************************
417  void attach_node(Node*& position, Node& node)
418  {
419  // Mark new node as leaf on attach to tree at position provided
420  node.mark_as_leaf();
421 
422  // Add the node here
423  position = &node;
424 
425  // One more.
426  ++current_size;
427  }
428 
429  //*************************************************************************
431  //*************************************************************************
432  void detach_node(Node*& position, Node*& replacement)
433  {
434  // Make temporary copy of actual nodes involved because we might lose
435  // their references in the process (e.g. position is the same as
436  // replacement or replacement is a child of position)
437  Node* detached = position;
438  Node* swap = replacement;
439 
440  // Update current position to point to swap (replacement) node first
441  position = swap;
442 
443  // Update replacement node to point to child in opposite direction
444  // otherwise we might lose the other child of the swap node
445  replacement = swap->children[1 - swap->dir];
446 
447  // Point swap node to detached node's children and weight
448  swap->children[kLeft] = detached->children[kLeft];
449  swap->children[kRight] = detached->children[kRight];
450  swap->weight = detached->weight;
451  }
452 
456  ETL_DECLARE_DEBUG_COUNT
457  };
458 
459  //***************************************************************************
462  //***************************************************************************
463  template <typename TKey, typename TMapped, typename TKeyCompare = etl::less<TKey> >
464  class imap : public etl::map_base
465  {
466  public:
467 
468  typedef TKey key_type;
469  typedef ETL_OR_STD::pair<const TKey, TMapped> value_type;
470  typedef TMapped mapped_type;
471  typedef TKeyCompare key_compare;
472  typedef value_type& reference;
473  typedef const value_type& const_reference;
474 #if ETL_CPP11_SUPPORTED
475  typedef value_type&& rvalue_reference;
476 #endif
477  typedef value_type* pointer;
478  typedef const value_type* const_pointer;
479  typedef size_t size_type;
480 
482  {
483  public:
484 
485  bool operator()(const_reference lhs, const_reference rhs) const
486  {
487  return (kcompare(lhs.first, rhs.first));
488  }
489 
490  private:
491 
492  key_compare kcompare;
493  };
494 
495  protected:
496 
497  //*************************************************************************
499  //*************************************************************************
500  struct Data_Node : public Node
501  {
502  explicit Data_Node(value_type value_)
503  : value(value_)
504  {
505  }
506 
507  ~Data_Node()
508  {
509 
510  }
511 
512  value_type value;
513  };
514 
517 
518  //*************************************************************************
520  //*************************************************************************
521  bool node_comp(const Data_Node& node1, const Data_Node& node2) const
522  {
523  return kcompare(node1.value.first, node2.value.first);
524  }
525  bool node_comp(const Data_Node& node, key_parameter_t key) const
526  {
527  return kcompare(node.value.first, key);
528  }
529  bool node_comp(key_parameter_t key, const Data_Node& node) const
530  {
531  return kcompare(key, node.value.first);
532  }
533 
534  private:
535 
537  ipool* p_node_pool;
538 
539  key_compare kcompare;
540  value_compare vcompare;
541 
542  //*************************************************************************
544  //*************************************************************************
545  static Data_Node* data_cast(Node* p_node)
546  {
547  return static_cast<Data_Node*>(p_node);
548  }
549 
550  //*************************************************************************
552  //*************************************************************************
553  static Data_Node& data_cast(Node& node)
554  {
555  return static_cast<Data_Node&>(node);
556  }
557 
558  //*************************************************************************
560  //*************************************************************************
561  static const Data_Node* data_cast(const Node* p_node)
562  {
563  return static_cast<const Data_Node*>(p_node);
564  }
565 
566  //*************************************************************************
568  //*************************************************************************
569  static const Data_Node& data_cast(const Node& node)
570  {
571  return static_cast<const Data_Node&>(node);
572  }
573 
574  public:
575 
576  //*************************************************************************
578  //*************************************************************************
579  class iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, value_type>
580  {
581  public:
582 
583  friend class imap;
584  friend class const_iterator;
585 
586  iterator()
587  : p_map(ETL_NULLPTR)
588  , p_node(ETL_NULLPTR)
589  {
590  }
591 
592  iterator(imap& map)
593  : p_map(&map)
594  , p_node(ETL_NULLPTR)
595  {
596  }
597 
598  iterator(imap& map, Node* node)
599  : p_map(&map)
600  , p_node(node)
601  {
602  }
603 
604  iterator(const iterator& other)
605  : p_map(other.p_map)
606  , p_node(other.p_node)
607  {
608  }
609 
610  ~iterator()
611  {
612  }
613 
614  iterator& operator ++()
615  {
616  p_map->next_node(p_node);
617  return *this;
618  }
619 
620  iterator operator ++(int)
621  {
622  iterator temp(*this);
623  p_map->next_node(p_node);
624  return temp;
625  }
626 
627  iterator& operator --()
628  {
629  p_map->prev_node(p_node);
630  return *this;
631  }
632 
633  iterator operator --(int)
634  {
635  iterator temp(*this);
636  p_map->prev_node(p_node);
637  return temp;
638  }
639 
640  iterator& operator =(const iterator& other)
641  {
642  p_map = other.p_map;
643  p_node = other.p_node;
644  return *this;
645  }
646 
647  reference operator *()
648  {
649  return imap::data_cast(p_node)->value;
650  }
651 
652  const_reference operator *() const
653  {
654  return imap::data_cast(p_node)->value;
655  }
656 
657  pointer operator &()
658  {
659  return &(imap::data_cast(p_node)->value);
660  }
661 
662  const_pointer operator &() const
663  {
664  return &(imap::data_cast(p_node)->value);
665  }
666 
667  pointer operator ->()
668  {
669  return &(imap::data_cast(p_node)->value);
670  }
671 
672  const_pointer operator ->() const
673  {
674  return &(imap::data_cast(p_node)->value);
675  }
676 
677  friend bool operator == (const iterator& lhs, const iterator& rhs)
678  {
679  return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node;
680  }
681 
682  friend bool operator != (const iterator& lhs, const iterator& rhs)
683  {
684  return !(lhs == rhs);
685  }
686 
687  private:
688 
689  // Pointer to map associated with this iterator
690  imap* p_map;
691 
692  // Pointer to the current node for this iterator
693  Node* p_node;
694  };
695 
696  friend class iterator;
697 
698  //*************************************************************************
700  //*************************************************************************
701  class const_iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, const value_type>
702  {
703  public:
704 
705  friend class imap;
706 
708  : p_map(ETL_NULLPTR)
709  , p_node(ETL_NULLPTR)
710  {
711  }
712 
713  const_iterator(const imap& map)
714  : p_map(&map)
715  , p_node(ETL_NULLPTR)
716  {
717  }
718 
719  const_iterator(const imap& map, const Node* node)
720  : p_map(&map)
721  , p_node(node)
722  {
723  }
724 
725  const_iterator(const typename imap::iterator& other)
726  : p_map(other.p_map)
727  , p_node(other.p_node)
728  {
729  }
730 
731  const_iterator(const const_iterator& other)
732  : p_map(other.p_map)
733  , p_node(other.p_node)
734  {
735  }
736 
737  ~const_iterator()
738  {
739  }
740 
741  const_iterator& operator ++()
742  {
743  p_map->next_node(p_node);
744  return *this;
745  }
746 
747  const_iterator operator ++(int)
748  {
749  const_iterator temp(*this);
750  p_map->next_node(p_node);
751  return temp;
752  }
753 
754  const_iterator& operator --()
755  {
756  p_map->prev_node(p_node);
757  return *this;
758  }
759 
760  const_iterator operator --(int)
761  {
762  const_iterator temp(*this);
763  p_map->prev_node(p_node);
764  return temp;
765  }
766 
767  const_iterator& operator =(const const_iterator& other)
768  {
769  p_map = other.p_map;
770  p_node = other.p_node;
771  return *this;
772  }
773 
774  const_reference operator *() const
775  {
776  return imap::data_cast(p_node)->value;
777  }
778 
779  const_pointer operator &() const
780  {
781  return imap::data_cast(p_node)->value;
782  }
783 
784  const_pointer operator ->() const
785  {
786  return &(imap::data_cast(p_node)->value);
787  }
788 
789  friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
790  {
791  return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node;
792  }
793 
794  friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
795  {
796  return !(lhs == rhs);
797  }
798 
799  private:
800  // Pointer to map associated with this iterator
801  const imap* p_map;
802 
803  // Pointer to the current node for this iterator
804  const Node* p_node;
805  };
806 
807  friend class const_iterator;
808 
809  typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
810 
811  typedef ETL_OR_STD::reverse_iterator<iterator> reverse_iterator;
812  typedef ETL_OR_STD::reverse_iterator<const_iterator> const_reverse_iterator;
813 
814  //*************************************************************************
816  //*************************************************************************
818  {
819  return iterator(*this, find_limit_node(root_node, kLeft));
820  }
821 
822  //*************************************************************************
824  //*************************************************************************
826  {
827  return const_iterator(*this, find_limit_node(root_node, kLeft));
828  }
829 
830  //*************************************************************************
832  //*************************************************************************
834  {
835  return iterator(*this);
836  }
837 
838  //*************************************************************************
840  //*************************************************************************
842  {
843  return const_iterator(*this);
844  }
845 
846  //*************************************************************************
848  //*************************************************************************
850  {
851  return const_iterator(*this, find_limit_node(root_node, kLeft));
852  }
853 
854  //*************************************************************************
856  //*************************************************************************
858  {
859  return const_iterator(*this);
860  }
861 
862  //*************************************************************************
864  //*************************************************************************
865  reverse_iterator rbegin()
866  {
867  return reverse_iterator(iterator(*this));
868  }
869 
870  //*************************************************************************
872  //*************************************************************************
873  const_reverse_iterator rbegin() const
874  {
875  return const_reverse_iterator(const_iterator(*this));
876  }
877 
878  //*************************************************************************
880  //*************************************************************************
881  reverse_iterator rend()
882  {
883  return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
884  }
885 
886  //*************************************************************************
888  //*************************************************************************
889  const_reverse_iterator rend() const
890  {
891  return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
892  }
893 
894  //*************************************************************************
896  //*************************************************************************
897  const_reverse_iterator crbegin() const
898  {
899  return const_reverse_iterator(const_iterator(*this));
900  }
901 
902  //*************************************************************************
904  //*************************************************************************
905  const_reverse_iterator crend() const
906  {
907  return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
908  }
909 
910  //*********************************************************************
914  //*********************************************************************
915  mapped_type& operator [](key_parameter_t key)
916  {
917  iterator i_element = find(key);
918 
919  if (!i_element.p_node)
920  {
921  // Doesn't exist, so create a new one.
922  i_element = insert(ETL_OR_STD::make_pair(key, mapped_type())).first;
923  }
924 
925  return i_element->second;
926  }
927 
928  //*********************************************************************
933  //*********************************************************************
934  mapped_type& at(key_parameter_t key)
935  {
936  iterator i_element = find(key);
937 
938  ETL_ASSERT(i_element.p_node != ETL_NULLPTR, ETL_ERROR(map_out_of_bounds));
939 
940  return i_element->second;
941  }
942 
943  //*********************************************************************
948  //*********************************************************************
949  const mapped_type& at(key_parameter_t key) const
950  {
951  const_iterator i_element = find(key);
952 
953  ETL_ASSERT(i_element.p_node != ETL_NULLPTR, ETL_ERROR(map_out_of_bounds));
954 
955  return i_element->second;
956  }
957 
958  //*********************************************************************
964  //*********************************************************************
965  template <typename TIterator>
966  void assign(TIterator first, TIterator last)
967  {
968  initialise();
969  insert(first, last);
970  }
971 
972  //*************************************************************************
974  //*************************************************************************
975  void clear()
976  {
977  initialise();
978  }
979 
980  //*********************************************************************
984  //*********************************************************************
986  {
987  return find_node(root_node, key) ? 1 : 0;
988  }
989 
990  //*************************************************************************
993  //*************************************************************************
994  ETL_OR_STD::pair<iterator, iterator> equal_range(key_parameter_t key)
995  {
996  return ETL_OR_STD::make_pair<iterator, iterator>(
997  iterator(*this, find_lower_node(root_node, key)),
998  iterator(*this, find_upper_node(root_node, key)));
999  }
1000 
1001  //*************************************************************************
1004  //*************************************************************************
1005  ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1006  {
1007  return ETL_OR_STD::make_pair<const_iterator, const_iterator>(
1008  const_iterator(*this, find_lower_node(root_node, key)),
1009  const_iterator(*this, find_upper_node(root_node, key)));
1010  }
1011 
1012  //*************************************************************************
1014  //*************************************************************************
1015  void erase(iterator position)
1016  {
1017  // Remove the node by its key
1018  erase((*position).first);
1019  }
1020 
1021  //*************************************************************************
1023  //*************************************************************************
1025  {
1026  // Find the parent node to be removed
1027  Node*& reference_node = find_node(root_node, position.p_node);
1028  iterator next(*this, reference_node);
1029  ++next;
1030 
1031  remove_node(root_node, (*position).first);
1032 
1033  return next;
1034  }
1035 
1036  //*************************************************************************
1037  // Erase the key specified.
1038  //*************************************************************************
1039  size_type erase(key_parameter_t key)
1040  {
1041  // Return 1 if key value was found and removed
1042  return remove_node(root_node, key) ? 1 : 0;
1043  }
1044 
1045  //*************************************************************************
1047  //*************************************************************************
1049  {
1050  iterator next;
1051  while (first != last)
1052  {
1053  next = erase(const_iterator(first++));
1054  }
1055 
1056  return next;
1057  }
1058 
1059  //*************************************************************************
1061  //*************************************************************************
1063  {
1064  iterator next;
1065  while (first != last)
1066  {
1067  next = erase(first++);
1068  }
1069 
1070  return next;
1071  }
1072 
1073  //*********************************************************************
1077  //*********************************************************************
1079  {
1080  return iterator(*this, find_node(root_node, key));
1081  }
1082 
1083  //*********************************************************************
1087  //*********************************************************************
1089  {
1090  return const_iterator(*this, find_node(root_node, key));
1091  }
1092 
1093  //*********************************************************************
1097  //*********************************************************************
1098  ETL_OR_STD::pair<iterator, bool> insert(const_reference value)
1099  {
1100  // Default to no inserted node
1101  Node* inserted_node = ETL_NULLPTR;
1102  bool inserted = false;
1103 
1104  ETL_ASSERT(!full(), ETL_ERROR(map_full));
1105 
1106  // Get next available free node
1107  Data_Node& node = allocate_data_node(value);
1108 
1109  // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1110  inserted_node = insert_node(root_node, node);
1111  inserted = inserted_node == &node;
1112 
1113  // Insert node into tree and return iterator to new node location in tree
1114  return ETL_OR_STD::make_pair(iterator(*this, inserted_node), inserted);
1115  }
1116 
1117 #if ETL_CPP11_SUPPORTED
1118  //*********************************************************************
1122  //*********************************************************************
1123  ETL_OR_STD::pair<iterator, bool> insert(rvalue_reference value)
1124  {
1125  // Default to no inserted node
1126  Node* inserted_node = ETL_NULLPTR;
1127  bool inserted = false;
1128 
1129  ETL_ASSERT(!full(), ETL_ERROR(map_full));
1130 
1131  // Get next available free node
1132  Data_Node& node = allocate_data_node(etl::move(value));
1133 
1134  // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1135  inserted_node = insert_node(root_node, node);
1136  inserted = inserted_node == &node;
1137 
1138  // Insert node into tree and return iterator to new node location in tree
1139  return ETL_OR_STD::make_pair(iterator(*this, inserted_node), inserted);
1140  }
1141 #endif
1142 
1143  //*********************************************************************
1148  //*********************************************************************
1149  iterator insert(iterator, const_reference value)
1150  {
1151  // Default to no inserted node
1152  Node* inserted_node = ETL_NULLPTR;
1153 
1154  ETL_ASSERT(!full(), ETL_ERROR(map_full));
1155 
1156  // Get next available free node
1157  Data_Node& node = allocate_data_node(value);
1158 
1159  // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1160  inserted_node = insert_node(root_node, node);
1161 
1162  // Insert node into tree and return iterator to new node location in tree
1163  return iterator(*this, inserted_node);
1164  }
1165 
1166 #if ETL_CPP11_SUPPORTED
1167  //*********************************************************************
1172  //*********************************************************************
1173  iterator insert(iterator, rvalue_reference value)
1174  {
1175  // Default to no inserted node
1176  Node* inserted_node = ETL_NULLPTR;
1177 
1178  ETL_ASSERT(!full(), ETL_ERROR(map_full));
1179 
1180  // Get next available free node
1181  Data_Node& node = allocate_data_node(etl::move(value));
1182 
1183  // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1184  inserted_node = insert_node(root_node, node);
1185 
1186  // Insert node into tree and return iterator to new node location in tree
1187  return iterator(*this, inserted_node);
1188  }
1189 #endif
1190 
1191  //*********************************************************************
1196  //*********************************************************************
1197  iterator insert(const_iterator, const_reference value)
1198  {
1199  // Default to no inserted node
1200  Node* inserted_node = ETL_NULLPTR;
1201 
1202  ETL_ASSERT(!full(), ETL_ERROR(map_full));
1203 
1204  // Get next available free node
1205  Data_Node& node = allocate_data_node(value);
1206 
1207  // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1208  inserted_node = insert_node(root_node, node);
1209 
1210  // Insert node into tree and return iterator to new node location in tree
1211  return iterator(*this, inserted_node);
1212  }
1213 
1214 #if ETL_CPP11_SUPPORTED
1215  //*********************************************************************
1220  //*********************************************************************
1221  iterator insert(const_iterator, rvalue_reference value)
1222  {
1223  // Default to no inserted node
1224  Node* inserted_node = ETL_NULLPTR;
1225 
1226  ETL_ASSERT(!full(), ETL_ERROR(map_full));
1227 
1228  // Get next available free node
1229  Data_Node& node = allocate_data_node(etl::move(value));
1230 
1231  // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1232  inserted_node = insert_node(root_node, node);
1233 
1234  // Insert node into tree and return iterator to new node location in tree
1235  return iterator(*this, inserted_node);
1236  }
1237 #endif
1238 
1239  //*********************************************************************
1245  //*********************************************************************
1246  template <class TIterator>
1247  void insert(TIterator first, TIterator last)
1248  {
1249  while (first != last)
1250  {
1251  insert(*first++);
1252  }
1253  }
1254 
1255  //*********************************************************************
1260  //*********************************************************************
1262  {
1263  return iterator(*this, find_lower_node(root_node, key));
1264  }
1265 
1266  //*********************************************************************
1271  //*********************************************************************
1273  {
1274  return const_iterator(*this, find_lower_node(root_node, key));
1275  }
1276 
1277  //*********************************************************************
1282  //*********************************************************************
1284  {
1285  return iterator(*this, find_upper_node(root_node, key));
1286  }
1287 
1288  //*********************************************************************
1293  //*********************************************************************
1295  {
1296  return const_iterator(*this, find_upper_node(root_node, key));
1297  }
1298 
1299  //*************************************************************************
1301  //*************************************************************************
1302  imap& operator = (const imap& rhs)
1303  {
1304  // Skip if doing self assignment
1305  if (this != &rhs)
1306  {
1307  assign(rhs.cbegin(), rhs.cend());
1308  }
1309 
1310  return *this;
1311  }
1312 
1313 #if ETL_CPP11_SUPPORTED
1314  //*************************************************************************
1316  //*************************************************************************
1317  imap& operator = (imap&& rhs)
1318  {
1319  // Skip if doing self assignment
1320  if (this != &rhs)
1321  {
1322  this->clear();
1323 
1324  typename etl::imap<TKey, TMapped, TKeyCompare>::iterator from = rhs.begin();
1325 
1326  while (from != rhs.end())
1327  {
1328  this->insert(etl::move(*from++));
1329  }
1330  }
1331 
1332  return *this;
1333  }
1334 #endif
1335 
1336  //*************************************************************************
1338  //*************************************************************************
1339  key_compare key_comp() const
1340  {
1341  return kcompare;
1342  };
1343 
1344  //*************************************************************************
1346  //*************************************************************************
1348  {
1349  return vcompare;
1350  };
1351 
1352  protected:
1353 
1354  //*************************************************************************
1356  //*************************************************************************
1357  imap(etl::ipool& node_pool, size_t max_size_)
1358  : etl::map_base(max_size_)
1359  , p_node_pool(&node_pool)
1360  {
1361  }
1362 
1363  //*************************************************************************
1365  //*************************************************************************
1366  void initialise()
1367  {
1368  const_iterator item = begin();
1369 
1370  while (item != end())
1371  {
1372  item = erase(item);
1373  }
1374  }
1375 
1376  private:
1377 
1378  //*************************************************************************
1380  //*************************************************************************
1381  Data_Node& allocate_data_node(const_reference value)
1382  {
1383  Data_Node& node = create_data_node();
1384  ::new (&node.value) value_type(value);
1385  ETL_INCREMENT_DEBUG_COUNT
1386  return node;
1387  }
1388 
1389 #if ETL_CPP11_SUPPORTED
1390  //*************************************************************************
1392  //*************************************************************************
1393  Data_Node& allocate_data_node(rvalue_reference value)
1394  {
1395  Data_Node& node = create_data_node();
1396  ::new (&node.value) value_type(etl::move(value));
1397  ETL_INCREMENT_DEBUG_COUNT
1398  return node;
1399  }
1400 #endif
1401 
1402  //*************************************************************************
1404  //*************************************************************************
1405  Data_Node& create_data_node()
1406  {
1407  Data_Node* (etl::ipool::*func)() = &etl::ipool::allocate<Data_Node>;
1408  return *(p_node_pool->*func)();
1409  }
1410 
1411  //*************************************************************************
1413  //*************************************************************************
1414  void destroy_data_node(Data_Node& node)
1415  {
1416  node.value.~value_type();
1417  p_node_pool->release(&node);
1418  ETL_DECREMENT_DEBUG_COUNT
1419  }
1420 
1421  //*************************************************************************
1423  //*************************************************************************
1424  Node* find_node(Node* position, key_parameter_t key)
1425  {
1426  Node* found = position;
1427  while (found)
1428  {
1429  // Downcast found to Data_Node class for comparison and other operations
1430  Data_Node& found_data_node = imap::data_cast(*found);
1431 
1432  // Compare the node value to the current position value
1433  if (node_comp(key, found_data_node))
1434  {
1435  // Keep searching for the node on the left
1436  found = found->children[kLeft];
1437  }
1438  else if (node_comp(found_data_node, key))
1439  {
1440  // Keep searching for the node on the right
1441  found = found->children[kRight];
1442  }
1443  else
1444  {
1445  // Node that matches the key provided was found, exit loop
1446  break;
1447  }
1448  }
1449 
1450  // Return the node found (might be ETL_NULLPTR)
1451  return found;
1452  }
1453 
1454  //*************************************************************************
1456  //*************************************************************************
1457  const Node* find_node(const Node* position, key_parameter_t key) const
1458  {
1459  const Node* found = position;
1460  while (found)
1461  {
1462  // Downcast found to Data_Node class for comparison and other operations
1463  const Data_Node& found_data_node = imap::data_cast(*found);
1464 
1465  // Compare the node value to the current position value
1466  if (node_comp(key, found_data_node))
1467  {
1468  // Keep searching for the node on the left
1469  found = found->children[kLeft];
1470  }
1471  else if (node_comp(found_data_node, key))
1472  {
1473  // Keep searching for the node on the right
1474  found = found->children[kRight];
1475  }
1476  else
1477  {
1478  // Node that matches the key provided was found, exit loop
1479  break;
1480  }
1481  }
1482 
1483  // Return the node found (might be ETL_NULLPTR)
1484  return found;
1485  }
1486 
1487  //*************************************************************************
1489  //*************************************************************************
1490  Node*& find_node(Node*& position, const Node* node)
1491  {
1492  Node* found = position;
1493  while (found)
1494  {
1495  if (found->children[kLeft] == node)
1496  {
1497  return found->children[kLeft];
1498  }
1499  else if (found->children[kRight] == node)
1500  {
1501  return found->children[kRight];
1502  }
1503  else
1504  {
1505  // Downcast found to Data_Node class for comparison and other operations
1506  Data_Node& found_data_node = imap::data_cast(*found);
1507  const Data_Node& data_node = imap::data_cast(*node);
1508 
1509  // Compare the node value to the current position value
1510  if (node_comp(data_node, found_data_node))
1511  {
1512  // Keep searching for the node on the left
1513  found = found->children[kLeft];
1514  }
1515  else if (node_comp(found_data_node, data_node))
1516  {
1517  // Keep searching for the node on the right
1518  found = found->children[kRight];
1519  }
1520  else
1521  {
1522  // Return position provided (it matches the node)
1523  return position;
1524  }
1525  }
1526  }
1527 
1528  // Return root node if nothing was found
1529  return root_node;
1530  }
1531 
1532  //*************************************************************************
1535  //*************************************************************************
1536  Node* find_parent_node(Node* position, const Node* node)
1537  {
1538  // Default to no parent node found
1539  Node* found = ETL_NULLPTR;
1540 
1541  // If the position provided is the same as the node then there is no parent
1542  if (position && node && position != node)
1543  {
1544  while (position)
1545  {
1546  // Is this position not the parent of the node we are looking for?
1547  if (position->children[kLeft] != node &&
1548  position->children[kRight] != node)
1549  {
1550  // Downcast node and position to Data_Node references for key comparisons
1551  const Data_Node& node_data_node = imap::data_cast(*node);
1552  Data_Node& position_data_node = imap::data_cast(*position);
1553  // Compare the node value to the current position value
1554  if (node_comp(node_data_node, position_data_node))
1555  {
1556  // Keep looking for parent on the left
1557  position = position->children[kLeft];
1558  }
1559  else if (node_comp(position_data_node, node_data_node))
1560  {
1561  // Keep looking for parent on the right
1562  position = position->children[kRight];
1563  }
1564  }
1565  else
1566  {
1567  // Return the current position as the parent node found
1568  found = position;
1569 
1570  // Parent node found, exit loop
1571  break;
1572  }
1573  }
1574  }
1575 
1576  // Return the parent node found (might be ETL_NULLPTR)
1577  return found;
1578  }
1579 
1580  //*************************************************************************
1583  //*************************************************************************
1584  const Node* find_parent_node(const Node* position, const Node* node) const
1585  {
1586  // Default to no parent node found
1587  const Node* found = ETL_NULLPTR;
1588 
1589  // If the position provided is the same as the node then there is no parent
1590  if (position && node && position != node)
1591  {
1592  while (position)
1593  {
1594  // Is this position not the parent of the node we are looking for?
1595  if (position->children[kLeft] != node &&
1596  position->children[kRight] != node)
1597  {
1598  // Downcast node and position to Data_Node references for key comparisons
1599  const Data_Node& node_data_node = imap::data_cast(*node);
1600  const Data_Node& position_data_node = imap::data_cast(*position);
1601  // Compare the node value to the current position value
1602  if (node_comp(node_data_node, position_data_node))
1603  {
1604  // Keep looking for parent on the left
1605  position = position->children[kLeft];
1606  }
1607  else if (node_comp(position_data_node, node_data_node))
1608  {
1609  // Keep looking for parent on the right
1610  position = position->children[kRight];
1611  }
1612  }
1613  else
1614  {
1615  // Return the current position as the parent node found
1616  found = position;
1617 
1618  // Parent node found, exit loop
1619  break;
1620  }
1621  }
1622  }
1623 
1624  // Return the parent node found (might be ETL_NULLPTR)
1625  return found;
1626  }
1627 
1628  //*************************************************************************
1630  //*************************************************************************
1631  Node* find_lower_node(Node* position, key_parameter_t key) const
1632  {
1633  // Something at this position? keep going
1634  Node* lower_node = ETL_NULLPTR;
1635  while (position)
1636  {
1637  // Downcast lower node to Data_Node reference for key comparisons
1638  Data_Node& data_node = imap::data_cast(*position);
1639  // Compare the key value to the current lower node key value
1640  if (node_comp(key, data_node))
1641  {
1642  lower_node = position;
1643  if (position->children[kLeft])
1644  {
1645  position = position->children[kLeft];
1646  }
1647  else
1648  {
1649  // Found lowest node
1650  break;
1651  }
1652  }
1653  else if (node_comp(data_node, key))
1654  {
1655  position = position->children[kRight];
1656  }
1657  else
1658  {
1659  // Make note of current position, but keep looking to left for more
1660  lower_node = position;
1661  position = position->children[kLeft];
1662  }
1663  }
1664 
1665  // Return the lower_node position found
1666  return lower_node;
1667  }
1668 
1669  //*************************************************************************
1671  //*************************************************************************
1672  Node* find_upper_node(Node* position, key_parameter_t key) const
1673  {
1674  // Keep track of parent of last upper node
1675  Node* upper_node = ETL_NULLPTR;
1676  // Start with position provided
1677  Node* node = position;
1678  while (node)
1679  {
1680  // Downcast position to Data_Node reference for key comparisons
1681  Data_Node& data_node = imap::data_cast(*node);
1682  // Compare the key value to the current upper node key value
1683  if (node_comp(key, data_node))
1684  {
1685  upper_node = node;
1686  node = node->children[kLeft];
1687  }
1688  else if (node_comp(data_node, key))
1689  {
1690  node = node->children[kRight];
1691  }
1692  else if (node->children[kRight])
1693  {
1694  upper_node = find_limit_node(node->children[kRight], kLeft);
1695  break;
1696  }
1697  else
1698  {
1699  break;
1700  }
1701  }
1702 
1703  // Return the upper node position found (might be ETL_NULLPTR)
1704  return upper_node;
1705  }
1706 
1707  //*************************************************************************
1709  //*************************************************************************
1710  Node* insert_node(Node*& position, Data_Node& node)
1711  {
1712  // Find the location where the node belongs
1713  Node* found = position;
1714 
1715  // Was position provided not empty? then find where the node belongs
1716  if (position)
1717  {
1718  // Find the critical parent node (default to ETL_NULLPTR)
1719  Node* critical_parent_node = ETL_NULLPTR;
1720  Node* critical_node = root_node;
1721 
1722  while (found)
1723  {
1724  // Search for critical weight node (all nodes whose weight factor
1725  // is set to kNeither (balanced)
1726  if (kNeither != found->weight)
1727  {
1728  critical_node = found;
1729  }
1730 
1731  // Downcast found to Data_Node class for comparison and other operations
1732  Data_Node& found_data_node = imap::data_cast(*found);
1733 
1734  // Is the node provided to the left of the current position?
1735  if (node_comp(node, found_data_node))
1736  {
1737  // Update direction taken to insert new node in parent node
1738  found->dir = kLeft;
1739  }
1740  // Is the node provided to the right of the current position?
1741  else if (node_comp(found_data_node, node))
1742  {
1743  // Update direction taken to insert new node in parent node
1744  found->dir = kRight;
1745  }
1746  else
1747  {
1748  // Update direction taken to insert new node in parent node
1749  found->dir = kNeither;
1750 
1751  // Clear critical node value to skip weight step below
1752  critical_node = ETL_NULLPTR;
1753 
1754  // Destroy the node provided (its a duplicate)
1755  destroy_data_node(node);
1756 
1757  // Exit loop, duplicate node found
1758  break;
1759  }
1760 
1761  // Is there a child of this parent node?
1762  if (found->children[found->dir])
1763  {
1764  // Will this node be the parent of the next critical node whose
1765  // weight factor is set to kNeither (balanced)?
1766  if (kNeither != found->children[found->dir]->weight)
1767  {
1768  critical_parent_node = found;
1769  }
1770 
1771  // Keep looking for empty spot to insert new node
1772  found = found->children[found->dir];
1773  }
1774  else
1775  {
1776  // Attatch node to right
1777  attach_node(found->children[found->dir], node);
1778 
1779  // Return newly added node
1780  found = found->children[found->dir];
1781 
1782  // Exit loop
1783  break;
1784  }
1785  }
1786 
1787  // Was a critical node found that should be checked for balance?
1788  if (critical_node)
1789  {
1790  if (critical_parent_node == ETL_NULLPTR && critical_node == root_node)
1791  {
1793  }
1794  else if (critical_parent_node == ETL_NULLPTR && critical_node == position)
1795  {
1796  balance_node(position);
1797  }
1798  else
1799  {
1800  if (critical_parent_node != ETL_NULLPTR)
1801  {
1802  balance_node(critical_parent_node->children[critical_parent_node->dir]);
1803  }
1804  }
1805  }
1806  }
1807  else
1808  {
1809  // Attatch node to current position
1810  attach_node(position, node);
1811 
1812  // Return newly added node at current position
1813  found = position;
1814  }
1815 
1816  // Return the node found (might be ETL_NULLPTR)
1817  return found;
1818  }
1819 
1820  //*************************************************************************
1822  //*************************************************************************
1823  void next_node(Node*&position)
1824  {
1825  if (position)
1826  {
1827  // Is there a tree on the right? then find the minimum of that tree
1828  if (position->children[kRight])
1829  {
1830  // Return minimum node found
1831  position = find_limit_node(position->children[kRight], kLeft);
1832  }
1833  // Otherwise find the parent of this node
1834  else
1835  {
1836  // Start with current position as parent
1837  Node* parent = position;
1838  do {
1839  // Update current position as previous parent
1840  position = parent;
1841  // Find parent of current position
1842  parent = find_parent_node(root_node, position);
1843  // Repeat while previous position was on right side of parent tree
1844  } while (parent && parent->children[kRight] == position);
1845 
1846  // Set parent node as the next position
1847  position = parent;
1848  }
1849  }
1850  }
1851 
1852  //*************************************************************************
1854  //*************************************************************************
1855  void next_node(const Node*& position) const
1856  {
1857  if (position)
1858  {
1859  // Is there a tree on the right? then find the minimum of that tree
1860  if (position->children[kRight])
1861  {
1862  // Return minimum node found
1863  position = find_limit_node(position->children[kRight], kLeft);
1864  }
1865  // Otherwise find the parent of this node
1866  else
1867  {
1868  // Start with current position as parent
1869  const Node* parent = position;
1870  do {
1871  // Update current position as previous parent
1872  position = parent;
1873  // Find parent of current position
1874  parent = find_parent_node(root_node, position);
1875  // Repeat while previous position was on right side of parent tree
1876  } while (parent && parent->children[kRight] == position);
1877 
1878  // Set parent node as the next position
1879  position = parent;
1880  }
1881  }
1882  }
1883 
1884  //*************************************************************************
1886  //*************************************************************************
1887  void prev_node(Node*&position)
1888  {
1889  // If starting at the terminal end, the previous node is the maximum node
1890  // from the root
1891  if (!position)
1892  {
1893  position = find_limit_node(root_node, kRight);
1894  }
1895  else
1896  {
1897  // Is there a tree on the left? then find the maximum of that tree
1898  if (position->children[kLeft])
1899  {
1900  // Return maximum node found
1901  position = find_limit_node(position->children[kLeft], kRight);
1902  }
1903  // Otherwise find the parent of this node
1904  else
1905  {
1906  // Start with current position as parent
1907  Node* parent = position;
1908  do {
1909  // Update current position as previous parent
1910  position = parent;
1911  // Find parent of current position
1912  parent = find_parent_node(root_node, position);
1913  // Repeat while previous position was on left side of parent tree
1914  } while (parent && parent->children[kLeft] == position);
1915 
1916  // Set parent node as the next position
1917  position = parent;
1918  }
1919  }
1920  }
1921 
1922  //*************************************************************************
1924  //*************************************************************************
1925  void prev_node(const Node*& position) const
1926  {
1927  // If starting at the terminal end, the previous node is the maximum node
1928  // from the root
1929  if (!position)
1930  {
1931  position = find_limit_node(root_node, kRight);
1932  }
1933  else
1934  {
1935  // Is there a tree on the left? then find the maximum of that tree
1936  if (position->children[kLeft])
1937  {
1938  // Return maximum node found
1939  position = find_limit_node(position->children[kLeft], kRight);
1940  }
1941  // Otherwise find the parent of this node
1942  else
1943  {
1944  // Start with current position as parent
1945  const Node* parent = position;
1946  do {
1947  // Update current position as previous parent
1948  position = parent;
1949  // Find parent of current position
1950  parent = find_parent_node(root_node, position);
1951  // Repeat while previous position was on left side of parent tree
1952  } while (parent && parent->children[kLeft] == position);
1953 
1954  // Set parent node as the next position
1955  position = parent;
1956  }
1957  }
1958  }
1959 
1960  //*************************************************************************
1963  //*************************************************************************
1964  Node* remove_node(Node*& position, key_parameter_t key)
1965  {
1966  // Step 1: Find the target node that matches the key provided, the
1967  // replacement node (might be the same as target node), and the critical
1968  // node to start rebalancing the tree from (up to the replacement node)
1969  Node* found_parent = ETL_NULLPTR;
1970  Node* found = ETL_NULLPTR;
1971  Node* replace_parent = ETL_NULLPTR;
1972  Node* replace = position;
1973  Node* balance_parent = ETL_NULLPTR;
1974  Node* balance = root_node;
1975  while (replace)
1976  {
1977  // Downcast found to Data_Node class for comparison and other operations
1978  Data_Node& replace_data_node = imap::data_cast(*replace);
1979 
1980  // Compare the key provided to the replace data node key
1981  if (node_comp(key, replace_data_node))
1982  {
1983  // Update the direction to the target/replace node
1984  replace->dir = kLeft;
1985  }
1986  else if (node_comp(replace_data_node, key))
1987  {
1988  // Update the direction to the target/replace node
1989  replace->dir = kRight;
1990  }
1991  else
1992  {
1993  // Update the direction to the replace node (target node found here)
1994  replace->dir = replace->children[kLeft] ? kLeft : kRight;
1995 
1996  // Note the target node was found (and its parent)
1997  found_parent = replace_parent;
1998  found = replace;
1999  }
2000  // Replacement node found if its missing a child in the replace->dir
2001  // value set above
2002  if (replace->children[replace->dir] == ETL_NULLPTR)
2003  {
2004  // Exit loop once replace node is found (target might not have been)
2005  break;
2006  }
2007 
2008  // If replacement node weight is kNeither or we are taking the shorter
2009  // path of replacement node and our sibling (on longer path) is
2010  // balanced then we need to update the balance node to match this
2011  // replacement node but all our ancestors will not require rebalancing
2012  if ((replace->weight == kNeither) ||
2013  (replace->weight == (1 - replace->dir) &&
2014  replace->children[1 - replace->dir]->weight == kNeither))
2015  {
2016  // Update balance node (and its parent) to replacement node
2017  balance_parent = replace_parent;
2018  balance = replace;
2019  }
2020 
2021  // Keep searching for the replacement node
2022  replace_parent = replace;
2023  replace = replace->children[replace->dir];
2024  }
2025 
2026  // If target node was found, proceed with rebalancing and replacement
2027  if (found)
2028  {
2029  // Step 2: Update weights from critical node to replacement parent node
2030  while (balance)
2031  {
2032  if (balance->children[balance->dir] == ETL_NULLPTR)
2033  {
2034  break;
2035  }
2036 
2037  if (balance->weight == kNeither)
2038  {
2039  balance->weight = 1 - balance->dir;
2040  }
2041  else if (balance->weight == balance->dir)
2042  {
2043  balance->weight = kNeither;
2044  }
2045  else
2046  {
2047  int weight = balance->children[1 - balance->dir]->weight;
2048  // Perform a 3 node rotation if weight is same as balance->dir
2049  if (weight == balance->dir)
2050  {
2051  // Is the root node being rebalanced (no parent)
2052  if (balance_parent == ETL_NULLPTR)
2053  {
2054  rotate_3node(root_node, 1 - balance->dir,
2055  balance->children[1 - balance->dir]->children[balance->dir]->weight);
2056  }
2057  else
2058  {
2059  rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir,
2060  balance->children[1 - balance->dir]->children[balance->dir]->weight);
2061  }
2062  }
2063  // Already balanced, rebalance and make it heavy in opposite
2064  // direction of the node being removed
2065  else if (weight == kNeither)
2066  {
2067  // Is the root node being rebalanced (no parent)
2068  if (balance_parent == ETL_NULLPTR)
2069  {
2070  rotate_2node(root_node, 1 - balance->dir);
2071  root_node->weight = balance->dir;
2072  }
2073  else
2074  {
2075  rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
2076  balance_parent->children[balance_parent->dir]->weight = balance->dir;
2077  }
2078  // Update balance node weight in opposite direction of node removed
2079  balance->weight = 1 - balance->dir;
2080  }
2081  // Rebalance and leave it balanced
2082  else
2083  {
2084  // Is the root node being rebalanced (no parent)
2085  if (balance_parent == ETL_NULLPTR)
2086  {
2087  rotate_2node(root_node, 1 - balance->dir);
2088  }
2089  else
2090  {
2091  rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
2092  }
2093  }
2094 
2095  // Is balance node the same as the target node found? then update
2096  // its parent after the rotation performed above
2097  if (balance == found)
2098  {
2099  if (balance_parent)
2100  {
2101  found_parent = balance_parent->children[balance_parent->dir];
2102  // Update dir since it is likely stale
2103  found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight;
2104  }
2105  else
2106  {
2107  found_parent = root_node;
2108  root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight;
2109  }
2110  }
2111  }
2112 
2113  // Next balance node to consider
2114  balance_parent = balance;
2115  balance = balance->children[balance->dir];
2116  } // while(balance)
2117 
2118  // Step 3: Swap found node with replacement node
2119  if (found_parent)
2120  {
2121  // Handle traditional case
2122  detach_node(found_parent->children[found_parent->dir],
2123  replace_parent->children[replace_parent->dir]);
2124  }
2125  // Handle root node removal
2126  else
2127  {
2128  // Valid replacement node for root node being removed?
2129  if (replace_parent)
2130  {
2131  detach_node(root_node, replace_parent->children[replace_parent->dir]);
2132  }
2133  else
2134  {
2135  // Target node and replacement node are both root node
2137  }
2138  }
2139 
2140  // Downcast found into data node
2141  Data_Node& found_data_node = imap::data_cast(*found);
2142 
2143  // One less.
2144  --current_size;
2145 
2146  // Destroy the node removed
2147  destroy_data_node(found_data_node);
2148  } // if(found)
2149 
2150  // Return node found (might be ETL_NULLPTR)
2151  return found;
2152  }
2153 
2154  // Disable copy construction.
2155  imap(const imap&);
2156 
2157  //*************************************************************************
2159  //*************************************************************************
2160 #if defined(ETL_POLYMORPHIC_MAP) || defined(ETL_POLYMORPHIC_CONTAINERS)
2161  public:
2162  virtual ~imap()
2163  {
2164  }
2165 #else
2166  protected:
2168  {
2169  }
2170 #endif
2171  };
2172 
2173  //*************************************************************************
2175  //*************************************************************************
2176  template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = etl::less<TKey> >
2177  class map : public etl::imap<TKey, TValue, TCompare>
2178  {
2179  public:
2180 
2181  static const size_t MAX_SIZE = MAX_SIZE_;
2182 
2183  //*************************************************************************
2185  //*************************************************************************
2187  : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2188  {
2189  this->initialise();
2190  }
2191 
2192  //*************************************************************************
2194  //*************************************************************************
2195  map(const map& other)
2196  : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2197  {
2198  if (this != &other)
2199  {
2200  this->assign(other.cbegin(), other.cend());
2201  }
2202  }
2203 
2204 #if ETL_CPP11_SUPPORTED
2205  //*************************************************************************
2207  //*************************************************************************
2208  map(map&& other)
2209  : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2210  {
2211  if (this != &other)
2212  {
2213  typename etl::imap<TKey, TValue, TCompare>::iterator from = other.begin();
2214 
2215  while (from != other.end())
2216  {
2217  this->insert(etl::move(*from++));
2218  }
2219  }
2220  }
2221 #endif
2222 
2223  //*************************************************************************
2228  //*************************************************************************
2229  template <typename TIterator>
2230  map(TIterator first, TIterator last)
2231  : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2232  {
2233  this->assign(first, last);
2234  }
2235 
2236 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
2237  //*************************************************************************
2239  //*************************************************************************
2240  map(std::initializer_list<typename etl::imap<TKey, TValue, TCompare>::value_type> init)
2241  : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2242  {
2243  this->assign(init.begin(), init.end());
2244  }
2245 #endif
2246 
2247  //*************************************************************************
2249  //*************************************************************************
2251  {
2252  this->initialise();
2253  }
2254 
2255  //*************************************************************************
2257  //*************************************************************************
2258  map& operator = (const map& rhs)
2259  {
2260  // Skip if doing self assignment
2261  if (this != &rhs)
2262  {
2263  this->assign(rhs.cbegin(), rhs.cend());
2264  }
2265 
2266  return *this;
2267  }
2268 
2269 #if ETL_CPP11_SUPPORTED
2270  //*************************************************************************
2272  //*************************************************************************
2273  map& operator = (map&& rhs)
2274  {
2275  // Skip if doing self assignment
2276  if (this != &rhs)
2277  {
2278  this->clear();
2279 
2280  typename etl::imap<TKey, TValue, TCompare>::iterator from = rhs.begin();
2281 
2282  while (from != rhs.end())
2283  {
2284  this->insert(etl::move(*from++));
2285  }
2286  }
2287 
2288  return *this;
2289  }
2290 #endif
2291 
2292  private:
2293 
2296  };
2297 
2298  //*************************************************************************
2300  //*************************************************************************
2301 #if ETL_CPP17_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
2302  template <typename T, typename... Ts>
2303  map(T, Ts...)
2304  ->map<etl::enable_if_t<(etl::is_same_v<T, Ts> && ...), typename T::first_type>,
2305  typename T::second_type,
2306  1U + sizeof...(Ts)>;
2307 #endif
2308 
2309  //***************************************************************************
2315  //***************************************************************************
2316  template <typename TKey, typename TMapped, typename TKeyCompare>
2318  {
2319  return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
2320  }
2321 
2322  //***************************************************************************
2328  //***************************************************************************
2329  template <typename TKey, typename TMapped, typename TKeyCompare>
2331  {
2332  return !(lhs == rhs);
2333  }
2334 
2335  //*************************************************************************
2341  //*************************************************************************
2342  template <typename TKey, typename TMapped, typename TKeyCompare>
2344  {
2345  return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
2346  }
2347 
2348  //*************************************************************************
2354  //*************************************************************************
2355  template <typename TKey, typename TMapped, typename TKeyCompare>
2357  {
2358  return (rhs < lhs);
2359  }
2360 
2361  //*************************************************************************
2367  //*************************************************************************
2368  template <typename TKey, typename TMapped, typename TKeyCompare>
2370  {
2371  return !(lhs > rhs);
2372  }
2373 
2374  //*************************************************************************
2380  //*************************************************************************
2381  template <typename TKey, typename TMapped, typename TKeyCompare>
2383  {
2384  return !(lhs < rhs);
2385  }
2386 }
2387 
2388 #include "private/minmax_pop.h"
2389 
2390 #undef ETL_FILE
2391 
2392 #endif
const_iterator
Definition: map.h:702
iterator.
Definition: map.h:580
Definition: map.h:482
A templated map implementation that uses a fixed size buffer.
Definition: map.h:2178
map(const map &other)
Copy constructor.
Definition: map.h:2195
~map()
Destructor.
Definition: map.h:2250
map(TIterator first, TIterator last)
Definition: map.h:2230
map()
Default constructor.
Definition: map.h:2186
bitset< MAXN > operator&(const bitset< MAXN > &lhs, const bitset< MAXN > &rhs)
Definition: bitset.h:1157
#define ETL_ASSERT(b, e)
Definition: error_handler.h:290
exception(string_type reason_, string_type file_, numeric_type line_)
Constructor.
Definition: exception.h:67
Definition: exception.h:47
const_reverse_iterator crend() const
Gets the reverse end of the list.
Definition: map.h:905
void detach_node(Node *&position, Node *&replacement)
Detach the node at the position provided.
Definition: map.h:432
ETL_OR_STD::pair< iterator, bool > insert(const_reference value)
Definition: map.h:1098
iterator lower_bound(key_parameter_t key)
Definition: map.h:1261
void erase(iterator position)
Erases the value at the specified position.
Definition: map.h:1015
iterator erase(iterator first, iterator last)
Erases a range of elements.
Definition: map.h:1048
iterator upper_bound(key_parameter_t key)
Definition: map.h:1283
const_iterator find(key_parameter_t key) const
Definition: map.h:1088
void rotate_2node(Node *&position, uint_least8_t dir)
Rotate two nodes at the position provided the to balance the tree.
Definition: map.h:313
mapped_type & at(key_parameter_t key)
Definition: map.h:934
void clear()
Clears the map.
Definition: map.h:975
const Node * find_limit_node(const Node *position, const int8_t dir) const
Definition: map.h:401
bool empty() const
Checks to see if the map is empty.
Definition: map.h:154
bool full() const
Checks to see if the map is full.
Definition: map.h:162
const_iterator end() const
Gets the end of the map.
Definition: map.h:841
iterator erase(const_iterator first, const_iterator last)
Erases a range of elements.
Definition: map.h:1062
size_type count(key_parameter_t key) const
Definition: map.h:985
Node * find_limit_node(Node *position, const int8_t dir) const
Definition: map.h:384
const size_type CAPACITY
The maximum size of the map.
Definition: map.h:454
void initialise()
Initialise the map.
Definition: map.h:1366
imap & operator=(const imap &rhs)
Assignment operator.
Definition: map.h:1302
size_t size_type
The type used for determining the size of map.
Definition: map.h:133
reverse_iterator rend()
Gets the reverse end of the list.
Definition: map.h:881
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(key_parameter_t key) const
Definition: map.h:1005
void assign(TIterator first, TIterator last)
Definition: map.h:966
void insert(TIterator first, TIterator last)
Definition: map.h:1247
iterator insert(iterator, const_reference value)
Definition: map.h:1149
map_base(size_type max_size_)
The constructor that is called from derived classes.
Definition: map.h:232
const_iterator upper_bound(key_parameter_t key) const
Definition: map.h:1294
key_compare key_comp() const
How to compare two key elements.
Definition: map.h:1339
const mapped_type & at(key_parameter_t key) const
Definition: map.h:949
size_type capacity() const
Definition: map.h:171
const_iterator lower_bound(key_parameter_t key) const
Definition: map.h:1272
~imap()
Destructor.
Definition: map.h:2167
etl::parameter_type< TKey >::type key_parameter_t
Defines the key value parameter type.
Definition: map.h:516
const_iterator cbegin() const
Gets the beginning of the map.
Definition: map.h:849
const_reverse_iterator rbegin() const
Gets the reverse beginning of the list.
Definition: map.h:873
Node * root_node
The node that acts as the map root.
Definition: map.h:455
size_type size() const
Gets the size of the map.
Definition: map.h:138
const_iterator cend() const
Gets the end of the map.
Definition: map.h:857
mapped_type & operator[](key_parameter_t key)
Definition: map.h:915
size_type max_size() const
Gets the maximum possible size of the map.
Definition: map.h:146
ETL_OR_STD::pair< iterator, iterator > equal_range(key_parameter_t key)
Definition: map.h:994
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:343
iterator begin()
Gets the beginning of the map.
Definition: map.h:817
size_t available() const
Definition: map.h:180
const_reverse_iterator crbegin() const
Gets the reverse beginning of the list.
Definition: map.h:897
iterator find(key_parameter_t key)
Definition: map.h:1078
iterator end()
Gets the end of the map.
Definition: map.h:833
const_reverse_iterator rend() const
Gets the reverse end of the list.
Definition: map.h:889
reverse_iterator rbegin()
Gets the reverse beginning of the list.
Definition: map.h:865
iterator erase(const_iterator position)
Erases the value at the specified position.
Definition: map.h:1024
size_type current_size
The number of the used nodes.
Definition: map.h:453
~map_base()
Destructor.
Definition: map.h:243
value_compare value_comp() const
How to compare two value elements.
Definition: map.h:1347
imap(etl::ipool &node_pool, size_t max_size_)
Constructor.
Definition: map.h:1357
void attach_node(Node *&position, Node &node)
Attach the provided node to the position provided.
Definition: map.h:417
iterator insert(const_iterator, const_reference value)
Definition: map.h:1197
const_iterator begin() const
Gets the beginning of the map.
Definition: map.h:825
bool node_comp(const Data_Node &node1, const Data_Node &node2) const
How to compare node elements.
Definition: map.h:521
void balance_node(Node *&critical_node)
Balance the critical node at the position provided as needed.
Definition: map.h:250
Definition: map.h:465
Definition: map.h:130
Definition: map.h:74
Definition: map.h:88
Definition: map.h:116
Definition: map.h:102
Definition: pool.h:118
Definition: pool.h:617
Definition: absolute.h:37
bool operator>(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:633
bool operator>=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:645
bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:594
void swap(etl::array< T, SIZE > &lhs, etl::array< T, SIZE > &rhs)
Template deduction guides.
Definition: array.h:570
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:582
bool operator==(const etl::imap< TKey, TMapped, TKeyCompare > &lhs, const etl::imap< TKey, TMapped, TKeyCompare > &rhs)
Template deduction guides.
Definition: map.h:2317
bool operator<(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:606
bool operator<=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:621
bool operator!=(const etl::imap< TKey, TMapped, TKeyCompare > &lhs, const etl::imap< TKey, TMapped, TKeyCompare > &rhs)
Definition: map.h:2330
The data node element in the map.
Definition: map.h:501
iterator
Definition: iterator.h:422
The node element in the map.
Definition: map.h:198
void mark_as_leaf()
Marks the node as a leaf.
Definition: map.h:216
Node()
Constructor.
Definition: map.h:202
etl::conditional< etl::is_fundamental< T >::value||etl::is_pointer< T >::value, T, const T & >::type type
By default fundamental and pointer types are passed by value.
Definition: parameter_type.h:48