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

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

cpp: fixed bugs found by the list tests

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