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

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

cpp: added swap for list, added stubs for the remaining list operations

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