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

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

cpp: added list modifiers tests and fixed bugs found by htem

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