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 "algorithm.h"
36#include "error_handler.h"
37#include "exception.h"
38#include "functional.h"
39#include "intrusive_links.h"
40#include "iterator.h"
41#include "nullptr.h"
42#include "static_assert.h"
43#include "type_traits.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
234 // previous node.
235 }
236
237 // Terminal node.
238 pnode->reverse();
239 }
240
241 //*************************************************************************
243 //*************************************************************************
244 bool empty() const
245 {
246 return (terminal_link.link_type::etl_next == &terminal_link);
247 }
248
249 //*************************************************************************
251 //*************************************************************************
252 size_t size() const
253 {
254 return current_size;
255 }
256
257 //*************************************************************************
260 //*************************************************************************
261 bool contains_node(const link_type& search_link) const
262 {
263 return is_link_in_list(&search_link);
264 }
265
266 //*************************************************************************
269 //*************************************************************************
270 bool contains_node(const link_type* search_link) const
271 {
272 return is_link_in_list(search_link);
273 }
274
275 protected:
276
278 link_type terminal_link;
279
281
282 //*************************************************************************
284 //*************************************************************************
286
287 //*************************************************************************
289 //*************************************************************************
290 bool is_trivial_list() const
291 {
292 return (terminal_link.link_type::etl_next == &terminal_link) || (terminal_link.link_type::etl_next->etl_next == &terminal_link);
293 }
294
295 //*************************************************************************
297 //*************************************************************************
298 void insert_link(link_type& previous, link_type& new_link)
299 {
300 // Connect to the intrusive_list.
301 etl::link_splice<link_type>(previous, new_link);
302 ++current_size;
303 }
304
305 //*************************************************************************
307 //*************************************************************************
308 void insert_link(link_type* previous, link_type& new_link)
309 {
310 // Connect to the intrusive_list.
311 etl::link_splice<link_type>(previous, new_link);
312 ++current_size;
313 }
314
315 //*************************************************************************
317 //*************************************************************************
318 void insert_link(link_type& previous, link_type* new_link)
319 {
320 // Connect to the intrusive_list.
321 etl::link_splice<link_type>(previous, new_link);
322 ++current_size;
323 }
324
325 //*************************************************************************
327 //*************************************************************************
328 void insert_link(link_type* previous, link_type* new_link)
329 {
330 // Connect to the intrusive_list.
331 etl::link_splice<link_type>(previous, new_link);
332 ++current_size;
333 }
334
335 //*************************************************************************
337 //*************************************************************************
338 void disconnect_link(link_type& link)
339 {
340 etl::unlink<link_type>(link);
341 --current_size;
342 }
343
344 //*************************************************************************
346 //*************************************************************************
347 void disconnect_link(link_type* link)
348 {
349 etl::unlink<link_type>(*link);
350 --current_size;
351 }
352
353 //*************************************************************************
355 //*************************************************************************
356 link_type* get_head()
357 {
358 return terminal_link.etl_next;
359 }
360
361 //*************************************************************************
363 //*************************************************************************
364 const link_type* get_head() const
365 {
366 return terminal_link.etl_next;
367 }
368
369 //*************************************************************************
371 //*************************************************************************
372 link_type* get_tail()
373 {
374 return terminal_link.etl_previous;
375 }
376
377 //*************************************************************************
379 //*************************************************************************
380 const link_type* get_tail() const
381 {
382 return terminal_link.etl_previous;
383 }
384
385 //*************************************************************************
387 //*************************************************************************
389 {
390 etl::link(terminal_link, terminal_link);
391 current_size = 0;
392 }
393
394 //*************************************************************************
396 //*************************************************************************
397 bool is_link_in_list(const link_type* search_link) const
398 {
399 link_type* p_link = terminal_link.link_type::etl_next;
400
401 while (p_link != &terminal_link)
402 {
403 if (search_link == p_link)
404 {
405 return true;
406 }
407
408 p_link = p_link->link_type::etl_next;
409 }
410
411 return false;
412 }
413
414 //*************************************************************************
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 //*************************************************************************
774 //*************************************************************************
775 reference front()
776 {
777 ETL_ASSERT_CHECK_EXTRA(!this->empty(), ETL_ERROR(intrusive_list_empty));
778 return *static_cast<pointer>(this->get_head());
779 }
780
781 //*************************************************************************
785 //*************************************************************************
786 const_reference front() const
787 {
788 ETL_ASSERT_CHECK_EXTRA(!this->empty(), ETL_ERROR(intrusive_list_empty));
789 return *static_cast<const_pointer>(this->get_head());
790 }
791
792 //*************************************************************************
796 //*************************************************************************
797 reference back()
798 {
799 ETL_ASSERT_CHECK_EXTRA(!this->empty(), ETL_ERROR(intrusive_list_empty));
800 return *static_cast<pointer>(this->get_tail());
801 }
802
803 //*************************************************************************
807 //*************************************************************************
808 const_reference back() const
809 {
810 ETL_ASSERT_CHECK_EXTRA(!this->empty(), ETL_ERROR(intrusive_list_empty));
811 return *static_cast<const_pointer>(this->get_tail());
812 }
813
814 //*************************************************************************
816 //*************************************************************************
817 iterator insert(const_iterator position, value_type& value)
818 {
819 this->insert_link(position.p_value->link_type::etl_previous, value);
820 return iterator(&value);
821 }
822
823 //*************************************************************************
826 //*************************************************************************
827 template <typename TIterator>
828 void insert(const_iterator position, TIterator first, TIterator last)
829 {
830 while (first != last)
831 {
832 // Set up the next free link.
833 this->insert_link(*position.p_value->link_type::etl_previous, *first);
834 ++first;
835 }
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 //*************************************************************************
853 //*************************************************************************
855 {
856 iterator next(position);
857 ++next;
858
859 this->disconnect_link(*position.p_value);
860
861 return next;
862 }
863
864 //*************************************************************************
867 //*************************************************************************
869 {
870 const link_type* cp_first = first.p_value;
871 const link_type* cp_last = last.p_value;
872
873 link_type* p_first = const_cast<link_type*>(cp_first);
874 link_type* p_last = const_cast<link_type*>(cp_last);
875
876 this->current_size -= static_cast<size_t>(etl::distance(first, last));
877
878 p_last = this->remove_link_range(p_first, p_last);
879
880 if (p_last == ETL_NULLPTR)
881 {
882 return end();
883 }
884 else
885 {
886 return iterator(static_cast<pointer>(p_last));
887 }
888 }
889
890 //*************************************************************************
892 //*************************************************************************
893 node_type* erase(const node_type& node)
894 {
895 return static_cast<node_type*>(this->remove_link(const_cast<node_type*>(&node)));
896 }
897
898 //*************************************************************************
900 //*************************************************************************
901 node_type* erase(const node_type* p_node)
902 {
903 return static_cast<node_type*>(this->remove_link(const_cast<node_type*>(p_node)));
904 }
905
906 //*************************************************************************
909 //*************************************************************************
910 template <typename TIsEqual>
911 void unique(TIsEqual isEqual)
912 {
913 if (this->empty())
914 {
915 return;
916 }
917
918 iterator i_item = begin();
919 ++i_item;
920 iterator i_previous = begin();
921
922 while (i_item != end())
923 {
924 if (isEqual(*i_previous, *i_item))
925 {
926 i_item = erase(i_item);
927 }
928 else
929 {
930 i_previous = i_item;
931 ++i_item;
932 }
933 }
934 }
935
936 //*************************************************************************
938 //*************************************************************************
939 void sort()
940 {
942 }
943
944 //*************************************************************************
968 //*************************************************************************
969 template <typename TCompare>
970 void sort(TCompare compare)
971 {
972 iterator i_left;
973 iterator i_right;
974 iterator i_node;
975 iterator i_head;
976 iterator i_tail;
977 int list_size = 1;
978 int number_of_merges;
979 int left_size;
980 int right_size;
981
982 if (this->is_trivial_list())
983 {
984 return;
985 }
986
987 while (true)
988 {
989 i_left = begin();
990 i_head = end();
991 i_tail = end();
992
993 number_of_merges = 0; // Count the number of merges we do in this pass.
994
995 while (i_left != end())
996 {
997 ++number_of_merges; // There exists a merge to be done.
998 i_right = i_left;
999 left_size = 0;
1000
1001 // Step 'list_size' places along from left
1002 for (int i = 0; i < list_size; ++i)
1003 {
1004 ++left_size;
1005 ++i_right;
1006
1007 if (i_right == end())
1008 {
1009 break;
1010 }
1011 }
1012
1013 // If right hasn't fallen off end, we have two lists to merge.
1014 right_size = list_size;
1015
1016 // Now we have two lists. Merge them.
1017 while (left_size > 0 || (right_size > 0 && i_right != end()))
1018 {
1019 // Decide whether the next node of merge comes from left or right.
1020 if (left_size == 0)
1021 {
1022 // Left is empty. The node must come from right.
1023 i_node = i_right++;
1024 --right_size;
1025 }
1026 else if (right_size == 0 || i_right == end())
1027 {
1028 // Right is empty. The node must come from left.
1029 i_node = i_left++;
1030 --left_size;
1031 }
1032 else if (!compare(*i_right, *i_left))
1033 {
1034 // First node of left is lower or same. The node must come from
1035 // left.
1036 i_node = i_left++;
1037 --left_size;
1038 }
1039 else
1040 {
1041 // First node of right is lower. The node must come from right.
1042 i_node = i_right;
1043 ++i_right;
1044 --right_size;
1045 }
1046
1047 // Add the next node to the merged head.
1048 if (i_head == end())
1049 {
1050 etl::link<link_type>(i_head.p_value, i_node.p_value);
1051 i_head = i_node;
1052 i_tail = i_node;
1053 }
1054 else
1055 {
1056 etl::link<link_type>(i_tail.p_value, i_node.p_value);
1057 i_tail = i_node;
1058 }
1059
1060 etl::link<link_type>(i_tail.p_value, this->terminal_link);
1061 }
1062
1063 // Now left has stepped `list_size' places along, and right has too.
1064 i_left = i_right;
1065 }
1066
1067 // If we have done only one merge, we're finished.
1068 if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case
1069 {
1070 return;
1071 }
1072
1073 // Otherwise repeat, merging lists twice the size
1074 list_size *= 2;
1075 }
1076 }
1077
1078 //*************************************************************************
1079 // Removes the values specified.
1080 //*************************************************************************
1081 void remove(const_reference value)
1082 {
1083 iterator i_item = begin();
1084
1085 while (i_item != end())
1086 {
1087 if (*i_item == value)
1088 {
1089 i_item = erase(i_item);
1090 }
1091 else
1092 {
1093 ++i_item;
1094 }
1095 }
1096 }
1097
1098 //*************************************************************************
1100 //*************************************************************************
1101 template <typename TPredicate>
1102 void remove_if(TPredicate predicate)
1103 {
1104 iterator i_item = begin();
1105
1106 while (i_item != end())
1107 {
1108 if (predicate(*i_item))
1109 {
1110 i_item = erase(i_item);
1111 }
1112 else
1113 {
1114 ++i_item;
1115 }
1116 }
1117 }
1118
1119 //*************************************************************************
1121 //*************************************************************************
1122 void splice(iterator position, list_type& other)
1123 {
1124 // No point splicing to ourself!
1125 if (&other != this)
1126 {
1127 if (!other.empty())
1128 {
1129 link_type& first = *other.get_head();
1130 link_type& last = *other.get_tail();
1131
1132 if (&other != this)
1133 {
1134 this->current_size += other.size();
1135 }
1136
1137 link_type& after = *position.p_value;
1138 link_type& before = *after.etl_previous;
1139
1140 etl::link<link_type>(before, first);
1141 etl::link<link_type>(last, after);
1142
1143 other.initialise();
1144 }
1145 }
1146 }
1147
1148 //*************************************************************************
1150 //*************************************************************************
1151 void splice(iterator position, list_type& other, iterator isource)
1152 {
1153 link_type& before = *position.p_value->link_type::etl_previous;
1154
1155 etl::unlink<link_type>(*isource.p_value);
1156 etl::link_splice<link_type>(before, *isource.p_value);
1157
1158 if (&other != this)
1159 {
1160 ++this->current_size;
1161 --other.current_size;
1162 }
1163 }
1164
1165 //*************************************************************************
1167 //*************************************************************************
1168 void splice(iterator position, list_type& other, iterator begin_, iterator end_)
1169 {
1170 if (!other.empty())
1171 {
1172 if (&other != this)
1173 {
1174 size_t n = static_cast<size_t>(etl::distance(begin_, end_));
1175 this->current_size += n;
1176 other.current_size -= n;
1177 }
1178
1179 link_type& first = *begin_.p_value;
1180 link_type& last = *end_.p_value->link_type::etl_previous;
1181
1182 // Unlink from the source list.
1183 etl::unlink(first, last);
1184
1185 // Fix our links.
1186 link_type& before = *position.p_value->link_type::etl_previous;
1187
1188 etl::link_splice<link_type>(before, first, last);
1189 }
1190 }
1191
1192 //*************************************************************************
1194 //*************************************************************************
1195 void merge(list_type& other)
1196 {
1197 merge(other, etl::less<value_type>());
1198 }
1199
1200 //*************************************************************************
1202 //*************************************************************************
1203 template <typename TCompare>
1204 void merge(list_type& other, TCompare compare)
1205 {
1206 if ((this != &other) && !other.empty())
1207 {
1208#if ETL_IS_DEBUG_BUILD
1209 ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(intrusive_list_unsorted));
1211#endif
1212
1213 link_type* other_begin = other.get_head();
1214 link_type* other_end = &other.terminal_link;
1215
1216 link_type* this_begin = this->get_head();
1217 link_type* this_end = &this->terminal_link;
1218
1219 while ((this_begin != this_end) && (other_begin != other_end))
1220 {
1221 // Find the place to insert.
1222 while ((this_begin != this_end) && !(compare(*static_cast<pointer>(other_begin), *static_cast<pointer>(this_begin))))
1223 {
1224 this_begin = this_begin->etl_next;
1225 }
1226
1227 // Insert.
1228 if (this_begin != this_end)
1229 {
1230 while ((other_begin != other_end) && (compare(*static_cast<pointer>(other_begin), *static_cast<pointer>(this_begin))))
1231 {
1232 link_type* value = other_begin;
1233 other_begin = other_begin->etl_next;
1234 etl::link_splice<link_type>(*this_begin->etl_previous, *value);
1235 }
1236 }
1237 }
1238
1239 // Any left over?
1240 if ((this_begin == this_end) && (other_begin != other_end))
1241 {
1242 etl::link_splice<link_type>(*this->get_tail(), *other_begin, *other_end->etl_previous);
1243 }
1244
1245 this->current_size += other.size();
1246
1247 other.initialise();
1248 }
1249 }
1250
1251 //*************************************************************************
1254 //*************************************************************************
1255 bool contains(const_reference value) const
1256 {
1257 const_iterator i_item = begin();
1258
1259 while (i_item != end())
1260 {
1261 if (*i_item == value)
1262 {
1263 return true;
1264 }
1265
1266 ++i_item;
1267 }
1268
1269 return false;
1270 }
1271
1272 private:
1273
1274#if ETL_USING_CPP17
1275 //***************************************************************************
1277 //***************************************************************************
1278 template <typename... TLinks>
1279 link_type* make_linked_list(size_t& count, link_type& first, TLinks&... links)
1280 {
1281 TLink* current = &first;
1282 ++count;
1283 ((current->etl_next = &links, static_cast<TLink&>(links).etl_previous = current, current = &links, ++count), ...);
1284
1285 return current;
1286 }
1287#elif ETL_USING_CPP11
1288 //***************************************************************************
1290 //***************************************************************************
1291 link_type* make_linked_list(size_t& count, link_type& first)
1292 {
1293 ++count;
1294
1295 return &first;
1296 }
1297
1298 //***************************************************************************
1300 //***************************************************************************
1301 template <typename... TLinks>
1302 link_type* make_linked_list(size_t& count, link_type& first, link_type& next, TLinks&... links)
1303 {
1304 ++count;
1305 first.etl_next = &next;
1306 next.etl_previous = &first;
1307
1308 return make_linked_list(count, next, static_cast<link_type&>(links)...);
1309 }
1310#endif
1311
1312 // Disabled.
1313 intrusive_list(const intrusive_list& other);
1314 intrusive_list& operator=(const intrusive_list& rhs);
1315 };
1316} // namespace etl
1317
1318#include "private/minmax_pop.h"
1319
1320#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:347
size_t size() const
Returns the number of elements.
Definition intrusive_list.h:252
link_type * get_tail()
Get the tail link.
Definition intrusive_list.h:372
void insert_link(link_type &previous, link_type &new_link)
Insert a link.
Definition intrusive_list.h:298
~intrusive_list_base()
Destructor.
Definition intrusive_list.h:285
void assign(TIterator first, TIterator last)
Definition intrusive_list.h:139
bool contains_node(const link_type *search_link) const
Definition intrusive_list.h:270
size_t current_size
Definition intrusive_list.h:280
bool is_link_in_list(const link_type *search_link) const
Tests if the link is in this list.
Definition intrusive_list.h:397
void disconnect_link(link_type &link)
Remove a link.
Definition intrusive_list.h:338
void insert_link(link_type &previous, link_type *new_link)
Insert a link.
Definition intrusive_list.h:318
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:356
bool empty() const
Returns true if the list has no elements.
Definition intrusive_list.h:244
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:388
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:328
const link_type * get_head() const
Get the head link.
Definition intrusive_list.h:364
link_type terminal_link
Definition intrusive_list.h:278
void insert_link(link_type *previous, link_type &new_link)
Insert a link.
Definition intrusive_list.h:308
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:261
const link_type * get_tail() const
Get the tail link.
Definition intrusive_list.h:380
bool is_trivial_list() const
Is the intrusive_list a trivial length?
Definition intrusive_list.h:290
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()
Definition intrusive_list.h:797
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:893
void unique(TIsEqual isEqual)
Definition intrusive_list.h:911
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:1122
iterator erase(const_iterator position)
Erases the value at the specified position.
Definition intrusive_list.h:854
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:1168
reference front()
Definition intrusive_list.h:775
void insert(const_iterator position, TIterator first, TIterator last)
Definition intrusive_list.h:828
void merge(list_type &other, TCompare compare)
Merge another list into this one. Both lists should be sorted.
Definition intrusive_list.h:1204
bool contains(const_reference value) const
Definition intrusive_list.h:1255
void sort(TCompare compare)
Definition intrusive_list.h:970
void splice(iterator position, list_type &other, iterator isource)
Splice an element from another list into this one.
Definition intrusive_list.h:1151
intrusive_list()
Constructor.
Definition intrusive_list.h:682
iterator erase(const_iterator first, const_iterator last)
Definition intrusive_list.h:868
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:841
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:1102
void sort()
Sort using in-place merge sort algorithm.
Definition intrusive_list.h:939
iterator insert(const_iterator position, value_type &value)
Inserts a value to the intrusive_list before the specified position.
Definition intrusive_list.h:817
const_reference front() const
Definition intrusive_list.h:786
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:901
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
Definition intrusive_list.h:808
void merge(list_type &other)
Merge another list into this one. Both lists should be sorted.
Definition intrusive_list.h:1195
ETL_NODISCARD ETL_CONSTEXPR14 bool is_sorted(TIterator begin, TIterator end)
Definition algorithm.h:1660
ETL_CONSTEXPR14 TIterator remove(TIterator first, TIterator last, const T &value)
Definition algorithm.h:2344
ETL_CONSTEXPR14 bool operator!=(const etl::bitset< Active_Bits, TElement > &lhs, const etl::bitset< Active_Bits, TElement > &rhs) ETL_NOEXCEPT
Definition bitset_new.h:2529
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
ETL_EXCEPTION_CONSTEXPR exception(string_type reason_, string_type, numeric_type)
Constructor.
Definition exception.h:81
bitset_ext
Definition absolute.h:40
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:541
Definition compare.h:51
iterator
Definition iterator.h:424
Definition functional.h:201