Embedded Template Library 1.0
Loading...
Searching...
No Matches
multiset.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2014 John Wellbelove, rlindeman
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_MULTISET_INCLUDED
32#define ETL_MULTISET_INCLUDED
33
34#include "platform.h"
35#include "algorithm.h"
36#include "iterator.h"
37#include "functional.h"
38#include "parameter_type.h"
39#include "pool.h"
40#include "exception.h"
41#include "error_handler.h"
42#include "debug_count.h"
43#include "nullptr.h"
44#include "type_traits.h"
45#include "nth_type.h"
46#include "utility.h"
47#include "placement_new.h"
48#include "initializer_list.h"
49
50#include <stddef.h>
51
52#include "private/minmax_push.h"
54
55//*****************************************************************************
58//*****************************************************************************
59
60namespace etl
61{
62 //***************************************************************************
65 //***************************************************************************
66 class multiset_exception : public etl::exception
67 {
68 public:
69
70 multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
71 : etl::exception(reason_, file_name_, line_number_)
72 {
73 }
74 };
75
76 //***************************************************************************
79 //***************************************************************************
80 class multiset_full : public etl::multiset_exception
81 {
82 public:
83
84 multiset_full(string_type file_name_, numeric_type line_number_)
85 : etl::multiset_exception(ETL_ERROR_TEXT("multiset:full", ETL_MULTISET_FILE_ID"A"), file_name_, line_number_)
86 {
87 }
88 };
89
90 //***************************************************************************
93 //***************************************************************************
94 class multiset_out_of_bounds : public etl::multiset_exception
95 {
96 public:
97
98 multiset_out_of_bounds(string_type file_name_, numeric_type line_number_)
99 : etl::multiset_exception(ETL_ERROR_TEXT("multiset:bounds", ETL_MULTISET_FILE_ID"B"), file_name_, line_number_)
100 {
101 }
102 };
103
104 //***************************************************************************
107 //***************************************************************************
108 class multiset_iterator : public etl::multiset_exception
109 {
110 public:
111
112 multiset_iterator(string_type file_name_, numeric_type line_number_)
113 : etl::multiset_exception(ETL_ERROR_TEXT("multiset:iterator", ETL_MULTISET_FILE_ID"C"), file_name_, line_number_)
114 {
115 }
116 };
117
118 //***************************************************************************
121 //***************************************************************************
123 {
124 public:
125
126 typedef size_t size_type;
127
128 //*************************************************************************
130 //*************************************************************************
132 {
133 return current_size;
134 }
135
136 //*************************************************************************
138 //*************************************************************************
140 {
141 return CAPACITY;
142 }
143
144 //*************************************************************************
146 //*************************************************************************
147 bool empty() const
148 {
149 return current_size == 0;
150 }
151
152 //*************************************************************************
154 //*************************************************************************
155 bool full() const
156 {
157 return current_size == CAPACITY;
158 }
159
160 //*************************************************************************
163 //*************************************************************************
165 {
166 return CAPACITY;
167 }
168
169 //*************************************************************************
172 //*************************************************************************
173 size_t available() const
174 {
175 return max_size() - size();
176 }
177
178 protected:
179
180 enum
181 {
182 kLeft,
183 kRight,
184 kNeither
185 };
186
187 //*************************************************************************
189 //*************************************************************************
190 struct Node
191 {
192 //***********************************************************************
194 //***********************************************************************
196 parent(ETL_NULLPTR),
197 weight(kNeither),
198 dir(kNeither)
199 {
200 children[0] = ETL_NULLPTR;
201 children[1] = ETL_NULLPTR;
202 }
203
204 //***********************************************************************
206 //***********************************************************************
208 {
209 weight = kNeither;
210 dir = kNeither;
211 parent = ETL_NULLPTR;
212 children[0] = ETL_NULLPTR;
213 children[1] = ETL_NULLPTR;
214 }
215
216 Node* parent;
217 Node* children[2];
218 uint_least8_t weight;
219 uint_least8_t dir;
220 };
221
222 //*************************************************************************
224 //*************************************************************************
226 : current_size(0)
227 , CAPACITY(max_size_)
228 , root_node(ETL_NULLPTR)
229 {
230 }
231
232 //*************************************************************************
234 //*************************************************************************
236 {
237 }
238
239 //*************************************************************************
241 //*************************************************************************
242 void attach_node(Node* parent, Node*& position, Node& node)
243 {
244 // Mark new node as leaf on attach to tree at position provided
245 node.mark_as_leaf();
246
247 // Keep track of this node's parent
248 node.parent = parent;
249
250 // Add the node here
251 position = &node;
252
253 // One more.
254 ++current_size;
255 }
256
257 //*************************************************************************
259 //*************************************************************************
260 void detach_node(Node*& position, Node*& replacement)
261 {
262 // Make temporary copy of actual nodes involved because we might lose
263 // their references in the process (e.g. position is the same as
264 // replacement or replacement is a child of position)
265 Node* detached = position;
266 Node* swap = replacement;
267
268 // Update current position to point to swap (replacement) node first
269 position = swap;
270
271 // Update replacement node to point to child in opposite direction
272 // otherwise we might lose the other child of the swap node
273 replacement = swap->children[1 - swap->dir];
274
275 if (replacement != ETL_NULLPTR)
276 {
277 replacement->parent = swap->parent;
278 }
279
280 // Point swap node to detached node's parent, children and weight
281 swap->parent = detached->parent;
282 swap->children[kLeft] = detached->children[kLeft];
283 swap->children[kRight] = detached->children[kRight];
284 if (swap->children[kLeft])
285 {
286 swap->children[kLeft]->parent = swap;
287 }
288 if (swap->children[kRight])
289 {
290 swap->children[kRight]->parent = swap;
291 }
292 swap->weight = detached->weight;
293 }
294
295 //*************************************************************************
297 //*************************************************************************
298 void balance_node(Node*& critical_node)
299 {
300 // Step 1: Update weights for all children of the critical node up to the
301 // newly inserted node. This step is costly (in terms of traversing nodes
302 // multiple times during insertion) but doesn't require as much recursion
303 Node* weight_node = critical_node->children[critical_node->dir];
304 while (weight_node)
305 {
306 // Keep going until we reach a terminal node (dir == kNeither)
307 if (kNeither != weight_node->dir)
308 {
309 // Does this insert balance the previous weight factor value?
310 if (weight_node->weight == 1 - weight_node->dir)
311 {
312 weight_node->weight = kNeither;
313 }
314 else
315 {
316 weight_node->weight = weight_node->dir;
317 }
318
319 // Update weight factor node to point to next node
320 weight_node = weight_node->children[weight_node->dir];
321 }
322 else
323 {
324 // Stop loop, terminal node found
325 break;
326 }
327 } // while(weight_node)
328
329 // Step 2: Update weight for critical_node or rotate tree to balance node
330 if (kNeither == critical_node->weight)
331 {
332 critical_node->weight = critical_node->dir;
333 }
334 // If direction is different than weight, then it will now be balanced
335 else if (critical_node->dir != critical_node->weight)
336 {
337 critical_node->weight = kNeither;
338 }
339 // Rotate is required to balance the tree at the critical node
340 else
341 {
342 // If critical node matches child node direction then perform a two
343 // node rotate in the direction of the critical node
344 if (critical_node->children[critical_node->dir] != ETL_NULLPTR) ETL_UNLIKELY
345 {
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 if (critical_node->children[critical_node->dir]->children[1 - critical_node->dir] != ETL_NULLPTR) ETL_UNLIKELY
355 {
356 rotate_3node(critical_node, critical_node->dir,
357 critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
358 }
359 }
360 }
361 }
362 }
363
364 //*************************************************************************
367 //*************************************************************************
368 Node* find_limit_node(Node* position, const int8_t dir) const
369 {
370 // Something at this position and in the direction specified? keep going
371 Node* limit_node = position;
372 while (limit_node && limit_node->children[dir])
373 {
374 limit_node = limit_node->children[dir];
375 }
376
377 // Return the limit node position found
378 return limit_node;
379 }
380
381 //*************************************************************************
383 //*************************************************************************
384 void next_node(Node*& position) const
385 {
386 if (position)
387 {
388 // Is there a tree on the right? then find the minimum of that tree
389 if (position->children[kRight])
390 {
391 // Return minimum node found
392 position = find_limit_node(position->children[kRight], kLeft);
393 }
394 // Otherwise find the parent of this node
395 else
396 {
397 // Start with current position as parent
398 Node* parent = position;
399 do {
400 // Update current position as previous parent
401 position = parent;
402 // Find parent of current position
403 parent = position->parent; // find_parent_node(root_node, position);
404 // Repeat while previous position was on right side of parent tree
405 } while (parent && parent->children[kRight] == position);
406
407 // Set parent node as the next position
408 position = parent;
409 }
410 }
411 }
412
413 //*************************************************************************
415 //*************************************************************************
416 void next_node(const Node*& position) const
417 {
418 if (position)
419 {
420 // Is there a tree on the right? then find the minimum of that tree
421 if (position->children[kRight])
422 {
423 // Return minimum node found
424 position = find_limit_node(position->children[kRight], kLeft);
425 }
426 // Otherwise find the parent of this node
427 else
428 {
429 // Start with current position as parent
430 const Node* parent = position;
431 do {
432 // Update current position as previous parent
433 position = parent;
434 // Find parent of current position
435 parent = position->parent;
436 // Repeat while previous position was on right side of parent tree
437 } while (parent && parent->children[kRight] == position);
438
439 // Set parent node as the next position
440 position = parent;
441 }
442 }
443 }
444
445 //*************************************************************************
447 //*************************************************************************
448 void prev_node(Node*& position) const
449 {
450 // If starting at the terminal end, the previous node is the maximum node
451 // from the root
452 if (!position)
453 {
454 position = find_limit_node(root_node, kRight);
455 }
456 else
457 {
458 // Is there a tree on the left? then find the maximum of that tree
459 if (position->children[kLeft])
460 {
461 // Return maximum node found
462 position = find_limit_node(position->children[kLeft], kRight);
463 }
464 // Otherwise find the parent of this node
465 else
466 {
467 // Start with current position as parent
468 Node* parent = position;
469 do {
470 // Update current position as previous parent
471 position = parent;
472 // Find parent of current position
473 parent = position->parent;
474 // Repeat while previous position was on left side of parent tree
475 } while (parent && parent->children[kLeft] == position);
476
477 // Set parent node as the next position
478 position = parent;
479 }
480 }
481 }
482
483 //*************************************************************************
485 //*************************************************************************
486 void prev_node(const Node*& position) const
487 {
488 // If starting at the terminal end, the previous node is the maximum node
489 // from the root
490 if (!position)
491 {
492 position = find_limit_node(root_node, kRight);
493 }
494 else
495 {
496 // Is there a tree on the left? then find the maximum of that tree
497 if (position->children[kLeft])
498 {
499 // Return maximum node found
500 position = find_limit_node(position->children[kLeft], kRight);
501 }
502 // Otherwise find the parent of this node
503 else
504 {
505 // Start with current position as parent
506 const Node* parent = position;
507 do {
508 // Update current position as previous parent
509 position = parent;
510 // Find parent of current position
511 parent = position->parent;
512 // Repeat while previous position was on left side of parent tree
513 } while (parent && parent->children[kLeft] == position);
514
515 // Set parent node as the next position
516 position = parent;
517 }
518 }
519 }
520
521 //*************************************************************************
523 //*************************************************************************
524 void rotate_2node(Node*& position, uint_least8_t dir)
525 {
526 // A C A B
527 // B C -> A E OR B C -> D A
528 // D E B D D E E C
529 // C (new position) becomes the root
530 // A (position) takes ownership of D as its children[kRight] child
531 // C (new position) takes ownership of A as its left child
532 // OR
533 // B (new position) becomes the root
534 // A (position) takes ownership of E as its left child
535 // B (new position) takes ownership of A as its right child
536
537 // Capture new root (either B or C depending on dir) and its parent
538 Node* new_root = position->children[dir];
539
540 // Replace position's previous child with new root's other child
541 position->children[dir] = new_root->children[1 - dir];
542 // Update new root's other child parent pointer
543 if (position->children[dir])
544 {
545 position->children[dir]->parent = position;
546 }
547
548 // New root's parent becomes current position's parent
549 new_root->parent = position->parent;
550 new_root->children[1 - dir] = position;
551 new_root->dir = 1 - dir;
552
553 // Clear weight factor from current position
554 position->weight = kNeither;
555 // Position's parent becomes new_root
556 position->parent = new_root;
557 position = new_root;
558 // Clear weight factor from new root
559 position->weight = kNeither;
560 }
561
562 //*************************************************************************
564 //*************************************************************************
565 void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
566 {
567 // --A-- --E-- --A-- --D--
568 // _B_ C -> B A OR B _C_ -> A C
569 // D E D F G C D E B F G E
570 // F G F G
571 // E (new position) becomes the root
572 // B (position) takes ownership of F as its left child
573 // A takes ownership of G as its right child
574 // OR
575 // D (new position) becomes the root
576 // A (position) takes ownership of F as its right child
577 // C takes ownership of G as its left child
578
579 // Capture new root (either E or D depending on dir)
580 Node* new_root = position->children[dir]->children[1 - dir];
581 // Set weight factor for B or C based on F or G existing and being a different than dir
582 position->children[dir]->weight = third != kNeither && third != dir ? dir : uint_least8_t(kNeither);
583
584 // Detach new root from its tree (replace with new roots child)
585 position->children[dir]->children[1 - dir] = new_root->children[dir];
586 // Update new roots child parent pointer
587 if (new_root->children[dir])
588 {
589 new_root->children[dir]->parent = position->children[dir];
590 }
591
592 // Attach current left tree to new root and update its parent
593 new_root->children[dir] = position->children[dir];
594 position->children[dir]->parent = new_root;
595
596 // Set weight factor for A based on F or G
597 position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
598
599 // Move new root's right tree to current roots left tree
600 position->children[dir] = new_root->children[1 - dir];
601 if (new_root->children[1 - dir])
602 {
603 new_root->children[1 - dir]->parent = position;
604 }
605
606 // Attach current root to new roots right tree and assume its parent
607 new_root->parent = position->parent;
608 new_root->children[1 - dir] = position;
609 new_root->dir = 1 - dir;
610
611 // Update current position's parent and replace with new root
612 position->parent = new_root;
613 position = new_root;
614 // Clear weight factor for new current position
615 position->weight = kNeither;
616 }
617
621 ETL_DECLARE_DEBUG_COUNT;
622 };
623
624 //***************************************************************************
627 //***************************************************************************
628 template <typename TKey, typename TCompare = ETL_OR_STD::less<TKey> >
630 {
631 public:
632
633 typedef TKey key_type;
634 typedef TKey value_type;
635 typedef TCompare key_compare;
636 typedef TCompare value_compare;
637 typedef value_type& reference;
638 typedef const value_type& const_reference;
639#if ETL_USING_CPP11
640 typedef value_type&& rvalue_reference;
641#endif
642 typedef value_type* pointer;
643 typedef const value_type* const_pointer;
644 typedef size_t size_type;
645
646 protected:
647
648 //*************************************************************************
650 //*************************************************************************
651 struct Data_Node : public Node
652 {
653 explicit Data_Node(value_type value_)
654 : value(value_)
655 {
656 }
657
658 value_type value;
659 };
660
662 typedef const TKey& key_parameter_t;
663
664 //*************************************************************************
666 //*************************************************************************
667 bool node_comp(const Data_Node& node1, const Data_Node& node2) const
668 {
669 return compare(node1.value, node2.value);
670 }
671
672 bool node_comp(const Data_Node& node, key_parameter_t key) const
673 {
674 return compare(node.value, key);
675 }
676
677 bool node_comp(key_parameter_t key, const Data_Node& node) const
678 {
679 return compare(key, node.value);
680 }
681
682#if ETL_USING_CPP11
683 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
684 bool node_comp(const Data_Node& node, const K& key) const
685 {
686 return compare(node.value, key);
687 }
688
689 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
690 bool node_comp(const K& key, const Data_Node& node) const
691 {
692 return compare(key, node.value);
693 }
694#endif
695
696 private:
697
699 ipool* p_node_pool;
700
701 key_compare compare;
702
703 //*************************************************************************
705 //*************************************************************************
706 static Data_Node* data_cast(Node* p_node)
707 {
708 return static_cast<Data_Node*>(p_node);
709 }
710
711 //*************************************************************************
713 //*************************************************************************
714 static Data_Node& data_cast(Node& node)
715 {
716 return static_cast<Data_Node&>(node);
717 }
718
719 //*************************************************************************
721 //*************************************************************************
722 static const Data_Node* data_cast(const Node* p_node)
723 {
724 return static_cast<const Data_Node*>(p_node);
725 }
726
727 //*************************************************************************
729 //*************************************************************************
730 static const Data_Node& data_cast(const Node& node)
731 {
732 return static_cast<const Data_Node&>(node);
733 }
734
735 public:
736 //*************************************************************************
738 //*************************************************************************
739 class iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, value_type>
740 {
741 public:
742
743 friend class imultiset;
744 friend class const_iterator;
745
746 iterator()
747 : p_multiset(ETL_NULLPTR)
748 , p_node(ETL_NULLPTR)
749 {
750 }
751
752 iterator(imultiset& multiset)
753 : p_multiset(&multiset)
754 , p_node(ETL_NULLPTR)
755 {
756 }
757
758 iterator(imultiset& multiset, Node* node)
759 : p_multiset(&multiset)
760 , p_node(node)
761 {
762 }
763
764 iterator(const iterator& other)
765 : p_multiset(other.p_multiset)
766 , p_node(other.p_node)
767 {
768 }
769
770 ~iterator()
771 {
772 }
773
774 iterator& operator ++()
775 {
776 p_multiset->next_node(p_node);
777 return *this;
778 }
779
780 iterator operator ++(int)
781 {
782 iterator temp(*this);
783 p_multiset->next_node(p_node);
784 return temp;
785 }
786
787 iterator& operator --()
788 {
789 p_multiset->prev_node(p_node);
790 return *this;
791 }
792
793 iterator operator --(int)
794 {
795 iterator temp(*this);
796 p_multiset->prev_node(p_node);
797 return temp;
798 }
799
800 iterator& operator =(const iterator& other)
801 {
802 p_multiset = other.p_multiset;
803 p_node = other.p_node;
804 return *this;
805 }
806
807 reference operator *() const
808 {
809 return imultiset::data_cast(p_node)->value;
810 }
811
812 pointer operator &() const
813 {
814 return &(imultiset::data_cast(p_node)->value);
815 }
816
817 pointer operator ->() const
818 {
819 return &(imultiset::data_cast(p_node)->value);
820 }
821
822 friend bool operator == (const iterator& lhs, const iterator& rhs)
823 {
824 return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node;
825 }
826
827 friend bool operator != (const iterator& lhs, const iterator& rhs)
828 {
829 return !(lhs == rhs);
830 }
831
832 private:
833
834 // Pointer to multiset associated with this iterator
835 imultiset* p_multiset;
836
837 // Pointer to the current node for this iterator
838 Node* p_node;
839 };
840
841 friend class iterator;
842
843 //*************************************************************************
845 //*************************************************************************
846 class const_iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, const value_type>
847 {
848 public:
849
850 friend class imultiset;
851
852 const_iterator()
853 : p_multiset(ETL_NULLPTR)
854 , p_node(ETL_NULLPTR)
855 {
856 }
857
858 const_iterator(const imultiset& multiset)
859 : p_multiset(&multiset)
860 , p_node(ETL_NULLPTR)
861 {
862 }
863
864 const_iterator(const imultiset& multiset, const Node* node)
865 : p_multiset(&multiset)
866 , p_node(node)
867 {
868 }
869
870 const_iterator(const typename imultiset::iterator& other)
871 : p_multiset(other.p_multiset)
872 , p_node(other.p_node)
873 {
874 }
875
876 const_iterator(const const_iterator& other)
877 : p_multiset(other.p_multiset)
878 , p_node(other.p_node)
879 {
880 }
881
882 ~const_iterator()
883 {
884 }
885
886 const_iterator& operator ++()
887 {
888 p_multiset->next_node(p_node);
889 return *this;
890 }
891
892 const_iterator operator ++(int)
893 {
894 const_iterator temp(*this);
895 p_multiset->next_node(p_node);
896 return temp;
897 }
898
899 const_iterator& operator --()
900 {
901 p_multiset->prev_node(p_node);
902 return *this;
903 }
904
905 const_iterator operator --(int)
906 {
907 const_iterator temp(*this);
908 p_multiset->prev_node(p_node);
909 return temp;
910 }
911
912 const_iterator& operator =(const const_iterator& other)
913 {
914 p_multiset = other.p_multiset;
915 p_node = other.p_node;
916 return *this;
917 }
918
919 const_reference 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 const_pointer operator ->() const
930 {
931 return &(imultiset::data_cast(p_node)->value);
932 }
933
934 friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
935 {
936 return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node;
937 }
938
939 friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
940 {
941 return !(lhs == rhs);
942 }
943
944 private:
945
946 // Convert to an iterator.
947 imultiset::iterator to_iterator() const
948 {
949 return imultiset::iterator(const_cast<imultiset&>(*p_multiset), const_cast<Node*>(p_node));
950 }
951
952 // Pointer to multiset associated with this iterator
953 const imultiset* p_multiset;
954
955 // Pointer to the current node for this iterator
956 const Node* p_node;
957 };
958
959 friend class const_iterator;
960
961 typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
962
963 typedef ETL_OR_STD::reverse_iterator<iterator> reverse_iterator;
964 typedef ETL_OR_STD::reverse_iterator<const_iterator> const_reverse_iterator;
965
966 //*************************************************************************
968 //*************************************************************************
970 {
971 return iterator(*this, find_limit_node(root_node, kLeft));
972 }
973
974 //*************************************************************************
976 //*************************************************************************
978 {
979 return const_iterator(*this, find_limit_node(root_node, kLeft));
980 }
981
982 //*************************************************************************
984 //*************************************************************************
986 {
987 return iterator(*this);
988 }
989
990 //*************************************************************************
992 //*************************************************************************
994 {
995 return const_iterator(*this);
996 }
997
998 //*************************************************************************
1000 //*************************************************************************
1002 {
1003 return const_iterator(*this, find_limit_node(root_node, kLeft));
1004 }
1005
1006 //*************************************************************************
1008 //*************************************************************************
1010 {
1011 return const_iterator(*this);
1012 }
1013
1014 //*************************************************************************
1016 //*************************************************************************
1017 reverse_iterator rbegin()
1018 {
1019 return reverse_iterator(iterator(*this));
1020 }
1021
1022 //*************************************************************************
1024 //*************************************************************************
1025 const_reverse_iterator rbegin() const
1026 {
1027 return const_reverse_iterator(const_iterator(*this));
1028 }
1029
1030 //*************************************************************************
1032 //*************************************************************************
1033 reverse_iterator rend()
1034 {
1035 return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
1036 }
1037
1038 //*************************************************************************
1040 //*************************************************************************
1041 const_reverse_iterator rend() const
1042 {
1043 return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
1044 }
1045
1046 //*************************************************************************
1048 //*************************************************************************
1049 const_reverse_iterator crbegin() const
1050 {
1051 return const_reverse_iterator(const_iterator(*this));
1052 }
1053
1054 //*************************************************************************
1056 //*************************************************************************
1057 const_reverse_iterator crend() const
1058 {
1059 return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
1060 }
1061
1062 //*********************************************************************
1068 //*********************************************************************
1069 template <typename TIterator>
1070 void assign(TIterator first, TIterator last)
1071 {
1072 initialise();
1073 insert(first, last);
1074 }
1075
1076 //*************************************************************************
1078 //*************************************************************************
1079 void clear()
1080 {
1081 initialise();
1082 }
1083
1084 //*********************************************************************
1088 //*********************************************************************
1089 size_type count(key_parameter_t key) const
1090 {
1091 return count_nodes(key);
1092 }
1093
1094#if ETL_USING_CPP11
1095 //*********************************************************************
1096 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1097 size_type count(const K& key) const
1098 {
1099 return count_nodes(key);
1100 }
1101#endif
1102
1103 //*************************************************************************
1106 //*************************************************************************
1107 ETL_OR_STD::pair<iterator, iterator> equal_range(key_parameter_t key)
1108 {
1109 return ETL_OR_STD::make_pair<iterator, iterator>(iterator(*this, find_lower_node(root_node, key)),
1110 iterator(*this, find_upper_node(root_node, key)));
1111 }
1112
1113#if ETL_USING_CPP11
1114 //*************************************************************************
1115 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1116 ETL_OR_STD::pair<iterator, iterator> equal_range(const K& key)
1117 {
1118 return ETL_OR_STD::make_pair<iterator, iterator>(iterator(*this, find_lower_node(root_node, key)),
1119 iterator(*this, find_upper_node(root_node, key)));
1120 }
1121#endif
1122
1123 //*************************************************************************
1126 //*************************************************************************
1127 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1128 {
1129 return ETL_OR_STD::make_pair<const_iterator, const_iterator>(const_iterator(*this, find_lower_node(root_node, key)),
1130 const_iterator(*this, find_upper_node(root_node, key)));
1131 }
1132
1133#if ETL_USING_CPP11
1134 //*************************************************************************
1135 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1136 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1137 {
1138 return ETL_OR_STD::make_pair<const_iterator, const_iterator>(const_iterator(*this, find_lower_node(root_node, key)),
1139 const_iterator(*this, find_upper_node(root_node, key)));
1140 }
1141#endif
1142
1143 //*************************************************************************
1145 //*************************************************************************
1147 {
1148 // Remove the node by its node specified in iterator position
1149 return erase(const_iterator(position));
1150 }
1151
1152 //*************************************************************************
1154 //*************************************************************************
1156 {
1157 // Cast const away from node to be removed. This is necessary because the
1158 // STL definition of this method requires we provide the next node in the
1159 // sequence as an iterator.
1160 Node* node = const_cast<Node*>(position.p_node);
1161 iterator next(*this, node);
1162 ++next;
1163
1164 // Remove the non-const node provided
1165 remove_node(node);
1166
1167 return next;
1168 }
1169
1170 //*************************************************************************
1171 // Erase the key specified.
1172 //*************************************************************************
1174 {
1175 // Number of nodes removed
1176 size_type d = 0;
1177 const_iterator lower(*this, find_lower_node(root_node, key_value));
1178 const_iterator upper(*this, find_upper_node(root_node, key_value));
1179 while (lower != upper)
1180 {
1181 // Increment count for each node removed
1182 ++d;
1183 // Remove node using the other erase method
1184 lower = erase(lower);
1185 }
1186
1187 // Return the total count erased
1188 return d;
1189 }
1190
1191 //*************************************************************************
1192#if ETL_USING_CPP11
1193 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1194 size_type erase(K&& key_value)
1195 {
1196 // Number of nodes removed
1197 size_type d = 0;
1198 const_iterator lower(*this, find_lower_node(root_node, etl::forward<K>(key_value)));
1199 const_iterator upper(*this, find_upper_node(root_node, etl::forward<K>(key_value)));
1200 while (lower != upper)
1201 {
1202 // Increment count for each node removed
1203 ++d;
1204 // Remove node using the other erase method
1205 lower = erase(lower);
1206 }
1207
1208 // Return the total count erased
1209 return d;
1210 }
1211#endif
1212
1213 //*************************************************************************
1215 //*************************************************************************
1217 {
1218 iterator next;
1219 while (first != last)
1220 {
1221 first = erase(first);
1222 }
1223
1224 return last.to_iterator();
1225 }
1226
1227 //*********************************************************************
1231 //*********************************************************************
1233 {
1234 return iterator(*this, find_node(root_node, key_value));
1235 }
1236
1237#if ETL_USING_CPP11
1238 //*********************************************************************
1239 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1240 iterator find(const K& k)
1241 {
1242 return iterator(*this, find_node(root_node, k));
1243 }
1244#endif
1245
1246 //*********************************************************************
1250 //*********************************************************************
1252 {
1253 return const_iterator(*this, find_node(root_node, key_value));
1254 }
1255
1256#if ETL_USING_CPP11
1257 //*********************************************************************
1258 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1259 const_iterator find(const K& k) const
1260 {
1261 return const_iterator(*this, find_node(root_node, k));
1262 }
1263#endif
1264
1265 //*********************************************************************
1269 //*********************************************************************
1270 iterator insert(const_reference value)
1271 {
1272 // Default to no inserted node
1273 Node* inserted_node = ETL_NULLPTR;
1274
1275 ETL_ASSERT(!full(), ETL_ERROR(multiset_full));
1276
1277 // Get next available free node
1278 Data_Node& node = allocate_data_node(value);
1279
1280 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1281 inserted_node = insert_node(root_node, node);
1282
1283 // Insert node into tree and return iterator to new node location in tree
1284 return iterator(*this, inserted_node);
1285 }
1286
1287#if ETL_USING_CPP11
1288 //*********************************************************************
1292 //*********************************************************************
1293 iterator insert(rvalue_reference value)
1294 {
1295 // Default to no inserted node
1296 Node* inserted_node = ETL_NULLPTR;
1297
1298 ETL_ASSERT(!full(), ETL_ERROR(multiset_full));
1299
1300 // Get next available free node
1301 Data_Node& node = allocate_data_node(etl::move(value));
1302
1303 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1304 inserted_node = insert_node(root_node, node);
1305
1306 // Insert node into tree and return iterator to new node location in tree
1307 return iterator(*this, inserted_node);
1308 }
1309#endif
1310
1311 //*********************************************************************
1316 //*********************************************************************
1317 iterator insert(const_iterator /*position*/, const_reference value)
1318 {
1319 // Ignore position provided and just do a normal insert
1320 return insert(value);
1321 }
1322
1323#if ETL_USING_CPP11
1324 //*********************************************************************
1329 //*********************************************************************
1330 iterator insert(const_iterator /*position*/, rvalue_reference value)
1331 {
1332 // Ignore position provided and just do a normal insert
1333 return insert(etl::move(value));
1334 }
1335#endif
1336
1337 //*********************************************************************
1343 //*********************************************************************
1344 template <class TIterator>
1345 void insert(TIterator first, TIterator last)
1346 {
1347 while (first != last)
1348 {
1349 insert(*first);
1350 ++first;
1351 }
1352 }
1353
1354 //*********************************************************************
1359 //*********************************************************************
1361 {
1362 return iterator(*this, find_lower_node(root_node, key));
1363 }
1364
1365#if ETL_USING_CPP11
1366 //*********************************************************************
1367 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1368 iterator lower_bound(const K& key)
1369 {
1370 return iterator(*this, find_lower_node(root_node, key));
1371 }
1372#endif
1373
1374 //*********************************************************************
1379 //*********************************************************************
1381 {
1382 return const_iterator(*this, find_lower_node(root_node, key));
1383 }
1384
1385#if ETL_USING_CPP11
1386 //*********************************************************************
1387 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1388 const_iterator lower_bound(const K& key) const
1389 {
1390 return const_iterator(*this, find_lower_node(root_node, key));
1391 }
1392#endif
1393
1394 //*********************************************************************
1399 //*********************************************************************
1401 {
1402 return iterator(*this, find_upper_node(root_node, key));
1403 }
1404
1405#if ETL_USING_CPP11
1406 //*********************************************************************
1407 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1408 iterator upper_bound(const K& key)
1409 {
1410 return iterator(*this, find_upper_node(root_node, key));
1411 }
1412#endif
1413
1414 //*********************************************************************
1419 //*********************************************************************
1421 {
1422 return const_iterator(*this, find_upper_node(root_node, key));
1423 }
1424
1425#if ETL_USING_CPP11
1426 //*********************************************************************
1427 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1428 const_iterator upper_bound(const K& key) const
1429 {
1430 return const_iterator(*this, find_upper_node(root_node, key));
1431 }
1432#endif
1433
1434 //*************************************************************************
1436 //*************************************************************************
1438 {
1439 // Skip if doing self assignment
1440 if (this != &rhs)
1441 {
1442 assign(rhs.cbegin(), rhs.cend());
1443 }
1444
1445 return *this;
1446 }
1447
1448#if ETL_USING_CPP11
1449 //*************************************************************************
1451 //*************************************************************************
1453 {
1454 // Skip if doing self assignment
1455 if (this != &rhs)
1456 {
1457 clear();
1458
1459 typename etl::imultiset<TKey, TCompare>::iterator from = rhs.begin();
1460
1461 while (from != rhs.end())
1462 {
1463 typename etl::imultiset<TKey, TCompare>::iterator temp = from;
1464 ++temp;
1465
1466 this->insert(etl::move(*from));
1467 from = temp;
1468 }
1469 }
1470
1471 return *this;
1472 }
1473#endif
1474
1475 //*************************************************************************
1477 //*************************************************************************
1478 key_compare key_comp() const
1479 {
1480 return compare;
1481 };
1482
1483 //*************************************************************************
1485 //*************************************************************************
1486 value_compare value_comp() const
1487 {
1488 return compare;
1489 };
1490
1491 //*************************************************************************
1493 //*************************************************************************
1495 {
1496 return find(key) != end();
1497 }
1498
1499#if ETL_USING_CPP11
1500 //*************************************************************************
1501 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1502 bool contains(const K& k) const
1503 {
1504 return find(k) != end();
1505 }
1506#endif
1507
1508 protected:
1509
1510 //*************************************************************************
1512 //*************************************************************************
1513 imultiset(etl::ipool& node_pool, size_t max_size_)
1514 : etl::multiset_base(max_size_)
1515 , p_node_pool(&node_pool)
1516 {
1517 }
1518
1519 //*************************************************************************
1521 //*************************************************************************
1523 {
1524 const_iterator item = begin();
1525
1526 while (item != end())
1527 {
1528 item = erase(item);
1529 }
1530 }
1531
1532 private:
1533
1534 //*************************************************************************
1536 //*************************************************************************
1537 Data_Node& allocate_data_node(const_reference value)
1538 {
1539 Data_Node* node = allocate_data_node();
1540 ::new ((void*)&node->value) value_type(value);
1541 ETL_INCREMENT_DEBUG_COUNT;
1542 return *node;
1543 }
1544
1545#if ETL_USING_CPP11
1546 //*************************************************************************
1548 //*************************************************************************
1549 Data_Node& allocate_data_node(rvalue_reference value)
1550 {
1551 Data_Node* node = allocate_data_node();
1552 ::new ((void*)&node->value) value_type(etl::move(value));
1553 ETL_INCREMENT_DEBUG_COUNT;
1554 return *node;
1555 }
1556#endif
1557
1558 //*************************************************************************
1560 //*************************************************************************
1561 Data_Node* allocate_data_node()
1562 {
1563 Data_Node* (etl::ipool::*func)() = &etl::ipool::allocate<Data_Node>;
1564 return (p_node_pool->*func)();
1565 }
1566
1567 //*************************************************************************
1569 //*************************************************************************
1570 void destroy_data_node(Data_Node& node)
1571 {
1572 node.value.~value_type();
1573 p_node_pool->release(&node);
1574 ETL_DECREMENT_DEBUG_COUNT;
1575 }
1576
1577 //*************************************************************************
1579 //*************************************************************************
1580 size_type count_nodes(key_parameter_t key) const
1581 {
1582 // Number of nodes that match the key provided result
1583 size_type result = 0;
1584
1585 // Find lower and upper nodes for the key provided
1586 const Node* lower = find_lower_node(root_node, key);
1587 const Node* upper = find_upper_node(root_node, key);
1588
1589 // Loop from lower node to upper node and find nodes that match
1590 while (lower != upper)
1591 {
1592 // Downcast found to Data_Node class for comparison and other operations
1593 const Data_Node& data_node = imultiset::data_cast(*lower);
1594
1595 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1596 {
1597 // This node matches the key provided
1598 ++result;
1599 }
1600
1601 // Move on to the next node
1602 next_node(lower);
1603 }
1604
1605 // Return the number of nodes that match
1606 return result;
1607 }
1608
1609#if ETL_USING_CPP11
1610 //*************************************************************************
1611 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1612 size_type count_nodes(const K& key) const
1613 {
1614 // Number of nodes that match the key provided result
1615 size_type result = 0;
1616
1617 // Find lower and upper nodes for the key provided
1618 const Node* lower = find_lower_node(root_node, key);
1619 const Node* upper = find_upper_node(root_node, key);
1620
1621 // Loop from lower node to upper node and find nodes that match
1622 while (lower != upper)
1623 {
1624 // Downcast found to Data_Node class for comparison and other operations
1625 const Data_Node& data_node = imultiset::data_cast(*lower);
1626
1627 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1628 {
1629 // This node matches the key provided
1630 ++result;
1631 }
1632
1633 // Move on to the next node
1634 next_node(lower);
1635 }
1636
1637 // Return the number of nodes that match
1638 return result;
1639 }
1640#endif
1641
1642 //*************************************************************************
1644 //*************************************************************************
1645 Node* find_node(Node* position, key_parameter_t key)
1646 {
1647 Node* found = ETL_NULLPTR;
1648 while (position)
1649 {
1650 // Downcast found to Data_Node class for comparison and other operations
1651 Data_Node& data_node = imultiset::data_cast(*position);
1652 // Compare the node value to the current position value
1653 if (node_comp(key, data_node))
1654 {
1655 // Keep searching for the node on the left
1656 position = position->children[kLeft];
1657 }
1658 else if (node_comp(data_node, key))
1659 {
1660 // Keep searching for the node on the right
1661 position = position->children[kRight];
1662 }
1663 else
1664 {
1665 // We found one, keep looking for more on the left
1666 found = position;
1667 position = position->children[kLeft];
1668 }
1669 }
1670
1671 // Return the node found (might be ETL_NULLPTR)
1672 return found;
1673 }
1674
1675#if ETL_USING_CPP11
1676 //*************************************************************************
1677 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1678 Node* find_node(Node* position, const K& key)
1679 {
1680 Node* found = ETL_NULLPTR;
1681 while (position)
1682 {
1683 // Downcast found to Data_Node class for comparison and other operations
1684 Data_Node& data_node = imultiset::data_cast(*position);
1685 // Compare the node value to the current position value
1686 if (node_comp(key, data_node))
1687 {
1688 // Keep searching for the node on the left
1689 position = position->children[kLeft];
1690 }
1691 else if (node_comp(data_node, key))
1692 {
1693 // Keep searching for the node on the right
1694 position = position->children[kRight];
1695 }
1696 else
1697 {
1698 // We found one, keep looking for more on the left
1699 found = position;
1700 position = position->children[kLeft];
1701 }
1702 }
1703
1704 // Return the node found (might be ETL_NULLPTR)
1705 return found;
1706 }
1707#endif
1708
1709 //*************************************************************************
1711 //*************************************************************************
1712 const Node* find_node(const Node* position, key_parameter_t key) const
1713 {
1714 const Node* found = ETL_NULLPTR;
1715 while (position)
1716 {
1717 // Downcast found to Data_Node class for comparison and other operations
1718 const Data_Node& data_node = imultiset::data_cast(*position);
1719 // Compare the node value to the current position value
1720 if (node_comp(key, data_node))
1721 {
1722 // Keep searching for the node on the left
1723 position = position->children[kLeft];
1724 }
1725 else if (node_comp(data_node, key))
1726 {
1727 // Keep searching for the node on the right
1728 position = position->children[kRight];
1729 }
1730 else
1731 {
1732 // We found one, keep looking for more on the left
1733 found = position;
1734 position = position->children[kLeft];
1735 }
1736 }
1737
1738 // Return the node found (might be ETL_NULLPTR)
1739 return found;
1740 }
1741
1742#if ETL_USING_CPP11
1743 //*************************************************************************
1744 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1745 const Node* find_node(const Node* position, const K& key) const
1746 {
1747 const Node* found = ETL_NULLPTR;
1748 while (position)
1749 {
1750 // Downcast found to Data_Node class for comparison and other operations
1751 const Data_Node& data_node = imultiset::data_cast(*position);
1752 // Compare the node value to the current position value
1753 if (node_comp(key, data_node))
1754 {
1755 // Keep searching for the node on the left
1756 position = position->children[kLeft];
1757 }
1758 else if (node_comp(data_node, key))
1759 {
1760 // Keep searching for the node on the right
1761 position = position->children[kRight];
1762 }
1763 else
1764 {
1765 // We found one, keep looking for more on the left
1766 found = position;
1767 position = position->children[kLeft];
1768 }
1769 }
1770
1771 // Return the node found (might be ETL_NULLPTR)
1772 return found;
1773 }
1774#endif
1775
1776 //*************************************************************************
1778 //*************************************************************************
1779 Node* find_lower_node(Node* position, key_parameter_t key) const
1780 {
1781 // Something at this position? keep going
1782 Node* lower_node = ETL_NULLPTR;
1783 while (position)
1784 {
1785 // Downcast lower node to Data_Node reference for key comparisons
1786 Data_Node& data_node = imultiset::data_cast(*position);
1787 // Compare the key value to the current lower node key value
1788 if (node_comp(key, data_node))
1789 {
1790 lower_node = position;
1791 if (position->children[kLeft])
1792 {
1793 position = position->children[kLeft];
1794 }
1795 else
1796 {
1797 // Found lowest node
1798 break;
1799 }
1800 }
1801 else if (node_comp(data_node, key))
1802 {
1803 position = position->children[kRight];
1804 }
1805 else
1806 {
1807 // Make note of current position, but keep looking to left for more
1808 lower_node = position;
1809 position = position->children[kLeft];
1810 }
1811 }
1812
1813 // Return the lower_node position found
1814 return lower_node;
1815 }
1816
1817#if ETL_USING_CPP11
1818 //*************************************************************************
1819 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1820 Node* find_lower_node(Node* position, const K& key) const
1821 {
1822 // Something at this position? keep going
1823 Node* lower_node = ETL_NULLPTR;
1824 while (position)
1825 {
1826 // Downcast lower node to Data_Node reference for key comparisons
1827 Data_Node& data_node = imultiset::data_cast(*position);
1828 // Compare the key value to the current lower node key value
1829 if (node_comp(key, data_node))
1830 {
1831 lower_node = position;
1832 if (position->children[kLeft])
1833 {
1834 position = position->children[kLeft];
1835 }
1836 else
1837 {
1838 // Found lowest node
1839 break;
1840 }
1841 }
1842 else if (node_comp(data_node, key))
1843 {
1844 position = position->children[kRight];
1845 }
1846 else
1847 {
1848 // Make note of current position, but keep looking to left for more
1849 lower_node = position;
1850 position = position->children[kLeft];
1851 }
1852 }
1853
1854 // Return the lower_node position found
1855 return lower_node;
1856 }
1857#endif
1858
1859 //*************************************************************************
1861 //*************************************************************************
1862 Node* find_upper_node(Node* position, key_parameter_t key) const
1863 {
1864 // Keep track of parent of last upper node
1865 Node* upper_node = ETL_NULLPTR;
1866 // Has an equal node been found? start with no
1867 bool found = false;
1868 while (position)
1869 {
1870 // Downcast position to Data_Node reference for key comparisons
1871 Data_Node& data_node = imultiset::data_cast(*position);
1872 // Compare the key value to the current upper node key value
1873 if (node_comp(data_node, key))
1874 {
1875 position = position->children[kRight];
1876 }
1877 else if (node_comp(key, data_node))
1878 {
1879 upper_node = position;
1880 // If a node equal to key hasn't been found go left
1881 if (!found && position->children[kLeft])
1882 {
1883 position = position->children[kLeft];
1884 }
1885 else
1886 {
1887 break;
1888 }
1889 }
1890 else
1891 {
1892 // We found an equal item, break on next bigger item
1893 found = true;
1894 next_node(position);
1895 }
1896 }
1897
1898 // Return the upper node position found (might be ETL_NULLPTR)
1899 return upper_node;
1900 }
1901
1902#if ETL_USING_CPP11
1903 //*************************************************************************
1904 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1905 Node* find_upper_node(Node* position, const K& key) const
1906 {
1907 // Keep track of parent of last upper node
1908 Node* upper_node = ETL_NULLPTR;
1909 // Has an equal node been found? start with no
1910 bool found = false;
1911 while (position)
1912 {
1913 // Downcast position to Data_Node reference for key comparisons
1914 Data_Node& data_node = imultiset::data_cast(*position);
1915 // Compare the key value to the current upper node key value
1916 if (node_comp(data_node, key))
1917 {
1918 position = position->children[kRight];
1919 }
1920 else if (node_comp(key, data_node))
1921 {
1922 upper_node = position;
1923 // If a node equal to key hasn't been found go left
1924 if (!found && position->children[kLeft])
1925 {
1926 position = position->children[kLeft];
1927 }
1928 else
1929 {
1930 break;
1931 }
1932 }
1933 else
1934 {
1935 // We found an equal item, break on next bigger item
1936 found = true;
1937 next_node(position);
1938 }
1939 }
1940
1941 // Return the upper node position found (might be ETL_NULLPTR)
1942 return upper_node;
1943 }
1944#endif
1945
1946 //*************************************************************************
1948 //*************************************************************************
1949 Node* insert_node(Node*& position, Data_Node& node)
1950 {
1951 // Find the location where the node belongs
1952 Node* found = position;
1953
1954 // Was position provided not empty? then find where the node belongs
1955 if (position)
1956 {
1957 // Find the critical parent node (default to ETL_NULLPTR)
1958 Node* critical_parent_node = ETL_NULLPTR;
1959 Node* critical_node = root_node;
1960
1961 while (found)
1962 {
1963 // Search for critical weight node (all nodes whose weight factor
1964 // is set to kNeither (balanced)
1965 if (kNeither != found->weight)
1966 {
1967 critical_node = found;
1968 }
1969
1970 // Downcast found to Data_Node class for comparison and other operations
1971 Data_Node& found_data_node = imultiset::data_cast(*found);
1972
1973 // Is the node provided to the left of the current position?
1974 if (node_comp(node, found_data_node))
1975 {
1976 // Update direction taken to insert new node in parent node
1977 found->dir = kLeft;
1978 }
1979 // Is the node provided to the right of the current position?
1980 else if (node_comp(found_data_node, node))
1981 {
1982 // Update direction taken to insert new node in parent node
1983 found->dir = kRight;
1984 }
1985 else
1986 {
1987 // Update direction taken to insert new node in parent (and
1988 // duplicate) node to the right.
1989 found->dir = kRight;
1990 }
1991
1992 // Is there a child of this parent node?
1993 if (found->children[found->dir])
1994 {
1995 // Will this node be the parent of the next critical node whose
1996 // weight factor is set to kNeither (balanced)?
1997 if (kNeither != found->children[found->dir]->weight)
1998 {
1999 critical_parent_node = found;
2000 }
2001
2002 // Keep looking for empty spot to insert new node
2003 found = found->children[found->dir];
2004 }
2005 else
2006 {
2007 // Attach node as a child of the parent node found
2008 attach_node(found, found->children[found->dir], node);
2009
2010 // Return newly added node
2011 found = found->children[found->dir];
2012
2013 // Exit loop
2014 break;
2015 }
2016 }
2017
2018 // Was a critical node found that should be checked for balance?
2019 if (critical_node)
2020 {
2021 if (critical_parent_node == ETL_NULLPTR && critical_node == root_node)
2022 {
2024 }
2025 else if (critical_parent_node == ETL_NULLPTR && critical_node == position)
2026 {
2027 balance_node(position);
2028 }
2029 else
2030 {
2031 if (critical_parent_node != ETL_NULLPTR)
2032 {
2033 balance_node(critical_parent_node->children[critical_parent_node->dir]);
2034 }
2035 }
2036 }
2037 }
2038 else
2039 {
2040 // Attach node to current position (which is assumed to be root)
2041 attach_node(ETL_NULLPTR, position, node);
2042
2043 // Return newly added node at current position
2044 found = position;
2045 }
2046
2047 // Return the node found (might be ETL_NULLPTR)
2048 return found;
2049 }
2050
2051 //*************************************************************************
2054 //*************************************************************************
2055 void remove_node(Node* node)
2056 {
2057 // If valid found node was provided then proceed with steps 1 through 5
2058 if (node)
2059 {
2060 // Downcast found node provided to Data_Node class
2061 Data_Node& data_node = imultiset::data_cast(*node);
2062
2063 // Keep track of node as found node
2064 Node* found = node;
2065
2066 // Step 1: Mark path from node provided back to the root node using the
2067 // internal temporary dir member value and using the parent pointer. This
2068 // will allow us to avoid recursion in finding the node in a tree that
2069 //might contain duplicate keys to be found.
2070 while (node)
2071 {
2072 if (node->parent)
2073 {
2074 // Which direction does parent use to get to this node?
2075 node->parent->dir =
2076 node->parent->children[kLeft] == node ? kLeft : kRight;
2077
2078 // Make this nodes parent the next node
2079 node = node->parent;
2080 }
2081 else
2082 {
2083 // Root node found - break loop
2084 break;
2085 }
2086 }
2087
2088 // Step 2: Follow the path provided above until we reach the node
2089 // provided and look for the balance node to start rebalancing the tree
2090 // from (up to the replacement node that will be found in step 3)
2091 Node* balance = root_node;
2092 while (node)
2093 {
2094 // Did we reach the node provided originally (found) then go to step 3
2095 if (node == found)
2096 {
2097 // Update the direction towards a replacement node at the found node
2098 node->dir = node->children[kLeft] ? kLeft : kRight;
2099
2100 // Exit loop and proceed with step 3
2101 break;
2102 }
2103 else
2104 {
2105 // If this nodes weight is kNeither or we are taking the shorter path
2106 // to the next node and our sibling (on longer path) is balanced then
2107 // we need to update the balance node to this node but all our
2108 // ancestors will not require rebalancing
2109 if ((node->weight == kNeither) ||
2110 (node->weight == (1 - node->dir) &&
2111 node->children[1 - node->dir]->weight == kNeither))
2112 {
2113 // Update balance node to this node
2114 balance = node;
2115 }
2116
2117 // Keep searching for found in the direction provided in step 1
2118 node = node->children[node->dir];
2119 }
2120 }
2121 // The value for node should not be ETL_NULLPTR at this point otherwise
2122 // step 1 failed to provide the correct path to found. Step 5 will fail
2123 // (probably subtly) if node should be ETL_NULLPTR at this point
2124
2125 // Step 3: Find the node (node should be equal to found at this point)
2126 // to replace found with (might end up equal to found) while also
2127 // continuing to update balance the same as in step 2 above.
2128 while (node)
2129 {
2130 // Replacement node found if its missing a child in the replace->dir
2131 // value set at the end of step 2 above
2132 if (node->children[node->dir] == ETL_NULLPTR)
2133 {
2134 // Exit loop once node to replace found is determined
2135 break;
2136 }
2137
2138 // If this nodes weight is kNeither or we are taking the shorter path
2139 // to the next node and our sibling (on longer path) is balanced then
2140 // we need to update the balance node to this node but all our
2141 // ancestors will not require rebalancing
2142 if ((node->weight == kNeither) ||
2143 (node->weight == (1 - node->dir) &&
2144 node->children[1 - node->dir]->weight == kNeither))
2145 {
2146 // Update balance node to this node
2147 balance = node;
2148 }
2149
2150 // Keep searching for replacement node in the direction specified above
2151 node = node->children[node->dir];
2152
2153 // Downcast node to Data_Node class for comparison operations
2154 Data_Node& replace_data_node = imultiset::data_cast(*node);
2155
2156 // Compare the key provided to the replace data node key
2157 if (node_comp(data_node, replace_data_node))
2158 {
2159 // Update the direction to the replace node
2160 node->dir = kLeft;
2161 }
2162 else if (node_comp(replace_data_node, data_node))
2163 {
2164 // Update the direction to the replace node
2165 node->dir = kRight;
2166 }
2167 else
2168 {
2169 // Update the direction to the replace node
2170 node->dir = node->children[kLeft] ? kLeft : kRight;
2171 }
2172 } // while(node)
2173
2174 // Step 4: Update weights from balance to parent of node determined
2175 // in step 3 above rotating (2 or 3 node rotations) as needed.
2176 while (balance)
2177 {
2178 // Break when balance node reaches the parent of replacement node
2179 if (balance->children[balance->dir] == ETL_NULLPTR)
2180 {
2181 break;
2182 }
2183
2184 // If balance node is balanced already (kNeither) then just imbalance
2185 // the node in the opposite direction of the node being removed
2186 if (balance->weight == kNeither)
2187 {
2188 balance->weight = 1 - balance->dir;
2189 }
2190 // If balance node is imbalanced in the opposite direction of the
2191 // node being removed then the node now becomes balanced
2192 else if (balance->weight == balance->dir)
2193 {
2194 balance->weight = kNeither;
2195 }
2196 // Otherwise a rotation is required at this node
2197 else
2198 {
2199 int weight = balance->children[1 - balance->dir]->weight;
2200 // Perform a 3 node rotation if weight is same as balance->dir
2201 if (weight == balance->dir)
2202 {
2203 // Is the root node being rebalanced (no parent)
2204 if (balance->parent == ETL_NULLPTR)
2205 {
2206 rotate_3node(root_node, 1 - balance->dir,
2207 balance->children[1 - balance->dir]->children[balance->dir]->weight);
2208 }
2209 else
2210 {
2211 rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
2212 balance->children[1 - balance->dir]->children[balance->dir]->weight);
2213 }
2214 }
2215 // Already balanced, rebalance and make it heavy in opposite
2216 // direction of the node being removed
2217 else if (weight == kNeither)
2218 {
2219 // Is the root node being rebalanced (no parent)
2220 if (balance->parent == ETL_NULLPTR)
2221 {
2222 rotate_2node(root_node, 1 - balance->dir);
2223 root_node->weight = balance->dir;
2224 }
2225 else
2226 {
2227 // Balance parent might change during rotate, keep local copy
2228 // to old parent so its weight can be updated after the 2 node
2229 // rotate is completed
2230 Node* old_parent = balance->parent;
2231 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2232 old_parent->children[old_parent->dir]->weight = balance->dir;
2233 }
2234 // Update balance node weight in opposite direction of node removed
2235 balance->weight = 1 - balance->dir;
2236 }
2237 // Rebalance and leave it balanced
2238 else
2239 {
2240 // Is the root node being rebalanced (no parent)
2241 if (balance->parent == ETL_NULLPTR)
2242 {
2243 rotate_2node(root_node, 1 - balance->dir);
2244 }
2245 else
2246 {
2247 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2248 }
2249 }
2250 }
2251
2252 // Next balance node to consider
2253 balance = balance->children[balance->dir];
2254 } // while(balance)
2255
2256 // Step 5: Swap found with node (replacement)
2257 if (found->parent)
2258 {
2259 // Handle traditional case
2260 detach_node(found->parent->children[found->parent->dir],
2261 node->parent->children[node->parent->dir]);
2262 }
2263 // Handle root node removal
2264 else
2265 {
2266 // Valid replacement node for root node being removed?
2267 if (node->parent)
2268 {
2269 detach_node(root_node, node->parent->children[node->parent->dir]);
2270 }
2271 else
2272 {
2273 // Found node and replacement node are both root node
2275 }
2276 }
2277
2278 // One less.
2279 --current_size;
2280
2281 // Destroy the node detached above
2282 destroy_data_node(data_node);
2283 } // if(found)
2284 }
2285
2286 // Disable copy construction.
2287 imultiset(const imultiset&);
2288
2289 //*************************************************************************
2291 //*************************************************************************
2292#if defined(ETL_POLYMORPHIC_MULTISET) || defined(ETL_POLYMORPHIC_CONTAINERS)
2293 public:
2294 virtual ~imultiset()
2295 {
2296 }
2297#else
2298 protected:
2300 {
2301 }
2302#endif
2303 };
2304
2305 //*************************************************************************
2307 //*************************************************************************
2308 template <typename TKey, const size_t MAX_SIZE_, typename TCompare = ETL_OR_STD::less<TKey> >
2309 class multiset : public etl::imultiset<TKey, TCompare>
2310 {
2311 public:
2312
2313 static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_;
2314
2315 //*************************************************************************
2317 //*************************************************************************
2319 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2320 {
2321 this->initialise();
2322 }
2323
2324 //*************************************************************************
2326 //*************************************************************************
2327 multiset(const multiset& other)
2328 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2329 {
2330 this->assign(other.cbegin(), other.cend());
2331 }
2332
2333#if ETL_USING_CPP11
2334 //*************************************************************************
2336 //*************************************************************************
2337 multiset(multiset&& other)
2338 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2339 {
2340 if (this != &other)
2341 {
2342 typename etl::imultiset<TKey, TCompare>::iterator from = other.begin();
2343
2344 while (from != other.end())
2345 {
2346 typename etl::imultiset<TKey, TCompare>::iterator temp = from;
2347 ++temp;
2348
2349 this->insert(etl::move(*from));
2350 from = temp;
2351 }
2352 }
2353 }
2354#endif
2355
2356 //*************************************************************************
2361 //*************************************************************************
2362 template <typename TIterator>
2363 multiset(TIterator first, TIterator last)
2364 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2365 {
2366 this->assign(first, last);
2367 }
2368
2369#if ETL_HAS_INITIALIZER_LIST
2370 //*************************************************************************
2372 //*************************************************************************
2373 multiset(std::initializer_list<typename etl::imultiset<TKey, TCompare>::value_type> init)
2374 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2375 {
2376 this->assign(init.begin(), init.end());
2377 }
2378#endif
2379
2380 //*************************************************************************
2382 //*************************************************************************
2384 {
2385 this->initialise();
2386 }
2387
2388 //*************************************************************************
2390 //*************************************************************************
2392 {
2393 // Skip if doing self assignment
2394 if (this != &rhs)
2395 {
2396 this->assign(rhs.cbegin(), rhs.cend());
2397 }
2398
2399 return *this;
2400 }
2401
2402#if ETL_USING_CPP11
2403 //*************************************************************************
2405 //*************************************************************************
2407 {
2408 if (this != &rhs)
2409 {
2410 this->clear();
2411
2412 typename etl::imultiset<TKey, TCompare>::iterator from = rhs.begin();
2413
2414 while (from != rhs.end())
2415 {
2416 this->insert(etl::move(*from));
2417 ++from;
2418 }
2419 }
2420
2421 return *this;
2422 }
2423#endif
2424
2425 private:
2426
2428 etl::pool<typename etl::imultiset<TKey, TCompare>::Data_Node, MAX_SIZE> node_pool;
2429 };
2430
2431 template <typename TKey, const size_t MAX_SIZE_, typename TCompare>
2432 ETL_CONSTANT size_t multiset<TKey, MAX_SIZE_, TCompare>::MAX_SIZE;
2433
2434 //*************************************************************************
2436 //*************************************************************************
2437#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
2438 template <typename... T>
2439 multiset(T...) -> multiset<etl::nth_type_t<0, T...>, sizeof...(T)>;
2440#endif
2441
2442 //*************************************************************************
2444 //*************************************************************************
2445#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
2446 template <typename TKey, typename TKeyCompare = etl::less<TKey>, typename... T>
2447 constexpr auto make_multiset(T&&... keys) -> etl::multiset<TKey, sizeof...(T), TKeyCompare>
2448 {
2449 return { etl::forward<T>(keys)... };
2450 }
2451#endif
2452
2453 //***************************************************************************
2459 //***************************************************************************
2460 template <typename TKey, typename TCompare>
2462 {
2463 return (lhs.size() == rhs.size()) && ETL_OR_STD::equal(lhs.begin(), lhs.end(), rhs.begin());
2464 }
2465
2466 //***************************************************************************
2472 //***************************************************************************
2473 template <typename TKey, typename TCompare>
2475 {
2476 return !(lhs == rhs);
2477 }
2478
2479 //*************************************************************************
2485 //*************************************************************************
2486 template <typename TKey, typename TCompare>
2488 {
2489 return ETL_OR_STD::lexicographical_compare(lhs.begin(), lhs.end(),
2490 rhs.begin(), rhs.end(),
2491 etl::imultiset<TKey, TCompare>::value_compare());
2492 }
2493
2494 //*************************************************************************
2500 //*************************************************************************
2501 template <typename TKey, typename TCompare>
2503 {
2504 return (rhs < lhs);
2505 }
2506
2507 //*************************************************************************
2513 //*************************************************************************
2514 template <typename TKey, typename TCompare>
2516 {
2517 return !(lhs > rhs);
2518 }
2519
2520 //*************************************************************************
2526 //*************************************************************************
2527 template <typename TKey, typename TCompare>
2529 {
2530 return !(lhs < rhs);
2531 }
2532}
2533
2534#include "private/minmax_pop.h"
2535
2536#endif
const_iterator
Definition multiset.h:847
iterator.
Definition multiset.h:740
A templated multiset implementation that uses a fixed size buffer.
Definition multiset.h:2310
multiset(const multiset &other)
Copy constructor.
Definition multiset.h:2327
multiset()
Default constructor.
Definition multiset.h:2318
~multiset()
Destructor.
Definition multiset.h:2383
multiset & operator=(const multiset &rhs)
Assignment operator.
Definition multiset.h:2391
multiset(TIterator first, TIterator last)
Definition multiset.h:2363
ETL_CONSTEXPR14 bool operator==(const etl::expected< TValue, TError > &lhs, const etl::expected< TValue2, TError2 > &rhs)
Equivalence operators.
Definition expected.h:962
#define ETL_ASSERT(b, e)
Definition error_handler.h:356
Definition exception.h:47
T * allocate()
Definition ipool.h:316
Definition ipool.h:103
iterator begin()
Gets the beginning of the multiset.
Definition multiset.h:969
iterator lower_bound(key_parameter_t key)
Definition multiset.h:1360
bool full() const
Checks to see if the set is full.
Definition multiset.h:155
void next_node(const Node *&position) const
Find the next node in sequence from the node provided.
Definition multiset.h:416
reverse_iterator rbegin()
Gets the reverse beginning of the list.
Definition multiset.h:1017
iterator insert(const_reference value)
Definition multiset.h:1270
void clear()
Clears the multiset.
Definition multiset.h:1079
const_iterator upper_bound(key_parameter_t key) const
Definition multiset.h:1420
size_type count(key_parameter_t key) const
Definition multiset.h:1089
imultiset & operator=(const imultiset &rhs)
Assignment operator.
Definition multiset.h:1437
bool contains(key_parameter_t key) const
Check if the set contains the key.
Definition multiset.h:1494
bool node_comp(const Data_Node &node1, const Data_Node &node2) const
How to compare node elements.
Definition multiset.h:667
const size_type CAPACITY
The maximum size of the set.
Definition multiset.h:619
size_t size_type
The type used for determining the size of set.
Definition multiset.h:126
const TKey & key_parameter_t
Defines the key value parameter type.
Definition multiset.h:662
void rotate_2node(Node *&position, uint_least8_t dir)
Rotate two nodes at the position provided the to balance the tree.
Definition multiset.h:524
const_reverse_iterator crbegin() const
Gets the reverse beginning of the list.
Definition multiset.h:1049
Node * find_limit_node(Node *position, const int8_t dir) const
Definition multiset.h:368
iterator erase(const_iterator first, const_iterator last)
Erases a range of elements.
Definition multiset.h:1216
iterator end()
Gets the end of the multiset.
Definition multiset.h:985
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(key_parameter_t key) const
Definition multiset.h:1127
const_iterator lower_bound(key_parameter_t key) const
Definition multiset.h:1380
size_type size() const
Gets the size of the set.
Definition multiset.h:131
void balance_node(Node *&critical_node)
Balance the critical node at the position provided as needed.
Definition multiset.h:298
const_iterator end() const
Gets the end of the multiset.
Definition multiset.h:993
const_iterator cend() const
Gets the end of the multiset.
Definition multiset.h:1009
const_iterator cbegin() const
Gets the beginning of the multiset.
Definition multiset.h:1001
iterator find(key_parameter_t key_value)
Definition multiset.h:1232
void next_node(Node *&position) const
Find the next node in sequence from the node provided.
Definition multiset.h:384
void initialise()
Initialise the multiset.
Definition multiset.h:1522
void assign(TIterator first, TIterator last)
Definition multiset.h:1070
const_iterator find(key_parameter_t key_value) const
Definition multiset.h:1251
size_type capacity() const
Definition multiset.h:164
reverse_iterator rend()
Gets the reverse end of the list.
Definition multiset.h:1033
void attach_node(Node *parent, Node *&position, Node &node)
Attach the provided node to the position provided.
Definition multiset.h:242
const_iterator begin() const
Gets the beginning of the multiset.
Definition multiset.h:977
ETL_OR_STD::pair< iterator, iterator > equal_range(key_parameter_t key)
Definition multiset.h:1107
void prev_node(Node *&position) const
Find the previous node in sequence from the node provided.
Definition multiset.h:448
void prev_node(const Node *&position) const
Find the previous node in sequence from the node provided.
Definition multiset.h:486
imultiset(etl::ipool &node_pool, size_t max_size_)
Constructor.
Definition multiset.h:1513
Node * root_node
The node that acts as the multiset root.
Definition multiset.h:620
size_type max_size() const
Gets the maximum possible size of the set.
Definition multiset.h:139
const_reverse_iterator rend() const
Gets the reverse end of the list.
Definition multiset.h:1041
~imultiset()
Destructor.
Definition multiset.h:2299
void insert(TIterator first, TIterator last)
Definition multiset.h:1345
value_compare value_comp() const
How to compare two value elements.
Definition multiset.h:1486
~multiset_base()
Destructor.
Definition multiset.h:235
iterator insert(const_iterator, const_reference value)
Definition multiset.h:1317
multiset_base(size_type max_size_)
The constructor that is called from derived classes.
Definition multiset.h:225
iterator upper_bound(key_parameter_t key)
Definition multiset.h:1400
key_compare key_comp() const
How to compare two key elements.
Definition multiset.h:1478
iterator erase(const_iterator position)
Erases the value at the specified position.
Definition multiset.h:1155
const_reverse_iterator rbegin() const
Gets the reverse beginning of the list.
Definition multiset.h:1025
void detach_node(Node *&position, Node *&replacement)
Detach the node at the position provided.
Definition multiset.h:260
iterator erase(iterator position)
Erases the value at the specified position.
Definition multiset.h:1146
const_reverse_iterator crend() const
Gets the reverse end of the list.
Definition multiset.h:1057
bool empty() const
Checks to see if the set is empty.
Definition multiset.h:147
size_type current_size
The number of the used nodes.
Definition multiset.h:618
size_t available() const
Definition multiset.h:173
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:565
Definition multiset.h:630
Definition multiset.h:123
Definition multiset.h:67
Definition multiset.h:81
bitset_ext
Definition absolute.h:39
ETL_CONSTEXPR14 void swap(etl::typed_storage_ext< T > &lhs, etl::typed_storage_ext< T > &rhs) ETL_NOEXCEPT
Swap two etl::typed_storage_ext.
Definition alignment.h:838
bool operator>(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1190
bool operator>=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1202
bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1151
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1139
bool operator<(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1163
bool operator<=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1178
Definition compare.h:51
The data node element in the multiset.
Definition multiset.h:652
iterator
Definition iterator.h:399
The node element in the multiset.
Definition multiset.h:191
void mark_as_leaf()
Marks the node as a leaf.
Definition multiset.h:207
Node()
Constructor.
Definition multiset.h:195