source: mainline/uspace/lib/cpp/include/impl/deque.hpp@ 6e93323

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

cpp: added deque iterators

  • Property mode set to 100644
File size: 25.2 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_DEQUE
30#define LIBCPP_DEQUE
31
32#include <initializer_list>
33#include <iterator>
34#include <memory>
35
36namespace std
37{
38 template<class T, class Allocator = allocator<T>>
39 class deque;
40
41 namespace aux
42 {
43 /**
44 * Note: We decided that these iterators contain a
45 * reference to the container and an index, which
46 * allows us to use the already implemented operator[]
47 * on deque and also allows us to conform to the requirement
48 * of the standard that functions such as push_back
49 * invalidate the .end() iterator.
50 */
51
52 template<class T, class Allocator>
53 class deque_const_iterator
54 {
55 public:
56 using size_type = typename deque<T, Allocator>::size_type;
57 using value_type = typename deque<T, Allocator>::value_type;
58 using reference = typename deque<T, Allocator>::const_reference;
59 using difference_type = size_type;
60 using pointer = const value_type*;
61 using iterator_category = random_access_iterator_tag;
62
63 deque_const_iterator(deque<T, Allocator>& deq, size_type idx)
64 : deq_{deq}, idx_{idx}
65 { /* DUMMY BODY */ }
66
67 deque_const_iterator& operator=(const deque_const_iterator& other)
68 {
69 deq_ = other.deq_;
70 idx_ = other.idx_;
71
72 return *this;
73 }
74
75 reference operator*() const
76 {
77 return deq_[idx_];
78 }
79
80 pointer operator->() const
81 {
82 return addressof(deq_[idx_]);
83 }
84
85 deque_const_iterator& operator++()
86 {
87 ++idx_;
88
89 return *this;
90 }
91
92 deque_const_iterator operator++(int)
93 {
94 return deque_const_iterator{deq_, idx_++};
95 }
96
97 deque_const_iterator& operator--()
98 {
99 --idx_;
100
101 return *this;
102 }
103
104 deque_const_iterator operator--(int)
105 {
106 return deque_const_iterator{deq_, idx_--};
107 }
108
109 deque_const_iterator operator+(difference_type n)
110 {
111 return deque_const_iterator{deq_, idx_ + n};
112 }
113
114 deque_const_iterator& operator+=(difference_type n)
115 {
116 idx_ += n;
117
118 return *this;
119 }
120
121 deque_const_iterator operator-(difference_type n)
122 {
123 return deque_const_iterator{deq_, idx_ - n};
124 }
125
126 deque_const_iterator& operator-=(difference_type n)
127 {
128 idx_ -= n;
129
130 return *this;
131 }
132
133 reference operator[](difference_type n) const
134 {
135 return deq_[idx_ + n];
136 }
137
138 size_type idx() const
139 {
140 return idx_;
141 }
142
143 private:
144 deque<T, Allocator>& deq_;
145 size_type idx_;
146 };
147
148 template<class T, class Allocator>
149 bool operator==(const deque_const_iterator<T, Allocator>& lhs,
150 const deque_const_iterator<T, Allocator>& rhs)
151 {
152 return lhs.idx() == rhs.idx();
153 }
154
155 template<class T, class Allocator>
156 bool operator!=(const deque_const_iterator<T, Allocator>& lhs,
157 const deque_const_iterator<T, Allocator>& rhs)
158 {
159 return !(lhs == rhs);
160 }
161
162 template<class T, class Allocator>
163 class deque_iterator
164 {
165 public:
166 using size_type = typename deque<T, Allocator>::size_type;
167 using value_type = typename deque<T, Allocator>::value_type;
168 using reference = typename deque<T, Allocator>::reference;
169 using difference_type = size_type;
170 using pointer = value_type*;
171 using iterator_category = random_access_iterator_tag;
172
173 deque_iterator(deque<T, Allocator>& deq, size_type idx)
174 : deq_{deq}, idx_{idx}
175 { /* DUMMY BODY */ }
176
177 deque_iterator(const deque_const_iterator<T, Allocator>& other)
178 : deq_{other.deq_}, idx_{other.idx_}
179 { /* DUMMY BODY */ }
180
181 deque_iterator& operator=(const deque_iterator& other)
182 {
183 deq_ = other.deq_;
184 idx_ = other.idx_;
185
186 return *this;
187 }
188
189 deque_iterator& operator=(const deque_const_iterator<T, Allocator>& other)
190 {
191 deq_ = other.deq_;
192 idx_ = other.idx_;
193
194 return *this;
195 }
196
197 reference operator*()
198 {
199 return deq_[idx_];
200 }
201
202 pointer operator->()
203 {
204 return addressof(deq_[idx_]);
205 }
206
207 deque_iterator& operator++()
208 {
209 ++idx_;
210
211 return *this;
212 }
213
214 deque_iterator operator++(int)
215 {
216 return deque_iterator{deq_, idx_++};
217 }
218
219 deque_iterator& operator--()
220 {
221 --idx_;
222
223 return *this;
224 }
225
226 deque_iterator operator--(int)
227 {
228 return deque_iterator{deq_, idx_--};
229 }
230
231 deque_iterator operator+(difference_type n)
232 {
233 return deque_iterator{deq_, idx_ + n};
234 }
235
236 deque_iterator& operator+=(difference_type n)
237 {
238 idx_ += n;
239
240 return *this;
241 }
242
243 deque_iterator operator-(difference_type n)
244 {
245 return deque_iterator{deq_, idx_ - n};
246 }
247
248 deque_iterator& operator-=(difference_type n)
249 {
250 idx_ -= n;
251
252 return *this;
253 }
254
255 reference operator[](difference_type n) const
256 {
257 return deq_[idx_ + n];
258 }
259
260 size_type idx() const
261 {
262 return idx_;
263 }
264
265 private:
266 deque<T, Allocator>& deq_;
267 size_type idx_;
268 };
269
270 template<class T, class Allocator>
271 bool operator==(const deque_iterator<T, Allocator>& lhs,
272 const deque_iterator<T, Allocator>& rhs)
273 {
274 return lhs.idx() == rhs.idx();
275 }
276
277 template<class T, class Allocator>
278 bool operator!=(const deque_iterator<T, Allocator>& lhs,
279 const deque_iterator<T, Allocator>& rhs)
280 {
281 return !(lhs == rhs);
282 }
283 }
284
285 /**
286 * 23.3.3 deque:
287 */
288
289 template<class T, class Allocator>
290 class deque
291 {
292 public:
293 using allocator_type = Allocator;
294 using value_type = T;
295 using reference = value_type&;
296 using const_reference = const value_type&;
297
298 using iterator = aux::deque_iterator<T, Allocator>;
299 using const_iterator = aux::deque_const_iterator<T, Allocator>;
300 using reverse_iterator = std::reverse_iterator<iterator>;
301 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
302
303 using size_type = typename allocator_traits<allocator_type>::size_type;
304 using difference_type = typename allocator_traits<allocator_type>::difference_type;
305 using pointer = typename allocator_traits<allocator_type>::pointer;
306 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
307
308 /**
309 * 23.3.3.2, construct/copy/destroy:
310 */
311
312 deque()
313 : deque{allocator_type{}}
314 { /* DUMMY BODY */ }
315
316 explicit deque(const allocator_type& alloc)
317 : allocator_{alloc}, front_bucket_idx_{bucket_size_},
318 back_bucket_idx_{0}, front_bucket_{default_front_},
319 back_bucket_{default_back_}, bucket_count_{default_bucket_count_},
320 bucket_capacity_{default_bucket_capacity_}, size_{}, data_{}
321 {
322 init_();
323 }
324
325 explicit deque(size_type n, const allocator_type& alloc = allocator_type{})
326 {
327 // TODO: implement
328 }
329
330 deque(size_type n, const value_type& value, const allocator_type& alloc = allocator_type{})
331 {
332 // TODO: implement
333 }
334
335 template<class InputIterator>
336 deque(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type{})
337 {
338 // TODO: implement
339 }
340
341 deque(const deque& other)
342 {
343 // TODO: implement
344 }
345
346 deque(deque&& other)
347 {
348 // TODO: implement
349 }
350
351 deque(const deque& other, const allocator_type& alloc)
352 {
353 // TODO: implement
354 }
355
356 deque(deque&& other, const allocator_type& alloc)
357 {
358 // TODO: implement
359 }
360
361 deque(initializer_list<T> init, const allocator_type& alloc = allocator_type{})
362 {
363 // TODO: implement
364 }
365
366 ~deque()
367 {
368 fini_();
369 }
370
371 deque& operator=(const deque& other)
372 {
373 // TODO: implement
374 }
375
376 deque& operator=(deque&& other)
377 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
378 {
379 // TODO: implement
380 }
381
382 deque& operator=(initializer_list<T> init)
383 {
384 // TODO: implement
385 }
386
387 template<class InputIterator>
388 void assign(InputIterator first, InputIterator last)
389 {
390 // TODO: implement
391 }
392
393 void assign(size_type n, const T& value)
394 {
395 // TODO: implement
396 }
397
398 void assign(initializer_list<T> init)
399 {
400 // TODO: implement
401 }
402
403 allocator_type get_allocator() const noexcept
404 {
405 return allocator_;
406 }
407
408 iterator begin() noexcept
409 {
410 return aux::deque_iterator{*this, 0};
411 }
412
413 const_iterator begin() const noexcept
414 {
415 return aux::deque_const_iterator{*this, 0};
416 }
417
418 iterator end() noexcept
419 {
420 return aux::deque_iterator{*this, size_};
421 }
422
423 const_iterator end() const noexcept
424 {
425 return aux::deque_const_iterator{*this, size_};
426 }
427
428 reverse_iterator rbegin() noexcept
429 {
430 return make_reverse_iterator(end());
431 }
432
433 const_reverse_iterator rbegin() const noexcept
434 {
435 return make_reverse_iterator(cend());
436 }
437
438 reverse_iterator rend() noexcept
439 {
440 return make_reverse_iterator(begin());
441 }
442
443 const_reverse_iterator rend() const noexcept
444 {
445 return make_reverse_iterator(cbegin());
446 }
447
448 const_iterator cbegin() const noexcept
449 {
450 return aux::deque_const_iterator{*this, 0};
451 }
452
453 const_iterator cend() const noexcept
454 {
455 return aux::deque_const_iterator{*this, size_};
456 }
457
458 const_reverse_iterator crbegin() const noexcept
459 {
460 return make_reverse_iterator(cend());
461 }
462
463 const_reverse_iterator crend() const noexcept
464 {
465 return make_reverse_iterator(cbegin());
466 }
467
468 /**
469 * 23.3.3.3, capacity:
470 */
471
472 size_type size() const noexcept
473 {
474 return size_;
475 }
476
477 size_type max_size() const noexcept
478 {
479 // TODO: implement
480 }
481
482 void resize(size_type sz)
483 {
484 // TODO: implement
485 }
486
487 void resize(size_type sz, const value_type& value)
488 {
489 // TODO: implement
490 }
491
492 void shrink_to_fit()
493 {
494 // TODO: implement
495 }
496
497 bool empty() const noexcept
498 {
499 return size_ == size_type{};
500 }
501
502 reference operator[](size_type idx)
503 {
504 return data_[get_bucket_index_(idx)][get_element_index_(idx)];
505 }
506
507 const_reference operator[](size_type idx) const
508 {
509 return data_[get_bucket_index_(idx)][get_element_index_(idx)];
510 }
511
512 reference at(size_type idx)
513 {
514 // TODO: implement
515 }
516
517 const_reference at(size_type idx) const
518 {
519 // TODO: implement
520 }
521
522 reference front()
523 {
524 // TODO: implement
525 }
526
527 const_reference front() const
528 {
529 // TODO: implement
530 }
531
532 reference back()
533 {
534 // TODO: implement
535 }
536
537 const_reference back() const
538 {
539 // TODO: implement
540 }
541
542 /**
543 * 23.3.3.4, modifiers:
544 */
545
546 template<class... Args>
547 void emplace_front(Args&&... args)
548 {
549 // TODO: implement
550 }
551
552 template<class... Args>
553 void emplace_back(Args&&... args)
554 {
555 // TODO: implement
556 }
557
558 template<class... Args>
559 iterator emplace(const_iterator position, Args&&... args)
560 {
561 // TODO: implement
562 }
563
564 void push_front(const value_type& value)
565 {
566 if (front_bucket_idx_ == 0)
567 add_new_bucket_front_();
568
569 data_[front_bucket_][--front_bucket_idx_] = value;
570 ++size_;
571 }
572
573 void push_front(value_type&& value)
574 {
575 if (front_bucket_idx_ == 0)
576 add_new_bucket_front_();
577
578 data_[front_bucket_][--front_bucket_idx_] = forward<value_type>(value);
579 ++size_;
580 }
581
582 void push_back(const value_type& value)
583 {
584 data_[back_bucket_][back_bucket_idx_++] = value;
585 ++size_;
586
587 if (back_bucket_idx_ >= bucket_size_)
588 add_new_bucket_back_();
589 }
590
591 void push_back(value_type&& value)
592 {
593 data_[back_bucket_][back_bucket_idx_++] = forward<value_type>(value);
594 ++size_;
595
596 if (back_bucket_idx_ >= bucket_size_)
597 add_new_bucket_back_();
598 }
599
600 iterator insert(const_iterator position, const value_type& value)
601 {
602 // TODO: implement
603 }
604
605 iterator insert(const_iterator position, value_type&& value)
606 {
607 // TODO: implement
608 }
609
610 iterator insert(const_iterator position, size_type n, const value_type& value)
611 {
612 // TODO: implement
613 }
614
615 template<class InputIterator>
616 iterator insert(const_iterator position, InputIterator first, InputIterator last)
617 {
618 // TODO: implement
619 }
620
621 iterator insert(const_iterator position, initializer_list<value_type> init)
622 {
623 // TODO: implement
624 }
625
626 void pop_back()
627 {
628 if (empty())
629 return;
630
631 if (back_bucket_idx_ == 0)
632 { // Means we gotta pop data_[front_bucket_][bucket_size_ - 1]!
633 if (data_[back_bucket_])
634 allocator_.deallocate(data_[back_bucket_], bucket_size_);
635
636 --back_bucket_;
637 back_bucket_idx_ = bucket_size_ - 1;
638 }
639 else
640 --back_bucket_idx_;
641
642 allocator_.destroy(&data_[back_bucket_][back_bucket_idx_]);
643 --size_;
644 }
645
646 void pop_front()
647 {
648 if (empty())
649 return;
650
651 if (front_bucket_idx_ >= bucket_size_)
652 { // Means we gotta pop data_[front_bucket_][0]!
653 if (data_[front_bucket_])
654 allocator_.deallocate(data_[front_bucket_], bucket_size_);
655
656 ++front_bucket_;
657 front_bucket_idx_ = 1;
658
659 allocator_.destroy(&data_[front_bucket_][0]);
660 }
661 else
662 {
663 allocator_.destroy(&data_[front_bucket_][front_bucket_idx_]);
664
665 ++front_bucket_idx_;
666 }
667
668 --size_;
669 }
670
671 iterator erase(const_iterator position)
672 {
673 // TODO: implement
674 }
675
676 iterator erase(const_iterator first, const_iterator last)
677 {
678 // TODO: implement
679 }
680
681 void swap(deque& other)
682 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
683 {
684 // TODO: implement
685 }
686
687 void clear() noexcept
688 {
689 fini_();
690
691 front_bucket_ = default_front_;
692 back_bucket_ = default_back_;
693 bucket_count_ = default_bucket_count_;
694 bucket_capacity_ = default_bucket_capacity_;
695 size_ = size_type{};
696
697 init_();
698 }
699
700 /* private: */
701 allocator_type allocator_;
702
703 /**
704 * Note: In our implementation, front_bucket_idx_
705 * points at the first element and back_bucket_idx_
706 * points at the one past last element. Because of this,
707 * some operations may be done in inverse order
708 * depending on the side they are applied to.
709 */
710 size_type front_bucket_idx_;
711 size_type back_bucket_idx_;
712 size_type front_bucket_;
713 size_type back_bucket_;
714
715 static constexpr size_type bucket_size_{16};
716 static constexpr size_type default_bucket_count_{2};
717 static constexpr size_type default_bucket_capacity_{4};
718 static constexpr size_type default_front_{1};
719 static constexpr size_type default_back_{2};
720
721 size_type bucket_count_;
722 size_type bucket_capacity_;
723 size_type size_{};
724
725 value_type** data_;
726
727 void init_()
728 {
729 data_ = new value_type*[bucket_capacity_];
730
731 for (size_type i = front_bucket_; i <= back_bucket_; ++i)
732 data_[i] = allocator_.allocate(bucket_size_);
733 }
734
735 void fini_()
736 {
737 for (size_type i = front_bucket_; i <= back_bucket_; ++i)
738 allocator_.deallocate(data_[i], bucket_size_);
739
740 delete[] data_;
741 data_ = nullptr;
742 }
743
744 bool has_bucket_space_back_() const
745 {
746 return back_bucket_ < bucket_capacity_ - 1;
747 }
748
749 bool has_bucket_space_front_() const
750 {
751 return front_bucket_ > 0;
752 }
753
754 void add_new_bucket_back_()
755 {
756 if (!has_bucket_space_back_())
757 expand_();
758
759 ++back_bucket_;
760 data_[back_bucket_] = allocator_.allocate(bucket_size_);
761 back_bucket_idx_ = size_type{};
762 }
763
764 void add_new_bucket_front_()
765 {
766 if (!has_bucket_space_front_())
767 expand_();
768
769 --front_bucket_;
770 data_[front_bucket_] = allocator_.allocate(bucket_size_);
771 front_bucket_idx_ = bucket_size_;
772 }
773
774 void expand_()
775 {
776 bucket_capacity_ *= 2;
777 value_type** new_data = new value_type*[bucket_capacity_];
778
779 size_type new_front = bucket_capacity_ / 4;
780 size_type new_back = bucket_capacity_ - bucket_capacity_ / 4 - 1;
781
782 for (size_type i = new_front, j = front_bucket_; i <= new_back; ++i, ++j)
783 new_data[i] = move(data_[j]);
784 std::swap(data_, new_data);
785
786 delete[] new_data;
787 front_bucket_ = new_front;
788 back_bucket_ = new_back;
789 }
790
791 size_type get_bucket_index_(size_type idx) const
792 {
793 if (idx < elements_in_front_bucket_())
794 return front_bucket_;
795
796 idx -= elements_in_front_bucket_();
797 return idx / bucket_size_ + front_bucket_ + 1;
798 }
799
800 size_type get_element_index_(size_type idx) const
801 {
802 if (idx < elements_in_front_bucket_())
803 return bucket_size_ - elements_in_front_bucket_() + idx;
804
805 idx -= elements_in_front_bucket_();
806 return idx % bucket_size_;
807 }
808
809 size_type elements_in_front_bucket_() const
810 {
811 return bucket_size_ - front_bucket_idx_;
812 }
813 };
814
815 template<class T, class Allocator>
816 bool operator==(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
817 {
818 // TODO: implement
819 return false;
820 }
821
822 template<class T, class Allocator>
823 bool operator<(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
824 {
825 // TODO: implement
826 return false;
827 }
828
829 template<class T, class Allocator>
830 bool operator!=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
831 {
832 // TODO: implement
833 return false;
834 }
835
836 template<class T, class Allocator>
837 bool operator>(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
838 {
839 // TODO: implement
840 return false;
841 }
842
843 template<class T, class Allocator>
844 bool operator<=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
845 {
846 // TODO: implement
847 return false;
848 }
849
850 template<class T, class Allocator>
851 bool operator>=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
852 {
853 // TODO: implement
854 return false;
855 }
856
857 /**
858 * 23.3.3.5, deque specialized algorithms:
859 */
860
861 template<class T, class Allocator>
862 void swap(deque<T, Allocator>& lhs, deque<T, Allocator>& rhs)
863 noexcept(noexcept(lhs.swap(rhs)))
864 {
865 lhs.swap(rhs);
866 }
867}
868
869#endif
Note: See TracBrowser for help on using the repository browser.