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 "debug_count.h"
37#include "error_handler.h"
38#include "exception.h"
39#include "functional.h"
40#include "initializer_list.h"
41#include "iterator.h"
42#include "nth_type.h"
43#include "nullptr.h"
44#include "parameter_type.h"
45#include "placement_new.h"
46#include "pool.h"
47#include "type_traits.h"
48#include "utility.h"
49
50#include <stddef.h>
51
53#include "private/minmax_push.h"
54
55//*****************************************************************************
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 //*************************************************************************
239 //*************************************************************************
240 void attach_node(Node* parent, Node*& position, Node& node)
241 {
242 // Mark new node as leaf on attach to tree at position provided
243 node.mark_as_leaf();
244
245 // Keep track of this node's parent
246 node.parent = parent;
247
248 // Add the node here
249 position = &node;
250
251 // One more.
252 ++current_size;
253 }
254
255 //*************************************************************************
257 //*************************************************************************
258 void detach_node(Node*& position, Node*& replacement)
259 {
260 // Make temporary copy of actual nodes involved because we might lose
261 // their references in the process (e.g. position is the same as
262 // replacement or replacement is a child of position)
263 Node* detached = position;
264 Node* swap = replacement;
265
266 // Update current position to point to swap (replacement) node first
267 position = swap;
268
269 // Update replacement node to point to child in opposite direction
270 // otherwise we might lose the other child of the swap node
271 replacement = swap->children[1 - swap->dir];
272
273 if (replacement != ETL_NULLPTR)
274 {
275 replacement->parent = swap->parent;
276 }
277
278 // Point swap node to detached node's parent, children and weight
279 swap->parent = detached->parent;
280 swap->children[kLeft] = detached->children[kLeft];
281 swap->children[kRight] = detached->children[kRight];
282 if (swap->children[kLeft])
283 {
284 swap->children[kLeft]->parent = swap;
285 }
286 if (swap->children[kRight])
287 {
288 swap->children[kRight]->parent = swap;
289 }
290 swap->weight = detached->weight;
291 }
292
293 //*************************************************************************
295 //*************************************************************************
296 void balance_node(Node*& critical_node)
297 {
298 // Step 1: Update weights for all children of the critical node up to the
299 // newly inserted node. This step is costly (in terms of traversing nodes
300 // multiple times during insertion) but doesn't require as much recursion
301 Node* weight_node = critical_node->children[critical_node->dir];
302 while (weight_node)
303 {
304 // Keep going until we reach a terminal node (dir == kNeither)
305 if (kNeither != weight_node->dir)
306 {
307 // Does this insert balance the previous weight factor value?
308 if (weight_node->weight == 1 - weight_node->dir)
309 {
310 weight_node->weight = kNeither;
311 }
312 else
313 {
314 weight_node->weight = weight_node->dir;
315 }
316
317 // Update weight factor node to point to next node
318 weight_node = weight_node->children[weight_node->dir];
319 }
320 else
321 {
322 // Stop loop, terminal node found
323 break;
324 }
325 } // while(weight_node)
326
327 // Step 2: Update weight for critical_node or rotate tree to balance node
328 if (kNeither == critical_node->weight)
329 {
330 critical_node->weight = critical_node->dir;
331 }
332 // If direction is different than weight, then it will now be balanced
333 else if (critical_node->dir != critical_node->weight)
334 {
335 critical_node->weight = kNeither;
336 }
337 // Rotate is required to balance the tree at the critical node
338 else
339 {
340 // If critical node matches child node direction then perform a two
341 // node rotate in the direction of the critical node
342 if (critical_node->children[critical_node->dir] != ETL_NULLPTR) ETL_UNLIKELY
343 {
344 if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
345 {
346 rotate_2node(critical_node, critical_node->dir);
347 }
348 // Otherwise perform a three node rotation in the direction of the
349 // critical node
350 else
351 {
352 if (critical_node->children[critical_node->dir]->children[1 - critical_node->dir] != ETL_NULLPTR) ETL_UNLIKELY
353 {
354 rotate_3node(critical_node, critical_node->dir, critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
355 }
356 }
357 }
358 }
359 }
360
361 //*************************************************************************
364 //*************************************************************************
365 Node* find_limit_node(Node* position, const int8_t dir) const
366 {
367 // Something at this position and in the direction specified? keep going
368 Node* limit_node = position;
369 while (limit_node && limit_node->children[dir])
370 {
371 limit_node = limit_node->children[dir];
372 }
373
374 // Return the limit node position found
375 return limit_node;
376 }
377
378 //*************************************************************************
380 //*************************************************************************
381 void next_node(Node*& position) const
382 {
383 if (position)
384 {
385 // Is there a tree on the right? then find the minimum of that tree
386 if (position->children[kRight])
387 {
388 // Return minimum node found
389 position = find_limit_node(position->children[kRight], kLeft);
390 }
391 // Otherwise find the parent of this node
392 else
393 {
394 // Start with current position as parent
395 Node* parent = position;
396 do {
397 // Update current position as previous parent
398 position = parent;
399 // Find parent of current position
400 parent = position->parent; // find_parent_node(root_node, position);
401 // Repeat while previous position was on
402 // right side of parent tree
403 } while (parent && parent->children[kRight] == position);
404
405 // Set parent node as the next position
406 position = parent;
407 }
408 }
409 }
410
411 //*************************************************************************
413 //*************************************************************************
414 void next_node(const Node*& position) const
415 {
416 if (position)
417 {
418 // Is there a tree on the right? then find the minimum of that tree
419 if (position->children[kRight])
420 {
421 // Return minimum node found
422 position = find_limit_node(position->children[kRight], kLeft);
423 }
424 // Otherwise find the parent of this node
425 else
426 {
427 // Start with current position as parent
428 const Node* parent = position;
429 do {
430 // Update current position as previous parent
431 position = parent;
432 // Find parent of current position
433 parent = position->parent;
434 // Repeat while previous position was on right side of parent tree
435 } while (parent && parent->children[kRight] == position);
436
437 // Set parent node as the next position
438 position = parent;
439 }
440 }
441 }
442
443 //*************************************************************************
445 //*************************************************************************
446 void prev_node(Node*& position) const
447 {
448 // If starting at the terminal end, the previous node is the maximum node
449 // from the root
450 if (!position)
451 {
452 position = find_limit_node(root_node, kRight);
453 }
454 else
455 {
456 // Is there a tree on the left? then find the maximum of that tree
457 if (position->children[kLeft])
458 {
459 // Return maximum node found
460 position = find_limit_node(position->children[kLeft], kRight);
461 }
462 // Otherwise find the parent of this node
463 else
464 {
465 // Start with current position as parent
466 Node* parent = position;
467 do {
468 // Update current position as previous parent
469 position = parent;
470 // Find parent of current position
471 parent = position->parent;
472 // Repeat while previous position was on left side of parent tree
473 } while (parent && parent->children[kLeft] == position);
474
475 // Set parent node as the next position
476 position = parent;
477 }
478 }
479 }
480
481 //*************************************************************************
483 //*************************************************************************
484 void prev_node(const Node*& position) const
485 {
486 // If starting at the terminal end, the previous node is the maximum node
487 // from the root
488 if (!position)
489 {
490 position = find_limit_node(root_node, kRight);
491 }
492 else
493 {
494 // Is there a tree on the left? then find the maximum of that tree
495 if (position->children[kLeft])
496 {
497 // Return maximum node found
498 position = find_limit_node(position->children[kLeft], kRight);
499 }
500 // Otherwise find the parent of this node
501 else
502 {
503 // Start with current position as parent
504 const Node* parent = position;
505 do {
506 // Update current position as previous parent
507 position = parent;
508 // Find parent of current position
509 parent = position->parent;
510 // Repeat while previous position was on left side of parent tree
511 } while (parent && parent->children[kLeft] == position);
512
513 // Set parent node as the next position
514 position = parent;
515 }
516 }
517 }
518
519 //*************************************************************************
521 //*************************************************************************
522 void rotate_2node(Node*& position, uint_least8_t dir)
523 {
524 // A C A B
525 // B C -> A E OR B C -> D A
526 // D E B D D E E C
527 // C (new position) becomes the root
528 // A (position) takes ownership of D as its children[kRight] child
529 // C (new position) takes ownership of A as its left child
530 // OR
531 // B (new position) becomes the root
532 // A (position) takes ownership of E as its left child
533 // B (new position) takes ownership of A as its right child
534
535 // Capture new root (either B or C depending on dir) and its parent
536 Node* new_root = position->children[dir];
537
538 // Replace position's previous child with new root's other child
539 position->children[dir] = new_root->children[1 - dir];
540 // Update new root's other child parent pointer
541 if (position->children[dir])
542 {
543 position->children[dir]->parent = position;
544 }
545
546 // New root's parent becomes current position's parent
547 new_root->parent = position->parent;
548 new_root->children[1 - dir] = position;
549 new_root->dir = 1 - dir;
550
551 // Clear weight factor from current position
552 position->weight = kNeither;
553 // Position's parent becomes new_root
554 position->parent = new_root;
555 position = new_root;
556 // Clear weight factor from new root
557 position->weight = kNeither;
558 }
559
560 //*************************************************************************
562 //*************************************************************************
563 void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
564 {
565 // --A-- --E-- --A-- --D--
566 // _B_ C -> B A OR B _C_ -> A C
567 // D E D F G C D E B F G E
568 // F G F G
569 // E (new position) becomes the root
570 // B (position) takes ownership of F as its left child
571 // A takes ownership of G as its right child
572 // OR
573 // D (new position) becomes the root
574 // A (position) takes ownership of F as its right child
575 // C takes ownership of G as its left child
576
577 // Capture new root (either E or D depending on dir)
578 Node* new_root = position->children[dir]->children[1 - dir];
579 // Set weight factor for B or C based on F or G existing and being a
580 // different than dir
581 position->children[dir]->weight = third != kNeither && third != dir ? dir : uint_least8_t(kNeither);
582
583 // Detach new root from its tree (replace with new roots child)
584 position->children[dir]->children[1 - dir] = new_root->children[dir];
585 // Update new roots child parent pointer
586 if (new_root->children[dir])
587 {
588 new_root->children[dir]->parent = position->children[dir];
589 }
590
591 // Attach current left tree to new root and update its parent
592 new_root->children[dir] = position->children[dir];
593 position->children[dir]->parent = new_root;
594
595 // Set weight factor for A based on F or G
596 position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
597
598 // Move new root's right tree to current roots left tree
599 position->children[dir] = new_root->children[1 - dir];
600 if (new_root->children[1 - dir])
601 {
602 new_root->children[1 - dir]->parent = position;
603 }
604
605 // Attach current root to new roots right tree and assume its parent
606 new_root->parent = position->parent;
607 new_root->children[1 - dir] = position;
608 new_root->dir = 1 - dir;
609
610 // Update current position's parent and replace with new root
611 position->parent = new_root;
612 position = new_root;
613 // Clear weight factor for new current position
614 position->weight = kNeither;
615 }
616
620 ETL_DECLARE_DEBUG_COUNT;
621 };
622
623 //***************************************************************************
626 //***************************************************************************
627 template <typename TKey, typename TCompare = ETL_OR_STD::less<TKey> >
629 {
630 public:
631
632 typedef TKey key_type;
633 typedef TKey value_type;
634 typedef TCompare key_compare;
635 typedef TCompare value_compare;
636 typedef value_type& reference;
637 typedef const value_type& const_reference;
638#if ETL_USING_CPP11
639 typedef value_type&& rvalue_reference;
640#endif
641 typedef value_type* pointer;
642 typedef const value_type* const_pointer;
643 typedef size_t size_type;
644
645 protected:
646
647 //*************************************************************************
649 //*************************************************************************
650 struct Data_Node : public Node
651 {
652 explicit Data_Node(value_type value_)
653 : value(value_)
654 {
655 }
656
657 value_type value;
658 };
659
661 typedef const TKey& key_parameter_t;
662
663 //*************************************************************************
665 //*************************************************************************
666 bool node_comp(const Data_Node& node1, const Data_Node& node2) const
667 {
668 return compare(node1.value, node2.value);
669 }
670
671 bool node_comp(const Data_Node& node, key_parameter_t key) const
672 {
673 return compare(node.value, key);
674 }
675
676 bool node_comp(key_parameter_t key, const Data_Node& node) const
677 {
678 return compare(key, node.value);
679 }
680
681#if ETL_USING_CPP11
682 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
683 bool node_comp(const Data_Node& node, const K& key) const
684 {
685 return compare(node.value, key);
686 }
687
688 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
689 bool node_comp(const K& key, const Data_Node& node) const
690 {
691 return compare(key, node.value);
692 }
693#endif
694
695 private:
696
698 ipool* p_node_pool;
699
700 key_compare compare;
701
702 //*************************************************************************
704 //*************************************************************************
705 static Data_Node* data_cast(Node* p_node)
706 {
707 return static_cast<Data_Node*>(p_node);
708 }
709
710 //*************************************************************************
712 //*************************************************************************
713 static Data_Node& data_cast(Node& node)
714 {
715 return static_cast<Data_Node&>(node);
716 }
717
718 //*************************************************************************
720 //*************************************************************************
721 static const Data_Node* data_cast(const Node* p_node)
722 {
723 return static_cast<const Data_Node*>(p_node);
724 }
725
726 //*************************************************************************
728 //*************************************************************************
729 static const Data_Node& data_cast(const Node& node)
730 {
731 return static_cast<const Data_Node&>(node);
732 }
733
734 public:
735
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 iterator& operator++()
773 {
774 p_multiset->next_node(p_node);
775 return *this;
776 }
777
778 iterator operator++(int)
779 {
780 iterator temp(*this);
781 p_multiset->next_node(p_node);
782 return temp;
783 }
784
785 iterator& operator--()
786 {
787 p_multiset->prev_node(p_node);
788 return *this;
789 }
790
791 iterator operator--(int)
792 {
793 iterator temp(*this);
794 p_multiset->prev_node(p_node);
795 return temp;
796 }
797
798 iterator& operator=(const iterator& other)
799 {
800 p_multiset = other.p_multiset;
801 p_node = other.p_node;
802 return *this;
803 }
804
805 reference operator*() const
806 {
807 return imultiset::data_cast(p_node)->value;
808 }
809
810 pointer operator&() const
811 {
812 return &(imultiset::data_cast(p_node)->value);
813 }
814
815 pointer operator->() const
816 {
817 return &(imultiset::data_cast(p_node)->value);
818 }
819
820 friend bool operator==(const iterator& lhs, const iterator& rhs)
821 {
822 return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node;
823 }
824
825 friend bool operator!=(const iterator& lhs, const iterator& rhs)
826 {
827 return !(lhs == rhs);
828 }
829
830 private:
831
832 // Pointer to multiset associated with this iterator
833 imultiset* p_multiset;
834
835 // Pointer to the current node for this iterator
836 Node* p_node;
837 };
838
839 friend class iterator;
840
841 //*************************************************************************
843 //*************************************************************************
844 class const_iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, const value_type>
845 {
846 public:
847
848 friend class imultiset;
849
850 const_iterator()
851 : p_multiset(ETL_NULLPTR)
852 , p_node(ETL_NULLPTR)
853 {
854 }
855
856 const_iterator(const imultiset& multiset)
857 : p_multiset(&multiset)
858 , p_node(ETL_NULLPTR)
859 {
860 }
861
862 const_iterator(const imultiset& multiset, const Node* node)
863 : p_multiset(&multiset)
864 , p_node(node)
865 {
866 }
867
868 const_iterator(const typename imultiset::iterator& other)
869 : p_multiset(other.p_multiset)
870 , p_node(other.p_node)
871 {
872 }
873
874 const_iterator(const const_iterator& other)
875 : p_multiset(other.p_multiset)
876 , p_node(other.p_node)
877 {
878 }
879
880 ~const_iterator() {}
881
882 const_iterator& operator++()
883 {
884 p_multiset->next_node(p_node);
885 return *this;
886 }
887
888 const_iterator operator++(int)
889 {
890 const_iterator temp(*this);
891 p_multiset->next_node(p_node);
892 return temp;
893 }
894
895 const_iterator& operator--()
896 {
897 p_multiset->prev_node(p_node);
898 return *this;
899 }
900
901 const_iterator operator--(int)
902 {
903 const_iterator temp(*this);
904 p_multiset->prev_node(p_node);
905 return temp;
906 }
907
908 const_iterator& operator=(const const_iterator& other)
909 {
910 p_multiset = other.p_multiset;
911 p_node = other.p_node;
912 return *this;
913 }
914
915 const_reference operator*() const
916 {
917 return imultiset::data_cast(p_node)->value;
918 }
919
920 const_pointer operator&() const
921 {
922 return imultiset::data_cast(p_node)->value;
923 }
924
925 const_pointer operator->() const
926 {
927 return &(imultiset::data_cast(p_node)->value);
928 }
929
930 friend bool operator==(const const_iterator& lhs, const const_iterator& rhs)
931 {
932 return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node;
933 }
934
935 friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs)
936 {
937 return !(lhs == rhs);
938 }
939
940 private:
941
942 // Convert to an iterator.
943 imultiset::iterator to_iterator() const
944 {
945 return imultiset::iterator(const_cast<imultiset&>(*p_multiset), const_cast<Node*>(p_node));
946 }
947
948 // Pointer to multiset associated with this iterator
949 const imultiset* p_multiset;
950
951 // Pointer to the current node for this iterator
952 const Node* p_node;
953 };
954
955 friend class const_iterator;
956
957 typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
958
959 typedef ETL_OR_STD::reverse_iterator<iterator> reverse_iterator;
960 typedef ETL_OR_STD::reverse_iterator<const_iterator> const_reverse_iterator;
961
962 //*************************************************************************
964 //*************************************************************************
966 {
967 return iterator(*this, find_limit_node(root_node, kLeft));
968 }
969
970 //*************************************************************************
972 //*************************************************************************
974 {
975 return const_iterator(*this, find_limit_node(root_node, kLeft));
976 }
977
978 //*************************************************************************
980 //*************************************************************************
982 {
983 return iterator(*this);
984 }
985
986 //*************************************************************************
988 //*************************************************************************
990 {
991 return const_iterator(*this);
992 }
993
994 //*************************************************************************
996 //*************************************************************************
998 {
999 return const_iterator(*this, find_limit_node(root_node, kLeft));
1000 }
1001
1002 //*************************************************************************
1004 //*************************************************************************
1006 {
1007 return const_iterator(*this);
1008 }
1009
1010 //*************************************************************************
1012 //*************************************************************************
1013 reverse_iterator rbegin()
1014 {
1015 return reverse_iterator(iterator(*this));
1016 }
1017
1018 //*************************************************************************
1020 //*************************************************************************
1021 const_reverse_iterator rbegin() const
1022 {
1023 return const_reverse_iterator(const_iterator(*this));
1024 }
1025
1026 //*************************************************************************
1028 //*************************************************************************
1029 reverse_iterator rend()
1030 {
1031 return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
1032 }
1033
1034 //*************************************************************************
1036 //*************************************************************************
1037 const_reverse_iterator rend() const
1038 {
1039 return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
1040 }
1041
1042 //*************************************************************************
1044 //*************************************************************************
1045 const_reverse_iterator crbegin() const
1046 {
1047 return const_reverse_iterator(const_iterator(*this));
1048 }
1049
1050 //*************************************************************************
1052 //*************************************************************************
1053 const_reverse_iterator crend() const
1054 {
1055 return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
1056 }
1057
1058 //*********************************************************************
1065 //*********************************************************************
1066 template <typename TIterator>
1067 void assign(TIterator first, TIterator last)
1068 {
1069 initialise();
1070 insert(first, last);
1071 }
1072
1073 //*************************************************************************
1075 //*************************************************************************
1076 void clear()
1077 {
1078 initialise();
1079 }
1080
1081 //*********************************************************************
1085 //*********************************************************************
1086 size_type count(key_parameter_t key) const
1087 {
1088 return count_nodes(key);
1089 }
1090
1091#if ETL_USING_CPP11
1092 //*********************************************************************
1093 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1094 size_type count(const K& key) const
1095 {
1096 return count_nodes(key);
1097 }
1098#endif
1099
1100 //*************************************************************************
1103 //*************************************************************************
1104 ETL_OR_STD::pair<iterator, iterator> equal_range(key_parameter_t key)
1105 {
1106 return ETL_OR_STD::make_pair<iterator, iterator>(iterator(*this, find_lower_node(root_node, key)),
1107 iterator(*this, find_upper_node(root_node, key)));
1108 }
1109
1110#if ETL_USING_CPP11
1111 //*************************************************************************
1112 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1113 ETL_OR_STD::pair<iterator, iterator> equal_range(const K& key)
1114 {
1115 return ETL_OR_STD::make_pair<iterator, iterator>(iterator(*this, find_lower_node(root_node, key)),
1116 iterator(*this, find_upper_node(root_node, key)));
1117 }
1118#endif
1119
1120 //*************************************************************************
1123 //*************************************************************************
1124 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1125 {
1126 return ETL_OR_STD::make_pair<const_iterator, const_iterator>(const_iterator(*this, find_lower_node(root_node, key)),
1127 const_iterator(*this, find_upper_node(root_node, key)));
1128 }
1129
1130#if ETL_USING_CPP11
1131 //*************************************************************************
1132 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1133 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1134 {
1135 return ETL_OR_STD::make_pair<const_iterator, const_iterator>(const_iterator(*this, find_lower_node(root_node, key)),
1136 const_iterator(*this, find_upper_node(root_node, key)));
1137 }
1138#endif
1139
1140 //*************************************************************************
1142 //*************************************************************************
1144 {
1145 // Remove the node by its node specified in iterator position
1146 return erase(const_iterator(position));
1147 }
1148
1149 //*************************************************************************
1151 //*************************************************************************
1153 {
1154 // Cast const away from node to be removed. This is necessary because the
1155 // STL definition of this method requires we provide the next node in the
1156 // sequence as an iterator.
1157 Node* node = const_cast<Node*>(position.p_node);
1158 iterator next(*this, node);
1159 ++next;
1160
1161 // Remove the non-const node provided
1162 remove_node(node);
1163
1164 return next;
1165 }
1166
1167 //*************************************************************************
1168 // Erase the key specified.
1169 //*************************************************************************
1171 {
1172 // Number of nodes removed
1173 size_type d = 0;
1174 const_iterator lower(*this, find_lower_node(root_node, key_value));
1175 const_iterator upper(*this, find_upper_node(root_node, key_value));
1176 while (lower != upper)
1177 {
1178 // Increment count for each node removed
1179 ++d;
1180 // Remove node using the other erase method
1181 lower = erase(lower);
1182 }
1183
1184 // Return the total count erased
1185 return d;
1186 }
1187
1188 //*************************************************************************
1189#if ETL_USING_CPP11
1190 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1191 size_type erase(K&& key_value)
1192 {
1193 // Number of nodes removed
1194 size_type d = 0;
1195 const_iterator lower(*this, find_lower_node(root_node, etl::forward<K>(key_value)));
1196 const_iterator upper(*this, find_upper_node(root_node, etl::forward<K>(key_value)));
1197 while (lower != upper)
1198 {
1199 // Increment count for each node removed
1200 ++d;
1201 // Remove node using the other erase method
1202 lower = erase(lower);
1203 }
1204
1205 // Return the total count erased
1206 return d;
1207 }
1208#endif
1209
1210 //*************************************************************************
1212 //*************************************************************************
1214 {
1215 iterator next;
1216 while (first != last)
1217 {
1218 first = erase(first);
1219 }
1220
1221 return last.to_iterator();
1222 }
1223
1224 //*********************************************************************
1228 //*********************************************************************
1230 {
1231 return iterator(*this, find_node(root_node, key_value));
1232 }
1233
1234#if ETL_USING_CPP11
1235 //*********************************************************************
1236 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1237 iterator find(const K& k)
1238 {
1239 return iterator(*this, find_node(root_node, k));
1240 }
1241#endif
1242
1243 //*********************************************************************
1247 //*********************************************************************
1249 {
1250 return const_iterator(*this, find_node(root_node, key_value));
1251 }
1252
1253#if ETL_USING_CPP11
1254 //*********************************************************************
1255 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1256 const_iterator find(const K& k) const
1257 {
1258 return const_iterator(*this, find_node(root_node, k));
1259 }
1260#endif
1261
1262 //*********************************************************************
1267 //*********************************************************************
1268 iterator insert(const_reference value)
1269 {
1270 // Default to no inserted node
1271 Node* inserted_node = ETL_NULLPTR;
1272
1273 ETL_ASSERT(!full(), ETL_ERROR(multiset_full));
1274
1275 // Get next available free node
1276 Data_Node& node = allocate_data_node(value);
1277
1278 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1279 inserted_node = insert_node(root_node, node);
1280
1281 // Insert node into tree and return iterator to new node location in tree
1282 return iterator(*this, inserted_node);
1283 }
1284
1285#if ETL_USING_CPP11
1286 //*********************************************************************
1291 //*********************************************************************
1292 iterator insert(rvalue_reference value)
1293 {
1294 // Default to no inserted node
1295 Node* inserted_node = ETL_NULLPTR;
1296
1297 ETL_ASSERT(!full(), ETL_ERROR(multiset_full));
1298
1299 // Get next available free node
1300 Data_Node& node = allocate_data_node(etl::move(value));
1301
1302 // Obtain the inserted node (might be ETL_NULLPTR if node was a duplicate)
1303 inserted_node = insert_node(root_node, node);
1304
1305 // Insert node into tree and return iterator to new node location in tree
1306 return iterator(*this, inserted_node);
1307 }
1308#endif
1309
1310 //*********************************************************************
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 //*********************************************************************
1330 //*********************************************************************
1331 iterator insert(const_iterator /*position*/, rvalue_reference value)
1332 {
1333 // Ignore position provided and just do a normal insert
1334 return insert(etl::move(value));
1335 }
1336#endif
1337
1338 //*********************************************************************
1345 //*********************************************************************
1346 template <class TIterator>
1347 void insert(TIterator first, TIterator last)
1348 {
1349 while (first != last)
1350 {
1351 insert(*first);
1352 ++first;
1353 }
1354 }
1355
1356 //*********************************************************************
1361 //*********************************************************************
1363 {
1364 return iterator(*this, find_lower_node(root_node, key));
1365 }
1366
1367#if ETL_USING_CPP11
1368 //*********************************************************************
1369 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1370 iterator lower_bound(const K& key)
1371 {
1372 return iterator(*this, find_lower_node(root_node, key));
1373 }
1374#endif
1375
1376 //*********************************************************************
1381 //*********************************************************************
1383 {
1384 return const_iterator(*this, find_lower_node(root_node, key));
1385 }
1386
1387#if ETL_USING_CPP11
1388 //*********************************************************************
1389 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1390 const_iterator lower_bound(const K& key) const
1391 {
1392 return const_iterator(*this, find_lower_node(root_node, key));
1393 }
1394#endif
1395
1396 //*********************************************************************
1401 //*********************************************************************
1403 {
1404 return iterator(*this, find_upper_node(root_node, key));
1405 }
1406
1407#if ETL_USING_CPP11
1408 //*********************************************************************
1409 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1410 iterator upper_bound(const K& key)
1411 {
1412 return iterator(*this, find_upper_node(root_node, key));
1413 }
1414#endif
1415
1416 //*********************************************************************
1421 //*********************************************************************
1423 {
1424 return const_iterator(*this, find_upper_node(root_node, key));
1425 }
1426
1427#if ETL_USING_CPP11
1428 //*********************************************************************
1429 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1430 const_iterator upper_bound(const K& key) const
1431 {
1432 return const_iterator(*this, find_upper_node(root_node, key));
1433 }
1434#endif
1435
1436 //*************************************************************************
1438 //*************************************************************************
1440 {
1441 // Skip if doing self assignment
1442 if (this != &rhs)
1443 {
1444 assign(rhs.cbegin(), rhs.cend());
1445 }
1446
1447 return *this;
1448 }
1449
1450#if ETL_USING_CPP11
1451 //*************************************************************************
1453 //*************************************************************************
1455 {
1456 // Skip if doing self assignment
1457 if (this != &rhs)
1458 {
1459 clear();
1460
1461 typename etl::imultiset<TKey, TCompare>::iterator from = rhs.begin();
1462
1463 while (from != rhs.end())
1464 {
1465 typename etl::imultiset<TKey, TCompare>::iterator temp = from;
1466 ++temp;
1467
1468 this->insert(etl::move(*from));
1469 from = temp;
1470 }
1471 }
1472
1473 return *this;
1474 }
1475#endif
1476
1477 //*************************************************************************
1479 //*************************************************************************
1480 key_compare key_comp() const
1481 {
1482 return compare;
1483 }
1484
1485 //*************************************************************************
1487 //*************************************************************************
1488 value_compare value_comp() const
1489 {
1490 return compare;
1491 }
1492
1493 //*************************************************************************
1495 //*************************************************************************
1497 {
1498 return find(key) != end();
1499 }
1500
1501#if ETL_USING_CPP11
1502 //*************************************************************************
1503 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1504 bool contains(const K& k) const
1505 {
1506 return find(k) != end();
1507 }
1508#endif
1509
1510 protected:
1511
1512 //*************************************************************************
1514 //*************************************************************************
1515 imultiset(etl::ipool& node_pool, size_t max_size_)
1516 : etl::multiset_base(max_size_)
1517 , p_node_pool(&node_pool)
1518 {
1519 }
1520
1521 //*************************************************************************
1523 //*************************************************************************
1525 {
1526 const_iterator item = begin();
1527
1528 while (item != end())
1529 {
1530 item = erase(item);
1531 }
1532 }
1533
1534 private:
1535
1536 //*************************************************************************
1538 //*************************************************************************
1539 Data_Node& allocate_data_node(const_reference value)
1540 {
1541 Data_Node* node = allocate_data_node();
1542 ::new ((void*)&node->value) value_type(value);
1543 ETL_INCREMENT_DEBUG_COUNT;
1544 return *node;
1545 }
1546
1547#if ETL_USING_CPP11
1548 //*************************************************************************
1550 //*************************************************************************
1551 Data_Node& allocate_data_node(rvalue_reference value)
1552 {
1553 Data_Node* node = allocate_data_node();
1554 ::new ((void*)&node->value) value_type(etl::move(value));
1555 ETL_INCREMENT_DEBUG_COUNT;
1556 return *node;
1557 }
1558#endif
1559
1560 //*************************************************************************
1562 //*************************************************************************
1563 Data_Node* allocate_data_node()
1564 {
1565 Data_Node* (etl::ipool::*func)() = &etl::ipool::allocate<Data_Node>;
1566 return (p_node_pool->*func)();
1567 }
1568
1569 //*************************************************************************
1571 //*************************************************************************
1572 void destroy_data_node(Data_Node& node)
1573 {
1574 node.value.~value_type();
1575 p_node_pool->release(&node);
1576 ETL_DECREMENT_DEBUG_COUNT;
1577 }
1578
1579 //*************************************************************************
1581 //*************************************************************************
1582 size_type count_nodes(key_parameter_t key) const
1583 {
1584 // Number of nodes that match the key provided result
1585 size_type result = 0;
1586
1587 // Find lower and upper nodes for the key provided
1588 const Node* lower = find_lower_node(root_node, key);
1589 const Node* upper = find_upper_node(root_node, key);
1590
1591 // Loop from lower node to upper node and find nodes that match
1592 while (lower != upper)
1593 {
1594 // Downcast found to Data_Node class for comparison and other operations
1595 const Data_Node& data_node = imultiset::data_cast(*lower);
1596
1597 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1598 {
1599 // This node matches the key provided
1600 ++result;
1601 }
1602
1603 // Move on to the next node
1604 next_node(lower);
1605 }
1606
1607 // Return the number of nodes that match
1608 return result;
1609 }
1610
1611#if ETL_USING_CPP11
1612 //*************************************************************************
1613 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1614 size_type count_nodes(const K& key) const
1615 {
1616 // Number of nodes that match the key provided result
1617 size_type result = 0;
1618
1619 // Find lower and upper nodes for the key provided
1620 const Node* lower = find_lower_node(root_node, key);
1621 const Node* upper = find_upper_node(root_node, key);
1622
1623 // Loop from lower node to upper node and find nodes that match
1624 while (lower != upper)
1625 {
1626 // Downcast found to Data_Node class for comparison and other operations
1627 const Data_Node& data_node = imultiset::data_cast(*lower);
1628
1629 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1630 {
1631 // This node matches the key provided
1632 ++result;
1633 }
1634
1635 // Move on to the next node
1636 next_node(lower);
1637 }
1638
1639 // Return the number of nodes that match
1640 return result;
1641 }
1642#endif
1643
1644 //*************************************************************************
1646 //*************************************************************************
1647 Node* find_node(Node* position, key_parameter_t key)
1648 {
1649 Node* found = ETL_NULLPTR;
1650 while (position)
1651 {
1652 // Downcast found to Data_Node class for comparison and other operations
1653 Data_Node& data_node = imultiset::data_cast(*position);
1654 // Compare the node value to the current position value
1655 if (node_comp(key, data_node))
1656 {
1657 // Keep searching for the node on the left
1658 position = position->children[kLeft];
1659 }
1660 else if (node_comp(data_node, key))
1661 {
1662 // Keep searching for the node on the right
1663 position = position->children[kRight];
1664 }
1665 else
1666 {
1667 // We found one, keep looking for more on the left
1668 found = position;
1669 position = position->children[kLeft];
1670 }
1671 }
1672
1673 // Return the node found (might be ETL_NULLPTR)
1674 return found;
1675 }
1676
1677#if ETL_USING_CPP11
1678 //*************************************************************************
1679 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1680 Node* find_node(Node* position, const K& key)
1681 {
1682 Node* found = ETL_NULLPTR;
1683 while (position)
1684 {
1685 // Downcast found to Data_Node class for comparison and other operations
1686 Data_Node& data_node = imultiset::data_cast(*position);
1687 // Compare the node value to the current position value
1688 if (node_comp(key, data_node))
1689 {
1690 // Keep searching for the node on the left
1691 position = position->children[kLeft];
1692 }
1693 else if (node_comp(data_node, key))
1694 {
1695 // Keep searching for the node on the right
1696 position = position->children[kRight];
1697 }
1698 else
1699 {
1700 // We found one, keep looking for more on the left
1701 found = position;
1702 position = position->children[kLeft];
1703 }
1704 }
1705
1706 // Return the node found (might be ETL_NULLPTR)
1707 return found;
1708 }
1709#endif
1710
1711 //*************************************************************************
1713 //*************************************************************************
1714 const Node* find_node(const Node* position, key_parameter_t key) const
1715 {
1716 const Node* found = ETL_NULLPTR;
1717 while (position)
1718 {
1719 // Downcast found to Data_Node class for comparison and other operations
1720 const Data_Node& data_node = imultiset::data_cast(*position);
1721 // Compare the node value to the current position value
1722 if (node_comp(key, data_node))
1723 {
1724 // Keep searching for the node on the left
1725 position = position->children[kLeft];
1726 }
1727 else if (node_comp(data_node, key))
1728 {
1729 // Keep searching for the node on the right
1730 position = position->children[kRight];
1731 }
1732 else
1733 {
1734 // We found one, keep looking for more on the left
1735 found = position;
1736 position = position->children[kLeft];
1737 }
1738 }
1739
1740 // Return the node found (might be ETL_NULLPTR)
1741 return found;
1742 }
1743
1744#if ETL_USING_CPP11
1745 //*************************************************************************
1746 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1747 const Node* find_node(const Node* position, const K& key) const
1748 {
1749 const Node* found = ETL_NULLPTR;
1750 while (position)
1751 {
1752 // Downcast found to Data_Node class for comparison and other operations
1753 const Data_Node& data_node = imultiset::data_cast(*position);
1754 // Compare the node value to the current position value
1755 if (node_comp(key, data_node))
1756 {
1757 // Keep searching for the node on the left
1758 position = position->children[kLeft];
1759 }
1760 else if (node_comp(data_node, key))
1761 {
1762 // Keep searching for the node on the right
1763 position = position->children[kRight];
1764 }
1765 else
1766 {
1767 // We found one, keep looking for more on the left
1768 found = position;
1769 position = position->children[kLeft];
1770 }
1771 }
1772
1773 // Return the node found (might be ETL_NULLPTR)
1774 return found;
1775 }
1776#endif
1777
1778 //*************************************************************************
1780 //*************************************************************************
1781 Node* find_lower_node(Node* position, key_parameter_t key) const
1782 {
1783 // Something at this position? keep going
1784 Node* lower_node = ETL_NULLPTR;
1785 while (position)
1786 {
1787 // Downcast lower node to Data_Node reference for key comparisons
1788 Data_Node& data_node = imultiset::data_cast(*position);
1789 // Compare the key value to the current lower node key value
1790 if (node_comp(key, data_node))
1791 {
1792 lower_node = position;
1793 if (position->children[kLeft])
1794 {
1795 position = position->children[kLeft];
1796 }
1797 else
1798 {
1799 // Found lowest node
1800 break;
1801 }
1802 }
1803 else if (node_comp(data_node, key))
1804 {
1805 position = position->children[kRight];
1806 }
1807 else
1808 {
1809 // Make note of current position, but keep looking to left for more
1810 lower_node = position;
1811 position = position->children[kLeft];
1812 }
1813 }
1814
1815 // Return the lower_node position found
1816 return lower_node;
1817 }
1818
1819#if ETL_USING_CPP11
1820 //*************************************************************************
1821 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1822 Node* find_lower_node(Node* position, const K& key) const
1823 {
1824 // Something at this position? keep going
1825 Node* lower_node = ETL_NULLPTR;
1826 while (position)
1827 {
1828 // Downcast lower node to Data_Node reference for key comparisons
1829 Data_Node& data_node = imultiset::data_cast(*position);
1830 // Compare the key value to the current lower node key value
1831 if (node_comp(key, data_node))
1832 {
1833 lower_node = position;
1834 if (position->children[kLeft])
1835 {
1836 position = position->children[kLeft];
1837 }
1838 else
1839 {
1840 // Found lowest node
1841 break;
1842 }
1843 }
1844 else if (node_comp(data_node, key))
1845 {
1846 position = position->children[kRight];
1847 }
1848 else
1849 {
1850 // Make note of current position, but keep looking to left for more
1851 lower_node = position;
1852 position = position->children[kLeft];
1853 }
1854 }
1855
1856 // Return the lower_node position found
1857 return lower_node;
1858 }
1859#endif
1860
1861 //*************************************************************************
1863 //*************************************************************************
1864 Node* find_upper_node(Node* position, key_parameter_t key) const
1865 {
1866 // Keep track of parent of last upper node
1867 Node* upper_node = ETL_NULLPTR;
1868 // Has an equal node been found? start with no
1869 bool found = false;
1870 while (position)
1871 {
1872 // Downcast position to Data_Node reference for key comparisons
1873 Data_Node& data_node = imultiset::data_cast(*position);
1874 // Compare the key value to the current upper node key value
1875 if (node_comp(data_node, key))
1876 {
1877 position = position->children[kRight];
1878 }
1879 else if (node_comp(key, data_node))
1880 {
1881 upper_node = position;
1882 // If a node equal to key hasn't been found go left
1883 if (!found && position->children[kLeft])
1884 {
1885 position = position->children[kLeft];
1886 }
1887 else
1888 {
1889 break;
1890 }
1891 }
1892 else
1893 {
1894 // We found an equal item, break on next bigger item
1895 found = true;
1896 next_node(position);
1897 }
1898 }
1899
1900 // Return the upper node position found (might be ETL_NULLPTR)
1901 return upper_node;
1902 }
1903
1904#if ETL_USING_CPP11
1905 //*************************************************************************
1906 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1907 Node* find_upper_node(Node* position, const K& key) const
1908 {
1909 // Keep track of parent of last upper node
1910 Node* upper_node = ETL_NULLPTR;
1911 // Has an equal node been found? start with no
1912 bool found = false;
1913 while (position)
1914 {
1915 // Downcast position to Data_Node reference for key comparisons
1916 Data_Node& data_node = imultiset::data_cast(*position);
1917 // Compare the key value to the current upper node key value
1918 if (node_comp(data_node, key))
1919 {
1920 position = position->children[kRight];
1921 }
1922 else if (node_comp(key, data_node))
1923 {
1924 upper_node = position;
1925 // If a node equal to key hasn't been found go left
1926 if (!found && position->children[kLeft])
1927 {
1928 position = position->children[kLeft];
1929 }
1930 else
1931 {
1932 break;
1933 }
1934 }
1935 else
1936 {
1937 // We found an equal item, break on next bigger item
1938 found = true;
1939 next_node(position);
1940 }
1941 }
1942
1943 // Return the upper node position found (might be ETL_NULLPTR)
1944 return upper_node;
1945 }
1946#endif
1947
1948 //*************************************************************************
1950 //*************************************************************************
1951 Node* insert_node(Node*& position, Data_Node& node)
1952 {
1953 // Find the location where the node belongs
1954 Node* found = position;
1955
1956 // Was position provided not empty? then find where the node belongs
1957 if (position)
1958 {
1959 // Find the critical parent node (default to ETL_NULLPTR)
1960 Node* critical_parent_node = ETL_NULLPTR;
1961 Node* critical_node = root_node;
1962
1963 while (found)
1964 {
1965 // Search for critical weight node (all nodes whose weight factor
1966 // is set to kNeither (balanced)
1967 if (kNeither != found->weight)
1968 {
1969 critical_node = found;
1970 }
1971
1972 // Downcast found to Data_Node class for comparison and other
1973 // operations
1974 Data_Node& found_data_node = imultiset::data_cast(*found);
1975
1976 // Is the node provided to the left of the current position?
1977 if (node_comp(node, found_data_node))
1978 {
1979 // Update direction taken to insert new node in parent node
1980 found->dir = kLeft;
1981 }
1982 // Is the node provided to the right of the current position?
1983 else if (node_comp(found_data_node, node))
1984 {
1985 // Update direction taken to insert new node in parent node
1986 found->dir = kRight;
1987 }
1988 else
1989 {
1990 // Update direction taken to insert new node in parent (and
1991 // duplicate) node to the right.
1992 found->dir = kRight;
1993 }
1994
1995 // Is there a child of this parent node?
1996 if (found->children[found->dir])
1997 {
1998 // Will this node be the parent of the next critical node whose
1999 // weight factor is set to kNeither (balanced)?
2000 if (kNeither != found->children[found->dir]->weight)
2001 {
2002 critical_parent_node = found;
2003 }
2004
2005 // Keep looking for empty spot to insert new node
2006 found = found->children[found->dir];
2007 }
2008 else
2009 {
2010 // Attach node as a child of the parent node found
2011 attach_node(found, found->children[found->dir], node);
2012
2013 // Return newly added node
2014 found = found->children[found->dir];
2015
2016 // Exit loop
2017 break;
2018 }
2019 }
2020
2021 // Was a critical node found that should be checked for balance?
2022 if (critical_node)
2023 {
2024 if (critical_parent_node == ETL_NULLPTR && critical_node == root_node)
2025 {
2027 }
2028 else if (critical_parent_node == ETL_NULLPTR && critical_node == position)
2029 {
2030 balance_node(position);
2031 }
2032 else
2033 {
2034 if (critical_parent_node != ETL_NULLPTR)
2035 {
2036 balance_node(critical_parent_node->children[critical_parent_node->dir]);
2037 }
2038 }
2039 }
2040 }
2041 else
2042 {
2043 // Attach node to current position (which is assumed to be root)
2044 attach_node(ETL_NULLPTR, position, node);
2045
2046 // Return newly added node at current position
2047 found = position;
2048 }
2049
2050 // Return the node found (might be ETL_NULLPTR)
2051 return found;
2052 }
2053
2054 //*************************************************************************
2057 //*************************************************************************
2058 void remove_node(Node* node)
2059 {
2060 // If valid found node was provided then proceed with steps 1 through 5
2061 if (node)
2062 {
2063 // Downcast found node provided to Data_Node class
2064 Data_Node& data_node = imultiset::data_cast(*node);
2065
2066 // Keep track of node as found node
2067 Node* found = node;
2068
2069 // Step 1: Mark path from node provided back to the root node using the
2070 // internal temporary dir member value and using the parent pointer.
2071 // This will allow us to avoid recursion in finding the node in a tree
2072 // that might contain duplicate keys to be found.
2073 while (node)
2074 {
2075 if (node->parent)
2076 {
2077 // Which direction does parent use to get to this node?
2078 node->parent->dir = node->parent->children[kLeft] == node ? kLeft : kRight;
2079
2080 // Make this nodes parent the next node
2081 node = node->parent;
2082 }
2083 else
2084 {
2085 // Root node found - break loop
2086 break;
2087 }
2088 }
2089
2090 // Step 2: Follow the path provided above until we reach the node
2091 // provided and look for the balance node to start rebalancing the tree
2092 // from (up to the replacement node that will be found in step 3)
2093 Node* balance = root_node;
2094 while (node)
2095 {
2096 // Did we reach the node provided originally (found) then go to step 3
2097 if (node == found)
2098 {
2099 // Update the direction towards a replacement node at the found node
2100 node->dir = node->children[kLeft] ? kLeft : kRight;
2101
2102 // Exit loop and proceed with step 3
2103 break;
2104 }
2105 else
2106 {
2107 // If this nodes weight is kNeither or we are taking the shorter
2108 // path to the next node and our sibling (on longer path) is
2109 // balanced then we need to update the balance node to this node but
2110 // all our ancestors will not require rebalancing
2111 if ((node->weight == kNeither) || (node->weight == (1 - node->dir) && 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) || (node->weight == (1 - node->dir) && node->children[1 - node->dir]->weight == kNeither))
2143 {
2144 // Update balance node to this node
2145 balance = node;
2146 }
2147
2148 // Keep searching for replacement node in the direction specified
2149 // above
2150 node = node->children[node->dir];
2151
2152 // Downcast node to Data_Node class for comparison operations
2153 Data_Node& replace_data_node = imultiset::data_cast(*node);
2154
2155 // Compare the key provided to the replace data node key
2156 if (node_comp(data_node, replace_data_node))
2157 {
2158 // Update the direction to the replace node
2159 node->dir = kLeft;
2160 }
2161 else if (node_comp(replace_data_node, data_node))
2162 {
2163 // Update the direction to the replace node
2164 node->dir = kRight;
2165 }
2166 else
2167 {
2168 // Update the direction to the replace node
2169 node->dir = 1 - found->dir;
2170 }
2171 } // while(node)
2172
2173 // Step 4: Update weights from balance to parent of node determined
2174 // in step 3 above rotating (2 or 3 node rotations) as needed.
2175 while (balance)
2176 {
2177 // Break when balance node reaches the parent of replacement node
2178 if (balance->children[balance->dir] == ETL_NULLPTR)
2179 {
2180 break;
2181 }
2182
2183 // If balance node is balanced already (kNeither) then just imbalance
2184 // the node in the opposite direction of the node being removed
2185 if (balance->weight == kNeither)
2186 {
2187 balance->weight = 1 - balance->dir;
2188 }
2189 // If balance node is imbalanced in the opposite direction of the
2190 // node being removed then the node now becomes balanced
2191 else if (balance->weight == balance->dir)
2192 {
2193 balance->weight = kNeither;
2194 }
2195 // Otherwise a rotation is required at this node
2196 else
2197 {
2198 int weight = balance->children[1 - balance->dir]->weight;
2199 // Perform a 3 node rotation if weight is same as balance->dir
2200 if (weight == balance->dir)
2201 {
2202 // Is the root node being rebalanced (no parent)
2203 if (balance->parent == ETL_NULLPTR)
2204 {
2205 rotate_3node(root_node, 1 - balance->dir, balance->children[1 - balance->dir]->children[balance->dir]->weight);
2206 }
2207 else
2208 {
2209 rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
2210 balance->children[1 - balance->dir]->children[balance->dir]->weight);
2211 }
2212 }
2213 // Already balanced, rebalance and make it heavy in opposite
2214 // direction of the node being removed
2215 else if (weight == kNeither)
2216 {
2217 // Is the root node being rebalanced (no parent)
2218 if (balance->parent == ETL_NULLPTR)
2219 {
2220 rotate_2node(root_node, 1 - balance->dir);
2221 root_node->weight = balance->dir;
2222 }
2223 else
2224 {
2225 // Balance parent might change during rotate, keep local copy
2226 // to old parent so its weight can be updated after the 2 node
2227 // rotate is completed
2228 Node* old_parent = balance->parent;
2229 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2230 old_parent->children[old_parent->dir]->weight = balance->dir;
2231 }
2232 // Update balance node weight in opposite direction of node
2233 // removed
2234 balance->weight = 1 - balance->dir;
2235 }
2236 // Rebalance and leave it balanced
2237 else
2238 {
2239 // Is the root node being rebalanced (no parent)
2240 if (balance->parent == ETL_NULLPTR)
2241 {
2242 rotate_2node(root_node, 1 - balance->dir);
2243 }
2244 else
2245 {
2246 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2247 }
2248 }
2249 }
2250
2251 // Next balance node to consider
2252 balance = balance->children[balance->dir];
2253 } // while(balance)
2254
2255 // Step 5: Swap found with node (replacement)
2256 if (found->parent)
2257 {
2258 // Handle traditional case
2259 detach_node(found->parent->children[found->parent->dir], node->parent->children[node->parent->dir]);
2260 }
2261 // Handle root node removal
2262 else
2263 {
2264 // Valid replacement node for root node being removed?
2265 if (node->parent)
2266 {
2267 detach_node(root_node, node->parent->children[node->parent->dir]);
2268 }
2269 else
2270 {
2271 // Found node and replacement node are both root node
2273 }
2274 }
2275
2276 // One less.
2277 --current_size;
2278
2279 // Destroy the node detached above
2280 destroy_data_node(data_node);
2281 } // if(found)
2282 }
2283
2284 // Disable copy construction.
2285 imultiset(const imultiset&);
2286
2287 //*************************************************************************
2289 //*************************************************************************
2290#if defined(ETL_POLYMORPHIC_MULTISET) || defined(ETL_POLYMORPHIC_CONTAINERS)
2291
2292 public:
2293
2294 virtual ~imultiset() {}
2295#else
2296
2297 protected:
2298
2300#endif
2301 };
2302
2303 //*************************************************************************
2305 //*************************************************************************
2306 template <typename TKey, const size_t MAX_SIZE_, typename TCompare = ETL_OR_STD::less<TKey> >
2307 class multiset : public etl::imultiset<TKey, TCompare>
2308 {
2309 public:
2310
2311 static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_;
2312
2313 //*************************************************************************
2315 //*************************************************************************
2317 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2318 {
2319 this->initialise();
2320 }
2321
2322 //*************************************************************************
2324 //*************************************************************************
2325 multiset(const multiset& other)
2326 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2327 {
2328 this->assign(other.cbegin(), other.cend());
2329 }
2330
2331#if ETL_USING_CPP11
2332 //*************************************************************************
2334 //*************************************************************************
2335 multiset(multiset&& other)
2336 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2337 {
2338 if (this != &other)
2339 {
2340 typename etl::imultiset<TKey, TCompare>::iterator from = other.begin();
2341
2342 while (from != other.end())
2343 {
2344 typename etl::imultiset<TKey, TCompare>::iterator temp = from;
2345 ++temp;
2346
2347 this->insert(etl::move(*from));
2348 from = temp;
2349 }
2350 }
2351 }
2352#endif
2353
2354 //*************************************************************************
2359 //*************************************************************************
2360 template <typename TIterator>
2361 multiset(TIterator first, TIterator last)
2362 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2363 {
2364 this->assign(first, last);
2365 }
2366
2367#if ETL_HAS_INITIALIZER_LIST
2368 //*************************************************************************
2370 //*************************************************************************
2371 multiset(std::initializer_list<typename etl::imultiset<TKey, TCompare>::value_type> init)
2372 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2373 {
2374 this->assign(init.begin(), init.end());
2375 }
2376#endif
2377
2378 //*************************************************************************
2380 //*************************************************************************
2382 {
2383 this->initialise();
2384 }
2385
2386 //*************************************************************************
2388 //*************************************************************************
2390 {
2391 // Skip if doing self assignment
2392 if (this != &rhs)
2393 {
2394 this->assign(rhs.cbegin(), rhs.cend());
2395 }
2396
2397 return *this;
2398 }
2399
2400#if ETL_USING_CPP11
2401 //*************************************************************************
2403 //*************************************************************************
2405 {
2406 if (this != &rhs)
2407 {
2408 this->clear();
2409
2410 typename etl::imultiset<TKey, TCompare>::iterator from = rhs.begin();
2411
2412 while (from != rhs.end())
2413 {
2414 this->insert(etl::move(*from));
2415 ++from;
2416 }
2417 }
2418
2419 return *this;
2420 }
2421#endif
2422
2423 private:
2424
2426 etl::pool<typename etl::imultiset<TKey, TCompare>::Data_Node, MAX_SIZE> node_pool;
2427 };
2428
2429 template <typename TKey, const size_t MAX_SIZE_, typename TCompare>
2430 ETL_CONSTANT size_t multiset<TKey, MAX_SIZE_, TCompare>::MAX_SIZE;
2431
2432 //*************************************************************************
2434 //*************************************************************************
2435#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
2436 template <typename... T>
2437 multiset(T...) -> multiset<etl::nth_type_t<0, T...>, sizeof...(T)>;
2438#endif
2439
2440 //*************************************************************************
2442 //*************************************************************************
2443#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
2444 template <typename TKey, typename TKeyCompare = etl::less<TKey>, typename... T>
2445 constexpr auto make_multiset(T&&... keys) -> etl::multiset<TKey, sizeof...(T), TKeyCompare>
2446 {
2447 return {etl::forward<T>(keys)...};
2448 }
2449#endif
2450
2451 //***************************************************************************
2457 //***************************************************************************
2458 template <typename TKey, typename TCompare>
2460 {
2461 return (lhs.size() == rhs.size()) && ETL_OR_STD::equal(lhs.begin(), lhs.end(), rhs.begin());
2462 }
2463
2464 //***************************************************************************
2470 //***************************************************************************
2471 template <typename TKey, typename TCompare>
2473 {
2474 return !(lhs == rhs);
2475 }
2476
2477 //*************************************************************************
2483 //*************************************************************************
2484 template <typename TKey, typename TCompare>
2486 {
2487 return ETL_OR_STD::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), etl::imultiset<TKey, TCompare>::value_compare());
2488 }
2489
2490 //*************************************************************************
2496 //*************************************************************************
2497 template <typename TKey, typename TCompare>
2499 {
2500 return (rhs < lhs);
2501 }
2502
2503 //*************************************************************************
2510 //*************************************************************************
2511 template <typename TKey, typename TCompare>
2513 {
2514 return !(lhs > rhs);
2515 }
2516
2517 //*************************************************************************
2523 //*************************************************************************
2524 template <typename TKey, typename TCompare>
2526 {
2527 return !(lhs < rhs);
2528 }
2529} // namespace etl
2530
2531#include "private/minmax_pop.h"
2532
2533#endif
const_iterator
Definition multiset.h:845
iterator.
Definition multiset.h:740
A templated multiset implementation that uses a fixed size buffer.
Definition multiset.h:2308
multiset(const multiset &other)
Copy constructor.
Definition multiset.h:2325
multiset()
Default constructor.
Definition multiset.h:2316
~multiset()
Destructor.
Definition multiset.h:2381
multiset & operator=(const multiset &rhs)
Assignment operator.
Definition multiset.h:2389
multiset(TIterator first, TIterator last)
Definition multiset.h:2361
ETL_CONSTEXPR14 bool operator!=(const etl::bitset< Active_Bits, TElement > &lhs, const etl::bitset< Active_Bits, TElement > &rhs) ETL_NOEXCEPT
Definition bitset_new.h:2529
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
Definition exception.h:59
T * allocate()
Definition ipool.h:333
Definition ipool.h:109
iterator begin()
Gets the beginning of the multiset.
Definition multiset.h:965
iterator lower_bound(key_parameter_t key)
Definition multiset.h:1362
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:414
reverse_iterator rbegin()
Gets the reverse beginning of the list.
Definition multiset.h:1013
iterator insert(const_reference value)
Definition multiset.h:1268
void clear()
Clears the multiset.
Definition multiset.h:1076
const_iterator upper_bound(key_parameter_t key) const
Definition multiset.h:1422
size_type count(key_parameter_t key) const
Definition multiset.h:1086
imultiset & operator=(const imultiset &rhs)
Assignment operator.
Definition multiset.h:1439
bool contains(key_parameter_t key) const
Check if the set contains the key.
Definition multiset.h:1496
bool node_comp(const Data_Node &node1, const Data_Node &node2) const
How to compare node elements.
Definition multiset.h:666
const size_type CAPACITY
The maximum size of the set.
Definition multiset.h:618
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:661
void rotate_2node(Node *&position, uint_least8_t dir)
Rotate two nodes at the position provided the to balance the tree.
Definition multiset.h:522
const_reverse_iterator crbegin() const
Gets the reverse beginning of the list.
Definition multiset.h:1045
Node * find_limit_node(Node *position, const int8_t dir) const
Definition multiset.h:365
iterator erase(const_iterator first, const_iterator last)
Erases a range of elements.
Definition multiset.h:1213
iterator end()
Gets the end of the multiset.
Definition multiset.h:981
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(key_parameter_t key) const
Definition multiset.h:1124
const_iterator lower_bound(key_parameter_t key) const
Definition multiset.h:1382
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:296
const_iterator end() const
Gets the end of the multiset.
Definition multiset.h:989
const_iterator cend() const
Gets the end of the multiset.
Definition multiset.h:1005
const_iterator cbegin() const
Gets the beginning of the multiset.
Definition multiset.h:997
iterator find(key_parameter_t key_value)
Definition multiset.h:1229
void next_node(Node *&position) const
Find the next node in sequence from the node provided.
Definition multiset.h:381
void initialise()
Initialise the multiset.
Definition multiset.h:1524
void assign(TIterator first, TIterator last)
Definition multiset.h:1067
const_iterator find(key_parameter_t key_value) const
Definition multiset.h:1248
size_type capacity() const
Definition multiset.h:164
reverse_iterator rend()
Gets the reverse end of the list.
Definition multiset.h:1029
void attach_node(Node *parent, Node *&position, Node &node)
Attach the provided node to the position provided.
Definition multiset.h:240
const_iterator begin() const
Gets the beginning of the multiset.
Definition multiset.h:973
ETL_OR_STD::pair< iterator, iterator > equal_range(key_parameter_t key)
Definition multiset.h:1104
void prev_node(Node *&position) const
Find the previous node in sequence from the node provided.
Definition multiset.h:446
void prev_node(const Node *&position) const
Find the previous node in sequence from the node provided.
Definition multiset.h:484
imultiset(etl::ipool &node_pool, size_t max_size_)
Constructor.
Definition multiset.h:1515
Node * root_node
The node that acts as the multiset root.
Definition multiset.h:619
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:1037
~imultiset()
Destructor.
Definition multiset.h:2299
void insert(TIterator first, TIterator last)
Definition multiset.h:1347
value_compare value_comp() const
How to compare two value elements.
Definition multiset.h:1488
~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:1402
key_compare key_comp() const
How to compare two key elements.
Definition multiset.h:1480
iterator erase(const_iterator position)
Erases the value at the specified position.
Definition multiset.h:1152
const_reverse_iterator rbegin() const
Gets the reverse beginning of the list.
Definition multiset.h:1021
void detach_node(Node *&position, Node *&replacement)
Detach the node at the position provided.
Definition multiset.h:258
iterator erase(iterator position)
Erases the value at the specified position.
Definition multiset.h:1143
const_reverse_iterator crend() const
Gets the reverse end of the list.
Definition multiset.h:1053
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:617
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:563
Definition multiset.h:629
Definition multiset.h:123
Definition multiset.h:67
Definition multiset.h:81
bitset_ext
Definition absolute.h:40
ETL_CONSTEXPR14 void swap(etl::typed_storage_ext< T > &lhs, etl::typed_storage_ext< T > &rhs) ETL_NOEXCEPT
Swap two etl::typed_storage_ext.
Definition alignment.h:856
ETL_CONSTEXPR14 bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1081
bool operator>(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1133
bool operator>=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1147
ETL_CONSTEXPR14 bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1093
bool operator<(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1106
bool operator<=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1120
Definition compare.h:51
The data node element in the multiset.
Definition multiset.h:651
iterator
Definition iterator.h:424
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