source: mainline/uspace/lib/cpp/include/__bits/adt/list.hpp

Last change on this file was 7dcce0a, checked in by jxsvoboda <5887334+jxsvoboda@…>, 6 years ago

cpp: abort and report when an unimplemented function is called

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