Embedded Template Library  1.0
multimap.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_MULTIMAP_INCLUDED
32 #define ETL_MULTIMAP_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 "9"
60 
61 //*****************************************************************************
64 //*****************************************************************************
65 
66 namespace etl
67 {
68  //***************************************************************************
71  //***************************************************************************
73  {
74  public:
75 
76  multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
77  : exception(reason_, file_name_, line_number_)
78  {
79  }
80  };
81 
82  //***************************************************************************
85  //***************************************************************************
87  {
88  public:
89 
90  multimap_full(string_type file_name_, numeric_type line_number_)
91  : etl::multimap_exception("multimap:full", file_name_, line_number_)
92  {
93  }
94  };
95 
96  //***************************************************************************
99  //***************************************************************************
101  {
102  public:
103 
104  multimap_out_of_bounds(string_type file_name_, numeric_type line_number_)
105  : etl::multimap_exception("multimap:bounds", file_name_, line_number_)
106  {
107  }
108  };
109 
110  //***************************************************************************
113  //***************************************************************************
115  {
116  public:
117 
118  multimap_iterator(string_type file_name_, numeric_type line_number_)
119  : etl::multimap_exception("multimap:iterator", file_name_, line_number_)
120  {
121  }
122  };
123 
124  //***************************************************************************
127  //***************************************************************************
129  {
130  public:
131 
132  typedef size_t size_type;
133 
134  //*************************************************************************
136  //*************************************************************************
137  size_type size() const
138  {
139  return current_size;
140  }
141 
142  //*************************************************************************
144  //*************************************************************************
146  {
147  return CAPACITY;
148  }
149 
150  //*************************************************************************
152  //*************************************************************************
153  bool empty() const
154  {
155  return current_size == 0;
156  }
157 
158  //*************************************************************************
160  //*************************************************************************
161  bool full() const
162  {
163  return current_size == CAPACITY;
164  }
165 
166  //*************************************************************************
169  //*************************************************************************
171  {
172  return CAPACITY;
173  }
174 
175  //*************************************************************************
178  //*************************************************************************
179  size_t available() const
180  {
181  return max_size() - size();
182  }
183 
184  protected:
185 
186  enum
187  {
188  kLeft,
189  kRight,
190  kNeither
191  };
192 
193  //*************************************************************************
195  //*************************************************************************
196  struct Node
197  {
198  //***********************************************************************
200  //***********************************************************************
201  Node() :
202  weight((uint_least8_t) kNeither),
203  dir((uint_least8_t) kNeither)
204  {
205  }
206 
207  //***********************************************************************
209  //***********************************************************************
211  {
212  weight = (uint_least8_t) kNeither;
213  dir = (uint_least8_t) kNeither;
214  parent = ETL_NULLPTR;
215  children[0] = ETL_NULLPTR;
216  children[1] = ETL_NULLPTR;
217  }
218 
219  Node* parent;
220  Node* children[2];
221  uint_least8_t weight;
222  uint_least8_t dir;
223  };
224 
225  //*************************************************************************
227  //*************************************************************************
229  : current_size(0)
230  , CAPACITY(max_size_)
231  , root_node(ETL_NULLPTR)
232  {
233  }
234 
235  //*************************************************************************
237  //*************************************************************************
239  {
240  }
241 
242  //*************************************************************************
244  //*************************************************************************
245  void balance_node(Node*& critical_node)
246  {
247  // Step 1: Update weights for all children of the critical node up to the
248  // newly inserted node. This step is costly (in terms of traversing nodes
249  // multiple times during insertion) but doesn't require as much recursion
250  Node* weight_node = critical_node->children[critical_node->dir];
251  while (weight_node)
252  {
253  // Keep going until we reach a terminal node (dir == (uint_least8_t) kNeither)
254  if ((uint_least8_t) kNeither != weight_node->dir)
255  {
256  // Does this insert balance the previous weight factor value?
257  if (weight_node->weight == 1 - weight_node->dir)
258  {
259  weight_node->weight = (uint_least8_t) kNeither;
260  }
261  else
262  {
263  weight_node->weight = weight_node->dir;
264  }
265 
266  // Update weight factor node to point to next node
267  weight_node = weight_node->children[weight_node->dir];
268  }
269  else
270  {
271  // Stop loop, terminal node found
272  break;
273  }
274  } // while(weight_node)
275 
276  // Step 2: Update weight for critical_node or rotate tree to balance node
277  if ((uint_least8_t) kNeither == critical_node->weight)
278  {
279  critical_node->weight = critical_node->dir;
280  }
281  // If direction is different than weight, then it will now be balanced
282  else if (critical_node->dir != critical_node->weight)
283  {
284  critical_node->weight = (uint_least8_t) kNeither;
285  }
286  // Rotate is required to balance the tree at the critical node
287  else
288  {
289  // If critical node matches child node direction then perform a two
290  // node rotate in the direction of the critical node
291  if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
292  {
293  rotate_2node(critical_node, critical_node->dir);
294  }
295  // Otherwise perform a three node rotation in the direction of the
296  // critical node
297  else
298  {
299  rotate_3node(critical_node, critical_node->dir,
300  critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
301  }
302  }
303  }
304 
305  //*************************************************************************
307  //*************************************************************************
308  void rotate_2node(Node*& position, uint_least8_t dir)
309  {
310  // A C A B
311  // B C -> A E OR B C -> D A
312  // D E B D D E E C
313  // C (new position) becomes the root
314  // A (position) takes ownership of D as its children[kRight] child
315  // C (new position) takes ownership of A as its left child
316  // OR
317  // B (new position) becomes the root
318  // A (position) takes ownership of E as its left child
319  // B (new position) takes ownership of A as its right child
320 
321  // Capture new root (either B or C depending on dir) and its parent
322  Node* new_root = position->children[dir];
323 
324  // Replace position's previous child with new root's other child
325  position->children[dir] = new_root->children[1 - dir];
326  // Update new root's other child parent pointer
327  if (position->children[dir])
328  {
329  position->children[dir]->parent = position;
330  }
331 
332  // New root's parent becomes current position's parent
333  new_root->parent = position->parent;
334  new_root->children[1 - dir] = position;
335  new_root->dir = 1 - dir;
336 
337  // Clear weight factor from current position
338  position->weight = (uint_least8_t) kNeither;
339  // Position's parent becomes new_root
340  position->parent = new_root;
341  position = new_root;
342  // Clear weight factor from new root
343  position->weight = (uint_least8_t) kNeither;
344  }
345 
346  //*************************************************************************
348  //*************************************************************************
349  void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
350  {
351  // --A-- --E-- --A-- --D--
352  // _B_ C -> B A OR B _C_ -> A C
353  // D E D F G C D E B F G E
354  // F G F G
355  // E (new position) becomes the root
356  // B (position) takes ownership of F as its left child
357  // A takes ownership of G as its right child
358  // OR
359  // D (new position) becomes the root
360  // A (position) takes ownership of F as its right child
361  // C takes ownership of G as its left child
362 
363  // Capture new root (either E or D depending on dir)
364  Node* new_root = position->children[dir]->children[1 - dir];
365  // Set weight factor for B or C based on F or G existing and being a different than dir
366  position->children[dir]->weight = third != (uint_least8_t) kNeither && third != dir ? dir : (uint_least8_t) kNeither;
367 
368  // Detach new root from its tree (replace with new roots child)
369  position->children[dir]->children[1 - dir] = new_root->children[dir];
370  // Update new roots child parent pointer
371  if (new_root->children[dir])
372  {
373  new_root->children[dir]->parent = position->children[dir];
374  }
375 
376  // Attach current left tree to new root and update its parent
377  new_root->children[dir] = position->children[dir];
378  position->children[dir]->parent = new_root;
379 
380  // Set weight factor for A based on F or G
381  position->weight = third != (uint_least8_t) kNeither && third == dir ? 1 - dir : (uint_least8_t) kNeither;
382 
383  // Move new root's right tree to current roots left tree
384  position->children[dir] = new_root->children[1 - dir];
385  if (new_root->children[1 - dir])
386  {
387  new_root->children[1 - dir]->parent = position;
388  }
389 
390  // Attach current root to new roots right tree and assume its parent
391  new_root->parent = position->parent;
392  new_root->children[1 - dir] = position;
393  new_root->dir = 1 - dir;
394 
395  // Update current position's parent and replace with new root
396  position->parent = new_root;
397  position = new_root;
398  // Clear weight factor for new current position
399  position->weight = (uint_least8_t) kNeither;
400  }
401 
402  //*************************************************************************
404  //*************************************************************************
405  void next_node(Node*& position) const
406  {
407  if (position)
408  {
409  // Is there a tree on the right? then find the minimum of that tree
410  if (position->children[(uint_least8_t) kRight])
411  {
412  // Return minimum node found
413  position = find_limit_node(position->children[(uint_least8_t) kRight], kLeft);
414  }
415  // Otherwise find the parent of this node
416  else
417  {
418  // Start with current position as parent
419  Node* parent = position;
420  do {
421  // Update current position as previous parent
422  position = parent;
423  // Find parent of current position
424  parent = position->parent; // find_parent_node(root_node, position);
425  // Repeat while previous position was on right side of parent tree
426  } while (parent && parent->children[(uint_least8_t) kRight] == position);
427 
428  // Set parent node as the next position
429  position = parent;
430  }
431  }
432  }
433 
434  //*************************************************************************
436  //*************************************************************************
437  void next_node(const Node*& position) const
438  {
439  if (position)
440  {
441  // Is there a tree on the right? then find the minimum of that tree
442  if (position->children[(uint_least8_t) kRight])
443  {
444  // Return minimum node found
445  position = find_limit_node(position->children[(uint_least8_t) kRight], kLeft);
446  }
447  // Otherwise find the parent of this node
448  else
449  {
450  // Start with current position as parent
451  const Node* parent = position;
452  do {
453  // Update current position as previous parent
454  position = parent;
455  // Find parent of current position
456  parent = position->parent;
457  // Repeat while previous position was on right side of parent tree
458  } while (parent && parent->children[(uint_least8_t) kRight] == position);
459 
460  // Set parent node as the next position
461  position = parent;
462  }
463  }
464  }
465 
466  //*************************************************************************
468  //*************************************************************************
469  void prev_node(Node*& position) const
470  {
471  // If starting at the terminal end, the previous node is the maximum node
472  // from the root
473  if (!position)
474  {
475  position = find_limit_node(root_node, kRight);
476  }
477  else
478  {
479  // Is there a tree on the left? then find the maximum of that tree
480  if (position->children[(uint_least8_t) kLeft])
481  {
482  // Return maximum node found
483  position = find_limit_node(position->children[(uint_least8_t) kLeft], kRight);
484  }
485  // Otherwise find the parent of this node
486  else
487  {
488  // Start with current position as parent
489  Node* parent = position;
490  do {
491  // Update current position as previous parent
492  position = parent;
493  // Find parent of current position
494  parent = position->parent;
495  // Repeat while previous position was on left side of parent tree
496  } while (parent && parent->children[(uint_least8_t) kLeft] == position);
497 
498  // Set parent node as the next position
499  position = parent;
500  }
501  }
502  }
503 
504  //*************************************************************************
506  //*************************************************************************
507  void prev_node(const Node*& position) const
508  {
509  // If starting at the terminal end, the previous node is the maximum node
510  // from the root
511  if (!position)
512  {
513  position = find_limit_node(root_node, kRight);
514  }
515  else
516  {
517  // Is there a tree on the left? then find the maximum of that tree
518  if (position->children[(uint_least8_t) kLeft])
519  {
520  // Return maximum node found
521  position = find_limit_node(position->children[(uint_least8_t) kLeft], kRight);
522  }
523  // Otherwise find the parent of this node
524  else
525  {
526  // Start with current position as parent
527  const Node* parent = position;
528  do {
529  // Update current position as previous parent
530  position = parent;
531  // Find parent of current position
532  parent = position->parent;
533  // Repeat while previous position was on left side of parent tree
534  } while (parent && parent->children[(uint_least8_t) kLeft] == position);
535 
536  // Set parent node as the next position
537  position = parent;
538  }
539  }
540  }
541 
542  //*************************************************************************
545  //*************************************************************************
546  Node* find_limit_node(Node* position, const int8_t dir) const
547  {
548  // Something at this position and in the direction specified? keep going
549  Node* limit_node = position;
550  while (limit_node && limit_node->children[dir])
551  {
552  limit_node = limit_node->children[dir];
553  }
554 
555  // Return the limit node position found
556  return limit_node;
557  }
558 
559  //*************************************************************************
561  //*************************************************************************
562  void attach_node(Node* parent, Node*& position, Node& node)
563  {
564  // Mark new node as leaf on attach to tree at position provided
565  node.mark_as_leaf();
566 
567  // Keep track of this node's parent
568  node.parent = parent;
569 
570  // Add the node here
571  position = &node;
572 
573  // One more.
574  ++current_size;
575  }
576 
577  //*************************************************************************
579  //*************************************************************************
580  void detach_node(Node*& position, Node*& replacement)
581  {
582  // Make temporary copy of actual nodes involved because we might lose
583  // their references in the process (e.g. position is the same as
584  // replacement or replacement is a child of position)
585  Node* detached = position;
586  Node* swap = replacement;
587 
588  // Update current position to point to swap (replacement) node first
589  position = swap;
590 
591  // Update replacement node to point to child in opposite direction
592  // otherwise we might lose the other child of the swap node
593  replacement = swap->children[1 - swap->dir];
594 
595  if (replacement != ETL_NULLPTR)
596  {
597  replacement->parent = swap->parent;
598  }
599 
600  // Point swap node to detached node's parent, children and weight
601  swap->parent = detached->parent;
602  swap->children[(uint_least8_t) kLeft] = detached->children[(uint_least8_t) kLeft];
603  swap->children[(uint_least8_t) kRight] = detached->children[(uint_least8_t) kRight];
604  if (swap->children[(uint_least8_t) kLeft])
605  {
606  swap->children[(uint_least8_t) kLeft]->parent = swap;
607  }
608  if (swap->children[(uint_least8_t) kRight])
609  {
610  swap->children[(uint_least8_t) kRight]->parent = swap;
611  }
612  swap->weight = detached->weight;
613  }
614 
618  ETL_DECLARE_DEBUG_COUNT
619  };
620 
621  //***************************************************************************
624  //***************************************************************************
625  template <typename TKey, typename TMapped, typename TKeyCompare = etl::less<TKey> >
627  {
628  public:
629 
630  typedef ETL_OR_STD::pair<const TKey, TMapped> value_type;
631  typedef const TKey key_type;
632  typedef TMapped mapped_type;
633  typedef TKeyCompare key_compare;
634  typedef value_type& reference;
635  typedef const value_type& const_reference;
636 #if ETL_CPP11_SUPPORTED
637  typedef value_type&& rvalue_reference;
638 #endif
639  typedef value_type* pointer;
640  typedef const value_type* const_pointer;
641  typedef size_t size_type;
642 
644  {
645  public:
646 
647  bool operator()(const_reference lhs, const_reference rhs) const
648  {
649  return (kcompare(lhs.first, rhs.first));
650  }
651 
652  private:
653 
654  key_compare kcompare;
655  };
656 
657  protected:
658 
659  //*************************************************************************
661  //*************************************************************************
662  struct Data_Node : public Node
663  {
664  explicit Data_Node(value_type value_)
665  : value(value_)
666  {
667  }
668 
669  value_type value;
670  };
671 
674 
675  //*************************************************************************
677  //*************************************************************************
678  bool node_comp(const Data_Node& node1, const Data_Node& node2) const
679  {
680  return kcompare(node1.value.first, node2.value.first);
681  }
682 
683  bool node_comp(const Data_Node& node, key_parameter_t key) const
684  {
685  return kcompare(node.value.first, key);
686  }
687 
688  bool node_comp(key_parameter_t key, const Data_Node& node) const
689  {
690  return kcompare(key, node.value.first);
691  }
692 
693  private:
694 
696  ipool* p_node_pool;
697 
698  key_compare kcompare;
699  value_compare vcompare;
700 
701  //*************************************************************************
703  //*************************************************************************
704  static Data_Node* data_cast(Node* p_node)
705  {
706  return static_cast<Data_Node*>(p_node);
707  }
708 
709  //*************************************************************************
711  //*************************************************************************
712  static Data_Node& data_cast(Node& node)
713  {
714  return static_cast<Data_Node&>(node);
715  }
716 
717  //*************************************************************************
719  //*************************************************************************
720  static const Data_Node* data_cast(const Node* p_node)
721  {
722  return static_cast<const Data_Node*>(p_node);
723  }
724 
725  //*************************************************************************
727  //*************************************************************************
728  static const Data_Node& data_cast(const Node& node)
729  {
730  return static_cast<const Data_Node&>(node);
731  }
732 
733  public:
734  //*************************************************************************
736  //*************************************************************************
737  class iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, value_type>
738  {
739  public:
740 
741  friend class imultimap;
742  friend class const_iterator;
743 
744  iterator()
745  : p_multimap(ETL_NULLPTR)
746  , p_node(ETL_NULLPTR)
747  {
748  }
749 
751  : p_multimap(&multimap)
752  , p_node(ETL_NULLPTR)
753  {
754  }
755 
757  : p_multimap(&multimap)
758  , p_node(node)
759  {
760  }
761 
762  iterator(const iterator& other)
763  : p_multimap(other.p_multimap)
764  , p_node(other.p_node)
765  {
766  }
767 
768  ~iterator()
769  {
770  }
771 
772  iterator& operator ++()
773  {
774  p_multimap->next_node(p_node);
775  return *this;
776  }
777 
778  iterator operator ++(int)
779  {
780  iterator temp(*this);
781  p_multimap->next_node(p_node);
782  return temp;
783  }
784 
785  iterator& operator --()
786  {
787  p_multimap->prev_node(p_node);
788  return *this;
789  }
790 
791  iterator operator --(int)
792  {
793  iterator temp(*this);
794  p_multimap->prev_node(p_node);
795  return temp;
796  }
797 
798  iterator& operator =(const iterator& other)
799  {
800  p_multimap = other.p_multimap;
801  p_node = other.p_node;
802  return *this;
803  }
804 
805  reference operator *()
806  {
807  return imultimap::data_cast(p_node)->value;
808  }
809 
810  const_reference operator *() const
811  {
812  return imultimap::data_cast(p_node)->value;
813  }
814 
815  pointer operator &()
816  {
817  return &(imultimap::data_cast(p_node)->value);
818  }
819 
820  const_pointer operator &() const
821  {
822  return &(imultimap::data_cast(p_node)->value);
823  }
824 
825  pointer operator ->()
826  {
827  return &(imultimap::data_cast(p_node)->value);
828  }
829 
830  const_pointer operator ->() const
831  {
832  return &(imultimap::data_cast(p_node)->value);
833  }
834 
835  friend bool operator == (const iterator& lhs, const iterator& rhs)
836  {
837  return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
838  }
839 
840  friend bool operator != (const iterator& lhs, const iterator& rhs)
841  {
842  return !(lhs == rhs);
843  }
844 
845  private:
846 
847  // Pointer to multimap associated with this iterator
848  imultimap* p_multimap;
849 
850  // Pointer to the current node for this iterator
851  Node* p_node;
852  };
853  friend class iterator;
854 
855  //*************************************************************************
857  //*************************************************************************
858  class const_iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, const value_type>
859  {
860  public:
861 
862  friend class imultimap;
863 
865  : p_multimap(ETL_NULLPTR)
866  , p_node(ETL_NULLPTR)
867  {
868  }
869 
871  : p_multimap(&multimap)
872  , p_node(ETL_NULLPTR)
873  {
874  }
875 
876  const_iterator(const imultimap& multimap, const Node* node)
877  : p_multimap(&multimap)
878  , p_node(node)
879  {
880  }
881 
882  const_iterator(const typename imultimap::iterator& other)
883  : p_multimap(other.p_multimap)
884  , p_node(other.p_node)
885  {
886  }
887 
888  const_iterator(const const_iterator& other)
889  : p_multimap(other.p_multimap)
890  , p_node(other.p_node)
891  {
892  }
893 
894  ~const_iterator()
895  {
896  }
897 
898  const_iterator& operator ++()
899  {
900  p_multimap->next_node(p_node);
901  return *this;
902  }
903 
904  const_iterator operator ++(int)
905  {
906  const_iterator temp(*this);
907  p_multimap->next_node(p_node);
908  return temp;
909  }
910 
911  const_iterator& operator --()
912  {
913  p_multimap->prev_node(p_node);
914  return *this;
915  }
916 
917  const_iterator operator --(int)
918  {
919  const_iterator temp(*this);
920  p_multimap->prev_node(p_node);
921  return temp;
922  }
923 
924  const_iterator& operator =(const const_iterator& other)
925  {
926  p_multimap = other.p_multimap;
927  p_node = other.p_node;
928  return *this;
929  }
930 
931  const_reference operator *() const
932  {
933  return imultimap::data_cast(p_node)->value;
934  }
935 
936  const_pointer operator &() const
937  {
938  return imultimap::data_cast(p_node)->value;
939  }
940 
941  const_pointer operator ->() const
942  {
943  return &(imultimap::data_cast(p_node)->value);
944  }
945 
946  friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
947  {
948  return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
949  }
950 
951  friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
952  {
953  return !(lhs == rhs);
954  }
955 
956  private:
957  // Pointer to multimap associated with this iterator
958  const imultimap* p_multimap;
959 
960  // Pointer to the current node for this iterator
961  const Node* p_node;
962  };
963  friend class const_iterator;
964 
965  typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
966 
967  typedef ETL_OR_STD::reverse_iterator<iterator> reverse_iterator;
968  typedef ETL_OR_STD::reverse_iterator<const_iterator> const_reverse_iterator;
969 
970  //*************************************************************************
972  //*************************************************************************
974  {
975  return iterator(*this, find_limit_node(root_node, kLeft));
976  }
977 
978  //*************************************************************************
980  //*************************************************************************
982  {
983  return const_iterator(*this, find_limit_node(root_node, kLeft));
984  }
985 
986  //*************************************************************************
988  //*************************************************************************
990  {
991  return iterator(*this);
992  }
993 
994  //*************************************************************************
996  //*************************************************************************
998  {
999  return const_iterator(*this);
1000  }
1001 
1002  //*************************************************************************
1004  //*************************************************************************
1006  {
1007  return const_iterator(*this, find_limit_node(root_node, kLeft));
1008  }
1009 
1010  //*************************************************************************
1012  //*************************************************************************
1014  {
1015  return const_iterator(*this);
1016  }
1017 
1018  //*************************************************************************
1020  //*************************************************************************
1021  reverse_iterator rbegin()
1022  {
1023  return reverse_iterator(iterator(*this));
1024  }
1025 
1026  //*************************************************************************
1028  //*************************************************************************
1029  const_reverse_iterator rbegin() const
1030  {
1031  return const_reverse_iterator(const_iterator(*this));
1032  }
1033 
1034  //*************************************************************************
1036  //*************************************************************************
1037  reverse_iterator rend()
1038  {
1039  return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
1040  }
1041 
1042  //*************************************************************************
1044  //*************************************************************************
1045  const_reverse_iterator rend() const
1046  {
1047  return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
1048  }
1049 
1050  //*************************************************************************
1052  //*************************************************************************
1053  const_reverse_iterator crbegin() const
1054  {
1055  return const_reverse_iterator(const_iterator(*this));
1056  }
1057 
1058  //*************************************************************************
1060  //*************************************************************************
1061  const_reverse_iterator crend() const
1062  {
1063  return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
1064  }
1065 
1066  //*********************************************************************
1072  //*********************************************************************
1073  template <typename TIterator>
1074  void assign(TIterator first, TIterator last)
1075  {
1076  initialise();
1077  insert(first, last);
1078  }
1079 
1080  //*************************************************************************
1082  //*************************************************************************
1083  void clear()
1084  {
1085  initialise();
1086  }
1087 
1088  //*********************************************************************
1092  //*********************************************************************
1094  {
1095  return count_nodes(key);
1096  }
1097 
1098  //*************************************************************************
1101  //*************************************************************************
1102  ETL_OR_STD::pair<iterator, iterator> equal_range(key_parameter_t key)
1103  {
1104  return ETL_OR_STD::make_pair<iterator, iterator>(
1105  iterator(*this, find_lower_node(root_node, key)),
1106  iterator(*this, find_upper_node(root_node, key)));
1107  }
1108 
1109  //*************************************************************************
1112  //*************************************************************************
1113  ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1114  {
1115  return ETL_OR_STD::make_pair<const_iterator, const_iterator>(
1116  const_iterator(*this, find_lower_node(root_node, key)),
1117  const_iterator(*this, find_upper_node(root_node, key)));
1118  }
1119 
1120  //*************************************************************************
1122  //*************************************************************************
1123  void erase(iterator position)
1124  {
1125  // Remove the node by its node specified in iterator position
1126  (void)erase(const_iterator(position));
1127  }
1128 
1129  //*************************************************************************
1131  //*************************************************************************
1133  {
1134  // Cast const away from node to be removed. This is necessary because the
1135  // STL definition of this method requires we provide the next node in the
1136  // sequence as an iterator.
1137  Node* node = const_cast<Node*>(position.p_node);
1138  iterator next(*this, node);
1139  ++next;
1140 
1141  // Remove the non-const node provided
1142  remove_node(node);
1143 
1144  return next;
1145  }
1146 
1147  //*************************************************************************
1148  // Erase the key specified.
1149  //*************************************************************************
1150  size_type erase(key_parameter_t key)
1151  {
1152  // Number of nodes removed
1153  size_type d = 0;
1154  const_iterator lower(*this, find_lower_node(root_node, key));
1155  const_iterator upper(*this, find_upper_node(root_node, key));
1156  while (lower != upper)
1157  {
1158  // Increment count for each node removed
1159  ++d;
1160  // Remove node using the other erase method
1161  (void)erase(lower++);
1162  }
1163 
1164  // Return the total count erased
1165  return d;
1166  }
1167 
1168  //*************************************************************************
1170  //*************************************************************************
1172  {
1173  iterator next;
1174  while (first != last)
1175  {
1176  next = erase(const_iterator(first++));
1177  }
1178 
1179  return next;
1180  }
1181 
1182  //*************************************************************************
1184  //*************************************************************************
1186  {
1187  iterator next;
1188  while (first != last)
1189  {
1190  next = erase(first++);
1191  }
1192 
1193  return next;
1194  }
1195 
1196  //*********************************************************************
1200  //*********************************************************************
1202  {
1203  return iterator(*this, find_node(root_node, key));
1204  }
1205 
1206  //*********************************************************************
1210  //*********************************************************************
1212  {
1213  return const_iterator(*this, find_node(root_node, key));
1214  }
1215 
1216  //*********************************************************************
1220  //*********************************************************************
1221  iterator insert(const_reference value)
1222  {
1223  // Default to no inserted node
1224  Node* inserted_node = ETL_NULLPTR;
1225 
1226  ETL_ASSERT(!full(), ETL_ERROR(multimap_full));
1227 
1228  // Get next available free node
1229  Data_Node& node = allocate_data_node(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 
1238 #if ETL_CPP11_SUPPORTED
1239  //*********************************************************************
1243  //*********************************************************************
1244  iterator insert(rvalue_reference value)
1245  {
1246  // Default to no inserted node
1247  Node* inserted_node = ETL_NULLPTR;
1248 
1249  ETL_ASSERT(!full(), ETL_ERROR(multimap_full));
1250 
1251  // Get next available free node
1252  Data_Node& node = allocate_data_node(etl::move(value));
1253 
1254  // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1255  inserted_node = insert_node(root_node, node);
1256 
1257  // Insert node into tree and return iterator to new node location in tree
1258  return iterator(*this, inserted_node);
1259  }
1260 #endif
1261 
1262  //*********************************************************************
1267  //*********************************************************************
1268  iterator insert(iterator /*position*/, const_reference value)
1269  {
1270  // Ignore position provided and just do a normal insert
1271  return insert(value);
1272  }
1273 
1274  //*********************************************************************
1279  //*********************************************************************
1280  iterator insert(const_iterator /*position*/, const_reference value)
1281  {
1282  // Ignore position provided and just do a normal insert
1283  return insert(value);
1284  }
1285 
1286 #if ETL_CPP11_SUPPORTED
1287  //*********************************************************************
1292  //*********************************************************************
1293  iterator insert(iterator /*position*/, rvalue_reference value)
1294  {
1295  // Ignore position provided and just do a normal insert
1296  return insert(etl::move(value));
1297  }
1298 
1299  //*********************************************************************
1304  //*********************************************************************
1305  iterator insert(const_iterator /*position*/, rvalue_reference value)
1306  {
1307  // Ignore position provided and just do a normal insert
1308  return insert(etl::move(value));
1309  }
1310 #endif
1311 
1312  //*********************************************************************
1318  //*********************************************************************
1319  template <class TIterator>
1320  void insert(TIterator first, TIterator last)
1321  {
1322  while (first != last)
1323  {
1324  insert(*first++);
1325  }
1326  }
1327 
1328  //*********************************************************************
1333  //*********************************************************************
1335  {
1336  return iterator(*this, find_lower_node(root_node, key));
1337  }
1338 
1339  //*********************************************************************
1344  //*********************************************************************
1346  {
1347  return const_iterator(*this, find_lower_node(root_node, key));
1348  }
1349 
1350  //*********************************************************************
1355  //*********************************************************************
1357  {
1358  return iterator(*this, find_upper_node(root_node, key));
1359  }
1360 
1361  //*********************************************************************
1366  //*********************************************************************
1368  {
1369  return const_iterator(*this, find_upper_node(root_node, key));
1370  }
1371 
1372  //*************************************************************************
1374  //*************************************************************************
1376  {
1377  // Skip if doing self assignment
1378  if (this != &rhs)
1379  {
1380  assign(rhs.cbegin(), rhs.cend());
1381  }
1382 
1383  return *this;
1384  }
1385 
1386 #if ETL_CPP11_SUPPORTED
1387  //*************************************************************************
1389  //*************************************************************************
1391  {
1392  // Skip if doing self assignment
1393  if (this != &rhs)
1394  {
1395  this->clear();
1396 
1397  iterator from = rhs.begin();
1398 
1399  while (from != rhs.end())
1400  {
1401  this->insert(etl::move(*from++));
1402  }
1403  }
1404 
1405  return *this;
1406  }
1407 #endif
1408 
1409  //*************************************************************************
1411  //*************************************************************************
1412  key_compare key_comp() const
1413  {
1414  return kcompare;
1415  };
1416 
1417  //*************************************************************************
1419  //*************************************************************************
1421  {
1422  return vcompare;
1423  };
1424 
1425  protected:
1426 
1427  //*************************************************************************
1429  //*************************************************************************
1430  imultimap(etl::ipool& node_pool, size_t max_size_)
1431  : multimap_base(max_size_)
1432  , p_node_pool(&node_pool)
1433  {
1434  }
1435 
1436  //*************************************************************************
1438  //*************************************************************************
1439  void initialise()
1440  {
1441  const_iterator item = begin();
1442 
1443  while (item != end())
1444  {
1445  item = erase(item);
1446  }
1447  }
1448 
1449  private:
1450 
1451  //*************************************************************************
1453  //*************************************************************************
1454  Data_Node& allocate_data_node(const_reference value)
1455  {
1456  Data_Node& node = create_data_node();
1457  ::new (&node.value) const value_type(value);
1458  ETL_INCREMENT_DEBUG_COUNT
1459  return node;
1460  }
1461 
1462 #if ETL_CPP11_SUPPORTED
1463  //*************************************************************************
1465  //*************************************************************************
1466  Data_Node& allocate_data_node(rvalue_reference value)
1467  {
1468  Data_Node& node = create_data_node();
1469  ::new (&node.value) const value_type(etl::move(value));
1470  ETL_INCREMENT_DEBUG_COUNT
1471  return node;
1472  }
1473 #endif
1474 
1475  //*************************************************************************
1477  //*************************************************************************
1478  Data_Node& create_data_node()
1479  {
1480  Data_Node* (etl::ipool::*func)() = &etl::ipool::allocate<Data_Node>;
1481  return *(p_node_pool->*func)();
1482  }
1483 
1484  //*************************************************************************
1486  //*************************************************************************
1487  void destroy_data_node(Data_Node& node)
1488  {
1489  node.value.~value_type();
1490  p_node_pool->release(&node);
1491  ETL_DECREMENT_DEBUG_COUNT
1492  }
1493 
1494  //*************************************************************************
1496  //*************************************************************************
1497  size_type count_nodes(key_parameter_t key) const
1498  {
1499  // Number of nodes that match the key provided result
1500  size_type result = 0;
1501 
1502  // Find lower and upper nodes for the key provided
1503  const Node* lower = find_lower_node(root_node, key);
1504  const Node* upper = find_upper_node(root_node, key);
1505 
1506  // Loop from lower node to upper node and find nodes that match
1507  while (lower != upper)
1508  {
1509  // Downcast found to Data_Node class for comparison and other operations
1510  const Data_Node& data_node = imultimap::data_cast(*lower);
1511 
1512  if (!node_comp(key, data_node) && !node_comp(data_node, key))
1513  {
1514  // This node matches the key provided
1515  ++result;
1516  }
1517 
1518  // Move on to the next node
1519  next_node(lower);
1520  }
1521 
1522  // Return the number of nodes that match
1523  return result;
1524  }
1525 
1526  //*************************************************************************
1528  //*************************************************************************
1529  Node* find_node(Node* position, key_parameter_t key) const
1530  {
1531  Node* found = ETL_NULLPTR;
1532  while (position)
1533  {
1534  // Downcast found to Data_Node class for comparison and other operations
1535  Data_Node& data_node = imultimap::data_cast(*position);
1536  // Compare the node value to the current position value
1537  if (node_comp(key, data_node))
1538  {
1539  // Keep searching for the node on the left
1540  position = position->children[(uint_least8_t) kLeft];
1541  }
1542  else if (node_comp(data_node, key))
1543  {
1544  // Keep searching for the node on the right
1545  position = position->children[(uint_least8_t) kRight];
1546  }
1547  else
1548  {
1549  // We found one, keep looking for more on the left
1550  found = position;
1551  position = position->children[(uint_least8_t) kLeft];
1552  }
1553  }
1554 
1555  // Return the node found (might be ETL_NULLPTR)
1556  return found;
1557  }
1558 
1559  //*************************************************************************
1561  //*************************************************************************
1562  const Node* find_node(const Node* position, key_parameter_t key) const
1563  {
1564  const Node* found = ETL_NULLPTR;
1565  while (position)
1566  {
1567  // Downcast found to Data_Node class for comparison and other operations
1568  const Data_Node& data_node = imultimap::data_cast(*position);
1569  // Compare the node value to the current position value
1570  if (node_comp(key, data_node))
1571  {
1572  // Keep searching for the node on the left
1573  position = position->children[(uint_least8_t) kLeft];
1574  }
1575  else if (node_comp(data_node, key))
1576  {
1577  // Keep searching for the node on the right
1578  position = position->children[(uint_least8_t) kRight];
1579  }
1580  else
1581  {
1582  // We found one, keep looking for more on the left
1583  found = position;
1584  position = position->children[(uint_least8_t) kLeft];
1585  }
1586  }
1587 
1588  // Return the node found (might be ETL_NULLPTR)
1589  return found;
1590  }
1591 
1592  //*************************************************************************
1594  //*************************************************************************
1595  Node* find_lower_node(Node* position, key_parameter_t key) const
1596  {
1597  // Something at this position? keep going
1598  Node* lower_node = ETL_NULLPTR;
1599  while (position)
1600  {
1601  // Downcast lower node to Data_Node reference for key comparisons
1602  Data_Node& data_node = imultimap::data_cast(*position);
1603  // Compare the key value to the current lower node key value
1604  if (node_comp(key, data_node))
1605  {
1606  lower_node = position;
1607  if (position->children[(uint_least8_t) kLeft])
1608  {
1609  position = position->children[(uint_least8_t) kLeft];
1610  }
1611  else
1612  {
1613  // Found lowest node
1614  break;
1615  }
1616  }
1617  else if (node_comp(data_node, key))
1618  {
1619  position = position->children[(uint_least8_t) kRight];
1620  }
1621  else
1622  {
1623  // Make note of current position, but keep looking to left for more
1624  lower_node = position;
1625  position = position->children[(uint_least8_t) kLeft];
1626  }
1627  }
1628 
1629  // Return the lower_node position found
1630  return lower_node;
1631  }
1632 
1633  //*************************************************************************
1635  //*************************************************************************
1636  Node* find_upper_node(Node* position, key_parameter_t key) const
1637  {
1638  // Keep track of parent of last upper node
1639  Node* upper_node = ETL_NULLPTR;
1640  // Has an equal node been found? start with no
1641  bool found = false;
1642  while (position)
1643  {
1644  // Downcast position to Data_Node reference for key comparisons
1645  Data_Node& data_node = imultimap::data_cast(*position);
1646  // Compare the key value to the current upper node key value
1647  if (node_comp(data_node, key))
1648  {
1649  position = position->children[(uint_least8_t) kRight];
1650  }
1651  else if (node_comp(key, data_node))
1652  {
1653  upper_node = position;
1654  // If a node equal to key hasn't been found go left
1655  if (!found && position->children[(uint_least8_t) kLeft])
1656  {
1657  position = position->children[(uint_least8_t) kLeft];
1658  }
1659  else
1660  {
1661  break;
1662  }
1663  }
1664  else
1665  {
1666  // We found an equal item, break on next bigger item
1667  found = true;
1668  next_node(position);
1669  }
1670  }
1671 
1672  // Return the upper node position found (might be ETL_NULLPTR)
1673  return upper_node;
1674  }
1675 
1676  //*************************************************************************
1678  //*************************************************************************
1679  Node* insert_node(Node*& position, Data_Node& node)
1680  {
1681  // Find the location where the node belongs
1682  Node* found = position;
1683 
1684  // Was position provided not empty? then find where the node belongs
1685  if (position)
1686  {
1687  // Find the critical parent node (default to ETL_NULLPTR)
1688  Node* critical_parent_node = ETL_NULLPTR;
1689  Node* critical_node = root_node;
1690 
1691  while (found)
1692  {
1693  // Search for critical weight node (all nodes whose weight factor
1694  // is set to (uint_least8_t) kNeither (balanced)
1695  if ((uint_least8_t) kNeither != found->weight)
1696  {
1697  critical_node = found;
1698  }
1699 
1700  // Downcast found to Data_Node class for comparison and other operations
1701  Data_Node& found_data_node = imultimap::data_cast(*found);
1702 
1703  // Is the node provided to the left of the current position?
1704  if (node_comp(node, found_data_node))
1705  {
1706  // Update direction taken to insert new node in parent node
1707  found->dir = (uint_least8_t) kLeft;
1708  }
1709  // Is the node provided to the right of the current position?
1710  else if (node_comp(found_data_node, node))
1711  {
1712  // Update direction taken to insert new node in parent node
1713  found->dir = (uint_least8_t) kRight;
1714  }
1715  else
1716  {
1717  // Update direction taken to insert new node in parent (and
1718  // duplicate) node to the right.
1719  found->dir = (uint_least8_t) kRight;
1720  }
1721 
1722  // Is there a child of this parent node?
1723  if (found->children[found->dir])
1724  {
1725  // Will this node be the parent of the next critical node whose
1726  // weight factor is set to (uint_least8_t) kNeither (balanced)?
1727  if ((uint_least8_t) kNeither != found->children[found->dir]->weight)
1728  {
1729  critical_parent_node = found;
1730  }
1731 
1732  // Keep looking for empty spot to insert new node
1733  found = found->children[found->dir];
1734  }
1735  else
1736  {
1737  // Attach node as a child of the parent node found
1738  attach_node(found, found->children[found->dir], node);
1739 
1740  // Return newly added node
1741  found = found->children[found->dir];
1742 
1743  // Exit loop
1744  break;
1745  }
1746  }
1747 
1748  // Was a critical node found that should be checked for balance?
1749  if (critical_node)
1750  {
1751  if (critical_parent_node == ETL_NULLPTR && critical_node == root_node)
1752  {
1754  }
1755  else if (critical_parent_node == ETL_NULLPTR && critical_node == position)
1756  {
1757  balance_node(position);
1758  }
1759  else
1760  {
1761  if (critical_parent_node != ETL_NULLPTR)
1762  {
1763  balance_node(critical_parent_node->children[critical_parent_node->dir]);
1764  }
1765  }
1766  }
1767  }
1768  else
1769  {
1770  // Attach node to current position (which is assumed to be root)
1771  attach_node(ETL_NULLPTR, position, node);
1772 
1773  // Return newly added node at current position
1774  found = position;
1775  }
1776 
1777  // Return the node found (might be ETL_NULLPTR)
1778  return found;
1779  }
1780 
1781  //*************************************************************************
1784  //*************************************************************************
1785  void remove_node(Node* node)
1786  {
1787  // If valid found node was provided then proceed with steps 1 through 5
1788  if (node)
1789  {
1790  // Downcast found node provided to Data_Node class
1791  Data_Node& data_node = imultimap::data_cast(*node);
1792 
1793  // Keep track of node as found node
1794  Node* found = node;
1795 
1796  // Step 1: Mark path from node provided back to the root node using the
1797  // internal temporary dir member value and using the parent pointer. This
1798  // will allow us to avoid recursion in finding the node in a tree that
1799  //might contain duplicate keys to be found.
1800  while (node)
1801  {
1802  if (node->parent)
1803  {
1804  // Which direction does parent use to get to this node?
1805  node->parent->dir =
1806  node->parent->children[(uint_least8_t) kLeft] == node ? (uint_least8_t) kLeft : (uint_least8_t) kRight;
1807 
1808  // Make this nodes parent the next node
1809  node = node->parent;
1810  }
1811  else
1812  {
1813  // Root node found - break loop
1814  break;
1815  }
1816  }
1817 
1818  // Step 2: Follow the path provided above until we reach the node
1819  // provided and look for the balance node to start rebalancing the tree
1820  // from (up to the replacement node that will be found in step 3)
1821  Node* balance = root_node;
1822  while (node)
1823  {
1824  // Did we reach the node provided originally (found) then go to step 3
1825  if (node == found)
1826  {
1827  // Update the direction towards a replacement node at the found node
1828  node->dir = node->children[(uint_least8_t) kLeft] ? (uint_least8_t) kLeft : (uint_least8_t) kRight;
1829 
1830  // Exit loop and proceed with step 3
1831  break;
1832  }
1833  else
1834  {
1835  // If this nodes weight is (uint_least8_t) kNeither or we are taking the shorter path
1836  // to the next node and our sibling (on longer path) is balanced then
1837  // we need to update the balance node to this node but all our
1838  // ancestors will not require rebalancing
1839  if ((node->weight == (uint_least8_t) kNeither) ||
1840  (node->weight == (1 - node->dir) &&
1841  node->children[1 - node->dir]->weight == (uint_least8_t) kNeither))
1842  {
1843  // Update balance node to this node
1844  balance = node;
1845  }
1846 
1847  // Keep searching for found in the direction provided in step 1
1848  node = node->children[node->dir];
1849  }
1850  }
1851  // The value for node should not be ETL_NULLPTR at this point otherwise
1852  // step 1 failed to provide the correct path to found. Step 5 will fail
1853  // (probably subtly) if node should be ETL_NULLPTR at this point
1854 
1855  // Step 3: Find the node (node should be equal to found at this point)
1856  // to replace found with (might end up equal to found) while also
1857  // continuing to update balance the same as in step 2 above.
1858  while (node)
1859  {
1860  // Replacement node found if its missing a child in the replace->dir
1861  // value set at the end of step 2 above
1862  if (node->children[node->dir] == ETL_NULLPTR)
1863  {
1864  // Exit loop once node to replace found is determined
1865  break;
1866  }
1867 
1868  // If this nodes weight is (uint_least8_t) kNeither or we are taking the shorter path
1869  // to the next node and our sibling (on longer path) is balanced then
1870  // we need to update the balance node to this node but all our
1871  // ancestors will not require rebalancing
1872  if ((node->weight == (uint_least8_t) kNeither) ||
1873  (node->weight == (1 - node->dir) &&
1874  node->children[1 - node->dir]->weight == (uint_least8_t) kNeither))
1875  {
1876  // Update balance node to this node
1877  balance = node;
1878  }
1879 
1880  // Keep searching for replacement node in the direction specified above
1881  node = node->children[node->dir];
1882 
1883  // Downcast node to Data_Node class for comparison operations
1884  Data_Node& replace_data_node = imultimap::data_cast(*node);
1885 
1886  // Compare the key provided to the replace data node key
1887  if (node_comp(data_node, replace_data_node))
1888  {
1889  // Update the direction to the replace node
1890  node->dir = (uint_least8_t) kLeft;
1891  }
1892  else if (node_comp(replace_data_node, data_node))
1893  {
1894  // Update the direction to the replace node
1895  node->dir = (uint_least8_t) kRight;
1896  }
1897  else
1898  {
1899  // Update the direction to the replace node
1900  node->dir = node->children[(uint_least8_t) kLeft] ? (uint_least8_t) kLeft : (uint_least8_t) kRight;
1901  }
1902  } // while(node)
1903 
1904  // Step 4: Update weights from balance to parent of node determined
1905  // in step 3 above rotating (2 or 3 node rotations) as needed.
1906  while (balance)
1907  {
1908  // Break when balance node reaches the parent of replacement node
1909  if (balance->children[balance->dir] == ETL_NULLPTR)
1910  {
1911  break;
1912  }
1913 
1914  // If balance node is balanced already ((uint_least8_t) kNeither) then just imbalance
1915  // the node in the opposite direction of the node being removed
1916  if (balance->weight == (uint_least8_t) kNeither)
1917  {
1918  balance->weight = 1 - balance->dir;
1919  }
1920  // If balance node is imbalanced in the opposite direction of the
1921  // node being removed then the node now becomes balanced
1922  else if (balance->weight == balance->dir)
1923  {
1924  balance->weight = (uint_least8_t) kNeither;
1925  }
1926  // Otherwise a rotation is required at this node
1927  else
1928  {
1929  int weight = balance->children[1 - balance->dir]->weight;
1930  // Perform a 3 node rotation if weight is same as balance->dir
1931  if (weight == balance->dir)
1932  {
1933  // Is the root node being rebalanced (no parent)
1934  if (balance->parent == ETL_NULLPTR)
1935  {
1936  rotate_3node(root_node, 1 - balance->dir,
1937  balance->children[1 - balance->dir]->children[balance->dir]->weight);
1938  }
1939  else
1940  {
1941  rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
1942  balance->children[1 - balance->dir]->children[balance->dir]->weight);
1943  }
1944  }
1945  // Already balanced, rebalance and make it heavy in opposite
1946  // direction of the node being removed
1947  else if (weight == (uint_least8_t) kNeither)
1948  {
1949  // Is the root node being rebalanced (no parent)
1950  if (balance->parent == ETL_NULLPTR)
1951  {
1952  rotate_2node(root_node, 1 - balance->dir);
1953  root_node->weight = balance->dir;
1954  }
1955  else
1956  {
1957  // Balance parent might change during rotate, keep local copy
1958  // to old parent so its weight can be updated after the 2 node
1959  // rotate is completed
1960  Node* old_parent = balance->parent;
1961  rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
1962  old_parent->children[old_parent->dir]->weight = balance->dir;
1963  }
1964  // Update balance node weight in opposite direction of node removed
1965  balance->weight = 1 - balance->dir;
1966  }
1967  // Rebalance and leave it balanced
1968  else
1969  {
1970  // Is the root node being rebalanced (no parent)
1971  if (balance->parent == ETL_NULLPTR)
1972  {
1973  rotate_2node(root_node, 1 - balance->dir);
1974  }
1975  else
1976  {
1977  rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
1978  }
1979  }
1980  }
1981 
1982  // Next balance node to consider
1983  balance = balance->children[balance->dir];
1984  } // while(balance)
1985 
1986  // Step 5: Swap found with node (replacement)
1987  if (found->parent)
1988  {
1989  // Handle traditional case
1990  detach_node(found->parent->children[found->parent->dir],
1991  node->parent->children[node->parent->dir]);
1992  }
1993  // Handle root node removal
1994  else
1995  {
1996  // Valid replacement node for root node being removed?
1997  if (node->parent)
1998  {
1999  detach_node(root_node, node->parent->children[node->parent->dir]);
2000  }
2001  else
2002  {
2003  // Found node and replacement node are both root node
2005  }
2006  }
2007 
2008  // One less.
2009  --current_size;
2010 
2011  // Destroy the node detached above
2012  destroy_data_node(data_node);
2013  } // if(found)
2014  }
2015 
2016  // Disable copy construction.
2017  imultimap(const imultimap&);
2018 
2019  //*************************************************************************
2021  //*************************************************************************
2022 #if defined(ETL_POLYMORPHIC_MULTIMAP) || defined(ETL_POLYMORPHIC_CONTAINERS)
2023  public:
2024  virtual ~imultimap()
2025  {
2026  }
2027 #else
2028  protected:
2030  {
2031  }
2032 #endif
2033  };
2034 
2035  //*************************************************************************
2037  //*************************************************************************
2038  template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = etl::less<TKey> >
2039  class multimap : public etl::imultimap<TKey, TValue, TCompare>
2040  {
2041  public:
2042 
2043  static const size_t MAX_SIZE = MAX_SIZE_;
2044 
2045  //*************************************************************************
2047  //*************************************************************************
2049  : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2050  {
2051  this->initialise();
2052  }
2053 
2054  //*************************************************************************
2056  //*************************************************************************
2057  multimap(const multimap& other)
2058  : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2059  {
2060  if (this != &other)
2061  {
2062  this->assign(other.cbegin(), other.cend());
2063  }
2064  }
2065 
2066 #if ETL_CPP11_SUPPORTED
2067  //*************************************************************************
2069  //*************************************************************************
2070  multimap(multimap&& other)
2071  : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2072  {
2073  if (this != &other)
2074  {
2075  typename etl::imultimap<TKey, TValue, TCompare>::iterator from = other.begin();
2076 
2077  while (from != other.end())
2078  {
2079  this->insert(etl::move(*from++));
2080  }
2081  }
2082  }
2083 #endif
2084 
2085  //*************************************************************************
2090  //*************************************************************************
2091  template <typename TIterator>
2092  multimap(TIterator first, TIterator last)
2093  : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2094  {
2095  this->assign(first, last);
2096  }
2097 
2098 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
2099  //*************************************************************************
2101  //*************************************************************************
2102  multimap(std::initializer_list<typename etl::imultimap<TKey, TValue, TCompare>::value_type> init)
2103  : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
2104  {
2105  this->assign(init.begin(), init.end());
2106  }
2107 #endif
2108 
2109  //*************************************************************************
2111  //*************************************************************************
2113  {
2114  this->initialise();
2115  }
2116 
2117  //*************************************************************************
2119  //*************************************************************************
2121  {
2122  // Skip if doing self assignment
2123  if (this != &rhs)
2124  {
2125  this->assign(rhs.cbegin(), rhs.cend());
2126  }
2127 
2128  return *this;
2129  }
2130 
2131 #if ETL_CPP11_SUPPORTED
2132  //*************************************************************************
2134  //*************************************************************************
2135  multimap& operator = (multimap&& rhs)
2136  {
2137  if (this != &rhs)
2138  {
2139  typename etl::imultimap<TKey, TValue, TCompare>::iterator from = rhs.begin();
2140 
2141  while (from != rhs.end())
2142  {
2143  this->insert(etl::move(*from++));
2144  }
2145  }
2146 
2147  return *this;
2148  }
2149 #endif
2150 
2151  private:
2152 
2155  };
2156 
2157  //*************************************************************************
2159  //*************************************************************************
2160 #if ETL_CPP17_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
2161  template <typename T, typename... Ts>
2162  multimap(T, Ts...)
2163  ->multimap<etl::enable_if_t<(etl::is_same_v<T, Ts> && ...), typename T::first_type>,
2164  typename T::second_type,
2165  1U + sizeof...(Ts)>;
2166 #endif
2167 
2168  //***************************************************************************
2174  //***************************************************************************
2175  template <typename TKey, typename TMapped, typename TKeyCompare>
2177  {
2178  return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
2179  }
2180 
2181  //***************************************************************************
2187  //***************************************************************************
2188  template <typename TKey, typename TMapped, typename TKeyCompare>
2190  {
2191  return !(lhs == rhs);
2192  }
2193 
2194  //*************************************************************************
2200  //*************************************************************************
2201  template <typename TKey, typename TMapped, typename TKeyCompare>
2203  {
2204  return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
2205  }
2206 
2207  //*************************************************************************
2213  //*************************************************************************
2214  template <typename TKey, typename TMapped, typename TKeyCompare>
2216  {
2217  return (rhs < lhs);
2218  }
2219 
2220  //*************************************************************************
2226  //*************************************************************************
2227  template <typename TKey, typename TMapped, typename TKeyCompare>
2229  {
2230  return !(lhs > rhs);
2231  }
2232 
2233  //*************************************************************************
2239  //*************************************************************************
2240  template <typename TKey, typename TMapped, typename TKeyCompare>
2242  {
2243  return !(lhs < rhs);
2244  }
2245 }
2246 
2247 #include "private/minmax_pop.h"
2248 
2249 #undef ETL_FILE
2250 
2251 #endif
const_iterator
Definition: multimap.h:859
iterator.
Definition: multimap.h:738
Definition: multimap.h:644
A templated multimap implementation that uses a fixed size buffer.
Definition: multimap.h:2040
multimap(TIterator first, TIterator last)
Definition: multimap.h:2092
multimap()
Default constructor.
Definition: multimap.h:2048
~multimap()
Destructor.
Definition: multimap.h:2112
multimap(const multimap &other)
Copy constructor.
Definition: multimap.h:2057
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
void assign(TIterator first, TIterator last)
Definition: multimap.h:1074
void attach_node(Node *parent, Node *&position, Node &node)
Attach the provided node to the position provided.
Definition: multimap.h:562
reverse_iterator rend()
Gets the reverse end of the list.
Definition: multimap.h:1037
reverse_iterator rbegin()
Gets the reverse beginning of the list.
Definition: multimap.h:1021
imultimap & operator=(const imultimap &rhs)
Assignment operator.
Definition: multimap.h:1375
size_type size() const
Gets the size of the map.
Definition: multimap.h:137
size_type current_size
The number of the used nodes.
Definition: multimap.h:615
void next_node(const Node *&position) const
Find the next node in sequence from the node provided.
Definition: multimap.h:437
Node * find_limit_node(Node *position, const int8_t dir) const
Definition: multimap.h:546
iterator lower_bound(key_parameter_t key)
Definition: multimap.h:1334
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(key_parameter_t key) const
Definition: multimap.h:1113
const_reverse_iterator rbegin() const
Gets the reverse beginning of the list.
Definition: multimap.h:1029
const_iterator upper_bound(key_parameter_t key) const
Definition: multimap.h:1367
iterator erase(iterator first, iterator last)
Erases a range of elements.
Definition: multimap.h:1171
ETL_OR_STD::pair< iterator, iterator > equal_range(key_parameter_t key)
Definition: multimap.h:1102
multimap_base(size_type max_size_)
The constructor that is called from derived classes.
Definition: multimap.h:228
iterator insert(const_reference value)
Definition: multimap.h:1221
bool node_comp(const Data_Node &node1, const Data_Node &node2) const
How to compare node elements.
Definition: multimap.h:678
iterator erase(const_iterator first, const_iterator last)
Erases a range of elements.
Definition: multimap.h:1185
~multimap_base()
The constructor that is called from derived classes.
Definition: multimap.h:238
void prev_node(const Node *&position) const
Find the previous node in sequence from the node provided.
Definition: multimap.h:507
size_t available() const
Definition: multimap.h:179
iterator end()
Gets the end of the multimap.
Definition: multimap.h:989
void clear()
Clears the multimap.
Definition: multimap.h:1083
void rotate_2node(Node *&position, uint_least8_t dir)
Rotate two nodes at the position provided the to balance the tree.
Definition: multimap.h:308
const size_type CAPACITY
The maximum size of the map.
Definition: multimap.h:616
void detach_node(Node *&position, Node *&replacement)
Detach the node at the position provided.
Definition: multimap.h:580
const_iterator find(key_parameter_t key) const
Definition: multimap.h:1211
const_reverse_iterator rend() const
Gets the reverse end of the list.
Definition: multimap.h:1045
const_iterator end() const
Gets the end of the multimap.
Definition: multimap.h:997
key_compare key_comp() const
How to compare two key elements.
Definition: multimap.h:1412
const_iterator cend() const
Gets the end of the multimap.
Definition: multimap.h:1013
iterator insert(const_iterator, const_reference value)
Definition: multimap.h:1280
iterator upper_bound(key_parameter_t key)
Definition: multimap.h:1356
bool empty() const
Checks to see if the map is empty.
Definition: multimap.h:153
void next_node(Node *&position) const
Find the next node in sequence from the node provided.
Definition: multimap.h:405
size_type capacity() const
Definition: multimap.h:170
void prev_node(Node *&position) const
Find the previous node in sequence from the node provided.
Definition: multimap.h:469
iterator insert(iterator, const_reference value)
Definition: multimap.h:1268
Node * root_node
The node that acts as the multimap root.
Definition: multimap.h:617
size_t size_type
The type used for determining the size of map.
Definition: multimap.h:132
const_reverse_iterator crbegin() const
Gets the reverse beginning of the list.
Definition: multimap.h:1053
iterator begin()
Gets the beginning of the multimap.
Definition: multimap.h:973
void insert(TIterator first, TIterator last)
Definition: multimap.h:1320
size_type max_size() const
Gets the maximum possible size of the map.
Definition: multimap.h:145
const_iterator cbegin() const
Gets the beginning of the multimap.
Definition: multimap.h:1005
const_reverse_iterator crend() const
Gets the reverse end of the list.
Definition: multimap.h:1061
void initialise()
Initialise the multimap.
Definition: multimap.h:1439
iterator find(key_parameter_t key)
Definition: multimap.h:1201
imultimap(etl::ipool &node_pool, size_t max_size_)
Constructor.
Definition: multimap.h:1430
value_compare value_comp() const
How to compare two value elements.
Definition: multimap.h:1420
const_iterator lower_bound(key_parameter_t key) const
Definition: multimap.h:1345
void rotate_3node(Node *&position, uint_least8_t dir, uint_least8_t third)
Rotate three nodes at the position provided the to balance the tree.
Definition: multimap.h:349
etl::parameter_type< TKey >::type key_parameter_t
Defines the key value parameter type.
Definition: multimap.h:673
const_iterator begin() const
Gets the beginning of the multimap.
Definition: multimap.h:981
void erase(iterator position)
Erases the value at the specified position.
Definition: multimap.h:1123
size_type count(key_parameter_t key) const
Definition: multimap.h:1093
bool full() const
Checks to see if the map is full.
Definition: multimap.h:161
~imultimap()
Destructor.
Definition: multimap.h:2029
iterator erase(const_iterator position)
Erases the value at the specified position.
Definition: multimap.h:1132
void balance_node(Node *&critical_node)
Balance the critical node at the position provided as needed.
Definition: multimap.h:245
Definition: multimap.h:627
Definition: multimap.h:129
Definition: multimap.h:73
Definition: multimap.h:87
Definition: multimap.h:115
Definition: multimap.h:101
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
bool operator==(const etl::imultimap< TKey, TMapped, TKeyCompare > &lhs, const etl::imultimap< TKey, TMapped, TKeyCompare > &rhs)
Template deduction guides.
Definition: multimap.h:2176
void swap(etl::array< T, SIZE > &lhs, etl::array< T, SIZE > &rhs)
Template deduction guides.
Definition: array.h:570
bool operator!=(const etl::imultimap< TKey, TMapped, TKeyCompare > &lhs, const etl::imultimap< TKey, TMapped, TKeyCompare > &rhs)
Definition: multimap.h:2189
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:582
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
The data node element in the multimap.
Definition: multimap.h:663
iterator
Definition: iterator.h:422
The node element in the multimap.
Definition: multimap.h:197
Node()
Constructor.
Definition: multimap.h:201
void mark_as_leaf()
Marks the node as a leaf.
Definition: multimap.h:210
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