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#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT
1357 //*********************************************************************
1359 //*********************************************************************
1360 template <typename... Args>
1361 iterator emplace(Args&&... args)
1362 {
1363 ETL_ASSERT(!full(), ETL_ERROR(multiset_full));
1364
1365 // Construct the value
1366 Data_Node* p_node = allocate_data_node();
1367 ::new ((void*)&p_node->value) value_type(etl::forward<Args>(args)...);
1368 ETL_INCREMENT_DEBUG_COUNT;
1369
1370 // Obtain the inserted node
1371 Node* inserted_node = insert_node(root_node, *p_node);
1372
1373 return iterator(*this, inserted_node);
1374 }
1375#else
1376 //*********************************************************************
1378 //*********************************************************************
1379 iterator emplace(const_reference value)
1380 {
1381 return insert(value);
1382 }
1383
1384 //*********************************************************************
1386 //*********************************************************************
1387 template <typename T1>
1388 iterator emplace(const T1& value1)
1389 {
1390 ETL_ASSERT(!full(), ETL_ERROR(multiset_full));
1391
1392 Data_Node* p_node = allocate_data_node();
1393 ::new ((void*)&p_node->value) value_type(value1);
1394 ETL_INCREMENT_DEBUG_COUNT;
1395
1396 Node* inserted_node = insert_node(root_node, *p_node);
1397 return iterator(*this, inserted_node);
1398 }
1399#endif
1400
1401 //*********************************************************************
1406 //*********************************************************************
1408 {
1409 return iterator(*this, find_lower_node(root_node, key));
1410 }
1411
1412#if ETL_USING_CPP11
1413 //*********************************************************************
1414 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1415 iterator lower_bound(const K& key)
1416 {
1417 return iterator(*this, find_lower_node(root_node, key));
1418 }
1419#endif
1420
1421 //*********************************************************************
1426 //*********************************************************************
1428 {
1429 return const_iterator(*this, find_lower_node(root_node, key));
1430 }
1431
1432#if ETL_USING_CPP11
1433 //*********************************************************************
1434 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1435 const_iterator lower_bound(const K& key) const
1436 {
1437 return const_iterator(*this, find_lower_node(root_node, key));
1438 }
1439#endif
1440
1441 //*********************************************************************
1446 //*********************************************************************
1448 {
1449 return iterator(*this, find_upper_node(root_node, key));
1450 }
1451
1452#if ETL_USING_CPP11
1453 //*********************************************************************
1454 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1455 iterator upper_bound(const K& key)
1456 {
1457 return iterator(*this, find_upper_node(root_node, key));
1458 }
1459#endif
1460
1461 //*********************************************************************
1466 //*********************************************************************
1468 {
1469 return const_iterator(*this, find_upper_node(root_node, key));
1470 }
1471
1472#if ETL_USING_CPP11
1473 //*********************************************************************
1474 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1475 const_iterator upper_bound(const K& key) const
1476 {
1477 return const_iterator(*this, find_upper_node(root_node, key));
1478 }
1479#endif
1480
1481 //*************************************************************************
1483 //*************************************************************************
1485 {
1486 // Skip if doing self assignment
1487 if (this != &rhs)
1488 {
1489 assign(rhs.cbegin(), rhs.cend());
1490 }
1491
1492 return *this;
1493 }
1494
1495#if ETL_USING_CPP11
1496 //*************************************************************************
1498 //*************************************************************************
1500 {
1501 // Skip if doing self assignment
1502 if (this != &rhs)
1503 {
1504 clear();
1505
1506 typename etl::imultiset<TKey, TCompare>::iterator from = rhs.begin();
1507
1508 while (from != rhs.end())
1509 {
1510 typename etl::imultiset<TKey, TCompare>::iterator temp = from;
1511 ++temp;
1512
1513 this->insert(etl::move(*from));
1514 from = temp;
1515 }
1516 }
1517
1518 return *this;
1519 }
1520#endif
1521
1522 //*************************************************************************
1524 //*************************************************************************
1525 key_compare key_comp() const
1526 {
1527 return compare;
1528 }
1529
1530 //*************************************************************************
1532 //*************************************************************************
1533 value_compare value_comp() const
1534 {
1535 return compare;
1536 }
1537
1538 //*************************************************************************
1540 //*************************************************************************
1542 {
1543 return find(key) != end();
1544 }
1545
1546#if ETL_USING_CPP11
1547 //*************************************************************************
1548 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1549 bool contains(const K& k) const
1550 {
1551 return find(k) != end();
1552 }
1553#endif
1554
1555 protected:
1556
1557 //*************************************************************************
1559 //*************************************************************************
1560 imultiset(etl::ipool& node_pool, size_t max_size_)
1561 : etl::multiset_base(max_size_)
1562 , p_node_pool(&node_pool)
1563 {
1564 }
1565
1566 //*************************************************************************
1568 //*************************************************************************
1570 {
1571 const_iterator item = begin();
1572
1573 while (item != end())
1574 {
1575 item = erase(item);
1576 }
1577 }
1578
1579 private:
1580
1581 //*************************************************************************
1583 //*************************************************************************
1584 Data_Node& allocate_data_node(const_reference value)
1585 {
1586 Data_Node* node = allocate_data_node();
1587 ::new ((void*)&node->value) value_type(value);
1588 ETL_INCREMENT_DEBUG_COUNT;
1589 return *node;
1590 }
1591
1592#if ETL_USING_CPP11
1593 //*************************************************************************
1595 //*************************************************************************
1596 Data_Node& allocate_data_node(rvalue_reference value)
1597 {
1598 Data_Node* node = allocate_data_node();
1599 ::new ((void*)&node->value) value_type(etl::move(value));
1600 ETL_INCREMENT_DEBUG_COUNT;
1601 return *node;
1602 }
1603#endif
1604
1605 //*************************************************************************
1607 //*************************************************************************
1608 Data_Node* allocate_data_node()
1609 {
1610 Data_Node* (etl::ipool::*func)() = &etl::ipool::allocate<Data_Node>;
1611 return (p_node_pool->*func)();
1612 }
1613
1614 //*************************************************************************
1616 //*************************************************************************
1617 void destroy_data_node(Data_Node& node)
1618 {
1619 node.value.~value_type();
1620 p_node_pool->release(&node);
1621 ETL_DECREMENT_DEBUG_COUNT;
1622 }
1623
1624 //*************************************************************************
1626 //*************************************************************************
1627 size_type count_nodes(key_parameter_t key) const
1628 {
1629 // Number of nodes that match the key provided result
1630 size_type result = 0;
1631
1632 // Find lower and upper nodes for the key provided
1633 const Node* lower = find_lower_node(root_node, key);
1634 const Node* upper = find_upper_node(root_node, key);
1635
1636 // Loop from lower node to upper node and find nodes that match
1637 while (lower != upper)
1638 {
1639 // Downcast found to Data_Node class for comparison and other operations
1640 const Data_Node& data_node = imultiset::data_cast(*lower);
1641
1642 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1643 {
1644 // This node matches the key provided
1645 ++result;
1646 }
1647
1648 // Move on to the next node
1649 next_node(lower);
1650 }
1651
1652 // Return the number of nodes that match
1653 return result;
1654 }
1655
1656#if ETL_USING_CPP11
1657 //*************************************************************************
1658 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1659 size_type count_nodes(const K& key) const
1660 {
1661 // Number of nodes that match the key provided result
1662 size_type result = 0;
1663
1664 // Find lower and upper nodes for the key provided
1665 const Node* lower = find_lower_node(root_node, key);
1666 const Node* upper = find_upper_node(root_node, key);
1667
1668 // Loop from lower node to upper node and find nodes that match
1669 while (lower != upper)
1670 {
1671 // Downcast found to Data_Node class for comparison and other operations
1672 const Data_Node& data_node = imultiset::data_cast(*lower);
1673
1674 if (!node_comp(key, data_node) && !node_comp(data_node, key))
1675 {
1676 // This node matches the key provided
1677 ++result;
1678 }
1679
1680 // Move on to the next node
1681 next_node(lower);
1682 }
1683
1684 // Return the number of nodes that match
1685 return result;
1686 }
1687#endif
1688
1689 //*************************************************************************
1691 //*************************************************************************
1692 Node* find_node(Node* position, key_parameter_t key)
1693 {
1694 Node* found = ETL_NULLPTR;
1695 while (position)
1696 {
1697 // Downcast found to Data_Node class for comparison and other operations
1698 Data_Node& data_node = imultiset::data_cast(*position);
1699 // Compare the node value to the current position value
1700 if (node_comp(key, data_node))
1701 {
1702 // Keep searching for the node on the left
1703 position = position->children[kLeft];
1704 }
1705 else if (node_comp(data_node, key))
1706 {
1707 // Keep searching for the node on the right
1708 position = position->children[kRight];
1709 }
1710 else
1711 {
1712 // We found one, keep looking for more on the left
1713 found = position;
1714 position = position->children[kLeft];
1715 }
1716 }
1717
1718 // Return the node found (might be ETL_NULLPTR)
1719 return found;
1720 }
1721
1722#if ETL_USING_CPP11
1723 //*************************************************************************
1724 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1725 Node* find_node(Node* position, const K& key)
1726 {
1727 Node* found = ETL_NULLPTR;
1728 while (position)
1729 {
1730 // Downcast found to Data_Node class for comparison and other operations
1731 Data_Node& data_node = imultiset::data_cast(*position);
1732 // Compare the node value to the current position value
1733 if (node_comp(key, data_node))
1734 {
1735 // Keep searching for the node on the left
1736 position = position->children[kLeft];
1737 }
1738 else if (node_comp(data_node, key))
1739 {
1740 // Keep searching for the node on the right
1741 position = position->children[kRight];
1742 }
1743 else
1744 {
1745 // We found one, keep looking for more on the left
1746 found = position;
1747 position = position->children[kLeft];
1748 }
1749 }
1750
1751 // Return the node found (might be ETL_NULLPTR)
1752 return found;
1753 }
1754#endif
1755
1756 //*************************************************************************
1758 //*************************************************************************
1759 const Node* find_node(const Node* position, key_parameter_t key) const
1760 {
1761 const Node* found = ETL_NULLPTR;
1762 while (position)
1763 {
1764 // Downcast found to Data_Node class for comparison and other operations
1765 const Data_Node& data_node = imultiset::data_cast(*position);
1766 // Compare the node value to the current position value
1767 if (node_comp(key, data_node))
1768 {
1769 // Keep searching for the node on the left
1770 position = position->children[kLeft];
1771 }
1772 else if (node_comp(data_node, key))
1773 {
1774 // Keep searching for the node on the right
1775 position = position->children[kRight];
1776 }
1777 else
1778 {
1779 // We found one, keep looking for more on the left
1780 found = position;
1781 position = position->children[kLeft];
1782 }
1783 }
1784
1785 // Return the node found (might be ETL_NULLPTR)
1786 return found;
1787 }
1788
1789#if ETL_USING_CPP11
1790 //*************************************************************************
1791 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1792 const Node* find_node(const Node* position, const K& key) const
1793 {
1794 const Node* found = ETL_NULLPTR;
1795 while (position)
1796 {
1797 // Downcast found to Data_Node class for comparison and other operations
1798 const Data_Node& data_node = imultiset::data_cast(*position);
1799 // Compare the node value to the current position value
1800 if (node_comp(key, data_node))
1801 {
1802 // Keep searching for the node on the left
1803 position = position->children[kLeft];
1804 }
1805 else if (node_comp(data_node, key))
1806 {
1807 // Keep searching for the node on the right
1808 position = position->children[kRight];
1809 }
1810 else
1811 {
1812 // We found one, keep looking for more on the left
1813 found = position;
1814 position = position->children[kLeft];
1815 }
1816 }
1817
1818 // Return the node found (might be ETL_NULLPTR)
1819 return found;
1820 }
1821#endif
1822
1823 //*************************************************************************
1825 //*************************************************************************
1826 Node* find_lower_node(Node* position, key_parameter_t key) const
1827 {
1828 // Something at this position? keep going
1829 Node* lower_node = ETL_NULLPTR;
1830 while (position)
1831 {
1832 // Downcast lower node to Data_Node reference for key comparisons
1833 Data_Node& data_node = imultiset::data_cast(*position);
1834 // Compare the key value to the current lower node key value
1835 if (node_comp(key, data_node))
1836 {
1837 lower_node = position;
1838 if (position->children[kLeft])
1839 {
1840 position = position->children[kLeft];
1841 }
1842 else
1843 {
1844 // Found lowest node
1845 break;
1846 }
1847 }
1848 else if (node_comp(data_node, key))
1849 {
1850 position = position->children[kRight];
1851 }
1852 else
1853 {
1854 // Make note of current position, but keep looking to left for more
1855 lower_node = position;
1856 position = position->children[kLeft];
1857 }
1858 }
1859
1860 // Return the lower_node position found
1861 return lower_node;
1862 }
1863
1864#if ETL_USING_CPP11
1865 //*************************************************************************
1866 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1867 Node* find_lower_node(Node* position, const K& key) const
1868 {
1869 // Something at this position? keep going
1870 Node* lower_node = ETL_NULLPTR;
1871 while (position)
1872 {
1873 // Downcast lower node to Data_Node reference for key comparisons
1874 Data_Node& data_node = imultiset::data_cast(*position);
1875 // Compare the key value to the current lower node key value
1876 if (node_comp(key, data_node))
1877 {
1878 lower_node = position;
1879 if (position->children[kLeft])
1880 {
1881 position = position->children[kLeft];
1882 }
1883 else
1884 {
1885 // Found lowest node
1886 break;
1887 }
1888 }
1889 else if (node_comp(data_node, key))
1890 {
1891 position = position->children[kRight];
1892 }
1893 else
1894 {
1895 // Make note of current position, but keep looking to left for more
1896 lower_node = position;
1897 position = position->children[kLeft];
1898 }
1899 }
1900
1901 // Return the lower_node position found
1902 return lower_node;
1903 }
1904#endif
1905
1906 //*************************************************************************
1908 //*************************************************************************
1909 Node* find_upper_node(Node* position, key_parameter_t key) const
1910 {
1911 // Keep track of parent of last upper node
1912 Node* upper_node = ETL_NULLPTR;
1913 // Has an equal node been found? start with no
1914 bool found = false;
1915 while (position)
1916 {
1917 // Downcast position to Data_Node reference for key comparisons
1918 Data_Node& data_node = imultiset::data_cast(*position);
1919 // Compare the key value to the current upper node key value
1920 if (node_comp(data_node, key))
1921 {
1922 position = position->children[kRight];
1923 }
1924 else if (node_comp(key, data_node))
1925 {
1926 upper_node = position;
1927 // If a node equal to key hasn't been found go left
1928 if (!found && position->children[kLeft])
1929 {
1930 position = position->children[kLeft];
1931 }
1932 else
1933 {
1934 break;
1935 }
1936 }
1937 else
1938 {
1939 // We found an equal item, break on next bigger item
1940 found = true;
1941 next_node(position);
1942 }
1943 }
1944
1945 // Return the upper node position found (might be ETL_NULLPTR)
1946 return upper_node;
1947 }
1948
1949#if ETL_USING_CPP11
1950 //*************************************************************************
1951 template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
1952 Node* find_upper_node(Node* position, const K& key) const
1953 {
1954 // Keep track of parent of last upper node
1955 Node* upper_node = ETL_NULLPTR;
1956 // Has an equal node been found? start with no
1957 bool found = false;
1958 while (position)
1959 {
1960 // Downcast position to Data_Node reference for key comparisons
1961 Data_Node& data_node = imultiset::data_cast(*position);
1962 // Compare the key value to the current upper node key value
1963 if (node_comp(data_node, key))
1964 {
1965 position = position->children[kRight];
1966 }
1967 else if (node_comp(key, data_node))
1968 {
1969 upper_node = position;
1970 // If a node equal to key hasn't been found go left
1971 if (!found && position->children[kLeft])
1972 {
1973 position = position->children[kLeft];
1974 }
1975 else
1976 {
1977 break;
1978 }
1979 }
1980 else
1981 {
1982 // We found an equal item, break on next bigger item
1983 found = true;
1984 next_node(position);
1985 }
1986 }
1987
1988 // Return the upper node position found (might be ETL_NULLPTR)
1989 return upper_node;
1990 }
1991#endif
1992
1993 //*************************************************************************
1995 //*************************************************************************
1996 Node* insert_node(Node*& position, Data_Node& node)
1997 {
1998 // Find the location where the node belongs
1999 Node* found = position;
2000
2001 // Was position provided not empty? then find where the node belongs
2002 if (position)
2003 {
2004 // Find the critical parent node (default to ETL_NULLPTR)
2005 Node* critical_parent_node = ETL_NULLPTR;
2006 Node* critical_node = root_node;
2007
2008 while (found)
2009 {
2010 // Search for critical weight node (all nodes whose weight factor
2011 // is set to kNeither (balanced)
2012 if (kNeither != found->weight)
2013 {
2014 critical_node = found;
2015 }
2016
2017 // Downcast found to Data_Node class for comparison and other
2018 // operations
2019 Data_Node& found_data_node = imultiset::data_cast(*found);
2020
2021 // Is the node provided to the left of the current position?
2022 if (node_comp(node, found_data_node))
2023 {
2024 // Update direction taken to insert new node in parent node
2025 found->dir = kLeft;
2026 }
2027 // Is the node provided to the right of the current position?
2028 else if (node_comp(found_data_node, node))
2029 {
2030 // Update direction taken to insert new node in parent node
2031 found->dir = kRight;
2032 }
2033 else
2034 {
2035 // Update direction taken to insert new node in parent (and
2036 // duplicate) node to the right.
2037 found->dir = kRight;
2038 }
2039
2040 // Is there a child of this parent node?
2041 if (found->children[found->dir])
2042 {
2043 // Will this node be the parent of the next critical node whose
2044 // weight factor is set to kNeither (balanced)?
2045 if (kNeither != found->children[found->dir]->weight)
2046 {
2047 critical_parent_node = found;
2048 }
2049
2050 // Keep looking for empty spot to insert new node
2051 found = found->children[found->dir];
2052 }
2053 else
2054 {
2055 // Attach node as a child of the parent node found
2056 attach_node(found, found->children[found->dir], node);
2057
2058 // Return newly added node
2059 found = found->children[found->dir];
2060
2061 // Exit loop
2062 break;
2063 }
2064 }
2065
2066 // Was a critical node found that should be checked for balance?
2067 if (critical_node)
2068 {
2069 if (critical_parent_node == ETL_NULLPTR && critical_node == root_node)
2070 {
2072 }
2073 else if (critical_parent_node == ETL_NULLPTR && critical_node == position)
2074 {
2075 balance_node(position);
2076 }
2077 else
2078 {
2079 if (critical_parent_node != ETL_NULLPTR)
2080 {
2081 balance_node(critical_parent_node->children[critical_parent_node->dir]);
2082 }
2083 }
2084 }
2085 }
2086 else
2087 {
2088 // Attach node to current position (which is assumed to be root)
2089 attach_node(ETL_NULLPTR, position, node);
2090
2091 // Return newly added node at current position
2092 found = position;
2093 }
2094
2095 // Return the node found (might be ETL_NULLPTR)
2096 return found;
2097 }
2098
2099 //*************************************************************************
2102 //*************************************************************************
2103 void remove_node(Node* node)
2104 {
2105 // If valid found node was provided then proceed with steps 1 through 5
2106 if (node)
2107 {
2108 // Downcast found node provided to Data_Node class
2109 Data_Node& data_node = imultiset::data_cast(*node);
2110
2111 // Keep track of node as found node
2112 Node* found = node;
2113
2114 // Step 1: Mark path from node provided back to the root node using the
2115 // internal temporary dir member value and using the parent pointer.
2116 // This will allow us to avoid recursion in finding the node in a tree
2117 // that might contain duplicate keys to be found.
2118 while (node)
2119 {
2120 if (node->parent)
2121 {
2122 // Which direction does parent use to get to this node?
2123 node->parent->dir = node->parent->children[kLeft] == node ? kLeft : kRight;
2124
2125 // Make this nodes parent the next node
2126 node = node->parent;
2127 }
2128 else
2129 {
2130 // Root node found - break loop
2131 break;
2132 }
2133 }
2134
2135 // Step 2: Follow the path provided above until we reach the node
2136 // provided and look for the balance node to start rebalancing the tree
2137 // from (up to the replacement node that will be found in step 3)
2138 Node* balance = root_node;
2139 while (node)
2140 {
2141 // Did we reach the node provided originally (found) then go to step 3
2142 if (node == found)
2143 {
2144 // Update the direction towards a replacement node at the found node
2145 node->dir = node->children[kLeft] ? kLeft : kRight;
2146
2147 // Exit loop and proceed with step 3
2148 break;
2149 }
2150 else
2151 {
2152 // If this nodes weight is kNeither or we are taking the shorter
2153 // path to the next node and our sibling (on longer path) is
2154 // balanced then we need to update the balance node to this node but
2155 // all our ancestors will not require rebalancing
2156 if ((node->weight == kNeither) || (node->weight == (1 - node->dir) && node->children[1 - node->dir]->weight == kNeither))
2157 {
2158 // Update balance node to this node
2159 balance = node;
2160 }
2161
2162 // Keep searching for found in the direction provided in step 1
2163 node = node->children[node->dir];
2164 }
2165 }
2166 // The value for node should not be ETL_NULLPTR at this point otherwise
2167 // step 1 failed to provide the correct path to found. Step 5 will fail
2168 // (probably subtly) if node should be ETL_NULLPTR at this point
2169
2170 // Step 3: Find the node (node should be equal to found at this point)
2171 // to replace found with (might end up equal to found) while also
2172 // continuing to update balance the same as in step 2 above.
2173 while (node)
2174 {
2175 // Replacement node found if its missing a child in the replace->dir
2176 // value set at the end of step 2 above
2177 if (node->children[node->dir] == ETL_NULLPTR)
2178 {
2179 // Exit loop once node to replace found is determined
2180 break;
2181 }
2182
2183 // If this nodes weight is kNeither or we are taking the shorter path
2184 // to the next node and our sibling (on longer path) is balanced then
2185 // we need to update the balance node to this node but all our
2186 // ancestors will not require rebalancing
2187 if ((node->weight == kNeither) || (node->weight == (1 - node->dir) && node->children[1 - node->dir]->weight == kNeither))
2188 {
2189 // Update balance node to this node
2190 balance = node;
2191 }
2192
2193 // Keep searching for replacement node in the direction specified
2194 // above
2195 node = node->children[node->dir];
2196
2197 // Downcast node to Data_Node class for comparison operations
2198 Data_Node& replace_data_node = imultiset::data_cast(*node);
2199
2200 // Compare the key provided to the replace data node key
2201 if (node_comp(data_node, replace_data_node))
2202 {
2203 // Update the direction to the replace node
2204 node->dir = kLeft;
2205 }
2206 else if (node_comp(replace_data_node, data_node))
2207 {
2208 // Update the direction to the replace node
2209 node->dir = kRight;
2210 }
2211 else
2212 {
2213 // Update the direction to the replace node
2214 node->dir = 1 - found->dir;
2215 }
2216 } // while(node)
2217
2218 // Step 4: Update weights from balance to parent of node determined
2219 // in step 3 above rotating (2 or 3 node rotations) as needed.
2220 while (balance)
2221 {
2222 // Break when balance node reaches the parent of replacement node
2223 if (balance->children[balance->dir] == ETL_NULLPTR)
2224 {
2225 break;
2226 }
2227
2228 // If balance node is balanced already (kNeither) then just imbalance
2229 // the node in the opposite direction of the node being removed
2230 if (balance->weight == kNeither)
2231 {
2232 balance->weight = 1 - balance->dir;
2233 }
2234 // If balance node is imbalanced in the opposite direction of the
2235 // node being removed then the node now becomes balanced
2236 else if (balance->weight == balance->dir)
2237 {
2238 balance->weight = kNeither;
2239 }
2240 // Otherwise a rotation is required at this node
2241 else
2242 {
2243 int weight = balance->children[1 - balance->dir]->weight;
2244 // Perform a 3 node rotation if weight is same as balance->dir
2245 if (weight == balance->dir)
2246 {
2247 // Is the root node being rebalanced (no parent)
2248 if (balance->parent == ETL_NULLPTR)
2249 {
2250 rotate_3node(root_node, 1 - balance->dir, balance->children[1 - balance->dir]->children[balance->dir]->weight);
2251 }
2252 else
2253 {
2254 rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
2255 balance->children[1 - balance->dir]->children[balance->dir]->weight);
2256 }
2257 }
2258 // Already balanced, rebalance and make it heavy in opposite
2259 // direction of the node being removed
2260 else if (weight == kNeither)
2261 {
2262 // Is the root node being rebalanced (no parent)
2263 if (balance->parent == ETL_NULLPTR)
2264 {
2265 rotate_2node(root_node, 1 - balance->dir);
2266 root_node->weight = balance->dir;
2267 }
2268 else
2269 {
2270 // Balance parent might change during rotate, keep local copy
2271 // to old parent so its weight can be updated after the 2 node
2272 // rotate is completed
2273 Node* old_parent = balance->parent;
2274 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2275 old_parent->children[old_parent->dir]->weight = balance->dir;
2276 }
2277 // Update balance node weight in opposite direction of node
2278 // removed
2279 balance->weight = 1 - balance->dir;
2280 }
2281 // Rebalance and leave it balanced
2282 else
2283 {
2284 // Is the root node being rebalanced (no parent)
2285 if (balance->parent == ETL_NULLPTR)
2286 {
2287 rotate_2node(root_node, 1 - balance->dir);
2288 }
2289 else
2290 {
2291 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
2292 }
2293 }
2294 }
2295
2296 // Next balance node to consider
2297 balance = balance->children[balance->dir];
2298 } // while(balance)
2299
2300 // Step 5: Swap found with node (replacement)
2301 if (found->parent)
2302 {
2303 // Handle traditional case
2304 detach_node(found->parent->children[found->parent->dir], node->parent->children[node->parent->dir]);
2305 }
2306 // Handle root node removal
2307 else
2308 {
2309 // Valid replacement node for root node being removed?
2310 if (node->parent)
2311 {
2312 detach_node(root_node, node->parent->children[node->parent->dir]);
2313 }
2314 else
2315 {
2316 // Found node and replacement node are both root node
2318 }
2319 }
2320
2321 // One less.
2322 --current_size;
2323
2324 // Destroy the node detached above
2325 destroy_data_node(data_node);
2326 } // if(found)
2327 }
2328
2329 // Disable copy construction.
2330 imultiset(const imultiset&);
2331
2332 //*************************************************************************
2334 //*************************************************************************
2335#if defined(ETL_POLYMORPHIC_MULTISET) || defined(ETL_POLYMORPHIC_CONTAINERS)
2336
2337 public:
2338
2339 virtual ~imultiset() {}
2340#else
2341
2342 protected:
2343
2345#endif
2346 };
2347
2348 //*************************************************************************
2350 //*************************************************************************
2351 template <typename TKey, const size_t MAX_SIZE_, typename TCompare = ETL_OR_STD::less<TKey> >
2352 class multiset : public etl::imultiset<TKey, TCompare>
2353 {
2354 public:
2355
2356 static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_;
2357
2358 //*************************************************************************
2360 //*************************************************************************
2362 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2363 {
2364 this->initialise();
2365 }
2366
2367 //*************************************************************************
2369 //*************************************************************************
2370 multiset(const multiset& other)
2371 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2372 {
2373 this->assign(other.cbegin(), other.cend());
2374 }
2375
2376#if ETL_USING_CPP11
2377 //*************************************************************************
2379 //*************************************************************************
2380 multiset(multiset&& other)
2381 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2382 {
2383 if (this != &other)
2384 {
2385 typename etl::imultiset<TKey, TCompare>::iterator from = other.begin();
2386
2387 while (from != other.end())
2388 {
2389 typename etl::imultiset<TKey, TCompare>::iterator temp = from;
2390 ++temp;
2391
2392 this->insert(etl::move(*from));
2393 from = temp;
2394 }
2395 }
2396 }
2397#endif
2398
2399 //*************************************************************************
2404 //*************************************************************************
2405 template <typename TIterator>
2406 multiset(TIterator first, TIterator last)
2407 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2408 {
2409 this->assign(first, last);
2410 }
2411
2412#if ETL_HAS_INITIALIZER_LIST
2413 //*************************************************************************
2415 //*************************************************************************
2416 multiset(std::initializer_list<typename etl::imultiset<TKey, TCompare>::value_type> init)
2417 : etl::imultiset<TKey, TCompare>(node_pool, MAX_SIZE)
2418 {
2419 this->assign(init.begin(), init.end());
2420 }
2421#endif
2422
2423 //*************************************************************************
2425 //*************************************************************************
2427 {
2428 this->initialise();
2429 }
2430
2431 //*************************************************************************
2433 //*************************************************************************
2435 {
2436 // Skip if doing self assignment
2437 if (this != &rhs)
2438 {
2439 this->assign(rhs.cbegin(), rhs.cend());
2440 }
2441
2442 return *this;
2443 }
2444
2445#if ETL_USING_CPP11
2446 //*************************************************************************
2448 //*************************************************************************
2450 {
2451 if (this != &rhs)
2452 {
2453 this->clear();
2454
2455 typename etl::imultiset<TKey, TCompare>::iterator from = rhs.begin();
2456
2457 while (from != rhs.end())
2458 {
2459 this->insert(etl::move(*from));
2460 ++from;
2461 }
2462 }
2463
2464 return *this;
2465 }
2466#endif
2467
2468 private:
2469
2471 etl::pool<typename etl::imultiset<TKey, TCompare>::Data_Node, MAX_SIZE> node_pool;
2472 };
2473
2474 template <typename TKey, const size_t MAX_SIZE_, typename TCompare>
2475 ETL_CONSTANT size_t multiset<TKey, MAX_SIZE_, TCompare>::MAX_SIZE;
2476
2477 //*************************************************************************
2479 //*************************************************************************
2480#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
2481 template <typename... T>
2482 multiset(T...) -> multiset<etl::nth_type_t<0, T...>, sizeof...(T)>;
2483#endif
2484
2485 //*************************************************************************
2487 //*************************************************************************
2488#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
2489 template <typename TKey, typename TKeyCompare = etl::less<TKey>, typename... T>
2490 constexpr auto make_multiset(T&&... keys) -> etl::multiset<TKey, sizeof...(T), TKeyCompare>
2491 {
2492 return {etl::forward<T>(keys)...};
2493 }
2494#endif
2495
2496 //***************************************************************************
2502 //***************************************************************************
2503 template <typename TKey, typename TCompare>
2505 {
2506 return (lhs.size() == rhs.size()) && ETL_OR_STD::equal(lhs.begin(), lhs.end(), rhs.begin());
2507 }
2508
2509 //***************************************************************************
2515 //***************************************************************************
2516 template <typename TKey, typename TCompare>
2518 {
2519 return !(lhs == rhs);
2520 }
2521
2522 //*************************************************************************
2528 //*************************************************************************
2529 template <typename TKey, typename TCompare>
2531 {
2532 return ETL_OR_STD::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), etl::imultiset<TKey, TCompare>::value_compare());
2533 }
2534
2535 //*************************************************************************
2541 //*************************************************************************
2542 template <typename TKey, typename TCompare>
2544 {
2545 return (rhs < lhs);
2546 }
2547
2548 //*************************************************************************
2555 //*************************************************************************
2556 template <typename TKey, typename TCompare>
2558 {
2559 return !(lhs > rhs);
2560 }
2561
2562 //*************************************************************************
2568 //*************************************************************************
2569 template <typename TKey, typename TCompare>
2571 {
2572 return !(lhs < rhs);
2573 }
2574} // namespace etl
2575
2576#include "private/minmax_pop.h"
2577
2578#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:2353
multiset(const multiset &other)
Copy constructor.
Definition multiset.h:2370
multiset()
Default constructor.
Definition multiset.h:2361
~multiset()
Destructor.
Definition multiset.h:2426
multiset & operator=(const multiset &rhs)
Assignment operator.
Definition multiset.h:2434
multiset(TIterator first, TIterator last)
Definition multiset.h:2406
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
Definition exception.h:59
T * allocate()
Definition ipool.h:334
Definition ipool.h:110
iterator begin()
Gets the beginning of the multiset.
Definition multiset.h:965
iterator lower_bound(key_parameter_t key)
Definition multiset.h:1407
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:1467
size_type count(key_parameter_t key) const
Definition multiset.h:1086
imultiset & operator=(const imultiset &rhs)
Assignment operator.
Definition multiset.h:1484
bool contains(key_parameter_t key) const
Check if the set contains the key.
Definition multiset.h:1541
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 emplace(const_reference value)
Emplaces a value to the multiset.
Definition multiset.h:1379
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:1427
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:1569
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:1560
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:2344
void insert(TIterator first, TIterator last)
Definition multiset.h:1347
value_compare value_comp() const
How to compare two value elements.
Definition multiset.h:1533
~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:1447
key_compare key_comp() const
How to compare two key elements.
Definition multiset.h:1525
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
iterator emplace(const T1 &value1)
Emplaces a value to the multiset.
Definition multiset.h:1388
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
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:1078
bool operator>(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1130
bool operator>=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1144
ETL_CONSTEXPR14 bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1090
bool operator<(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1103
bool operator<=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1117
Definition compare.h:51
The data node element in the multiset.
Definition multiset.h:651
iterator
Definition iterator.h:482
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
ETL_CONSTEXPR14 bool operator==(const etl::to_arithmetic_result< T > &lhs, const etl::to_arithmetic_result< T > &rhs)
Equality test for etl::to_arithmetic_result.
Definition to_arithmetic.h:903
ETL_CONSTEXPR14 bool operator!=(const etl::to_arithmetic_result< T > &lhs, const etl::to_arithmetic_result< T > &rhs)
Inequality test for etl::to_arithmetic_result.
Definition to_arithmetic.h:937