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

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

cpp: moved list_node to an auxiliary header as it will be used in hash maps

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