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

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

cpp: added missing noexcept specifier

  • Property mode set to 100644
File size: 23.4 KB
Line 
1/*
2 * Copyright (c) 2017 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
91 template<class T>
92 class list_const_iterator
93 {
94 public:
95 using value_type = typename list<T>::value_type;
96 using reference = typename list<T>::const_reference;
97
98 using iterator_category = forward_iterator_tag;
99
100 list_const_iterator(list_node<value_type>* node = nullptr,
101 list_node<value_type>* head = nullptr)
102 : current_{node}, head_{head}
103 { /* DUMMY BODY */ }
104
105 list_const_iterator(const list_const_iterator&) = default;
106 list_const_iterator& operator=(const list_const_iterator&) = default;
107 list_const_iterator(list_const_iterator&&) = default;
108 list_const_iterator& operator=(list_const_iterator&&) = default;
109
110 reference operator*() const
111 {
112 return current_->value;
113 }
114
115 list_const_iterator& operator++()
116 {
117 if (current_)
118 {
119 if (current_->next == head_)
120 current_ = nullptr;
121 else
122 current_ = current_->next;
123 }
124
125 return *this;
126 }
127
128 list_const_iterator operator++(int)
129 {
130 auto bckp = current_;
131
132 if (current_)
133 {
134 if (current_->next == head_)
135 current_ = nullptr;
136 else
137 current_ = current_->next;
138 }
139
140 return list_const_iterator{bckp};
141 }
142
143 list_node<value_type>* node()
144 {
145 return current_;
146 }
147
148 const list_node<value_type>* node() const
149 {
150 return current_;
151 }
152
153 private:
154 list_node<value_type>* current_;
155 list_node<value_type>* head_;
156 };
157
158 template<class T>
159 bool operator==(const list_const_iterator<T>& lhs, const list_const_iterator<T>& rhs)
160 {
161 return lhs.node() == rhs.node();
162 }
163
164 template<class T>
165 bool operator!=(const list_const_iterator<T>& lhs, const list_const_iterator<T>& rhs)
166 {
167 return !(lhs == rhs);
168 }
169
170 template<class T>
171 class list_iterator
172 {
173 public:
174 using value_type = typename list<T>::value_type;
175 using reference = typename list<T>::reference;
176
177 using iterator_category = forward_iterator_tag;
178
179 list_iterator(list_node<value_type>* node = nullptr,
180 list_node<value_type>* head = nullptr)
181 : current_{node}, head_{head}
182 { /* DUMMY BODY */ }
183
184 list_iterator(const list_iterator&) = default;
185 list_iterator& operator=(const list_iterator&) = default;
186 list_iterator(list_iterator&&) = default;
187 list_iterator& operator=(list_iterator&&) = default;
188
189 reference operator*()
190 {
191 return current_->value;
192 }
193
194 list_iterator& operator++()
195 {
196 if (current_)
197 {
198 if (current_->next == head_)
199 current_ = nullptr;
200 else
201 current_ = current_->next;
202 }
203
204 return *this;
205 }
206
207 list_iterator operator++(int)
208 {
209 auto bckp = current_;
210
211 if (current_)
212 {
213 if (current_->next == head_)
214 current_ = nullptr;
215 else
216 current_ = current_->next;
217 }
218
219 return list_iterator{bckp};
220 }
221
222 list_node<value_type>* node()
223 {
224 return current_;
225 }
226
227 const list_node<value_type>* node() const
228 {
229 return current_;
230 }
231
232 operator list_const_iterator<T>() const
233 {
234 return list_const_iterator<T>{current_};
235 }
236
237 private:
238 list_node<value_type>* current_;
239 list_node<value_type>* head_;
240 };
241
242 template<class T>
243 bool operator==(const list_iterator<T>& lhs, const list_iterator<T>& rhs)
244 {
245 return lhs.node() == rhs.node();
246 }
247
248 template<class T>
249 bool operator!=(const list_iterator<T>& lhs, const list_iterator<T>& rhs)
250 {
251 return !(lhs == rhs);
252 }
253 }
254
255 /**
256 * 23.3.5, class template list:
257 */
258
259 template<class T, class Allocator>
260 class list
261 {
262 public:
263 using value_type = T;
264 using reference = value_type&;
265 using const_reference = const value_type&;
266 using allocator_type = Allocator;
267
268 using iterator = aux::list_iterator<value_type>;
269 using const_iterator = aux::list_const_iterator<value_type>;
270 using size_type = size_t;
271 using difference_type = ptrdiff_t;
272
273 using pointer = typename allocator_traits<allocator_type>::pointer;
274 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
275
276 using reverse_iterator = std::reverse_iterator<iterator>;
277 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
278
279 /**
280 * 23.3.5.2, construct/copy/destroy:
281 */
282
283 list()
284 : list{allocator_type{}}
285 { /* DUMMY BODY */ }
286
287 explicit list(const allocator_type& alloc)
288 : allocator_{alloc}, head_{nullptr}, size_{}
289 { /* DUMMY BODY */ }
290
291 explicit list(size_type n, const allocator_type& alloc = allocator_type{})
292 : allocator_{alloc}, head_{nullptr}, size_{}
293 {
294 init_(
295 aux::insert_iterator<value_type>{value_type{}},
296 aux::insert_iterator<value_type>{size_}
297 );
298 }
299
300 list(size_type n, const value_type& val,
301 const allocator_type& alloc = allocator_type{})
302 : allocator_{alloc}, head_{nullptr}, size_{}
303 {
304 init_(
305 aux::insert_iterator<value_type>{val},
306 aux::insert_iterator<value_type>{n}
307 );
308 }
309
310 template<class InputIterator>
311 list(InputIterator first, InputIterator last,
312 const allocator_type& alloc = allocator_type{})
313 : allocator_{alloc}, head_{nullptr}, size_{}
314 {
315 init_(first, last);
316 }
317
318 list(const list& other)
319 : list{other, other.allocator_}
320 { /* DUMMY BODY */ }
321
322 list(list&& other)
323 : allocator_{move(other.allocator_)},
324 head_{move(other.head_)},
325 size_{move(other.size_)}
326 {
327 other.head_ = nullptr;
328 }
329
330 list(const list& other, const allocator_type alloc)
331 : allocator_{alloc}, head_{nullptr}, size_{other.size_}
332 {
333 init_(other.begin(), other.end());
334 }
335
336 list(list&& other, const allocator_type& alloc)
337 : allocator_{alloc},
338 head_{move(other.head_)},
339 size_{move(other.size_)}
340 {
341 other.head_ = nullptr;
342 }
343
344 list(initializer_list<value_type> init, const allocator_type& alloc)
345 : allocator_{alloc}, head_{nullptr}, size_{}
346 {
347 init_(init.begin(), init.end());
348 }
349
350 ~list()
351 {
352 fini_();
353 }
354
355 list& operator=(const list& other)
356 {
357 fini_();
358
359 allocator_ = other.allocator_;
360
361 init_(other.begin(), other.end());
362 }
363
364 list& operator=(list&& other)
365 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
366 {
367 fini_();
368
369 allocator_ = move(other.allocator_);
370
371 init_(
372 make_move_iterator(other.begin()),
373 make_move_iterator(other.end())
374 );
375 }
376
377 list& operator=(initializer_list<value_type> init)
378 {
379 fini_();
380
381 init_(init.begin(), init.end());
382 }
383
384 template<class InputIterator>
385 void assign(InputIterator first, InputIterator last)
386 {
387 fini_();
388
389 init_(first, last);
390 }
391
392 void assign(size_type n, const value_type& val)
393 {
394 fini_();
395
396 init_(
397 aux::insert_iterator<value_type>{val},
398 aux::insert_iterator<value_type>{n}
399 );
400 }
401
402 void assign(initializer_list<value_type> init)
403 {
404 fini_();
405
406 init_(init.begin(), init.end());
407 }
408
409 allocator_type get_allocator() const noexcept
410 {
411 return allocator_;
412 }
413
414 iterator begin() noexcept
415 {
416 return iterator{head_, head_};
417 }
418
419 const_iterator begin() const noexcept
420 {
421 return cbegin();
422 }
423
424 iterator end() noexcept
425 {
426 return iterator{nullptr, head_};
427 }
428
429 const_iterator end() const noexcept
430 {
431 return cend();
432 }
433
434 reverse_iterator rbegin() noexcept
435 {
436 return make_reverse_iterator(end());
437 }
438
439 const_reverse_iterator rbegin() const noexcept
440 {
441 return make_reverse_iterator(cend());
442 }
443
444 reverse_iterator rend() noexcept
445 {
446 return make_reverse_iterator(begin());
447 }
448
449 const_reverse_iterator rend() const noexcept
450 {
451 return make_reverse_iterator(cbegin());
452 }
453
454 const_iterator cbegin() const noexcept
455 {
456 return const_iterator{head_, head_};
457 }
458
459 const_iterator cend() const noexcept
460 {
461 return const_iterator{nullptr, head_};
462 }
463
464 const_reverse_iterator crbegin() const noexcept
465 {
466 return rbegin();
467 }
468
469 /**
470 * 23.3.5.3, capacity:
471 */
472
473 bool empty() const noexcept
474 {
475 return size_ == 0;
476 }
477
478 size_type size() const noexcept
479 {
480 return size_;
481 }
482
483 size_type max_size() const noexcept
484 {
485 return allocator_traits<allocator_type>::max_size(allocator_);
486 }
487
488 void resize(size_type sz)
489 {
490 // TODO: implement
491 }
492
493 void resize(size_type sz, const value_type& val)
494 {
495 // TODO: implement
496 }
497
498 reference front()
499 {
500 // TODO: bounds checking
501 return head_->value;
502 }
503
504 const_reference front() const
505 {
506 // TODO: bounds checking
507 return head_->value;
508 }
509
510 reference back()
511 {
512 // TODO: bounds checking
513 return head_->prev->value;
514 }
515
516 const_reference back() const
517 {
518 // TODO: bounds checking
519 return head_->prev->value;
520 }
521
522 /**
523 * 23.3.5.4, modifiers:
524 * Note: These should have no effect when an exception
525 * is thrown while inserting, but since the only
526 * functions that can throw are the constructors,
527 * creating the node before any modifications to the
528 * list itself will satisfy this requirement.
529 */
530
531 template<class... Args>
532 void emplace_front(Args&&... args)
533 {
534 prepend_new_(forward<Args>(args)...);
535 }
536
537 void pop_front()
538 {
539 if (head_)
540 {
541 --size_;
542
543 if (head_->next == head_)
544 {
545 delete head_;
546 head_ = nullptr;
547 }
548 else
549 {
550 auto tmp = head_;
551 head_->prev->next = head_->next;
552 head_->next->prev = head_->prev;
553 head_ = head_->next;
554
555 delete tmp;
556 }
557 }
558 }
559
560 template<class... Args>
561 void emplace_back(Args&&... args)
562 {
563 append_new_(forward<Args>(args)...);
564 }
565
566 void push_front(const value_type& value)
567 {
568 prepend_new_(value);
569 }
570
571 void push_front(value_type&& value)
572 {
573 prepend_new_(forward<value_type>(value));
574 }
575
576 void push_back(const value_type& value)
577 {
578 append_new_(value);
579 }
580
581 void push_back(value_type&& value)
582 {
583 append_new_(forward<value_type>(value));
584 }
585
586 void pop_back()
587 {
588 if (head_)
589 {
590 --size_;
591 auto target = head_->prev;
592
593 if (!target)
594 {
595 delete head_;
596 head_ = nullptr;
597 }
598 else
599 {
600 auto tmp = target;
601 target->prev->next = target->next;
602 target->next->prev = target->prev;
603 target = target->next;
604
605 delete tmp;
606 }
607 }
608 }
609
610 template<class... Args>
611 iterator emplace(const_iterator position, Args&&... args)
612 {
613 auto node = position.node();
614 node->prepend(new aux::list_node<value_type>{forward<Args>(args)...});
615 ++size_;
616
617 if (node == head_)
618 head_ = head_->prev;
619
620 return iterator{node->prev};
621 }
622
623 iterator insert(const_iterator position, const value_type& val)
624 {
625 return emplace(position, val);
626 }
627
628 iterator insert(const_iterator position, value_type&& val)
629 {
630 return emplace(position, forward<value_type>(val));
631 }
632
633 iterator insert(const_iterator position, size_type n, const value_type& val)
634 {
635 return insert(
636 position,
637 aux::insert_iterator<value_type>{0u, val},
638 aux::insert_iterator<value_type>{n}
639 );
640 }
641
642 template<class InputIterator>
643 iterator insert(const_iterator position, InputIterator first, InputIterator last)
644 {
645 auto node = position.node()->prev;
646
647 while (first != last)
648 {
649 node->append(new aux::list_node<value_type>{*first++});
650 node = node->next;
651 ++size_;
652 }
653
654 return iterator{position.node()->next};
655 }
656
657 iterator insert(const_iterator position, initializer_list<value_type> init)
658 {
659 return insert(position, init.begin(), init.end());
660 }
661
662 iterator erase(const_iterator position)
663 {
664 auto node = position.node();
665 --size_;
666
667 if (node != get_last_())
668 {
669 auto next = node->next;
670 auto prev = node->prev;
671
672 next->prev = prev;
673 prev->next = next;
674
675 delete node;
676
677 return iterator{next};
678 }
679 else
680 {
681 auto prev = node->prev;
682 head_->prev = prev;
683 prev->next = head_;
684
685 delete node;
686
687 return end();
688 }
689 }
690
691 iterator erase(const_iterator first, const_iterator last)
692 {
693 if (first == last)
694 return end();
695
696 auto first_node = first.node();
697 auto last_node = last.node();
698 auto prev = first_node->prev;
699 auto next = last_node->next;
700
701 prev->append(next);
702
703 while (first_node != next)
704 {
705 auto tmp = first_node;
706 first_node = first_node->next;
707 --size_;
708
709 delete tmp;
710 }
711
712 return iterator{next};
713 }
714
715 void swap(list& other)
716 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
717 {
718 std::swap(allocator_, other.allocator_);
719 std::swap(head_, other.head_);
720 std::swap(size_, other.size_);
721 }
722
723 void clear() noexcept
724 {
725 fini_();
726 }
727
728 private:
729 allocator_type allocator_;
730 aux::list_node<value_type>* head_;
731 size_type size_;
732
733 template<class InputIterator>
734 void init_(InputIterator first, InputIterator last)
735 {
736 while (first != last)
737 {
738 auto node = append_new_();
739 allocator_.construct(&node->value, *first++);
740 }
741 }
742
743 void fini_()
744 {
745 if (!head_)
746 return;
747
748 for (size_type i = size_type{}; i < size_; ++i)
749 {
750 head_ = head_->next;
751 delete head_->prev;
752 }
753
754 head_ = nullptr;
755 size_ = size_type{};
756 }
757
758 template<class... Args>
759 aux::list_node<value_type>* append_new_(Args&&... args)
760 {
761 auto node = new aux::list_node<value_type>{forward<Args>(args)...};
762 auto last = get_last_();
763
764 if (!last)
765 head_ = node;
766 else
767 last->append(node);
768
769 ++size_;
770
771 return node;
772 }
773
774 template<class... Args>
775 aux::list_node<value_type>* prepend_new_(Args&&... args)
776 {
777 auto node = new aux::list_node<value_type>{forward<Args>(args)...};
778
779 if (!head_)
780 head_ = node;
781 else
782 {
783 head_->prepend(node);
784 head_ = head_->prev;
785 }
786
787 ++size_;
788
789 return node;
790 }
791
792 aux::list_node<value_type>* get_last_()
793 {
794 if (!head_)
795 return nullptr;
796
797 return head_->prev;
798 }
799
800 template<class InputIterator>
801 void insert_range_(InputIterator first, InputIterator last,
802 aux::list_node<value_type>* where = nullptr)
803 {
804 if (first == last)
805 return;
806
807 if (!where)
808 where = get_last_();
809
810 while (first != last)
811 {
812 where->append(new aux::list_node<value_type>{*first++});
813 where = where->next;
814 }
815 }
816 };
817}
818
819#endif
Note: See TracBrowser for help on using the repository browser.