Embedded Template Library 1.0
Loading...
Searching...
No Matches
intrusive_list.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) 2016 John Wellbelove
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_INTRUSIVE_LIST_INCLUDED
32#define ETL_INTRUSIVE_LIST_INCLUDED
33
34#include "platform.h"
35#include "nullptr.h"
36#include "type_traits.h"
37#include "exception.h"
38#include "error_handler.h"
39#include "intrusive_links.h"
40#include "static_assert.h"
41#include "algorithm.h"
42#include "iterator.h"
43#include "functional.h"
44
45#include <stddef.h>
46
47#include "private/minmax_push.h"
48
49namespace etl
50{
51 //***************************************************************************
54 //***************************************************************************
55 class intrusive_list_exception : public exception
56 {
57 public:
58
59 intrusive_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
60 : exception(reason_, file_name_, line_number_)
61 {
62 }
63 };
64
65 //***************************************************************************
68 //***************************************************************************
69 class intrusive_list_empty : public intrusive_list_exception
70 {
71 public:
72
73 intrusive_list_empty(string_type file_name_, numeric_type line_number_)
74 : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:empty", ETL_INTRUSIVE_LIST_FILE_ID"A"), file_name_, line_number_)
75 {
76 }
77 };
78
79 //***************************************************************************
82 //***************************************************************************
83 class intrusive_list_iterator_exception : public intrusive_list_exception
84 {
85 public:
86
87 intrusive_list_iterator_exception(string_type file_name_, numeric_type line_number_)
88 : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:iterator", ETL_INTRUSIVE_LIST_FILE_ID"B"), file_name_, line_number_)
89 {
90 }
91 };
92
93 //***************************************************************************
96 //***************************************************************************
97 class intrusive_list_unsorted : public intrusive_list_exception
98 {
99 public:
100
101 intrusive_list_unsorted(string_type file_name_, numeric_type line_number_)
102 : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:unsorted", ETL_INTRUSIVE_LIST_FILE_ID"C"), file_name_, line_number_)
103 {
104 }
105 };
106
107 //***************************************************************************
110 //***************************************************************************
111 class intrusive_list_value_is_already_linked : public intrusive_list_exception
112 {
113 public:
114
115 intrusive_list_value_is_already_linked(string_type file_name_, numeric_type line_number_)
116 : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:value is already linked", ETL_INTRUSIVE_LIST_FILE_ID"D"), file_name_, line_number_)
117 {
118 }
119 };
120
121 //***************************************************************************
124 //***************************************************************************
125 template <typename TLink>
127 {
128 public:
129
130 // Node typedef.
131 typedef TLink link_type;
132
133 //*************************************************************************
137 //*************************************************************************
138 template <typename TIterator>
139 void assign(TIterator first, TIterator last)
140 {
141#if ETL_IS_DEBUG_BUILD
142 intmax_t d = etl::distance(first, last);
144#endif
145
146 initialise();
147
148 link_type* p_last_link = &terminal_link;
149
150 // Add all of the elements.
151 while (first != last)
152 {
153 link_type& link = *first++;
154 etl::link_splice<link_type>(p_last_link, link);
155 p_last_link = &link;
156 ++current_size;
157 }
158 }
159
160 //*************************************************************************
162 //*************************************************************************
163 void push_front(link_type& value)
164 {
165 ETL_ASSERT_OR_RETURN(!value.is_linked(), ETL_ERROR(intrusive_list_value_is_already_linked));
166
168 }
169
170 //*************************************************************************
172 //*************************************************************************
174 {
175 ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(intrusive_list_empty));
176
178 }
179
180 //*************************************************************************
182 //*************************************************************************
183 void push_back(link_type& value)
184 {
185 ETL_ASSERT_OR_RETURN(!value.is_linked(), ETL_ERROR(intrusive_list_value_is_already_linked));
186
187 insert_link(terminal_link.link_type::etl_previous, value);
188 }
189
190 //*************************************************************************
192 //*************************************************************************
193 void pop_back()
194 {
195 ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(intrusive_list_empty));
196
198 }
199
200 //*************************************************************************
202 //*************************************************************************
203 void clear()
204 {
205 // Unlink all of the items.
206 link_type* p_unlink = terminal_link.etl_next;
207
208 while (p_unlink != &terminal_link)
209 {
210 link_type* p_next = p_unlink->etl_next;
211 p_unlink->clear();
212 p_unlink = p_next;
213 }
214
215 initialise();
216 }
217
218 //*************************************************************************
220 //*************************************************************************
221 void reverse()
222 {
223 if (is_trivial_list())
224 {
225 return;
226 }
227
228 link_type* pnode = terminal_link.etl_next;
229
230 while (pnode != &terminal_link)
231 {
232 pnode->reverse();
233 pnode = pnode->etl_previous; // Now we've reversed it, we must go to the previous node.
234 }
235
236 // Terminal node.
237 pnode->reverse();
238 }
239
240 //*************************************************************************
242 //*************************************************************************
243 bool empty() const
244 {
245 return (terminal_link.link_type::etl_next == &terminal_link);
246 }
247
248 //*************************************************************************
250 //*************************************************************************
251 size_t size() const
252 {
253 return current_size;
254 }
255
256 //*************************************************************************
259 //*************************************************************************
260 bool contains_node(const link_type& search_link) const
261 {
262 return is_link_in_list(&search_link);;
263 }
264
265 //*************************************************************************
268 //*************************************************************************
269 bool contains_node(const link_type* search_link) const
270 {
271 return is_link_in_list(search_link);;
272 }
273
274 protected:
275
277 link_type terminal_link;
278
280
281 //*************************************************************************
283 //*************************************************************************
285 {
286 }
287
288 //*************************************************************************
290 //*************************************************************************
291 bool is_trivial_list() const
292 {
293 return (terminal_link.link_type::etl_next == &terminal_link) || (terminal_link.link_type::etl_next->etl_next == &terminal_link);
294 }
295
296 //*************************************************************************
298 //*************************************************************************
299 void insert_link(link_type& previous, link_type& new_link)
300 {
301 // Connect to the intrusive_list.
302 etl::link_splice<link_type>(previous, new_link);
303 ++current_size;
304 }
305
306 //*************************************************************************
308 //*************************************************************************
309 void insert_link(link_type* previous, link_type& new_link)
310 {
311 // Connect to the intrusive_list.
312 etl::link_splice<link_type>(previous, new_link);
313 ++current_size;
314 }
315
316 //*************************************************************************
318 //*************************************************************************
319 void insert_link(link_type& previous, link_type* new_link)
320 {
321 // Connect to the intrusive_list.
322 etl::link_splice<link_type>(previous, new_link);
323 ++current_size;
324 }
325
326 //*************************************************************************
328 //*************************************************************************
329 void insert_link(link_type* previous, link_type* new_link)
330 {
331 // Connect to the intrusive_list.
332 etl::link_splice<link_type>(previous, new_link);
333 ++current_size;
334 }
335
336 //*************************************************************************
338 //*************************************************************************
339 void disconnect_link(link_type& link)
340 {
341 etl::unlink<link_type>(link);
342 --current_size;
343 }
344
345 //*************************************************************************
347 //*************************************************************************
348 void disconnect_link(link_type* link)
349 {
350 etl::unlink<link_type>(*link);
351 --current_size;
352 }
353
354 //*************************************************************************
356 //*************************************************************************
357 link_type* get_head()
358 {
359 return terminal_link.etl_next;
360 }
361
362 //*************************************************************************
364 //*************************************************************************
365 const link_type* get_head() const
366 {
367 return terminal_link.etl_next;
368 }
369
370 //*************************************************************************
372 //*************************************************************************
373 link_type* get_tail()
374 {
375 return terminal_link.etl_previous;
376 }
377
378 //*************************************************************************
380 //*************************************************************************
381 const link_type* get_tail() const
382 {
383 return terminal_link.etl_previous;
384 }
385
386 //*************************************************************************
388 //*************************************************************************
390 {
391 etl::link(terminal_link, terminal_link);
392 current_size = 0;
393 }
394
395 //*************************************************************************
397 //*************************************************************************
398 bool is_link_in_list(const link_type* search_link) const
399 {
400 link_type* p_link = terminal_link.link_type::etl_next;
401
402 while (p_link != &terminal_link)
403 {
404 if (search_link == p_link)
405 {
406 return true;
407 }
408
409 p_link = p_link->link_type::etl_next;
410 }
411
412 return false;
413 }
414
415 //*************************************************************************
418 //*************************************************************************
419 link_type* remove_link(link_type* link)
420 {
421 link_type* result = ETL_NULLPTR;
422
423 if (is_link_in_list(link))
424 {
425 link_type* p_next = link->etl_next;
426
427 disconnect_link(link);
428
429 if (p_next != &terminal_link)
430 {
431 result = p_next;
432 }
433 }
434
435 return result;
436 }
437
438 //*************************************************************************
440 //*************************************************************************
441 link_type* remove_link_range(link_type* p_first, link_type* p_last)
442 {
443 // Join the ends.
444 etl::link<link_type>(p_first->etl_previous, p_last);
445
446 while (p_first != p_last)
447 {
448 link_type* p_next = p_first->etl_next;
449 p_first->clear();
450 p_first = p_next;
451 }
452
453 if (p_last == &terminal_link)
454 {
455 return ETL_NULLPTR;
456 }
457 else
458 {
459 return p_last;
460 }
461 }
462 };
463
464 //***************************************************************************
468 //***************************************************************************
469 template <typename TValue, typename TLink>
471 {
472 public:
473
474 // Node typedef.
475 typedef typename etl::intrusive_list_base<TLink>::link_type link_type;
476
477 typedef intrusive_list<TValue, TLink> list_type;
478
479 typedef TValue node_type;
480
481 // STL style typedefs.
482 typedef TValue value_type;
483 typedef value_type* pointer;
484 typedef const value_type* const_pointer;
485 typedef value_type& reference;
486 typedef const value_type& const_reference;
487 typedef size_t size_type;
488
489 //*************************************************************************
491 //*************************************************************************
492 class iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, value_type>
493 {
494 public:
495
496 friend class intrusive_list;
497 friend class const_iterator;
498
499 iterator()
500 : p_value(ETL_NULLPTR)
501 {
502 }
503
504 iterator(const iterator& other)
505 : p_value(other.p_value)
506 {
507 }
508
509 iterator& operator ++()
510 {
511 // Read the appropriate 'etl_next'.
512 p_value = p_value->etl_next;
513 return *this;
514 }
515
516 iterator operator ++(int)
517 {
518 iterator temp(*this);
519 // Read the appropriate 'etl_next'.
520 p_value = p_value->etl_next;
521 return temp;
522 }
523
524 iterator& operator --()
525 {
526 // Read the appropriate 'etl_previous'.
527 p_value = p_value->etl_previous;
528 return *this;
529 }
530
531 iterator operator --(int)
532 {
533 iterator temp(*this);
534 // Read the appropriate 'etl_previous'.
535 p_value = p_value->etl_previous;
536 return temp;
537 }
538
539 iterator& operator =(const iterator& other)
540 {
541 p_value = other.p_value;
542 return *this;
543 }
544
545 reference operator *() const
546 {
548 return *static_cast<pointer>(p_value);
550 }
551
552 pointer operator &() const
553 {
554 return static_cast<pointer>(p_value);
555 }
556
557 pointer operator ->() const
558 {
559 return static_cast<pointer>(p_value);
560 }
561
562 friend bool operator == (const iterator& lhs, const iterator& rhs)
563 {
564 return lhs.p_value == rhs.p_value;
565 }
566
567 friend bool operator != (const iterator& lhs, const iterator& rhs)
568 {
569 return !(lhs == rhs);
570 }
571
572 private:
573
574 iterator(link_type* value)
575 : p_value(value)
576 {
577 }
578
579 link_type* p_value;
580 };
581
582 //*************************************************************************
584 //*************************************************************************
585 class const_iterator : public etl::iterator<ETL_OR_STD::bidirectional_iterator_tag, const value_type>
586 {
587 public:
588
589 friend class intrusive_list;
590
591 const_iterator()
592 : p_value(ETL_NULLPTR)
593 {
594 }
595
596 const_iterator(const typename intrusive_list::iterator& other)
597 : p_value(other.p_value)
598 {
599 }
600
601 const_iterator(const const_iterator& other)
602 : p_value(other.p_value)
603 {
604 }
605
606 const_iterator& operator ++()
607 {
608 // Read the appropriate 'etl_next'.
609 p_value = p_value->etl_next;
610 return *this;
611 }
612
613 const_iterator operator ++(int)
614 {
615 const_iterator temp(*this);
616 // Read the appropriate 'etl_next'.
617 p_value = p_value->etl_next;
618 return temp;
619 }
620
621 const_iterator& operator --()
622 {
623 // Read the appropriate 'etl_previous'.
624 p_value = p_value->etl_previous;
625 return *this;
626 }
627
628 const_iterator operator --(int)
629 {
630 const_iterator temp(*this);
631 // Read the appropriate 'etl_previous'.
632 p_value = p_value->etl_previous;
633 return temp;
634 }
635
636 const_iterator& operator =(const const_iterator& other)
637 {
638 p_value = other.p_value;
639 return *this;
640 }
641
642 const_reference operator *() const
643 {
644 return *static_cast<const_pointer>(p_value);
645 }
646
647 const_pointer operator &() const
648 {
649 return static_cast<const_pointer>(p_value);
650 }
651
652 const_pointer operator ->() const
653 {
654 return static_cast<const_pointer>(p_value);
655 }
656
657 friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
658 {
659 return lhs.p_value == rhs.p_value;
660 }
661
662 friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
663 {
664 return !(lhs == rhs);
665 }
666
667 private:
668
669 const_iterator(const link_type* value)
670 : p_value(value)
671 {
672 }
673
674 const link_type* p_value;
675 };
676
677 typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
678
679 //*************************************************************************
681 //*************************************************************************
683 {
684 this->initialise();
685 }
686
687 //*************************************************************************
689 //*************************************************************************
691 {
692 this->clear();
693 }
694
695 //*************************************************************************
697 //*************************************************************************
698 template <typename TIterator>
699 intrusive_list(TIterator first, TIterator last, typename etl::enable_if<!etl::is_integral<TIterator>::value, int>::type = 0)
700 {
701 this->assign(first, last);
702 }
703
704#if ETL_USING_CPP11
705 //*************************************************************************
707 //*************************************************************************
708 template <typename... TLinks>
709 intrusive_list(link_type& first, TLinks&... links)
710 {
711 ETL_STATIC_ASSERT((etl::is_base_of_all<link_type, TLinks...>::value), "Mixed link types");
712
713 this->current_size = 0;
714 this->terminal_link.etl_next = &first;
715 link_type* last = make_linked_list(this->current_size, first, static_cast<link_type&>(links)...);
716 first.etl_previous = &this->terminal_link;
717 last->etl_next = &this->terminal_link;
718 this->terminal_link.etl_previous = last;
719 }
720#endif
721
722 //*************************************************************************
724 //*************************************************************************
726 {
727 return iterator(this->get_head());
728 }
729
730 //*************************************************************************
732 //*************************************************************************
734 {
735 return const_iterator(this->get_head());
736 }
737
738 //*************************************************************************
740 //*************************************************************************
742 {
743 return const_iterator(this->get_head());
744 }
745
746 //*************************************************************************
748 //*************************************************************************
750 {
751 return iterator(&this->terminal_link);
752 }
753
754 //*************************************************************************
756 //*************************************************************************
758 {
759 return const_iterator(&this->terminal_link);
760 }
761
762 //*************************************************************************
764 //*************************************************************************
766 {
767 return const_iterator(&this->terminal_link);
768 }
769
770 //*************************************************************************
772 //*************************************************************************
773 reference front()
774 {
775 return *static_cast<pointer>(this->get_head());
776 }
777
778 //*************************************************************************
780 //*************************************************************************
781 const_reference front() const
782 {
783 return *static_cast<const_pointer>(this->get_head());
784 }
785
786 //*************************************************************************
788 //*************************************************************************
789 reference back()
790 {
791 return *static_cast<pointer>(this->get_tail());
792 }
793
794 //*************************************************************************
796 //*************************************************************************
797 const_reference back() const
798 {
799 return *static_cast<const_pointer>(this->get_tail());
800 }
801
802 //*************************************************************************
804 //*************************************************************************
805 iterator insert(const_iterator position, value_type& value)
806 {
807 this->insert_link(position.p_value->link_type::etl_previous, value);
808 return iterator(&value);
809 }
810
811 //*************************************************************************
813 //*************************************************************************
814 template <typename TIterator>
815 void insert(const_iterator position, TIterator first, TIterator last)
816 {
817 while (first != last)
818 {
819 // Set up the next free link.
820 this->insert_link(*position.p_value->link_type::etl_previous, *first);
821 ++first;
822 }
823 }
824
825 //*************************************************************************
827 //*************************************************************************
829 {
830 iterator next(position);
831 ++next;
832
833 this->disconnect_link(*position.p_value);
834
835 return next;
836 }
837
838 //*************************************************************************
840 //*************************************************************************
842 {
843 iterator next(position);
844 ++next;
845
846 this->disconnect_link(*position.p_value);
847
848 return next;
849 }
850
851 //*************************************************************************
854 //*************************************************************************
856 {
857 const link_type* cp_first = first.p_value;
858 const link_type* cp_last = last.p_value;
859
860 link_type* p_first = const_cast<link_type*>(cp_first);
861 link_type* p_last = const_cast<link_type*>(cp_last);
862
863 this->current_size -= etl::distance(first, last);
864
865 p_last = this->remove_link_range(p_first, p_last);
866
867 if (p_last == ETL_NULLPTR)
868 {
869 return end();
870 }
871 else
872 {
873 return iterator(static_cast<pointer>(p_last));
874 }
875 }
876
877 //*************************************************************************
879 //*************************************************************************
880 node_type* erase(const node_type& node)
881 {
882 return static_cast<node_type*>(this->remove_link(const_cast<node_type*>(&node)));
883 }
884
885 //*************************************************************************
887 //*************************************************************************
888 node_type* erase(const node_type* p_node)
889 {
890 return static_cast<node_type*>(this->remove_link(const_cast<node_type*>(p_node)));
891 }
892
893 //*************************************************************************
896 //*************************************************************************
897 template <typename TIsEqual>
898 void unique(TIsEqual isEqual)
899 {
900 if (this->empty())
901 {
902 return;
903 }
904
905 iterator i_item = begin();
906 ++i_item;
907 iterator i_previous = begin();
908
909 while (i_item != end())
910 {
911 if (isEqual(*i_previous, *i_item))
912 {
913 i_item = erase(i_item);
914 }
915 else
916 {
917 i_previous = i_item;
918 ++i_item;
919 }
920 }
921 }
922
923 //*************************************************************************
925 //*************************************************************************
926 void sort()
927 {
929 }
930
931 //*************************************************************************
955 //*************************************************************************
956 template <typename TCompare>
957 void sort(TCompare compare)
958 {
959 iterator i_left;
960 iterator i_right;
961 iterator i_node;
962 iterator i_head;
963 iterator i_tail;
964 int list_size = 1;
965 int number_of_merges;
966 int left_size;
967 int right_size;
968
969 if (this->is_trivial_list())
970 {
971 return;
972 }
973
974 while (true)
975 {
976 i_left = begin();
977 i_head = end();
978 i_tail = end();
979
980 number_of_merges = 0; // Count the number of merges we do in this pass.
981
982 while (i_left != end())
983 {
984 ++number_of_merges; // There exists a merge to be done.
985 i_right = i_left;
986 left_size = 0;
987
988 // Step 'list_size' places along from left
989 for (int i = 0; i < list_size; ++i)
990 {
991 ++left_size;
992 ++i_right;
993
994 if (i_right == end())
995 {
996 break;
997 }
998 }
999
1000 // If right hasn't fallen off end, we have two lists to merge.
1001 right_size = list_size;
1002
1003 // Now we have two lists. Merge them.
1004 while (left_size > 0 || (right_size > 0 && i_right != end()))
1005 {
1006 // Decide whether the next node of merge comes from left or right.
1007 if (left_size == 0)
1008 {
1009 // Left is empty. The node must come from right.
1010 i_node = i_right++;
1011 --right_size;
1012 }
1013 else if (right_size == 0 || i_right == end())
1014 {
1015 // Right is empty. The node must come from left.
1016 i_node = i_left++;
1017 --left_size;
1018 }
1019 else if (!compare(*i_right, *i_left))
1020 {
1021 // First node of left is lower or same. The node must come from left.
1022 i_node = i_left++;
1023 --left_size;
1024 }
1025 else
1026 {
1027 // First node of right is lower. The node must come from right.
1028 i_node = i_right;
1029 ++i_right;
1030 --right_size;
1031 }
1032
1033 // Add the next node to the merged head.
1034 if (i_head == end())
1035 {
1036 etl::link<link_type>(i_head.p_value, i_node.p_value);
1037 i_head = i_node;
1038 i_tail = i_node;
1039 }
1040 else
1041 {
1042 etl::link<link_type>(i_tail.p_value, i_node.p_value);
1043 i_tail = i_node;
1044 }
1045
1046 etl::link<link_type>(i_tail.p_value, this->terminal_link);
1047 }
1048
1049 // Now left has stepped `list_size' places along, and right has too.
1050 i_left = i_right;
1051 }
1052
1053 // If we have done only one merge, we're finished.
1054 if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case
1055 {
1056 return;
1057 }
1058
1059 // Otherwise repeat, merging lists twice the size
1060 list_size *= 2;
1061 }
1062 }
1063
1064 //*************************************************************************
1065 // Removes the values specified.
1066 //*************************************************************************
1067 void remove(const_reference value)
1068 {
1069 iterator i_item = begin();
1070
1071 while (i_item != end())
1072 {
1073 if (*i_item == value)
1074 {
1075 i_item = erase(i_item);
1076 }
1077 else
1078 {
1079 ++i_item;
1080 }
1081 }
1082 }
1083
1084 //*************************************************************************
1086 //*************************************************************************
1087 template <typename TPredicate>
1088 void remove_if(TPredicate predicate)
1089 {
1090 iterator i_item = begin();
1091
1092 while (i_item != end())
1093 {
1094 if (predicate(*i_item))
1095 {
1096 i_item = erase(i_item);
1097 }
1098 else
1099 {
1100 ++i_item;
1101 }
1102 }
1103 }
1104
1105 //*************************************************************************
1107 //*************************************************************************
1108 void splice(iterator position, list_type& other)
1109 {
1110 // No point splicing to ourself!
1111 if (&other != this)
1112 {
1113 if (!other.empty())
1114 {
1115 link_type& first = *other.get_head();
1116 link_type& last = *other.get_tail();
1117
1118 if (&other != this)
1119 {
1120 this->current_size += other.size();
1121 }
1122
1123 link_type& after = *position.p_value;
1124 link_type& before = *after.etl_previous;
1125
1126 etl::link<link_type>(before, first);
1127 etl::link<link_type>(last, after);
1128
1129 other.initialise();
1130 }
1131 }
1132 }
1133
1134 //*************************************************************************
1136 //*************************************************************************
1137 void splice(iterator position, list_type& other, iterator isource)
1138 {
1139 link_type& before = *position.p_value->link_type::etl_previous;
1140
1141 etl::unlink<link_type>(*isource.p_value);
1142 etl::link_splice<link_type>(before, *isource.p_value);
1143
1144 if (&other != this)
1145 {
1146 ++this->current_size;
1147 --other.current_size;
1148 }
1149 }
1150
1151 //*************************************************************************
1153 //*************************************************************************
1154 void splice(iterator position, list_type& other, iterator begin_, iterator end_)
1155 {
1156 if (!other.empty())
1157 {
1158 if (&other != this)
1159 {
1160 size_t n = etl::distance(begin_, end_);
1161 this->current_size += n;
1162 other.current_size -= n;
1163 }
1164
1165 link_type& first = *begin_.p_value;
1166 link_type& last = *end_.p_value->link_type::etl_previous;
1167
1168 // Unlink from the source list.
1169 etl::unlink(first, last);
1170
1171 // Fix our links.
1172 link_type& before = *position.p_value->link_type::etl_previous;
1173
1174 etl::link_splice<link_type>(before, first, last);
1175 }
1176 }
1177
1178 //*************************************************************************
1180 //*************************************************************************
1181 void merge(list_type& other)
1182 {
1183 merge(other, etl::less<value_type>());
1184 }
1185
1186 //*************************************************************************
1188 //*************************************************************************
1189 template <typename TCompare>
1190 void merge(list_type& other, TCompare compare)
1191 {
1192 if ((this != &other) && !other.empty())
1193 {
1194#if ETL_IS_DEBUG_BUILD
1195 ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(intrusive_list_unsorted));
1197#endif
1198
1199 link_type* other_begin = other.get_head();
1200 link_type* other_end = &other.terminal_link;
1201
1202 link_type* this_begin = this->get_head();
1203 link_type* this_end = &this->terminal_link;
1204
1205 while ((this_begin != this_end) && (other_begin != other_end))
1206 {
1207 // Find the place to insert.
1208 while ((this_begin != this_end) && !(compare(*static_cast<pointer>(other_begin), *static_cast<pointer>(this_begin))))
1209 {
1210 this_begin = this_begin->etl_next;
1211 }
1212
1213 // Insert.
1214 if (this_begin != this_end)
1215 {
1216 while ((other_begin != other_end) && (compare(*static_cast<pointer>(other_begin), *static_cast<pointer>(this_begin))))
1217 {
1218 link_type* value = other_begin;
1219 other_begin = other_begin->etl_next;
1220 etl::link_splice<link_type>(*this_begin->etl_previous, *value);
1221 }
1222 }
1223 }
1224
1225 // Any left over?
1226 if ((this_begin == this_end) && (other_begin != other_end))
1227 {
1228 etl::link_splice<link_type>(*this->get_tail(), *other_begin, *other_end->etl_previous);
1229 }
1230
1231 this->current_size += other.size();
1232
1233 other.initialise();
1234 }
1235 }
1236
1237 //*************************************************************************
1240 //*************************************************************************
1241 bool contains(const_reference value) const
1242 {
1243 const_iterator i_item = begin();
1244
1245 while (i_item != end())
1246 {
1247 if (*i_item == value)
1248 {
1249 return true;
1250 }
1251
1252 ++i_item;
1253 }
1254
1255 return false;
1256 }
1257
1258 private:
1259
1260#if ETL_USING_CPP17
1261 //***************************************************************************
1263 //***************************************************************************
1264 template <typename... TLinks>
1265 link_type* make_linked_list(size_t& count, link_type& first, TLinks&... links)
1266 {
1267 TLink* current = &first;
1268 ++count;
1269 ((current->etl_next = &links, static_cast<TLink&>(links).etl_previous = current, current = &links, ++count), ...);
1270
1271 return current;
1272 }
1273#elif ETL_USING_CPP11
1274 //***************************************************************************
1276 //***************************************************************************
1277 link_type* make_linked_list(size_t& count, link_type& first)
1278 {
1279 ++count;
1280
1281 return &first;
1282 }
1283
1284 //***************************************************************************
1286 //***************************************************************************
1287 template <typename... TLinks>
1288 link_type* make_linked_list(size_t& count, link_type& first, link_type& next, TLinks&... links)
1289 {
1290 ++count;
1291 first.etl_next = &next;
1292 next.etl_previous = &first;
1293
1294 return make_linked_list(count, next, static_cast<link_type&>(links)...);
1295 }
1296#endif
1297
1298 // Disabled.
1299 intrusive_list(const intrusive_list& other);
1300 intrusive_list& operator = (const intrusive_list& rhs);
1301 };
1302}
1303
1304#include "private/minmax_pop.h"
1305
1306#endif
const_iterator
Definition intrusive_list.h:586
iterator.
Definition intrusive_list.h:493
Definition intrusive_list.h:127
void disconnect_link(link_type *link)
Remove a link.
Definition intrusive_list.h:348
size_t size() const
Returns the number of elements.
Definition intrusive_list.h:251
link_type * get_tail()
Get the tail link.
Definition intrusive_list.h:373
void insert_link(link_type &previous, link_type &new_link)
Insert a link.
Definition intrusive_list.h:299
~intrusive_list_base()
Destructor.
Definition intrusive_list.h:284
void assign(TIterator first, TIterator last)
Definition intrusive_list.h:139
bool contains_node(const link_type *search_link) const
Definition intrusive_list.h:269
size_t current_size
Definition intrusive_list.h:279
bool is_link_in_list(const link_type *search_link) const
Tests if the link is in this list.
Definition intrusive_list.h:398
void disconnect_link(link_type &link)
Remove a link.
Definition intrusive_list.h:339
void insert_link(link_type &previous, link_type *new_link)
Insert a link.
Definition intrusive_list.h:319
void pop_back()
Removes a value from the back of the intrusive_list.
Definition intrusive_list.h:193
link_type * get_head()
Get the head link.
Definition intrusive_list.h:357
bool empty() const
Returns true if the list has no elements.
Definition intrusive_list.h:243
link_type * remove_link_range(link_type *p_first, link_type *p_last)
Removes a range of links.
Definition intrusive_list.h:441
void initialise()
Initialise the intrusive_list.
Definition intrusive_list.h:389
void reverse()
Reverses the list.
Definition intrusive_list.h:221
void insert_link(link_type *previous, link_type *new_link)
Insert a link.
Definition intrusive_list.h:329
const link_type * get_head() const
Get the head link.
Definition intrusive_list.h:365
link_type terminal_link
Definition intrusive_list.h:277
void insert_link(link_type *previous, link_type &new_link)
Insert a link.
Definition intrusive_list.h:309
void clear()
Clears the intrusive_list.
Definition intrusive_list.h:203
void push_front(link_type &value)
Pushes a value to the front of the intrusive_list.
Definition intrusive_list.h:163
void push_back(link_type &value)
Pushes a value to the back of the intrusive_list.
Definition intrusive_list.h:183
void pop_front()
Removes a value from the front of the intrusive_list.
Definition intrusive_list.h:173
bool contains_node(const link_type &search_link) const
Definition intrusive_list.h:260
const link_type * get_tail() const
Get the tail link.
Definition intrusive_list.h:381
bool is_trivial_list() const
Is the intrusive_list a trivial length?
Definition intrusive_list.h:291
link_type * remove_link(link_type *link)
Definition intrusive_list.h:419
Definition intrusive_list.h:70
Definition intrusive_list.h:84
Definition intrusive_list.h:98
Definition intrusive_list.h:112
~intrusive_list()
Destructor.
Definition intrusive_list.h:690
const_iterator end() const
Gets the end of the intrusive_list.
Definition intrusive_list.h:757
reference back()
Gets a reference to the last element.
Definition intrusive_list.h:789
iterator begin()
Gets the beginning of the intrusive_list.
Definition intrusive_list.h:725
node_type * erase(const node_type &node)
Erases the specified node.
Definition intrusive_list.h:880
void unique(TIsEqual isEqual)
Definition intrusive_list.h:898
const_iterator begin() const
Gets the beginning of the intrusive_list.
Definition intrusive_list.h:733
void splice(iterator position, list_type &other)
Splice another list into this one.
Definition intrusive_list.h:1108
iterator erase(const_iterator position)
Erases the value at the specified position.
Definition intrusive_list.h:841
void splice(iterator position, list_type &other, iterator begin_, iterator end_)
Splice a range of elements from another list into this one.
Definition intrusive_list.h:1154
reference front()
Gets a reference to the first element.
Definition intrusive_list.h:773
void insert(const_iterator position, TIterator first, TIterator last)
Inserts a range of values to the intrusive_list after the specified position.
Definition intrusive_list.h:815
void merge(list_type &other, TCompare compare)
Merge another list into this one. Both lists should be sorted.
Definition intrusive_list.h:1190
bool contains(const_reference value) const
Definition intrusive_list.h:1241
void sort(TCompare compare)
Definition intrusive_list.h:957
void splice(iterator position, list_type &other, iterator isource)
Splice an element from another list into this one.
Definition intrusive_list.h:1137
intrusive_list()
Constructor.
Definition intrusive_list.h:682
iterator erase(const_iterator first, const_iterator last)
Definition intrusive_list.h:855
const_iterator cend() const
Gets the end of the intrusive_list.
Definition intrusive_list.h:765
iterator erase(iterator position)
Erases the value at the specified position.
Definition intrusive_list.h:828
const_iterator cbegin() const
Gets the beginning of the intrusive_list.
Definition intrusive_list.h:741
void remove_if(TPredicate predicate)
Removes according to a predicate.
Definition intrusive_list.h:1088
void sort()
Sort using in-place merge sort algorithm.
Definition intrusive_list.h:926
iterator insert(const_iterator position, value_type &value)
Inserts a value to the intrusive_list before the specified position.
Definition intrusive_list.h:805
const_reference front() const
Gets a const reference to the first element.
Definition intrusive_list.h:781
iterator end()
Gets the end of the intrusive_list.
Definition intrusive_list.h:749
node_type * erase(const node_type *p_node)
Erases the specified node.
Definition intrusive_list.h:888
intrusive_list(TIterator first, TIterator last, typename etl::enable_if<!etl::is_integral< TIterator >::value, int >::type=0)
Constructor from range.
Definition intrusive_list.h:699
const_reference back() const
Gets a const reference to the last element.
Definition intrusive_list.h:797
void merge(list_type &other)
Merge another list into this one. Both lists should be sorted.
Definition intrusive_list.h:1181
ETL_CONSTEXPR14 bool operator==(const etl::expected< TValue, TError > &lhs, const etl::expected< TValue2, TError2 > &rhs)
Equivalence operators.
Definition expected.h:962
ETL_NODISCARD ETL_CONSTEXPR14 bool is_sorted(TIterator begin, TIterator end)
Definition algorithm.h:1709
ETL_CONSTEXPR14 TIterator remove(TIterator first, TIterator last, const T &value)
Definition algorithm.h:2300
#define ETL_ASSERT(b, e)
Definition error_handler.h:356
ETL_CONSTEXPR exception(string_type reason_, string_type, numeric_type line_)
Constructor.
Definition exception.h:69
enable_if
Definition type_traits_generator.h:1254
bitset_ext
Definition absolute.h:39
ETL_CONSTEXPR14 enable_if<!etl::is_specialization< TRep2, etl::chrono::duration >::value, etl::chrono::duration< typenameetl::common_type< TRep1, TRep2 >::type, TPeriod1 > >::type operator*(const etl::chrono::duration< TRep1, TPeriod1 > &lhs, const TRep2 &rhs) ETL_NOEXCEPT
Operator *.
Definition duration.h:545
Definition compare.h:51
iterator
Definition iterator.h:399
Definition functional.h:170