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

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

cpp: added assign, front/back emplace and fixed bugs

  • Property mode set to 100644
File size: 31.0 KB
RevLine 
[7a7ecbd]1/*
[3a06cc6]2 * Copyright (c) 2018 Jaroslav Jindrak
[7a7ecbd]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>
[3a06cc6]33#include <iterator>
[7a7ecbd]34#include <memory>
35
36namespace std
37{
[3a06cc6]38 template<class T, class Allocator = allocator<T>>
39 class deque;
[7a7ecbd]40
41 namespace aux
42 {
[6e93323]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
[7a7ecbd]52 template<class T, class Allocator>
[6e93323]53 class deque_const_iterator
[7a7ecbd]54 {
[3a06cc6]55 public:
[6e93323]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
[5072c67]63 deque_const_iterator(const deque<T, Allocator>& deq, size_type idx)
[3a06cc6]64 : deq_{deq}, idx_{idx}
65 { /* DUMMY BODY */ }
66
[6e93323]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
[5072c67]138 difference_type operator-(const deque_const_iterator& rhs)
139 {
140 return idx_ - rhs.idx_;
141 }
142
[6e93323]143 size_type idx() const
144 {
145 return idx_;
146 }
147
[3a06cc6]148 private:
[5072c67]149 const deque<T, Allocator>& deq_;
[3a06cc6]150 size_type idx_;
[7a7ecbd]151 };
152
153 template<class T, class Allocator>
[6e93323]154 bool operator==(const deque_const_iterator<T, Allocator>& lhs,
155 const deque_const_iterator<T, Allocator>& rhs)
156 {
157 return lhs.idx() == rhs.idx();
158 }
159
160 template<class T, class Allocator>
161 bool operator!=(const deque_const_iterator<T, Allocator>& lhs,
162 const deque_const_iterator<T, Allocator>& rhs)
[7a7ecbd]163 {
[6e93323]164 return !(lhs == rhs);
165 }
166
167 template<class T, class Allocator>
168 class deque_iterator
169 {
170 public:
171 using size_type = typename deque<T, Allocator>::size_type;
172 using value_type = typename deque<T, Allocator>::value_type;
173 using reference = typename deque<T, Allocator>::reference;
174 using difference_type = size_type;
175 using pointer = value_type*;
176 using iterator_category = random_access_iterator_tag;
177
178 deque_iterator(deque<T, Allocator>& deq, size_type idx)
179 : deq_{deq}, idx_{idx}
180 { /* DUMMY BODY */ }
181
182 deque_iterator(const deque_const_iterator<T, Allocator>& other)
183 : deq_{other.deq_}, idx_{other.idx_}
184 { /* DUMMY BODY */ }
185
186 deque_iterator& operator=(const deque_iterator& other)
187 {
188 deq_ = other.deq_;
189 idx_ = other.idx_;
190
191 return *this;
192 }
193
194 deque_iterator& operator=(const deque_const_iterator<T, Allocator>& other)
195 {
196 deq_ = other.deq_;
197 idx_ = other.idx_;
198
199 return *this;
200 }
201
202 reference operator*()
203 {
204 return deq_[idx_];
205 }
206
207 pointer operator->()
208 {
209 return addressof(deq_[idx_]);
210 }
211
212 deque_iterator& operator++()
213 {
214 ++idx_;
215
216 return *this;
217 }
218
219 deque_iterator operator++(int)
220 {
221 return deque_iterator{deq_, idx_++};
222 }
223
224 deque_iterator& operator--()
225 {
226 --idx_;
227
228 return *this;
229 }
230
231 deque_iterator operator--(int)
232 {
233 return deque_iterator{deq_, idx_--};
234 }
235
236 deque_iterator operator+(difference_type n)
237 {
238 return deque_iterator{deq_, idx_ + n};
239 }
240
241 deque_iterator& operator+=(difference_type n)
242 {
243 idx_ += n;
244
245 return *this;
246 }
247
248 deque_iterator operator-(difference_type n)
249 {
250 return deque_iterator{deq_, idx_ - n};
251 }
252
253 deque_iterator& operator-=(difference_type n)
254 {
255 idx_ -= n;
256
257 return *this;
258 }
259
260 reference operator[](difference_type n) const
261 {
262 return deq_[idx_ + n];
263 }
264
[5072c67]265 difference_type operator-(const deque_iterator& rhs)
266 {
267 return idx_ - rhs.idx_;
268 }
269
[6e93323]270 size_type idx() const
271 {
272 return idx_;
273 }
274
275 private:
276 deque<T, Allocator>& deq_;
277 size_type idx_;
[7a7ecbd]278 };
[6e93323]279
280 template<class T, class Allocator>
281 bool operator==(const deque_iterator<T, Allocator>& lhs,
282 const deque_iterator<T, Allocator>& rhs)
283 {
284 return lhs.idx() == rhs.idx();
285 }
286
287 template<class T, class Allocator>
288 bool operator!=(const deque_iterator<T, Allocator>& lhs,
289 const deque_iterator<T, Allocator>& rhs)
290 {
291 return !(lhs == rhs);
292 }
[7a7ecbd]293 }
294
295 /**
296 * 23.3.3 deque:
297 */
298
[3a06cc6]299 template<class T, class Allocator>
[7a7ecbd]300 class deque
301 {
302 public:
303 using allocator_type = Allocator;
304 using value_type = T;
305 using reference = value_type&;
306 using const_reference = const value_type&;
307
308 using iterator = aux::deque_iterator<T, Allocator>;
309 using const_iterator = aux::deque_const_iterator<T, Allocator>;
310 using reverse_iterator = std::reverse_iterator<iterator>;
311 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
312
313 using size_type = typename allocator_traits<allocator_type>::size_type;
314 using difference_type = typename allocator_traits<allocator_type>::difference_type;
315 using pointer = typename allocator_traits<allocator_type>::pointer;
316 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
317
318 /**
319 * 23.3.3.2, construct/copy/destroy:
320 */
321
322 deque()
323 : deque{allocator_type{}}
324 { /* DUMMY BODY */ }
325
326 explicit deque(const allocator_type& alloc)
[3a06cc6]327 : allocator_{alloc}, front_bucket_idx_{bucket_size_},
328 back_bucket_idx_{0}, front_bucket_{default_front_},
329 back_bucket_{default_back_}, bucket_count_{default_bucket_count_},
330 bucket_capacity_{default_bucket_capacity_}, size_{}, data_{}
[7a7ecbd]331 {
[3a06cc6]332 init_();
[7a7ecbd]333 }
334
335 explicit deque(size_type n, const allocator_type& alloc = allocator_type{})
[5072c67]336 : allocator_{alloc}, front_bucket_idx_{bucket_size_}, back_bucket_idx_{},
337 front_bucket_{}, back_bucket_{}, bucket_count_{},
338 bucket_capacity_{}, size_{n}, data_{}
[7a7ecbd]339 {
[5072c67]340 prepare_for_size_(n);
341 init_();
342
343 for (size_type i = 0; i < size_; ++i)
344 allocator_.construct(&(*this)[i]);
345 back_bucket_idx_ = size_ % bucket_size_;
[7a7ecbd]346 }
347
348 deque(size_type n, const value_type& value, const allocator_type& alloc = allocator_type{})
[5072c67]349 : allocator_{alloc}, front_bucket_idx_{bucket_size_}, back_bucket_idx_{},
350 front_bucket_{}, back_bucket_{}, bucket_count_{},
351 bucket_capacity_{}, size_{n}, data_{}
[7a7ecbd]352 {
[5072c67]353 prepare_for_size_(n);
354 init_();
355
356 for (size_type i = 0; i < size_; ++i)
357 (*this)[i] = value;
358 back_bucket_idx_ = size_ % bucket_size_;
[7a7ecbd]359 }
360
361 template<class InputIterator>
[5072c67]362 deque(InputIterator first, InputIterator last,
363 const allocator_type& alloc = allocator_type{})
364 : allocator_{alloc}, front_bucket_idx_{bucket_size_},
365 back_bucket_idx_{}, front_bucket_{}, back_bucket_{},
366 bucket_count_{}, bucket_capacity_{}, size_{},
367 data_{}
[7a7ecbd]368 {
[5072c67]369 copy_from_range_(first, last);
[7a7ecbd]370 }
371
372 deque(const deque& other)
[5072c67]373 : deque{other.begin(), other.end(), other.allocator_}
374 { /* DUMMY BODY */ }
[7a7ecbd]375
376 deque(deque&& other)
[5072c67]377 : allocator_{move(other.allocator_)},
378 front_bucket_idx_{other.front_bucket_idx_},
379 back_bucket_idx_{other.front_bucket_idx_},
380 front_bucket_{other.front_bucket_},
381 back_bucket_{other.back_bucket_},
382 bucket_count_{other.bucket_count_},
383 bucket_capacity_{other.bucket_capacity_},
384 size_{other.size_}, data_{other.data_}
[7a7ecbd]385 {
[5072c67]386 other.data_ = nullptr;
387 other.clear();
[7a7ecbd]388 }
389
390 deque(const deque& other, const allocator_type& alloc)
[5072c67]391 : deque{other.begin(), other.end(), alloc}
392 { /* DUMMY BODY */ }
[7a7ecbd]393
394 deque(deque&& other, const allocator_type& alloc)
[5072c67]395 : allocator_{alloc},
396 front_bucket_idx_{other.front_bucket_idx_},
397 back_bucket_idx_{other.front_bucket_idx_},
398 front_bucket_{other.front_bucket_},
399 back_bucket_{other.back_bucket_},
400 bucket_count_{other.bucket_count_},
401 bucket_capacity_{other.bucket_capacity_},
402 size_{other.size_}, data_{other.data_}
[7a7ecbd]403 {
[5072c67]404 other.data_ = nullptr;
405 other.clear();
[7a7ecbd]406 }
407
408 deque(initializer_list<T> init, const allocator_type& alloc = allocator_type{})
[5072c67]409 : allocator_{alloc}, front_bucket_idx_{bucket_size_},
410 back_bucket_idx_{}, front_bucket_{}, back_bucket_{},
411 bucket_count_{}, bucket_capacity_{}, size_{},
412 data_{}
[7a7ecbd]413 {
[5072c67]414 copy_from_range_(init.begin(), init.end());
[7a7ecbd]415 }
416
417 ~deque()
418 {
[3a06cc6]419 fini_();
[7a7ecbd]420 }
421
422 deque& operator=(const deque& other)
423 {
[0f158be5]424 if (data_)
425 fini_();
426
427 copy_from_range_(other.begin(), other.end());
428
429 return *this;
[7a7ecbd]430 }
431
432 deque& operator=(deque&& other)
433 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
434 {
[5072c67]435 swap(other);
436 other.clear();
[7a7ecbd]437 }
438
439 deque& operator=(initializer_list<T> init)
440 {
[0f158be5]441 if (data_)
442 fini_();
443
444 copy_from_range_(init.begin(), init.end());
445
446 return *this;
[7a7ecbd]447 }
448
449 template<class InputIterator>
450 void assign(InputIterator first, InputIterator last)
451 {
[db05684]452 copy_from_range_(first, last);
[7a7ecbd]453 }
454
455 void assign(size_type n, const T& value)
456 {
[db05684]457 prepare_for_size_(n);
458 init_();
459 size_ = n;
460
461 auto it = begin();
462 for (size_type i = size_type{}; i < n; ++i)
463 *it++ = value;
[7a7ecbd]464 }
465
466 void assign(initializer_list<T> init)
467 {
[db05684]468 copy_from_range_(init.begin(), init.end());
[7a7ecbd]469 }
470
471 allocator_type get_allocator() const noexcept
472 {
473 return allocator_;
474 }
475
476 iterator begin() noexcept
477 {
[6e93323]478 return aux::deque_iterator{*this, 0};
[7a7ecbd]479 }
480
481 const_iterator begin() const noexcept
482 {
[6e93323]483 return aux::deque_const_iterator{*this, 0};
[7a7ecbd]484 }
485
486 iterator end() noexcept
487 {
[6e93323]488 return aux::deque_iterator{*this, size_};
[7a7ecbd]489 }
490
491 const_iterator end() const noexcept
492 {
[6e93323]493 return aux::deque_const_iterator{*this, size_};
[7a7ecbd]494 }
495
496 reverse_iterator rbegin() noexcept
497 {
[6e93323]498 return make_reverse_iterator(end());
[7a7ecbd]499 }
500
501 const_reverse_iterator rbegin() const noexcept
502 {
[6e93323]503 return make_reverse_iterator(cend());
[7a7ecbd]504 }
505
506 reverse_iterator rend() noexcept
507 {
[6e93323]508 return make_reverse_iterator(begin());
[7a7ecbd]509 }
510
511 const_reverse_iterator rend() const noexcept
512 {
[6e93323]513 return make_reverse_iterator(cbegin());
[7a7ecbd]514 }
515
516 const_iterator cbegin() const noexcept
517 {
[6e93323]518 return aux::deque_const_iterator{*this, 0};
[7a7ecbd]519 }
520
521 const_iterator cend() const noexcept
522 {
[6e93323]523 return aux::deque_const_iterator{*this, size_};
[7a7ecbd]524 }
525
526 const_reverse_iterator crbegin() const noexcept
527 {
[6e93323]528 return make_reverse_iterator(cend());
[7a7ecbd]529 }
530
531 const_reverse_iterator crend() const noexcept
532 {
[6e93323]533 return make_reverse_iterator(cbegin());
[7a7ecbd]534 }
535
536 /**
537 * 23.3.3.3, capacity:
538 */
539
540 size_type size() const noexcept
541 {
[3a06cc6]542 return size_;
[7a7ecbd]543 }
544
545 size_type max_size() const noexcept
546 {
[db05684]547 return allocator_traits<allocator_type>::max_size(allocator_);
[7a7ecbd]548 }
549
550 void resize(size_type sz)
551 {
[289c954a]552 if (sz <= size_)
553 {
554 for (size_type i = 0; i < size_ - sz; ++i)
555 pop_back();
556 }
557 else
558 {
559 value_type value{};
560 for (size_type i = 0; i < sz - size_; ++i)
561 push_back(value);
562 }
[7a7ecbd]563 }
564
565 void resize(size_type sz, const value_type& value)
566 {
[289c954a]567 if (sz <= size_)
568 {
569 for (size_type i = 0; i < size_ - sz; ++i)
570 pop_back();
571 }
572 else
573 {
574 for (size_type i = 0; i < sz - size_; ++i)
575 push_back(value);
576 }
[7a7ecbd]577 }
578
579 void shrink_to_fit()
580 {
[289c954a]581 /**
582 * We lazily allocate buckets and eagerily deallocate them.
583 * We cannot go into smaller pieces as buckets have fixed size.
584 * Because of this, shrink_to_fit has no effect (as permitted
585 * by the standard).
586 */
[7a7ecbd]587 }
588
589 bool empty() const noexcept
590 {
[3a06cc6]591 return size_ == size_type{};
[7a7ecbd]592 }
593
594 reference operator[](size_type idx)
595 {
[3a06cc6]596 return data_[get_bucket_index_(idx)][get_element_index_(idx)];
[7a7ecbd]597 }
598
[3a06cc6]599 const_reference operator[](size_type idx) const
[7a7ecbd]600 {
[3a06cc6]601 return data_[get_bucket_index_(idx)][get_element_index_(idx)];
[7a7ecbd]602 }
603
604 reference at(size_type idx)
605 {
[5072c67]606 // TODO: bounds checking
607 return operator[](idx);
[7a7ecbd]608 }
609
[3a06cc6]610 const_reference at(size_type idx) const
[7a7ecbd]611 {
[5072c67]612 // TODO: bounds checking
613 return operator[](idx);
[7a7ecbd]614 }
615
616 reference front()
617 {
[5072c67]618 return *begin();
[7a7ecbd]619 }
620
621 const_reference front() const
622 {
[5072c67]623 return *cbegin();
[7a7ecbd]624 }
625
626 reference back()
627 {
[5072c67]628 auto tmp = end();
629
630 return *(--tmp);
[7a7ecbd]631 }
632
633 const_reference back() const
634 {
[5072c67]635 auto tmp = cend();
636
637 return *(--tmp);
[7a7ecbd]638 }
639
640 /**
641 * 23.3.3.4, modifiers:
642 */
643
644 template<class... Args>
645 void emplace_front(Args&&... args)
646 {
[db05684]647 if (front_bucket_idx_ == 0)
648 add_new_bucket_front_();
649
650 allocator_traits<allocator_type>::construct(
651 allocator_,
652 &data_[front_bucket_][--front_bucket_idx_],
653 forward<Args>(args)...
654 );
655
656 ++size_;
[7a7ecbd]657 }
658
659 template<class... Args>
660 void emplace_back(Args&&... args)
661 {
[db05684]662 allocator_traits<allocator_type>::construct(
663 allocator_,
664 &data_[back_bucket_][back_bucket_idx_++],
665 forward<Args>(args)...
666 );
667
668 ++size_;
669
670 if (back_bucket_idx_ >= bucket_size_)
671 add_new_bucket_back_();
[7a7ecbd]672 }
673
674 template<class... Args>
675 iterator emplace(const_iterator position, Args&&... args)
676 {
677 // TODO: implement
678 }
679
680 void push_front(const value_type& value)
681 {
[3a06cc6]682 if (front_bucket_idx_ == 0)
683 add_new_bucket_front_();
684
685 data_[front_bucket_][--front_bucket_idx_] = value;
686 ++size_;
[7a7ecbd]687 }
688
689 void push_front(value_type&& value)
690 {
[3a06cc6]691 if (front_bucket_idx_ == 0)
692 add_new_bucket_front_();
693
694 data_[front_bucket_][--front_bucket_idx_] = forward<value_type>(value);
695 ++size_;
[7a7ecbd]696 }
697
698 void push_back(const value_type& value)
699 {
[3a06cc6]700 data_[back_bucket_][back_bucket_idx_++] = value;
701 ++size_;
702
703 if (back_bucket_idx_ >= bucket_size_)
704 add_new_bucket_back_();
[7a7ecbd]705 }
706
707 void push_back(value_type&& value)
708 {
[3a06cc6]709 data_[back_bucket_][back_bucket_idx_++] = forward<value_type>(value);
710 ++size_;
711
712 if (back_bucket_idx_ >= bucket_size_)
713 add_new_bucket_back_();
[7a7ecbd]714 }
715
716 iterator insert(const_iterator position, const value_type& value)
717 {
718 // TODO: implement
719 }
720
721 iterator insert(const_iterator position, value_type&& value)
722 {
723 // TODO: implement
724 }
725
726 iterator insert(const_iterator position, size_type n, const value_type& value)
727 {
728 // TODO: implement
729 }
730
731 template<class InputIterator>
732 iterator insert(const_iterator position, InputIterator first, InputIterator last)
733 {
734 // TODO: implement
735 }
736
737 iterator insert(const_iterator position, initializer_list<value_type> init)
738 {
739 // TODO: implement
740 }
741
742 void pop_back()
743 {
[3a06cc6]744 if (empty())
745 return;
746
747 if (back_bucket_idx_ == 0)
748 { // Means we gotta pop data_[front_bucket_][bucket_size_ - 1]!
749 if (data_[back_bucket_])
750 allocator_.deallocate(data_[back_bucket_], bucket_size_);
751
752 --back_bucket_;
753 back_bucket_idx_ = bucket_size_ - 1;
754 }
755 else
756 --back_bucket_idx_;
757
758 allocator_.destroy(&data_[back_bucket_][back_bucket_idx_]);
759 --size_;
[7a7ecbd]760 }
761
762 void pop_front()
763 {
[3a06cc6]764 if (empty())
765 return;
766
767 if (front_bucket_idx_ >= bucket_size_)
768 { // Means we gotta pop data_[front_bucket_][0]!
769 if (data_[front_bucket_])
770 allocator_.deallocate(data_[front_bucket_], bucket_size_);
771
772 ++front_bucket_;
773 front_bucket_idx_ = 1;
774
775 allocator_.destroy(&data_[front_bucket_][0]);
776 }
777 else
778 {
779 allocator_.destroy(&data_[front_bucket_][front_bucket_idx_]);
780
781 ++front_bucket_idx_;
782 }
783
784 --size_;
[7a7ecbd]785 }
786
787 iterator erase(const_iterator position)
788 {
789 // TODO: implement
790 }
791
[3a06cc6]792 iterator erase(const_iterator first, const_iterator last)
[7a7ecbd]793 {
794 // TODO: implement
795 }
796
797 void swap(deque& other)
798 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
799 {
800 // TODO: implement
801 }
802
803 void clear() noexcept
804 {
[5072c67]805 if (data_)
806 fini_();
[3a06cc6]807
808 front_bucket_ = default_front_;
809 back_bucket_ = default_back_;
810 bucket_count_ = default_bucket_count_;
811 bucket_capacity_ = default_bucket_capacity_;
812 size_ = size_type{};
813
814 init_();
[7a7ecbd]815 }
816
[35b706e8]817 private:
[7a7ecbd]818 allocator_type allocator_;
819
[3a06cc6]820 /**
821 * Note: In our implementation, front_bucket_idx_
822 * points at the first element and back_bucket_idx_
823 * points at the one past last element. Because of this,
824 * some operations may be done in inverse order
825 * depending on the side they are applied to.
826 */
[7a7ecbd]827 size_type front_bucket_idx_;
828 size_type back_bucket_idx_;
[3a06cc6]829 size_type front_bucket_;
830 size_type back_bucket_;
[7a7ecbd]831
832 static constexpr size_type bucket_size_{16};
[3a06cc6]833 static constexpr size_type default_bucket_count_{2};
834 static constexpr size_type default_bucket_capacity_{4};
835 static constexpr size_type default_front_{1};
836 static constexpr size_type default_back_{2};
[7a7ecbd]837
838 size_type bucket_count_;
839 size_type bucket_capacity_;
[3a06cc6]840 size_type size_{};
[7a7ecbd]841
842 value_type** data_;
[3a06cc6]843
844 void init_()
845 {
846 data_ = new value_type*[bucket_capacity_];
847
848 for (size_type i = front_bucket_; i <= back_bucket_; ++i)
849 data_[i] = allocator_.allocate(bucket_size_);
850 }
851
[5072c67]852 void prepare_for_size_(size_type size)
853 {
854 if (data_)
855 fini_();
856
857 if (size < bucket_size_) // Always front_bucket_ != back_bucket_.
858 bucket_count_ = bucket_capacity_ = 2;
859 else if (size % bucket_size_ == 0)
[db05684]860 bucket_count_ = bucket_capacity_ = size / bucket_size_ + 2;
[5072c67]861 else
862 bucket_count_ = bucket_capacity_ = size / bucket_size_ + 2;
863
864 front_bucket_ = 0;
865 back_bucket_ = bucket_capacity_ - 1;
[db05684]866
867 front_bucket_idx_ = bucket_size_;
868 back_bucket_idx_ = size % bucket_size_;
[5072c67]869 }
870
871 template<class Iterator>
872 void copy_from_range_(Iterator first, Iterator last)
873 {
874 size_ = distance(first, last);
875 prepare_for_size_(size_);
876 init_();
877
878 auto it = begin();
879 while (first != last)
880 *it++ = *first++;
881 }
882
[3a06cc6]883 void fini_()
884 {
885 for (size_type i = front_bucket_; i <= back_bucket_; ++i)
886 allocator_.deallocate(data_[i], bucket_size_);
887
888 delete[] data_;
889 data_ = nullptr;
890 }
891
892 bool has_bucket_space_back_() const
893 {
894 return back_bucket_ < bucket_capacity_ - 1;
895 }
896
897 bool has_bucket_space_front_() const
898 {
899 return front_bucket_ > 0;
900 }
901
902 void add_new_bucket_back_()
903 {
904 if (!has_bucket_space_back_())
905 expand_();
906
907 ++back_bucket_;
908 data_[back_bucket_] = allocator_.allocate(bucket_size_);
909 back_bucket_idx_ = size_type{};
910 }
911
912 void add_new_bucket_front_()
913 {
914 if (!has_bucket_space_front_())
915 expand_();
916
917 --front_bucket_;
918 data_[front_bucket_] = allocator_.allocate(bucket_size_);
919 front_bucket_idx_ = bucket_size_;
920 }
921
922 void expand_()
923 {
924 bucket_capacity_ *= 2;
925 value_type** new_data = new value_type*[bucket_capacity_];
926
927 size_type new_front = bucket_capacity_ / 4;
928 size_type new_back = bucket_capacity_ - bucket_capacity_ / 4 - 1;
929
930 for (size_type i = new_front, j = front_bucket_; i <= new_back; ++i, ++j)
931 new_data[i] = move(data_[j]);
932 std::swap(data_, new_data);
933
934 delete[] new_data;
935 front_bucket_ = new_front;
936 back_bucket_ = new_back;
937 }
938
939 size_type get_bucket_index_(size_type idx) const
940 {
941 if (idx < elements_in_front_bucket_())
942 return front_bucket_;
943
944 idx -= elements_in_front_bucket_();
945 return idx / bucket_size_ + front_bucket_ + 1;
946 }
947
948 size_type get_element_index_(size_type idx) const
949 {
950 if (idx < elements_in_front_bucket_())
951 return bucket_size_ - elements_in_front_bucket_() + idx;
952
953 idx -= elements_in_front_bucket_();
954 return idx % bucket_size_;
955 }
956
957 size_type elements_in_front_bucket_() const
958 {
959 return bucket_size_ - front_bucket_idx_;
960 }
[7a7ecbd]961 };
962
963 template<class T, class Allocator>
964 bool operator==(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
965 {
966 // TODO: implement
[3a06cc6]967 return false;
[7a7ecbd]968 }
969
970 template<class T, class Allocator>
971 bool operator<(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
972 {
973 // TODO: implement
[3a06cc6]974 return false;
[7a7ecbd]975 }
976
977 template<class T, class Allocator>
[3a06cc6]978 bool operator!=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
[7a7ecbd]979 {
980 // TODO: implement
[3a06cc6]981 return false;
[7a7ecbd]982 }
983
984 template<class T, class Allocator>
985 bool operator>(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
986 {
987 // TODO: implement
[3a06cc6]988 return false;
[7a7ecbd]989 }
990
991 template<class T, class Allocator>
992 bool operator<=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
993 {
994 // TODO: implement
[3a06cc6]995 return false;
[7a7ecbd]996 }
997
998 template<class T, class Allocator>
999 bool operator>=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
1000 {
1001 // TODO: implement
[3a06cc6]1002 return false;
[7a7ecbd]1003 }
1004
1005 /**
1006 * 23.3.3.5, deque specialized algorithms:
1007 */
1008
1009 template<class T, class Allocator>
1010 void swap(deque<T, Allocator>& lhs, deque<T, Allocator>& rhs)
1011 noexcept(noexcept(lhs.swap(rhs)))
1012 {
1013 lhs.swap(rhs);
1014 }
1015}
1016
1017#endif
Note: See TracBrowser for help on using the repository browser.