source: mainline/uspace/lib/cpp/include/__bits/adt/deque.hpp@ 34b2f54d

Last change on this file since 34b2f54d was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 36.4 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2018 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_ADT_DEQUE
8#define LIBCPP_BITS_ADT_DEQUE
9
10#include <__bits/insert_iterator.hpp>
11#include <algorithm>
12#include <initializer_list>
13#include <iterator>
14#include <memory>
15
16namespace std
17{
18 template<class T, class Allocator = allocator<T>>
19 class deque;
20
21 namespace aux
22 {
23 /**
24 * Note: We decided that these iterators contain a
25 * reference to the container and an index, which
26 * allows us to use the already implemented operator[]
27 * on deque and also allows us to conform to the requirement
28 * of the standard that functions such as push_back
29 * invalidate the .end() iterator.
30 */
31
32 template<class T, class Allocator>
33 class deque_iterator;
34
35 template<class T, class Allocator>
36 class deque_const_iterator
37 {
38 public:
39 using size_type = typename deque<T, Allocator>::size_type;
40 using value_type = typename deque<T, Allocator>::value_type;
41 using reference = typename deque<T, Allocator>::const_reference;
42 using difference_type = size_type;
43 using pointer = const value_type*;
44 using iterator_category = random_access_iterator_tag;
45
46 deque_const_iterator(const deque<T, Allocator>& deq, size_type idx)
47 : deq_{deq}, idx_{idx}
48 { /* DUMMY BODY */ }
49
50 deque_const_iterator(const deque_const_iterator& other)
51 : deq_{other.deq_}, idx_{other.idx_}
52 { /* DUMMY BODY */ }
53
54 deque_const_iterator& operator=(const deque_const_iterator& other)
55 {
56 deq_ = other.deq_;
57 idx_ = other.idx_;
58
59 return *this;
60 }
61
62 reference operator*() const
63 {
64 return deq_[idx_];
65 }
66
67 pointer operator->() const
68 {
69 return addressof(deq_[idx_]);
70 }
71
72 deque_const_iterator& operator++()
73 {
74 ++idx_;
75
76 return *this;
77 }
78
79 deque_const_iterator operator++(int)
80 {
81 return deque_const_iterator{deq_, idx_++};
82 }
83
84 deque_const_iterator& operator--()
85 {
86 --idx_;
87
88 return *this;
89 }
90
91 deque_const_iterator operator--(int)
92 {
93 return deque_const_iterator{deq_, idx_--};
94 }
95
96 deque_const_iterator operator+(difference_type n)
97 {
98 return deque_const_iterator{deq_, idx_ + n};
99 }
100
101 deque_const_iterator& operator+=(difference_type n)
102 {
103 idx_ += n;
104
105 return *this;
106 }
107
108 deque_const_iterator operator-(difference_type n)
109 {
110 return deque_const_iterator{deq_, idx_ - n};
111 }
112
113 deque_const_iterator& operator-=(difference_type n)
114 {
115 idx_ -= n;
116
117 return *this;
118 }
119
120 reference operator[](difference_type n) const
121 {
122 return deq_[idx_ + n];
123 }
124
125 difference_type operator-(const deque_const_iterator& rhs)
126 {
127 return idx_ - rhs.idx_;
128 }
129
130 size_type idx() const
131 {
132 return idx_;
133 }
134
135 operator deque_iterator<T, Allocator>()
136 {
137 return deque_iterator{
138 const_cast<deque<T, Allocator>&>(deq_), idx_
139 };
140 }
141
142 private:
143 const deque<T, Allocator>& deq_;
144 size_type idx_;
145 };
146
147 template<class T, class Allocator>
148 bool operator==(const deque_const_iterator<T, Allocator>& lhs,
149 const deque_const_iterator<T, Allocator>& rhs)
150 {
151 return lhs.idx() == rhs.idx();
152 }
153
154 template<class T, class Allocator>
155 bool operator!=(const deque_const_iterator<T, Allocator>& lhs,
156 const deque_const_iterator<T, Allocator>& rhs)
157 {
158 return !(lhs == rhs);
159 }
160
161 template<class T, class Allocator>
162 class deque_iterator
163 {
164 public:
165 using size_type = typename deque<T, Allocator>::size_type;
166 using value_type = typename deque<T, Allocator>::value_type;
167 using reference = typename deque<T, Allocator>::reference;
168 using difference_type = size_type;
169 using pointer = value_type*;
170 using iterator_category = random_access_iterator_tag;
171
172 deque_iterator(deque<T, Allocator>& deq, size_type idx)
173 : deq_{deq}, idx_{idx}
174 { /* DUMMY BODY */ }
175
176 deque_iterator(const deque_iterator& other)
177 : deq_{other.deq_}, idx_{other.idx_}
178 { /* DUMMY BODY */ }
179
180 deque_iterator(const deque_const_iterator<T, Allocator>& other)
181 : deq_{other.deq_}, idx_{other.idx_}
182 { /* DUMMY BODY */ }
183
184 deque_iterator& operator=(const deque_iterator& other)
185 {
186 deq_ = other.deq_;
187 idx_ = other.idx_;
188
189 return *this;
190 }
191
192 deque_iterator& operator=(const deque_const_iterator<T, Allocator>& other)
193 {
194 deq_ = other.deq_;
195 idx_ = other.idx_;
196
197 return *this;
198 }
199
200 reference operator*()
201 {
202 return deq_[idx_];
203 }
204
205 pointer operator->()
206 {
207 return addressof(deq_[idx_]);
208 }
209
210 deque_iterator& operator++()
211 {
212 ++idx_;
213
214 return *this;
215 }
216
217 deque_iterator operator++(int)
218 {
219 return deque_iterator{deq_, idx_++};
220 }
221
222 deque_iterator& operator--()
223 {
224 --idx_;
225
226 return *this;
227 }
228
229 deque_iterator operator--(int)
230 {
231 return deque_iterator{deq_, idx_--};
232 }
233
234 deque_iterator operator+(difference_type n)
235 {
236 return deque_iterator{deq_, idx_ + n};
237 }
238
239 deque_iterator& operator+=(difference_type n)
240 {
241 idx_ += n;
242
243 return *this;
244 }
245
246 deque_iterator operator-(difference_type n)
247 {
248 return deque_iterator{deq_, idx_ - n};
249 }
250
251 deque_iterator& operator-=(difference_type n)
252 {
253 idx_ -= n;
254
255 return *this;
256 }
257
258 reference operator[](difference_type n) const
259 {
260 return deq_[idx_ + n];
261 }
262
263 difference_type operator-(const deque_iterator& rhs)
264 {
265 return idx_ - rhs.idx_;
266 }
267
268 size_type idx() const
269 {
270 return idx_;
271 }
272
273 operator deque_const_iterator<T, Allocator>()
274 {
275 return deque_const_iterator{deq_, idx_};
276 }
277
278 private:
279 deque<T, Allocator>& deq_;
280 size_type idx_;
281 };
282
283 template<class T, class Allocator>
284 bool operator==(const deque_iterator<T, Allocator>& lhs,
285 const deque_iterator<T, Allocator>& rhs)
286 {
287 return lhs.idx() == rhs.idx();
288 }
289
290 template<class T, class Allocator>
291 bool operator!=(const deque_iterator<T, Allocator>& lhs,
292 const deque_iterator<T, Allocator>& rhs)
293 {
294 return !(lhs == rhs);
295 }
296 }
297
298 /**
299 * 23.3.3 deque:
300 */
301
302 template<class T, class Allocator>
303 class deque
304 {
305 public:
306 using allocator_type = Allocator;
307 using value_type = T;
308 using reference = value_type&;
309 using const_reference = const value_type&;
310
311 using iterator = aux::deque_iterator<T, Allocator>;
312 using const_iterator = aux::deque_const_iterator<T, Allocator>;
313 using reverse_iterator = std::reverse_iterator<iterator>;
314 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
315
316 using size_type = typename allocator_traits<allocator_type>::size_type;
317 using difference_type = typename allocator_traits<allocator_type>::difference_type;
318 using pointer = typename allocator_traits<allocator_type>::pointer;
319 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
320
321 /**
322 * 23.3.3.2, construct/copy/destroy:
323 */
324
325 deque()
326 : deque{allocator_type{}}
327 { /* DUMMY BODY */ }
328
329 explicit deque(const allocator_type& alloc)
330 : allocator_{alloc}, front_bucket_idx_{bucket_size_},
331 back_bucket_idx_{0}, front_bucket_{default_front_},
332 back_bucket_{default_back_}, bucket_count_{default_bucket_count_},
333 bucket_capacity_{default_bucket_capacity_}, size_{}, data_{}
334 {
335 init_();
336 }
337
338 explicit deque(size_type n, const allocator_type& alloc = allocator_type{})
339 : allocator_{alloc}, front_bucket_idx_{bucket_size_}, back_bucket_idx_{},
340 front_bucket_{}, back_bucket_{}, bucket_count_{},
341 bucket_capacity_{}, size_{n}, data_{}
342 {
343 prepare_for_size_(n);
344 init_();
345
346 for (size_type i = 0; i < size_; ++i)
347 allocator_.construct(&(*this)[i]);
348 back_bucket_idx_ = size_ % bucket_size_;
349 }
350
351 deque(size_type n, const value_type& value, const allocator_type& alloc = allocator_type{})
352 : allocator_{alloc}, front_bucket_idx_{bucket_size_}, back_bucket_idx_{},
353 front_bucket_{}, back_bucket_{}, bucket_count_{},
354 bucket_capacity_{}, size_{n}, data_{}
355 {
356 prepare_for_size_(n);
357 init_();
358
359 for (size_type i = 0; i < size_; ++i)
360 (*this)[i] = value;
361 back_bucket_idx_ = size_ % bucket_size_;
362 }
363
364 template<class InputIterator>
365 deque(InputIterator first, InputIterator last,
366 const allocator_type& alloc = allocator_type{})
367 : allocator_{alloc}, front_bucket_idx_{bucket_size_},
368 back_bucket_idx_{}, front_bucket_{}, back_bucket_{},
369 bucket_count_{}, bucket_capacity_{}, size_{},
370 data_{}
371 {
372 copy_from_range_(first, last);
373 }
374
375 deque(const deque& other)
376 : deque{other.begin(), other.end(), other.allocator_}
377 { /* DUMMY BODY */ }
378
379 deque(deque&& other)
380 : allocator_{move(other.allocator_)},
381 front_bucket_idx_{other.front_bucket_idx_},
382 back_bucket_idx_{other.back_bucket_idx_},
383 front_bucket_{other.front_bucket_},
384 back_bucket_{other.back_bucket_},
385 bucket_count_{other.bucket_count_},
386 bucket_capacity_{other.bucket_capacity_},
387 size_{other.size_}, data_{other.data_}
388 {
389 other.data_ = nullptr;
390 other.clear();
391 }
392
393 deque(const deque& other, const allocator_type& alloc)
394 : deque{other.begin(), other.end(), alloc}
395 { /* DUMMY BODY */ }
396
397 deque(deque&& other, const allocator_type& alloc)
398 : allocator_{alloc},
399 front_bucket_idx_{other.front_bucket_idx_},
400 back_bucket_idx_{other.front_bucket_idx_},
401 front_bucket_{other.front_bucket_},
402 back_bucket_{other.back_bucket_},
403 bucket_count_{other.bucket_count_},
404 bucket_capacity_{other.bucket_capacity_},
405 size_{other.size_}, data_{other.data_}
406 {
407 other.data_ = nullptr;
408 other.clear();
409 }
410
411 deque(initializer_list<T> init, const allocator_type& alloc = allocator_type{})
412 : allocator_{alloc}, front_bucket_idx_{bucket_size_},
413 back_bucket_idx_{}, front_bucket_{}, back_bucket_{},
414 bucket_count_{}, bucket_capacity_{}, size_{},
415 data_{}
416 {
417 copy_from_range_(init.begin(), init.end());
418 }
419
420 ~deque()
421 {
422 fini_();
423 }
424
425 deque& operator=(const deque& other)
426 {
427 if (data_)
428 fini_();
429
430 copy_from_range_(other.begin(), other.end());
431
432 return *this;
433 }
434
435 deque& operator=(deque&& other)
436 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
437 {
438 swap(other);
439 other.clear();
440
441 return *this;
442 }
443
444 deque& operator=(initializer_list<T> init)
445 {
446 if (data_)
447 fini_();
448
449 copy_from_range_(init.begin(), init.end());
450
451 return *this;
452 }
453
454 template<class InputIterator>
455 void assign(InputIterator first, InputIterator last)
456 {
457 copy_from_range_(first, last);
458 }
459
460 void assign(size_type n, const T& value)
461 {
462 prepare_for_size_(n);
463 init_();
464 size_ = n;
465
466 auto it = begin();
467 for (size_type i = size_type{}; i < n; ++i)
468 *it++ = value;
469 }
470
471 void assign(initializer_list<T> init)
472 {
473 copy_from_range_(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 aux::deque_iterator{*this, 0};
484 }
485
486 const_iterator begin() const noexcept
487 {
488 return aux::deque_const_iterator{*this, 0};
489 }
490
491 iterator end() noexcept
492 {
493 return aux::deque_iterator{*this, size_};
494 }
495
496 const_iterator end() const noexcept
497 {
498 return aux::deque_const_iterator{*this, size_};
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 aux::deque_const_iterator{*this, 0};
524 }
525
526 const_iterator cend() const noexcept
527 {
528 return aux::deque_const_iterator{*this, size_};
529 }
530
531 const_reverse_iterator crbegin() const noexcept
532 {
533 return make_reverse_iterator(cend());
534 }
535
536 const_reverse_iterator crend() const noexcept
537 {
538 return make_reverse_iterator(cbegin());
539 }
540
541 /**
542 * 23.3.3.3, capacity:
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 if (sz <= size_)
558 {
559 auto count = size_ - sz;
560 for (size_type i = 0; i < count; ++i)
561 pop_back();
562 }
563 else
564 {
565 value_type value{};
566 auto count = sz - size_;
567 for (size_type i = 0; i < count; ++i)
568 push_back(value);
569 }
570 }
571
572 void resize(size_type sz, const value_type& value)
573 {
574 if (sz <= size_)
575 {
576 auto count = size_ - sz;
577 for (size_type i = 0; i < count; ++i)
578 pop_back();
579 }
580 else
581 {
582 auto count = sz - size_;
583 for (size_type i = 0; i < count; ++i)
584 push_back(value);
585 }
586 }
587
588 void shrink_to_fit()
589 {
590 /**
591 * We lazily allocate buckets and eagerily deallocate them.
592 * We cannot go into smaller pieces as buckets have fixed size.
593 * Because of this, shrink_to_fit has no effect (as permitted
594 * by the standard).
595 */
596 }
597
598 bool empty() const noexcept
599 {
600 return size_ == size_type{};
601 }
602
603 reference operator[](size_type idx)
604 {
605 return data_[get_bucket_index_(idx)][get_element_index_(idx)];
606 }
607
608 const_reference operator[](size_type idx) const
609 {
610 return data_[get_bucket_index_(idx)][get_element_index_(idx)];
611 }
612
613 reference at(size_type idx)
614 {
615 // TODO: bounds checking
616 return operator[](idx);
617 }
618
619 const_reference at(size_type idx) const
620 {
621 // TODO: bounds checking
622 return operator[](idx);
623 }
624
625 reference front()
626 {
627 return *begin();
628 }
629
630 const_reference front() const
631 {
632 return *cbegin();
633 }
634
635 reference back()
636 {
637 auto tmp = end();
638
639 return *(--tmp);
640 }
641
642 const_reference back() const
643 {
644 auto tmp = cend();
645
646 return *(--tmp);
647 }
648
649 /**
650 * 23.3.3.4, modifiers:
651 */
652
653 template<class... Args>
654 void emplace_front(Args&&... args)
655 {
656 if (front_bucket_idx_ == 0)
657 add_new_bucket_front_();
658
659 allocator_traits<allocator_type>::construct(
660 allocator_,
661 &data_[front_bucket_][--front_bucket_idx_],
662 forward<Args>(args)...
663 );
664
665 ++size_;
666 }
667
668 template<class... Args>
669 void emplace_back(Args&&... args)
670 {
671 allocator_traits<allocator_type>::construct(
672 allocator_,
673 &data_[back_bucket_][back_bucket_idx_++],
674 forward<Args>(args)...
675 );
676
677 ++size_;
678
679 if (back_bucket_idx_ >= bucket_size_)
680 add_new_bucket_back_();
681 }
682
683 template<class... Args>
684 iterator emplace(const_iterator position, Args&&... args)
685 {
686 auto idx = position.idx();
687 shift_right_(idx, 1);
688
689 allocator_traits<allocator_type>::construct(
690 allocator_,
691 &data_[get_bucket_index_(idx)][get_element_index_(idx)],
692 forward<Args>(args)...
693 );
694 ++size_;
695
696 return iterator{*this, idx};
697 }
698
699 void push_front(const value_type& value)
700 {
701 if (front_bucket_idx_ == 0)
702 add_new_bucket_front_();
703
704 data_[front_bucket_][--front_bucket_idx_] = value;
705 ++size_;
706 }
707
708 void push_front(value_type&& value)
709 {
710 if (front_bucket_idx_ == 0)
711 add_new_bucket_front_();
712
713 data_[front_bucket_][--front_bucket_idx_] = forward<value_type>(value);
714 ++size_;
715 }
716
717 void push_back(const value_type& value)
718 {
719 data_[back_bucket_][back_bucket_idx_++] = value;
720 ++size_;
721
722 if (back_bucket_idx_ >= bucket_size_)
723 add_new_bucket_back_();
724 }
725
726 void push_back(value_type&& value)
727 {
728 data_[back_bucket_][back_bucket_idx_++] = forward<value_type>(value);
729 ++size_;
730
731 if (back_bucket_idx_ >= bucket_size_)
732 add_new_bucket_back_();
733 }
734
735 iterator insert(const_iterator position, const value_type& value)
736 {
737 auto idx = position.idx();
738 shift_right_(idx, 1);
739
740 /**
741 * Note: One may notice that when working with the deque
742 * iterator, we use its index without any checks.
743 * This is because a valid iterator will always have
744 * a valid index as functions like pop_back or erase
745 * invalidate iterators.
746 */
747 data_[get_bucket_index_(idx)][get_element_index_(idx)] = value;
748 ++size_;
749
750 return iterator{*this, idx};
751 }
752
753 iterator insert(const_iterator position, value_type&& value)
754 {
755 auto idx = position.idx();
756 shift_right_(idx, 1);
757
758 data_[get_bucket_index_(idx)][get_element_index_(idx)] = forward<value_type>(value);
759 ++size_;
760
761 return iterator{*this, idx};
762 }
763
764 iterator insert(const_iterator position, size_type n, const value_type& value)
765 {
766 return insert(
767 position,
768 aux::insert_iterator<int>{0u, value},
769 aux::insert_iterator<int>{n}
770 );
771 }
772
773 template<class InputIterator>
774 iterator insert(const_iterator position, InputIterator first, InputIterator last)
775 {
776 auto idx = position.idx();
777 auto count = distance(first, last);
778
779 if (idx < size_ / 2)
780 {
781 shift_left_(idx, count);
782
783 iterator it{*this, idx - 1};
784 while (first != last)
785 *it++ = *first++;
786 }
787 else
788 {
789 shift_right_(idx, count);
790
791 iterator it{*this, idx};
792 while (first != last)
793 *it++ = *first++;
794 }
795
796 size_ += count;
797
798 return iterator{*this, idx};
799 }
800
801 iterator insert(const_iterator position, initializer_list<value_type> init)
802 {
803 return insert(position, init.begin(), init.end());
804 }
805
806 void pop_back()
807 {
808 if (empty())
809 return;
810
811 if (back_bucket_idx_ == 0)
812 { // Means we gotta pop data_[back_bucket_ - 1][bucket_size_ - 1]!
813 if (data_[back_bucket_])
814 allocator_.deallocate(data_[back_bucket_], bucket_size_);
815
816 --back_bucket_;
817 back_bucket_idx_ = bucket_size_ - 1;
818 }
819 else
820 --back_bucket_idx_;
821
822 allocator_.destroy(&data_[back_bucket_][back_bucket_idx_]);
823 --size_;
824 }
825
826 void pop_front()
827 {
828 if (empty())
829 return;
830
831 if (front_bucket_idx_ >= bucket_size_)
832 { // Means we gotta pop data_[front_bucket_ + 1][0]!
833 if (data_[front_bucket_])
834 allocator_.deallocate(data_[front_bucket_], bucket_size_);
835
836 ++front_bucket_;
837 front_bucket_idx_ = 1;
838
839 allocator_.destroy(&data_[front_bucket_][0]);
840 }
841 else
842 {
843 allocator_.destroy(&data_[front_bucket_][front_bucket_idx_]);
844
845 ++front_bucket_idx_;
846 }
847
848 --size_;
849 }
850
851 iterator erase(const_iterator position)
852 {
853 auto idx = position.idx();
854 copy(
855 iterator{*this, idx + 1},
856 end(),
857 iterator{*this, idx}
858 );
859
860 /**
861 * Note: We need to not only decrement size,
862 * but also take care of any issues caused
863 * by decrement bucket indices, which pop_back
864 * does for us.
865 */
866 pop_back();
867
868 return iterator{*this, idx};
869 }
870
871 iterator erase(const_iterator first, const_iterator last)
872 {
873 if (first == last)
874 return first;
875
876 auto first_idx = first.idx();
877 auto last_idx = last.idx();
878 auto count = distance(first, last);
879
880 copy(
881 iterator{*this, last_idx},
882 end(),
883 iterator{*this, first_idx}
884 );
885
886 for (size_type i = 0; i < count; ++i)
887 pop_back();
888
889 return iterator{*this, first_idx};
890 }
891
892 void swap(deque& other)
893 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
894 {
895 std::swap(allocator_, other.allocator_);
896 std::swap(front_bucket_idx_, other.front_bucket_idx_);
897 std::swap(back_bucket_idx_, other.back_bucket_idx_);
898 std::swap(front_bucket_, other.front_bucket_);
899 std::swap(back_bucket_, other.back_bucket_);
900 std::swap(bucket_count_, other.bucket_count_);
901 std::swap(bucket_capacity_, other.bucket_capacity_);
902 std::swap(size_, other.size_);
903 std::swap(data_, other.data_);
904 }
905
906 void clear() noexcept
907 {
908 if (data_)
909 fini_();
910
911 front_bucket_ = default_front_;
912 back_bucket_ = default_back_;
913 bucket_count_ = default_bucket_count_;
914 bucket_capacity_ = default_bucket_capacity_;
915 size_ = size_type{};
916
917 init_();
918 }
919
920 private:
921 allocator_type allocator_;
922
923 /**
924 * Note: In our implementation, front_bucket_idx_
925 * points at the first element and back_bucket_idx_
926 * points at the one past last element. Because of this,
927 * some operations may be done in inverse order
928 * depending on the side they are applied to.
929 */
930 size_type front_bucket_idx_;
931 size_type back_bucket_idx_;
932 size_type front_bucket_;
933 size_type back_bucket_;
934
935 static constexpr size_type bucket_size_{16};
936 static constexpr size_type default_bucket_count_{2};
937 static constexpr size_type default_bucket_capacity_{4};
938 static constexpr size_type default_front_{1};
939 static constexpr size_type default_back_{2};
940
941 size_type bucket_count_;
942 size_type bucket_capacity_;
943 size_type size_{};
944
945 value_type** data_;
946
947 void init_()
948 {
949 data_ = new value_type*[bucket_capacity_];
950
951 for (size_type i = front_bucket_; i <= back_bucket_; ++i)
952 data_[i] = allocator_.allocate(bucket_size_);
953 }
954
955 void prepare_for_size_(size_type size)
956 {
957 if (data_)
958 fini_();
959
960 bucket_count_ = bucket_capacity_ = size / bucket_size_ + 2;
961
962 front_bucket_ = 0;
963 back_bucket_ = bucket_capacity_ - 1;
964
965 front_bucket_idx_ = bucket_size_;
966 back_bucket_idx_ = size % bucket_size_;
967 }
968
969 template<class Iterator>
970 void copy_from_range_(Iterator first, Iterator last)
971 {
972 size_ = distance(first, last);
973 prepare_for_size_(size_);
974 init_();
975
976 auto it = begin();
977 while (first != last)
978 *it++ = *first++;
979 }
980
981 void ensure_space_front_(size_type idx, size_type count)
982 {
983 auto free_space = bucket_size_ - elements_in_front_bucket_();
984 if (front_bucket_idx_ == 0)
985 free_space = 0;
986
987 if (count <= free_space)
988 {
989 front_bucket_idx_ -= count;
990 return;
991 }
992
993 count -= free_space;
994
995 auto buckets_needed = count / bucket_size_;
996 if (count % bucket_size_ != 0)
997 ++buckets_needed;
998
999 for (size_type i = size_type{}; i < buckets_needed; ++i)
1000 add_new_bucket_front_();
1001
1002 front_bucket_idx_ = bucket_size_ - (count % bucket_size_);
1003 }
1004
1005 void ensure_space_back_(size_type idx, size_type count)
1006 {
1007 auto free_space = bucket_size_ - back_bucket_idx_;
1008 if (count < free_space)
1009 return;
1010
1011 count -= free_space;
1012 auto buckets_needed = count / bucket_size_;
1013 if (count % bucket_size_ != 0)
1014 ++buckets_needed;
1015
1016 for (size_type i = size_type{}; i < buckets_needed; ++i)
1017 add_new_bucket_back_();
1018
1019 back_bucket_idx_ = (back_bucket_idx_ + count) % bucket_size_;
1020 }
1021
1022 void shift_right_(size_type idx, size_type count)
1023 {
1024 ensure_space_back_(idx, count);
1025
1026 iterator it{*this, idx};
1027 copy_backward(it, end(), end() + count - 1);
1028
1029 }
1030
1031 void shift_left_(size_type idx, size_type count)
1032 {
1033 ensure_space_front_(idx, count);
1034
1035 copy(
1036 iterator{*this, count},
1037 iterator{*this, idx + count - 1},
1038 iterator{*this, 0}
1039 );
1040 }
1041
1042 void fini_()
1043 {
1044 for (size_type i = front_bucket_; i <= back_bucket_; ++i)
1045 allocator_.deallocate(data_[i], bucket_size_);
1046
1047 delete[] data_;
1048 data_ = nullptr;
1049 }
1050
1051 bool has_bucket_space_back_() const
1052 {
1053 return back_bucket_ < bucket_capacity_ - 1;
1054 }
1055
1056 bool has_bucket_space_front_() const
1057 {
1058 return front_bucket_ > 0;
1059 }
1060
1061 void add_new_bucket_back_()
1062 {
1063 if (!has_bucket_space_back_())
1064 expand_();
1065
1066 ++back_bucket_;
1067 ++bucket_count_;
1068 data_[back_bucket_] = allocator_.allocate(bucket_size_);
1069 back_bucket_idx_ = size_type{};
1070 }
1071
1072 void add_new_bucket_front_()
1073 {
1074 if (!has_bucket_space_front_())
1075 expand_();
1076
1077 --front_bucket_;
1078 ++bucket_count_;
1079 data_[front_bucket_] = allocator_.allocate(bucket_size_);
1080 front_bucket_idx_ = bucket_size_;
1081 }
1082
1083 void expand_()
1084 {
1085 bucket_capacity_ *= 2;
1086 value_type** new_data = new value_type*[bucket_capacity_];
1087
1088 /**
1089 * Note: This currently expands both sides whenever one reaches
1090 * its limit. Might be better to expand only one (or both when
1091 * the other is near its limit)?
1092 */
1093 size_type new_front = bucket_capacity_ / 4;
1094 size_type new_back = new_front + bucket_count_ - 1;
1095
1096 for (size_type i = new_front, j = front_bucket_; i <= new_back; ++i, ++j)
1097 new_data[i] = move(data_[j]);
1098 std::swap(data_, new_data);
1099
1100 delete[] new_data;
1101 front_bucket_ = new_front;
1102 back_bucket_ = new_back;
1103 }
1104
1105 size_type get_bucket_index_(size_type idx) const
1106 {
1107 if (idx < elements_in_front_bucket_())
1108 return front_bucket_;
1109
1110 idx -= elements_in_front_bucket_();
1111 return idx / bucket_size_ + front_bucket_ + 1;
1112 }
1113
1114 size_type get_element_index_(size_type idx) const
1115 {
1116 if (idx < elements_in_front_bucket_())
1117 return bucket_size_ - elements_in_front_bucket_() + idx;
1118
1119 idx -= elements_in_front_bucket_();
1120 return idx % bucket_size_;
1121 }
1122
1123 size_type elements_in_front_bucket_() const
1124 {
1125 return bucket_size_ - front_bucket_idx_;
1126 }
1127 };
1128
1129 template<class T, class Allocator>
1130 bool operator==(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
1131 {
1132 if (lhs.size() != rhs.size())
1133 return false;
1134
1135 for (decltype(lhs.size()) i = 0; i < lhs.size(); ++i)
1136 {
1137 if (lhs[i] != rhs[i])
1138 return false;
1139 }
1140
1141 return true;
1142 }
1143
1144 template<class T, class Allocator>
1145 bool operator<(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
1146 {
1147 auto min_size = min(lhs.size(), rhs.size());
1148 for (decltype(lhs.size()) i = 0; i < min_size; ++i)
1149 {
1150 if (lhs[i] >= rhs[i])
1151 return false;
1152 }
1153
1154 if (lhs.size() == rhs.size())
1155 return true;
1156 else
1157 return lhs.size() < rhs.size();
1158 }
1159
1160 template<class T, class Allocator>
1161 bool operator!=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
1162 {
1163 return !(lhs == rhs);
1164 }
1165
1166 template<class T, class Allocator>
1167 bool operator>(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
1168 {
1169 return rhs < lhs;
1170 }
1171
1172 template<class T, class Allocator>
1173 bool operator<=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
1174 {
1175 return !(rhs < lhs);
1176 }
1177
1178 template<class T, class Allocator>
1179 bool operator>=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
1180 {
1181 return !(lhs < rhs);
1182 }
1183
1184 /**
1185 * 23.3.3.5, deque specialized algorithms:
1186 */
1187
1188 template<class T, class Allocator>
1189 void swap(deque<T, Allocator>& lhs, deque<T, Allocator>& rhs)
1190 noexcept(noexcept(lhs.swap(rhs)))
1191 {
1192 lhs.swap(rhs);
1193 }
1194}
1195
1196#endif
Note: See TracBrowser for help on using the repository browser.