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