source: mainline/uspace/lib/cpp/include/impl/list.hpp@ 7452b155

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7452b155 was 7452b155, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: added the rest of list tests and fixed bugs found by them

  • Property mode set to 100644
File size: 34.9 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_LIST
30#define LIBCPP_LIST
31
32#include <__bits/insert_iterator.hpp>
33#include <__bits/list.hpp>
34#include <cstdlib>
35#include <iterator>
36#include <memory>
37#include <utility>
38
39namespace std
40{
41 template<class T, class Allocator = allocator<T>>
42 class list;
43
44 namespace aux
45 {
46 template<class T>
47 class list_iterator;
48
49 template<class T>
50 class list_const_iterator
51 {
52 public:
53 using value_type = typename list<T>::value_type;
54 using reference = typename list<T>::const_reference;
55 using pointer = typename list<T>::const_pointer;
56 using difference_type = typename list<T>::difference_type;
57 using size_type = typename list<T>::size_type;
58
59 using iterator_category = bidirectional_iterator_tag;
60
61 list_const_iterator(list_node<value_type>* node = nullptr,
62 list_node<value_type>* head = nullptr,
63 bool end = true)
64 : current_{node}, head_{head}, end_{end}
65 { /* DUMMY BODY */ }
66
67 list_const_iterator(const list_const_iterator&) = default;
68 list_const_iterator& operator=(const list_const_iterator&) = default;
69 list_const_iterator(list_const_iterator&&) = default;
70 list_const_iterator& operator=(list_const_iterator&&) = default;
71
72 list_const_iterator(const list_iterator<T>& other)
73 : current_{other.node()}, head_{other.head()}, end_{other.end()}
74 { /* DUMMY BODY */ }
75
76 reference operator*() const
77 {
78 return current_->value;
79 }
80
81 list_const_iterator& operator++()
82 {
83 if (!end_ && current_)
84 {
85 if (current_->next == head_)
86 end_ = true;
87 else
88 current_ = current_->next;
89 }
90
91 return *this;
92 }
93
94 list_const_iterator operator++(int)
95 {
96 auto old = *this;
97 ++(*this);
98
99 return old;
100 }
101
102 list_const_iterator& operator--()
103 {
104 if (end_)
105 end_ = false;
106 else if (current_)
107 {
108 if (current_ != head_)
109 current_ = current_->prev;
110 else
111 end_ = true;
112 }
113
114 return *this;
115 }
116
117 list_const_iterator operator--(int)
118 {
119 auto old = *this;
120 --(*this);
121
122 return old;
123 }
124
125 list_node<value_type>* node()
126 {
127 return const_cast<list_node<value_type>*>(current_);
128 }
129
130 const list_node<value_type>* node() const
131 {
132 return current_;
133 }
134
135 list_node<value_type>* head()
136 {
137 return const_cast<list_node<value_type>*>(head_);
138 }
139
140 const list_node<value_type>* head() const
141 {
142 return head_;
143 }
144
145 list_const_iterator operator-(difference_type n) const
146 {
147 /**
148 * Note: This operator is for internal purposes only,
149 * so we do not provide inverse operator or shortcut
150 * -= operator.
151 */
152 auto tmp = current_;
153
154 for (difference_type i = 0; i < n; ++i)
155 tmp = tmp->prev;
156
157 return list_const_iterator{tmp};
158 }
159
160 bool end() const
161 {
162 return end_;
163 }
164
165 private:
166 const list_node<value_type>* current_;
167 const list_node<value_type>* head_;
168 bool end_;
169 };
170
171 template<class T>
172 bool operator==(const list_const_iterator<T>& lhs, const list_const_iterator<T>& rhs)
173 {
174 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
175 }
176
177 template<class T>
178 bool operator!=(const list_const_iterator<T>& lhs, const list_const_iterator<T>& rhs)
179 {
180 return !(lhs == rhs);
181 }
182
183 template<class T>
184 class list_iterator
185 {
186 public:
187 using value_type = typename list<T>::value_type;
188 using reference = typename list<T>::reference;
189 using pointer = typename list<T>::pointer;
190 using difference_type = typename list<T>::difference_type;
191 using size_type = typename list<T>::size_type;
192
193 using iterator_category = bidirectional_iterator_tag;
194
195 list_iterator(list_node<value_type>* node = nullptr,
196 list_node<value_type>* head = nullptr,
197 bool end = true)
198 : current_{node}, head_{head}, end_{end}
199 { /* DUMMY BODY */ }
200
201 list_iterator(const list_iterator&) = default;
202 list_iterator& operator=(const list_iterator&) = default;
203 list_iterator(list_iterator&&) = default;
204 list_iterator& operator=(list_iterator&&) = default;
205
206 reference operator*() const
207 {
208 return current_->value;
209 }
210
211 list_iterator& operator++()
212 {
213 if (!end_ && current_)
214 {
215 if (current_->next == head_)
216 end_ = true;
217 else
218 current_ = current_->next;
219 }
220
221 return *this;
222 }
223
224 list_iterator operator++(int)
225 {
226 auto old = *this;
227 ++(*this);
228
229 return old;
230 }
231
232 list_iterator& operator--()
233 {
234 if (end_)
235 end_ = false;
236 else if (current_)
237 {
238 if (current_ != head_)
239 current_ = current_->prev;
240 else
241 end_ = true;
242 }
243
244 return *this;
245 }
246
247 list_iterator operator--(int)
248 {
249 auto old = *this;
250 --(*this);
251
252 return old;
253 }
254
255 list_node<value_type>* node()
256 {
257 return current_;
258 }
259
260 const list_node<value_type>* node() const
261 {
262 return current_;
263 }
264
265 list_node<value_type>* head()
266 {
267 return head_;
268 }
269
270 const list_node<value_type>* head() const
271 {
272 return head_;
273 }
274
275 list_iterator operator-(difference_type n) const
276 {
277 /**
278 * Note: This operator is for internal purposes only,
279 * so we do not provide inverse operator or shortcut
280 * -= operator.
281 */
282 auto tmp = current_;
283
284 for (difference_type i = 0; i < n; ++i)
285 tmp = tmp->prev;
286
287 return list_iterator{tmp};
288 }
289
290 bool end() const
291 {
292 return end_;
293 }
294
295 private:
296 list_node<value_type>* current_;
297 list_node<value_type>* head_;
298 bool end_;
299 };
300
301 template<class T>
302 bool operator==(const list_iterator<T>& lhs, const list_iterator<T>& rhs)
303 {
304 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
305 }
306
307 template<class T>
308 bool operator!=(const list_iterator<T>& lhs, const list_iterator<T>& rhs)
309 {
310 return !(lhs == rhs);
311 }
312
313 template<class T>
314 bool operator==(const list_const_iterator<T>& lhs, const list_iterator<T>& rhs)
315 {
316 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
317 }
318
319 template<class T>
320 bool operator!=(const list_const_iterator<T>& lhs, const list_iterator<T>& rhs)
321 {
322 return !(lhs == rhs);
323 }
324
325 template<class T>
326 bool operator==(const list_iterator<T>& lhs, const list_const_iterator<T>& rhs)
327 {
328 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
329 }
330
331 template<class T>
332 bool operator!=(const list_iterator<T>& lhs, const list_const_iterator<T>& rhs)
333 {
334 return !(lhs == rhs);
335 }
336 }
337
338 /**
339 * 23.3.5, class template list:
340 */
341
342 template<class T, class Allocator>
343 class list
344 {
345 public:
346 using value_type = T;
347 using reference = value_type&;
348 using const_reference = const value_type&;
349 using allocator_type = Allocator;
350
351 using iterator = aux::list_iterator<value_type>;
352 using const_iterator = aux::list_const_iterator<value_type>;
353 using size_type = size_t;
354 using difference_type = ptrdiff_t;
355
356 using pointer = typename allocator_traits<allocator_type>::pointer;
357 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
358
359 using reverse_iterator = std::reverse_iterator<iterator>;
360 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
361
362 /**
363 * 23.3.5.2, construct/copy/destroy:
364 */
365
366 list()
367 : list{allocator_type{}}
368 { /* DUMMY BODY */ }
369
370 explicit list(const allocator_type& alloc)
371 : allocator_{alloc}, head_{nullptr}, size_{}
372 { /* DUMMY BODY */ }
373
374 explicit list(size_type n, const allocator_type& alloc = allocator_type{})
375 : allocator_{alloc}, head_{nullptr}, size_{}
376 {
377 init_(
378 aux::insert_iterator<value_type>{size_type{}, value_type{}},
379 aux::insert_iterator<value_type>{size_, value_type{}}
380 );
381 }
382
383 list(size_type n, const value_type& val,
384 const allocator_type& alloc = allocator_type{})
385 : allocator_{alloc}, head_{nullptr}, size_{}
386 {
387 init_(
388 aux::insert_iterator<value_type>{size_type{}, val},
389 aux::insert_iterator<value_type>{n, value_type{}}
390 );
391 }
392
393 template<class InputIterator>
394 list(InputIterator first, InputIterator last,
395 const allocator_type& alloc = allocator_type{})
396 : allocator_{alloc}, head_{nullptr}, size_{}
397 {
398 init_(first, last);
399 }
400
401 list(const list& other)
402 : list{other, other.allocator_}
403 { /* DUMMY BODY */ }
404
405 list(list&& other)
406 : allocator_{move(other.allocator_)},
407 head_{move(other.head_)},
408 size_{move(other.size_)}
409 {
410 other.head_ = nullptr;
411 other.size_ = size_type{};
412 }
413
414 list(const list& other, const allocator_type alloc)
415 : allocator_{alloc}, head_{nullptr}, size_{}
416 { // Size is set in init_.
417 init_(other.begin(), other.end());
418 }
419
420 list(list&& other, const allocator_type& alloc)
421 : allocator_{alloc},
422 head_{move(other.head_)},
423 size_{move(other.size_)}
424 {
425 other.head_ = nullptr;
426 other.size_ = size_type{};
427 }
428
429 list(initializer_list<value_type> init, const allocator_type& alloc = allocator_type{})
430 : allocator_{alloc}, head_{nullptr}, size_{}
431 {
432 init_(init.begin(), init.end());
433 }
434
435 ~list()
436 {
437 fini_();
438 }
439
440 list& operator=(const list& other)
441 {
442 fini_();
443
444 allocator_ = other.allocator_;
445
446 init_(other.begin(), other.end());
447
448 return *this;
449 }
450
451 list& operator=(list&& other)
452 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
453 {
454 fini_();
455
456 head_ = move(other.head_);
457 size_ = move(other.size_);
458 allocator_ = move(other.allocator_);
459
460 other.head_ = nullptr;
461 other.size_ = size_type{};
462
463 return *this;
464 }
465
466 list& operator=(initializer_list<value_type> init)
467 {
468 fini_();
469
470 init_(init.begin(), init.end());
471
472 return *this;
473 }
474
475 template<class InputIterator>
476 void assign(InputIterator first, InputIterator last)
477 {
478 fini_();
479
480 init_(first, last);
481 }
482
483 void assign(size_type n, const value_type& val)
484 {
485 fini_();
486
487 init_(
488 aux::insert_iterator<value_type>{size_type{}, val},
489 aux::insert_iterator<value_type>{n, value_type{}}
490 );
491 }
492
493 void assign(initializer_list<value_type> init)
494 {
495 fini_();
496
497 init_(init.begin(), init.end());
498 }
499
500 allocator_type get_allocator() const noexcept
501 {
502 return allocator_;
503 }
504
505 iterator begin() noexcept
506 {
507 return iterator{head_, head_, size_ == 0U};
508 }
509
510 const_iterator begin() const noexcept
511 {
512 return cbegin();
513 }
514
515 iterator end() noexcept
516 {
517 return iterator{get_last_(), head_, true};
518 }
519
520 const_iterator end() const noexcept
521 {
522 return cend();
523 }
524
525 reverse_iterator rbegin() noexcept
526 {
527 return make_reverse_iterator(end());
528 }
529
530 const_reverse_iterator rbegin() const noexcept
531 {
532 return make_reverse_iterator(cend());
533 }
534
535 reverse_iterator rend() noexcept
536 {
537 return make_reverse_iterator(begin());
538 }
539
540 const_reverse_iterator rend() const noexcept
541 {
542 return make_reverse_iterator(cbegin());
543 }
544
545 const_iterator cbegin() const noexcept
546 {
547 return const_iterator{head_, head_, size_ == 0U};
548 }
549
550 const_iterator cend() const noexcept
551 {
552 return const_iterator{get_last_(), head_, true};
553 }
554
555 const_reverse_iterator crbegin() const noexcept
556 {
557 return rbegin();
558 }
559
560 /**
561 * 23.3.5.3, capacity:
562 */
563
564 bool empty() const noexcept
565 {
566 return size_ == 0;
567 }
568
569 size_type size() const noexcept
570 {
571 return size_;
572 }
573
574 size_type max_size() const noexcept
575 {
576 return allocator_traits<allocator_type>::max_size(allocator_);
577 }
578
579 void resize(size_type sz)
580 {
581 // TODO: implement
582 }
583
584 void resize(size_type sz, const value_type& val)
585 {
586 // TODO: implement
587 }
588
589 reference front()
590 {
591 // TODO: bounds checking
592 return head_->value;
593 }
594
595 const_reference front() const
596 {
597 // TODO: bounds checking
598 return head_->value;
599 }
600
601 reference back()
602 {
603 // TODO: bounds checking
604 return head_->prev->value;
605 }
606
607 const_reference back() const
608 {
609 // TODO: bounds checking
610 return head_->prev->value;
611 }
612
613 /**
614 * 23.3.5.4, modifiers:
615 * Note: These should have no effect when an exception
616 * is thrown while inserting, but since the only
617 * functions that can throw are the constructors,
618 * creating the node before any modifications to the
619 * list itself will satisfy this requirement.
620 */
621
622 template<class... Args>
623 void emplace_front(Args&&... args)
624 {
625 prepend_new_(forward<Args>(args)...);
626 }
627
628 void pop_front()
629 {
630 if (head_)
631 {
632 --size_;
633
634 if (head_->next == head_)
635 {
636 delete head_;
637 head_ = nullptr;
638 }
639 else
640 {
641 auto tmp = head_;
642 head_->prev->next = head_->next;
643 head_->next->prev = head_->prev;
644 head_ = head_->next;
645
646 delete tmp;
647 }
648 }
649 }
650
651 template<class... Args>
652 void emplace_back(Args&&... args)
653 {
654 append_new_(forward<Args>(args)...);
655 }
656
657 void push_front(const value_type& value)
658 {
659 prepend_new_(value);
660 }
661
662 void push_front(value_type&& value)
663 {
664 prepend_new_(forward<value_type>(value));
665 }
666
667 void push_back(const value_type& value)
668 {
669 append_new_(value);
670 }
671
672 void push_back(value_type&& value)
673 {
674 append_new_(forward<value_type>(value));
675 }
676
677 void pop_back()
678 {
679 if (head_)
680 {
681 --size_;
682 auto target = head_->prev;
683
684 if (!target)
685 {
686 delete head_;
687 head_ = nullptr;
688 }
689 else
690 {
691 auto tmp = target;
692 target->prev->next = target->next;
693 target->next->prev = target->prev;
694 target = target->next;
695
696 delete tmp;
697 }
698 }
699 }
700
701 template<class... Args>
702 iterator emplace(const_iterator position, Args&&... args)
703 {
704 auto node = position.node();
705 node->prepend(new aux::list_node<value_type>{forward<Args>(args)...});
706 ++size_;
707
708 if (node == head_)
709 head_ = head_->prev;
710
711 return iterator{node->prev, head_, false};
712 }
713
714 iterator insert(const_iterator position, const value_type& val)
715 {
716 return emplace(position, val);
717 }
718
719 iterator insert(const_iterator position, value_type&& val)
720 {
721 return emplace(position, forward<value_type>(val));
722 }
723
724 iterator insert(const_iterator position, size_type n, const value_type& val)
725 {
726 return insert(
727 position,
728 aux::insert_iterator<value_type>{size_type{}, val},
729 aux::insert_iterator<value_type>{n, value_type{}}
730 );
731 }
732
733 template<class InputIterator>
734 iterator insert(const_iterator position, InputIterator first, InputIterator last)
735 {
736 auto node = position.node()->prev;
737
738 while (first != last)
739 {
740 node->append(new aux::list_node<value_type>{*first++});
741 node = node->next;
742 ++size_;
743 }
744
745 return iterator{position.node()->next, head_, false};
746 }
747
748 iterator insert(const_iterator position, initializer_list<value_type> init)
749 {
750 return insert(position, init.begin(), init.end());
751 }
752
753 iterator erase(const_iterator position)
754 {
755 auto node = position.node();
756
757 if (node == head_)
758 {
759 if (size_ == 1)
760 {
761 delete head_;
762 head_ = nullptr;
763 size_ = 0;
764
765 return end();
766 }
767 else
768 head_ = node->next;
769 }
770
771 auto next = node->next;
772
773 --size_;
774
775 node->unlink();
776 delete node;
777
778 return iterator{next, head_, size_ == 0U};
779 }
780
781 iterator erase(const_iterator first, const_iterator last)
782 {
783 if (first == last)
784 return end();
785
786 auto first_node = first.node();
787 auto last_node = last.node()->prev;
788 auto prev = first_node->prev;
789 auto next = last_node->next;
790
791 first_node->prev = nullptr;
792 last_node->next = nullptr;
793 prev->next = next;
794 next->prev = prev;
795
796 while (first_node)
797 {
798 if (first_node == head_)
799 {
800 head_ = next;
801 head_->prev = prev;
802 }
803
804 auto tmp = first_node;
805 first_node = first_node->next;
806 --size_;
807
808 delete tmp;
809 }
810
811 return iterator{next, head_, size_ == 0U};
812 }
813
814 void swap(list& other)
815 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
816 {
817 std::swap(allocator_, other.allocator_);
818 std::swap(head_, other.head_);
819 std::swap(size_, other.size_);
820 }
821
822 void clear() noexcept
823 {
824 fini_();
825 }
826
827 /**
828 * 23.3.5.5, list operations:
829 */
830
831 void splice(const_iterator position, list& other)
832 {
833 if (!head_)
834 {
835 swap(other);
836 return;
837 }
838
839 auto other_first = other.head_;
840 auto other_last = other.get_last_();
841 auto node = position.node();
842 auto prev = node->prev;
843
844 // Insert a link range.
845 prev->next = other_first;
846 other_first->prev = prev;
847 node->prev = other_last;
848 other_last->next = node;
849
850 size_ += other.size_;
851
852 if (node == head_)
853 head_ = other_first;
854 other.head_ = nullptr;
855 other.size_ = 0;
856 }
857
858 void splice(const_iterator position, list&& other)
859 {
860 splice(position, other);
861 }
862
863 void splice(const_iterator position, list& other, const_iterator it)
864 {
865 if (&other == this)
866 return;
867
868 auto node = position.node();
869 auto target = it.node();
870
871 // Unlink from other.
872 target->prev->next = target->next;
873 target->next->prev = target->prev;
874
875 // Link to us.
876 node->prev->next = target;
877 target->prev = node->prev;
878
879 node->prev = target;
880 target->next = node;
881
882 --other.size_;
883 ++size_;
884
885 if (it.node() == other.head_)
886 other.advance_head_();
887 }
888
889 void splice(const_iterator position, list&& other, const_iterator it)
890 {
891 splice(position, other, it);
892 }
893
894 void splice(const_iterator position, list& other,
895 const_iterator first, const_iterator last)
896 {
897 if (&other == this || other.empty())
898 return;
899
900 if (first == other.begin() && last == other.end())
901 { // [first, last) is everything in other.
902 splice(position, other);
903 return;
904 }
905
906 // [first_node, last_node] is the inserted range.
907 aux::list_node<value_type>* first_node{};
908 aux::list_node<value_type>* last_node{};
909
910 if (first == other.begin())
911 { // The range is a prefix of other.
912 other.head_ = last.node();
913 other.head_->prev = first.node()->prev;
914 first.node()->prev->next = last.node();
915
916 first_node = first.node();
917 last_node = last.node()->prev;
918 }
919 else if (last == other.end())
920 { // The range is a suffix of other.
921 auto new_last = first.node()->prev;
922 auto old_last = other.head_->prev;
923 other.head_->prev = new_last;
924 new_last->next = other.head_;
925
926 first_node = first.node();
927 last_node = old_last;
928 }
929 else
930 { // The range is a subrange of other.
931 first_node = first.node();
932 last_node = last.node()->prev;
933
934 first_node->prev->next = last.node();
935 last.node()->prev = first_node->prev;
936 }
937
938 if (!head_)
939 { // Assimilate the range.
940 head_ = first_node;
941 first_node->prev = last_node;
942 last_node->next = first_node;
943 }
944 else
945 {
946 auto target = position.node();
947 target->prev->next = first_node;
948 first_node->prev = target->prev;
949
950 target->prev = last_node;
951 last_node->next = target;
952 }
953
954 auto count = distance(
955 iterator{first_node, nullptr, false},
956 iterator{last_node, nullptr, false}
957 );
958 ++count;
959
960 size_ += count;
961 other.size_ -= count;
962 }
963
964 void splice(const_iterator position, list&& other,
965 const_iterator first, const_iterator last)
966 {
967 splice(position, other, first, last);
968 }
969
970 void remove(const value_type& val)
971 {
972 if (!head_)
973 return;
974
975 auto it = begin();
976 while (it != end())
977 {
978 if (*it == val)
979 it = erase(it);
980 else
981 ++it;
982 }
983 }
984
985 template<class Predicate>
986 void remove_if(Predicate pred)
987 {
988 if (!head_)
989 return;
990
991 auto it = begin();
992 while (it != end())
993 {
994 if (pred(*it))
995 it = erase(it);
996 else
997 ++it;
998 }
999 }
1000
1001 void unique()
1002 {
1003 if (!head_)
1004 return;
1005
1006 auto it = begin();
1007 ++it;
1008
1009 while (it != end())
1010 {
1011 if (*it == *(it - 1))
1012 it = erase(it);
1013 else
1014 ++it;
1015 }
1016 }
1017
1018 template<class BinaryPredicate>
1019 void unique(BinaryPredicate pred)
1020 {
1021 if (!head_)
1022 return;
1023
1024 auto it = begin();
1025 ++it;
1026
1027 while (it != end())
1028 {
1029 if (pred(*it, *(it - 1)))
1030 it = erase(it);
1031 else
1032 ++it;
1033 }
1034 }
1035
1036 // TODO: make a generic base for algorithms like merge
1037 // and quicksort that uses a swapper (the <algorithm>
1038 // versions would use std::swap and list versions would
1039 // use a swapper that swaps list nodes)
1040
1041 void merge(list& other)
1042 {
1043 // TODO: implement
1044 }
1045
1046 void merge(list&& other)
1047 {
1048 merge(other);
1049 }
1050
1051 template<class Compare>
1052 void merge(list& other, Compare comp)
1053 {
1054 // TODO: implement
1055 }
1056
1057 template<class Compare>
1058 void merge(list&& other, Compare comp)
1059 {
1060 merge(other, comp);
1061 }
1062
1063 void reverse() noexcept
1064 {
1065 // TODO: implement
1066 }
1067
1068 void sort()
1069 {
1070 // TODO: implement
1071 }
1072
1073 template<class Compare>
1074 void sort(Compare comp)
1075 {
1076 // TODO: implement
1077 }
1078
1079 private:
1080 allocator_type allocator_;
1081 aux::list_node<value_type>* head_;
1082 size_type size_;
1083
1084 template<class InputIterator>
1085 void init_(InputIterator first, InputIterator last)
1086 {
1087 while (first != last)
1088 {
1089 auto node = append_new_();
1090 allocator_.construct(&node->value, *first++);
1091 }
1092 }
1093
1094 void fini_()
1095 {
1096 if (!head_)
1097 return;
1098
1099 head_->prev->next = nullptr;
1100 while (head_)
1101 {
1102 auto tmp = head_;
1103 head_ = head_->next;
1104
1105 delete tmp;
1106 }
1107
1108 head_ = nullptr;
1109 size_ = size_type{};
1110 }
1111
1112 template<class... Args>
1113 aux::list_node<value_type>* append_new_(Args&&... args)
1114 {
1115 auto node = new aux::list_node<value_type>{forward<Args>(args)...};
1116 auto last = get_last_();
1117
1118 if (!last)
1119 head_ = node;
1120 else
1121 last->append(node);
1122
1123 ++size_;
1124
1125 return node;
1126 }
1127
1128 template<class... Args>
1129 aux::list_node<value_type>* prepend_new_(Args&&... args)
1130 {
1131 auto node = new aux::list_node<value_type>{forward<Args>(args)...};
1132
1133 if (!head_)
1134 head_ = node;
1135 else
1136 {
1137 head_->prepend(node);
1138 head_ = head_->prev;
1139 }
1140
1141 ++size_;
1142
1143 return node;
1144 }
1145
1146 aux::list_node<value_type>* get_last_() const
1147 {
1148 if (!head_)
1149 return nullptr;
1150
1151 return head_->prev;
1152 }
1153
1154 template<class InputIterator>
1155 void insert_range_(InputIterator first, InputIterator last,
1156 aux::list_node<value_type>* where = nullptr)
1157 {
1158 if (first == last)
1159 return;
1160
1161 if (!where)
1162 where = get_last_();
1163
1164 while (first != last)
1165 {
1166 where->append(new aux::list_node<value_type>{*first++});
1167 where = where->next;
1168 }
1169 }
1170
1171 void advance_head_()
1172 {
1173 if (size_ == 1)
1174 {
1175 head_ = nullptr;
1176 size_ = 0;
1177 }
1178 else
1179 { // The head_ is deleted outside.
1180 head_->next->prev = head_->prev;
1181 head_->prev->next = head_->next;
1182 head_ = head_->next;
1183 }
1184 }
1185 };
1186
1187 template<class T, class Allocator>
1188 void swap(list<T, Allocator>& lhs, list<T, Allocator>& rhs)
1189 noexcept(noexcept(lhs.swap(rhs)))
1190 {
1191 lhs.swap(rhs);
1192 }
1193}
1194
1195#endif
Note: See TracBrowser for help on using the repository browser.