1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_CONTAINERS_CIRCULAR_DEQUE_H_
6 #define BASE_CONTAINERS_CIRCULAR_DEQUE_H_
7
8 #include <algorithm>
9 #include <cstddef>
10 #include <iterator>
11 #include <type_traits>
12 #include <utility>
13
14 #include "base/containers/vector_buffer.h"
15 #include "base/logging.h"
16 #include "base/template_util.h"
17
18 // base::circular_deque is similar to std::deque. Unlike std::deque, the
19 // storage is provided in a flat circular buffer conceptually similar to a
20 // vector. The beginning and end will wrap around as necessary so that
21 // pushes and pops will be constant time as long as a capacity expansion is
22 // not required.
23 //
24 // The API should be identical to std::deque with the following differences:
25 //
26 // - ITERATORS ARE NOT STABLE. Mutating the container will invalidate all
27 // iterators.
28 //
29 // - Insertions may resize the vector and so are not constant time (std::deque
30 // guarantees constant time for insertions at the ends).
31 //
32 // - Container-wide comparisons are not implemented. If you want to compare
33 // two containers, use an algorithm so the expensive iteration is explicit.
34 //
35 // If you want a similar container with only a queue API, use base::queue in
36 // base/containers/queue.h.
37 //
38 // Constructors:
39 // circular_deque();
40 // circular_deque(size_t count);
41 // circular_deque(size_t count, const T& value);
42 // circular_deque(InputIterator first, InputIterator last);
43 // circular_deque(const circular_deque&);
44 // circular_deque(circular_deque&&);
45 // circular_deque(std::initializer_list<value_type>);
46 //
47 // Assignment functions:
48 // circular_deque& operator=(const circular_deque&);
49 // circular_deque& operator=(circular_deque&&);
50 // circular_deque& operator=(std::initializer_list<T>);
51 // void assign(size_t count, const T& value);
52 // void assign(InputIterator first, InputIterator last);
53 // void assign(std::initializer_list<T> value);
54 //
55 // Random accessors:
56 // T& at(size_t);
57 // const T& at(size_t) const;
58 // T& operator[](size_t);
59 // const T& operator[](size_t) const;
60 //
61 // End accessors:
62 // T& front();
63 // const T& front() const;
64 // T& back();
65 // const T& back() const;
66 //
67 // Iterator functions:
68 // iterator begin();
69 // const_iterator begin() const;
70 // const_iterator cbegin() const;
71 // iterator end();
72 // const_iterator end() const;
73 // const_iterator cend() const;
74 // reverse_iterator rbegin();
75 // const_reverse_iterator rbegin() const;
76 // const_reverse_iterator crbegin() const;
77 // reverse_iterator rend();
78 // const_reverse_iterator rend() const;
79 // const_reverse_iterator crend() const;
80 //
81 // Memory management:
82 // void reserve(size_t); // SEE IMPLEMENTATION FOR SOME GOTCHAS.
83 // size_t capacity() const;
84 // void shrink_to_fit();
85 //
86 // Size management:
87 // void clear();
88 // bool empty() const;
89 // size_t size() const;
90 // void resize(size_t);
91 // void resize(size_t count, const T& value);
92 //
93 // Positional insert and erase:
94 // void insert(const_iterator pos, size_type count, const T& value);
95 // void insert(const_iterator pos,
96 // InputIterator first, InputIterator last);
97 // iterator insert(const_iterator pos, const T& value);
98 // iterator insert(const_iterator pos, T&& value);
99 // iterator emplace(const_iterator pos, Args&&... args);
100 // iterator erase(const_iterator pos);
101 // iterator erase(const_iterator first, const_iterator last);
102 //
103 // End insert and erase:
104 // void push_front(const T&);
105 // void push_front(T&&);
106 // void push_back(const T&);
107 // void push_back(T&&);
108 // T& emplace_front(Args&&...);
109 // T& emplace_back(Args&&...);
110 // void pop_front();
111 // void pop_back();
112 //
113 // General:
114 // void swap(circular_deque&);
115
116 namespace base {
117
118 template <class T>
119 class circular_deque;
120
121 namespace internal {
122
123 // Start allocating nonempty buffers with this many entries. This is the
124 // external capacity so the internal buffer will be one larger (= 4) which is
125 // more even for the allocator. See the descriptions of internal vs. external
126 // capacity on the comment above the buffer_ variable below.
127 constexpr size_t kCircularBufferInitialCapacity = 3;
128
129 template <typename T>
130 class circular_deque_const_iterator {
131 public:
132 using difference_type = std::ptrdiff_t;
133 using value_type = T;
134 using pointer = const T*;
135 using reference = const T&;
136 using iterator_category = std::random_access_iterator_tag;
137
circular_deque_const_iterator()138 circular_deque_const_iterator() : parent_deque_(nullptr), index_(0) {
139 #if DCHECK_IS_ON()
140 created_generation_ = 0;
141 #endif // DCHECK_IS_ON()
142 }
143
144 // Dereferencing.
145 const T& operator*() const {
146 CheckUnstableUsage();
147 parent_deque_->CheckValidIndex(index_);
148 return parent_deque_->buffer_[index_];
149 }
150 const T* operator->() const {
151 CheckUnstableUsage();
152 parent_deque_->CheckValidIndex(index_);
153 return &parent_deque_->buffer_[index_];
154 }
155 const value_type& operator[](difference_type i) const { return *(*this + i); }
156
157 // Increment and decrement.
158 circular_deque_const_iterator& operator++() {
159 Increment();
160 return *this;
161 }
162 circular_deque_const_iterator operator++(int) {
163 circular_deque_const_iterator ret = *this;
164 Increment();
165 return ret;
166 }
167 circular_deque_const_iterator& operator--() {
168 Decrement();
169 return *this;
170 }
171 circular_deque_const_iterator operator--(int) {
172 circular_deque_const_iterator ret = *this;
173 Decrement();
174 return ret;
175 }
176
177 // Random access mutation.
178 friend circular_deque_const_iterator operator+(
179 const circular_deque_const_iterator& iter,
180 difference_type offset) {
181 circular_deque_const_iterator ret = iter;
182 ret.Add(offset);
183 return ret;
184 }
185 circular_deque_const_iterator& operator+=(difference_type offset) {
186 Add(offset);
187 return *this;
188 }
189 friend circular_deque_const_iterator operator-(
190 const circular_deque_const_iterator& iter,
191 difference_type offset) {
192 circular_deque_const_iterator ret = iter;
193 ret.Add(-offset);
194 return ret;
195 }
196 circular_deque_const_iterator& operator-=(difference_type offset) {
197 Add(-offset);
198 return *this;
199 }
200
201 friend std::ptrdiff_t operator-(const circular_deque_const_iterator& lhs,
202 const circular_deque_const_iterator& rhs) {
203 lhs.CheckComparable(rhs);
204 return lhs.OffsetFromBegin() - rhs.OffsetFromBegin();
205 }
206
207 // Comparisons.
208 friend bool operator==(const circular_deque_const_iterator& lhs,
209 const circular_deque_const_iterator& rhs) {
210 lhs.CheckComparable(rhs);
211 return lhs.index_ == rhs.index_;
212 }
213 friend bool operator!=(const circular_deque_const_iterator& lhs,
214 const circular_deque_const_iterator& rhs) {
215 return !(lhs == rhs);
216 }
217 friend bool operator<(const circular_deque_const_iterator& lhs,
218 const circular_deque_const_iterator& rhs) {
219 lhs.CheckComparable(rhs);
220 return lhs.OffsetFromBegin() < rhs.OffsetFromBegin();
221 }
222 friend bool operator<=(const circular_deque_const_iterator& lhs,
223 const circular_deque_const_iterator& rhs) {
224 return !(lhs > rhs);
225 }
226 friend bool operator>(const circular_deque_const_iterator& lhs,
227 const circular_deque_const_iterator& rhs) {
228 lhs.CheckComparable(rhs);
229 return lhs.OffsetFromBegin() > rhs.OffsetFromBegin();
230 }
231 friend bool operator>=(const circular_deque_const_iterator& lhs,
232 const circular_deque_const_iterator& rhs) {
233 return !(lhs < rhs);
234 }
235
236 protected:
237 friend class circular_deque<T>;
238
circular_deque_const_iterator(const circular_deque<T> * parent,size_t index)239 circular_deque_const_iterator(const circular_deque<T>* parent, size_t index)
240 : parent_deque_(parent), index_(index) {
241 #if DCHECK_IS_ON()
242 created_generation_ = parent->generation_;
243 #endif // DCHECK_IS_ON()
244 }
245
246 // Returns the offset from the beginning index of the buffer to the current
247 // item.
OffsetFromBegin()248 size_t OffsetFromBegin() const {
249 if (index_ >= parent_deque_->begin_)
250 return index_ - parent_deque_->begin_; // On the same side as begin.
251 return parent_deque_->buffer_.capacity() - parent_deque_->begin_ + index_;
252 }
253
254 // Most uses will be ++ and -- so use a simplified implementation.
Increment()255 void Increment() {
256 CheckUnstableUsage();
257 parent_deque_->CheckValidIndex(index_);
258 index_++;
259 if (index_ == parent_deque_->buffer_.capacity())
260 index_ = 0;
261 }
Decrement()262 void Decrement() {
263 CheckUnstableUsage();
264 parent_deque_->CheckValidIndexOrEnd(index_);
265 if (index_ == 0)
266 index_ = parent_deque_->buffer_.capacity() - 1;
267 else
268 index_--;
269 }
Add(difference_type delta)270 void Add(difference_type delta) {
271 CheckUnstableUsage();
272 #if DCHECK_IS_ON()
273 if (delta <= 0)
274 parent_deque_->CheckValidIndexOrEnd(index_);
275 else
276 parent_deque_->CheckValidIndex(index_);
277 #endif
278 // It should be valid to add 0 to any iterator, even if the container is
279 // empty and the iterator points to end(). The modulo below will divide
280 // by 0 if the buffer capacity is empty, so it's important to check for
281 // this case explicitly.
282 if (delta == 0)
283 return;
284
285 difference_type new_offset = OffsetFromBegin() + delta;
286 DCHECK(new_offset >= 0 &&
287 new_offset <= static_cast<difference_type>(parent_deque_->size()));
288 index_ = (new_offset + parent_deque_->begin_) %
289 parent_deque_->buffer_.capacity();
290 }
291
292 #if DCHECK_IS_ON()
CheckUnstableUsage()293 void CheckUnstableUsage() const {
294 DCHECK(parent_deque_);
295 // Since circular_deque doesn't guarantee stability, any attempt to
296 // dereference this iterator after a mutation (i.e. the generation doesn't
297 // match the original) in the container is illegal.
298 DCHECK_EQ(created_generation_, parent_deque_->generation_)
299 << "circular_deque iterator dereferenced after mutation.";
300 }
CheckComparable(const circular_deque_const_iterator & other)301 void CheckComparable(const circular_deque_const_iterator& other) const {
302 DCHECK_EQ(parent_deque_, other.parent_deque_);
303 // Since circular_deque doesn't guarantee stability, two iterators that
304 // are compared must have been generated without mutating the container.
305 // If this fires, the container was mutated between generating the two
306 // iterators being compared.
307 DCHECK_EQ(created_generation_, other.created_generation_);
308 }
309 #else
CheckUnstableUsage()310 inline void CheckUnstableUsage() const {}
CheckComparable(const circular_deque_const_iterator &)311 inline void CheckComparable(const circular_deque_const_iterator&) const {}
312 #endif // DCHECK_IS_ON()
313
314 const circular_deque<T>* parent_deque_;
315 size_t index_;
316
317 #if DCHECK_IS_ON()
318 // The generation of the parent deque when this iterator was created. The
319 // container will update the generation for every modification so we can
320 // test if the container was modified by comparing them.
321 uint64_t created_generation_;
322 #endif // DCHECK_IS_ON()
323 };
324
325 template <typename T>
326 class circular_deque_iterator : public circular_deque_const_iterator<T> {
327 using base = circular_deque_const_iterator<T>;
328
329 public:
330 friend class circular_deque<T>;
331
332 using difference_type = std::ptrdiff_t;
333 using value_type = T;
334 using pointer = T*;
335 using reference = T&;
336 using iterator_category = std::random_access_iterator_tag;
337
338 // Expose the base class' constructor.
circular_deque_iterator()339 circular_deque_iterator() : circular_deque_const_iterator<T>() {}
340
341 // Dereferencing.
342 T& operator*() const { return const_cast<T&>(base::operator*()); }
343 T* operator->() const { return const_cast<T*>(base::operator->()); }
344 T& operator[](difference_type i) {
345 return const_cast<T&>(base::operator[](i));
346 }
347
348 // Random access mutation.
349 friend circular_deque_iterator operator+(const circular_deque_iterator& iter,
350 difference_type offset) {
351 circular_deque_iterator ret = iter;
352 ret.Add(offset);
353 return ret;
354 }
355 circular_deque_iterator& operator+=(difference_type offset) {
356 base::Add(offset);
357 return *this;
358 }
359 friend circular_deque_iterator operator-(const circular_deque_iterator& iter,
360 difference_type offset) {
361 circular_deque_iterator ret = iter;
362 ret.Add(-offset);
363 return ret;
364 }
365 circular_deque_iterator& operator-=(difference_type offset) {
366 base::Add(-offset);
367 return *this;
368 }
369
370 // Increment and decrement.
371 circular_deque_iterator& operator++() {
372 base::Increment();
373 return *this;
374 }
375 circular_deque_iterator operator++(int) {
376 circular_deque_iterator ret = *this;
377 base::Increment();
378 return ret;
379 }
380 circular_deque_iterator& operator--() {
381 base::Decrement();
382 return *this;
383 }
384 circular_deque_iterator operator--(int) {
385 circular_deque_iterator ret = *this;
386 base::Decrement();
387 return ret;
388 }
389
390 private:
circular_deque_iterator(const circular_deque<T> * parent,size_t index)391 circular_deque_iterator(const circular_deque<T>* parent, size_t index)
392 : circular_deque_const_iterator<T>(parent, index) {}
393 };
394
395 } // namespace internal
396
397 template <typename T>
398 class circular_deque {
399 private:
400 using VectorBuffer = internal::VectorBuffer<T>;
401
402 public:
403 using value_type = T;
404 using size_type = std::size_t;
405 using difference_type = std::ptrdiff_t;
406 using reference = value_type&;
407 using const_reference = const value_type&;
408 using pointer = value_type*;
409 using const_pointer = const value_type*;
410
411 using iterator = internal::circular_deque_iterator<T>;
412 using const_iterator = internal::circular_deque_const_iterator<T>;
413 using reverse_iterator = std::reverse_iterator<iterator>;
414 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
415
416 // ---------------------------------------------------------------------------
417 // Constructor
418
419 constexpr circular_deque() = default;
420
421 // Constructs with |count| copies of |value| or default constructed version.
circular_deque(size_type count)422 circular_deque(size_type count) { resize(count); }
circular_deque(size_type count,const T & value)423 circular_deque(size_type count, const T& value) { resize(count, value); }
424
425 // Range constructor.
426 template <class InputIterator>
circular_deque(InputIterator first,InputIterator last)427 circular_deque(InputIterator first, InputIterator last) {
428 assign(first, last);
429 }
430
431 // Copy/move.
circular_deque(const circular_deque & other)432 circular_deque(const circular_deque& other) : buffer_(other.size() + 1) {
433 assign(other.begin(), other.end());
434 }
circular_deque(circular_deque && other)435 circular_deque(circular_deque&& other) noexcept
436 : buffer_(std::move(other.buffer_)),
437 begin_(other.begin_),
438 end_(other.end_) {
439 other.begin_ = 0;
440 other.end_ = 0;
441 }
442
circular_deque(std::initializer_list<value_type> init)443 circular_deque(std::initializer_list<value_type> init) { assign(init); }
444
~circular_deque()445 ~circular_deque() { DestructRange(begin_, end_); }
446
447 // ---------------------------------------------------------------------------
448 // Assignments.
449 //
450 // All of these may invalidate iterators and references.
451
452 circular_deque& operator=(const circular_deque& other) {
453 if (&other == this)
454 return *this;
455
456 reserve(other.size());
457 assign(other.begin(), other.end());
458 return *this;
459 }
460 circular_deque& operator=(circular_deque&& other) noexcept {
461 if (&other == this)
462 return *this;
463
464 // We're about to overwrite the buffer, so don't free it in clear to
465 // avoid doing it twice.
466 ClearRetainCapacity();
467 buffer_ = std::move(other.buffer_);
468 begin_ = other.begin_;
469 end_ = other.end_;
470
471 other.begin_ = 0;
472 other.end_ = 0;
473
474 IncrementGeneration();
475 return *this;
476 }
477 circular_deque& operator=(std::initializer_list<value_type> ilist) {
478 reserve(ilist.size());
479 assign(std::begin(ilist), std::end(ilist));
480 return *this;
481 }
482
assign(size_type count,const value_type & value)483 void assign(size_type count, const value_type& value) {
484 ClearRetainCapacity();
485 reserve(count);
486 for (size_t i = 0; i < count; i++)
487 emplace_back(value);
488 IncrementGeneration();
489 }
490
491 // This variant should be enabled only when InputIterator is an iterator.
492 template <typename InputIterator>
493 typename std::enable_if<::base::internal::is_iterator<InputIterator>::value,
494 void>::type
assign(InputIterator first,InputIterator last)495 assign(InputIterator first, InputIterator last) {
496 // Possible future enhancement, dispatch on iterator tag type. For forward
497 // iterators we can use std::difference to preallocate the space required
498 // and only do one copy.
499 ClearRetainCapacity();
500 for (; first != last; ++first)
501 emplace_back(*first);
502 IncrementGeneration();
503 }
504
assign(std::initializer_list<value_type> value)505 void assign(std::initializer_list<value_type> value) {
506 reserve(std::distance(value.begin(), value.end()));
507 assign(value.begin(), value.end());
508 }
509
510 // ---------------------------------------------------------------------------
511 // Accessors.
512 //
513 // Since this class assumes no exceptions, at() and operator[] are equivalent.
514
at(size_type i)515 const value_type& at(size_type i) const {
516 DCHECK(i < size());
517 size_t right_size = buffer_.capacity() - begin_;
518 if (begin_ <= end_ || i < right_size)
519 return buffer_[begin_ + i];
520 return buffer_[i - right_size];
521 }
at(size_type i)522 value_type& at(size_type i) {
523 return const_cast<value_type&>(
524 const_cast<const circular_deque*>(this)->at(i));
525 }
526
527 value_type& operator[](size_type i) { return at(i); }
528 const value_type& operator[](size_type i) const {
529 return const_cast<circular_deque*>(this)->at(i);
530 }
531
front()532 value_type& front() {
533 DCHECK(!empty());
534 return buffer_[begin_];
535 }
front()536 const value_type& front() const {
537 DCHECK(!empty());
538 return buffer_[begin_];
539 }
540
back()541 value_type& back() {
542 DCHECK(!empty());
543 return *(--end());
544 }
back()545 const value_type& back() const {
546 DCHECK(!empty());
547 return *(--end());
548 }
549
550 // ---------------------------------------------------------------------------
551 // Iterators.
552
begin()553 iterator begin() { return iterator(this, begin_); }
begin()554 const_iterator begin() const { return const_iterator(this, begin_); }
cbegin()555 const_iterator cbegin() const { return const_iterator(this, begin_); }
556
end()557 iterator end() { return iterator(this, end_); }
end()558 const_iterator end() const { return const_iterator(this, end_); }
cend()559 const_iterator cend() const { return const_iterator(this, end_); }
560
rbegin()561 reverse_iterator rbegin() { return reverse_iterator(end()); }
rbegin()562 const_reverse_iterator rbegin() const {
563 return const_reverse_iterator(end());
564 }
crbegin()565 const_reverse_iterator crbegin() const { return rbegin(); }
566
rend()567 reverse_iterator rend() { return reverse_iterator(begin()); }
rend()568 const_reverse_iterator rend() const {
569 return const_reverse_iterator(begin());
570 }
crend()571 const_reverse_iterator crend() const { return rend(); }
572
573 // ---------------------------------------------------------------------------
574 // Memory management.
575
576 // IMPORTANT NOTE ON reserve(...): This class implements auto-shrinking of
577 // the buffer when elements are deleted and there is "too much" wasted space.
578 // So if you call reserve() with a large size in anticipation of pushing many
579 // elements, but pop an element before the queue is full, the capacity you
580 // reserved may be lost.
581 //
582 // As a result, it's only worthwhile to call reserve() when you're adding
583 // many things at once with no intermediate operations.
reserve(size_type new_capacity)584 void reserve(size_type new_capacity) {
585 if (new_capacity > capacity())
586 SetCapacityTo(new_capacity);
587 }
588
capacity()589 size_type capacity() const {
590 // One item is wasted to indicate end().
591 return buffer_.capacity() == 0 ? 0 : buffer_.capacity() - 1;
592 }
593
shrink_to_fit()594 void shrink_to_fit() {
595 if (empty()) {
596 // Optimize empty case to really delete everything if there was
597 // something.
598 if (buffer_.capacity())
599 buffer_ = VectorBuffer();
600 } else {
601 SetCapacityTo(size());
602 }
603 }
604
605 // ---------------------------------------------------------------------------
606 // Size management.
607
608 // This will additionally reset the capacity() to 0.
clear()609 void clear() {
610 // This can't resize(0) because that requires a default constructor to
611 // compile, which not all contained classes may implement.
612 ClearRetainCapacity();
613 buffer_ = VectorBuffer();
614 }
615
empty()616 bool empty() const { return begin_ == end_; }
617
size()618 size_type size() const {
619 if (begin_ <= end_)
620 return end_ - begin_;
621 return buffer_.capacity() - begin_ + end_;
622 }
623
624 // When reducing size, the elements are deleted from the end. When expanding
625 // size, elements are added to the end with |value| or the default
626 // constructed version. Even when using resize(count) to shrink, a default
627 // constructor is required for the code to compile, even though it will not
628 // be called.
629 //
630 // There are two versions rather than using a default value to avoid
631 // creating a temporary when shrinking (when it's not needed). Plus if
632 // the default constructor is desired when expanding usually just calling it
633 // for each element is faster than making a default-constructed temporary and
634 // copying it.
resize(size_type count)635 void resize(size_type count) {
636 // SEE BELOW VERSION if you change this. The code is mostly the same.
637 if (count > size()) {
638 // This could be slightly more efficient but expanding a queue with
639 // identical elements is unusual and the extra computations of emplacing
640 // one-by-one will typically be small relative to calling the constructor
641 // for every item.
642 ExpandCapacityIfNecessary(count - size());
643 while (size() < count)
644 emplace_back();
645 } else if (count < size()) {
646 size_t new_end = (begin_ + count) % buffer_.capacity();
647 DestructRange(new_end, end_);
648 end_ = new_end;
649
650 ShrinkCapacityIfNecessary();
651 }
652 IncrementGeneration();
653 }
resize(size_type count,const value_type & value)654 void resize(size_type count, const value_type& value) {
655 // SEE ABOVE VERSION if you change this. The code is mostly the same.
656 if (count > size()) {
657 ExpandCapacityIfNecessary(count - size());
658 while (size() < count)
659 emplace_back(value);
660 } else if (count < size()) {
661 size_t new_end = (begin_ + count) % buffer_.capacity();
662 DestructRange(new_end, end_);
663 end_ = new_end;
664
665 ShrinkCapacityIfNecessary();
666 }
667 IncrementGeneration();
668 }
669
670 // ---------------------------------------------------------------------------
671 // Insert and erase.
672 //
673 // Insertion and deletion in the middle is O(n) and invalidates all existing
674 // iterators.
675 //
676 // The implementation of insert isn't optimized as much as it could be. If
677 // the insertion requires that the buffer be grown, it will first be grown
678 // and everything moved, and then the items will be inserted, potentially
679 // moving some items twice. This simplifies the implementation substantially
680 // and means less generated templatized code. Since this is an uncommon
681 // operation for deques, and already relatively slow, it doesn't seem worth
682 // the benefit to optimize this.
683
insert(const_iterator pos,size_type count,const T & value)684 void insert(const_iterator pos, size_type count, const T& value) {
685 ValidateIterator(pos);
686
687 // Optimize insert at the beginning.
688 if (pos == begin()) {
689 ExpandCapacityIfNecessary(count);
690 for (size_t i = 0; i < count; i++)
691 push_front(value);
692 return;
693 }
694
695 iterator insert_cur(this, pos.index_);
696 iterator insert_end;
697 MakeRoomFor(count, &insert_cur, &insert_end);
698 while (insert_cur < insert_end) {
699 new (&buffer_[insert_cur.index_]) T(value);
700 ++insert_cur;
701 }
702
703 IncrementGeneration();
704 }
705
706 // This enable_if keeps this call from getting confused with the (pos, count,
707 // value) version when value is an integer.
708 template <class InputIterator>
709 typename std::enable_if<::base::internal::is_iterator<InputIterator>::value,
710 void>::type
insert(const_iterator pos,InputIterator first,InputIterator last)711 insert(const_iterator pos, InputIterator first, InputIterator last) {
712 ValidateIterator(pos);
713
714 size_t inserted_items = std::distance(first, last);
715 if (inserted_items == 0)
716 return; // Can divide by 0 when doing modulo below, so return early.
717
718 // Make a hole to copy the items into.
719 iterator insert_cur;
720 iterator insert_end;
721 if (pos == begin()) {
722 // Optimize insert at the beginning, nothing needs to be shifted and the
723 // hole is the |inserted_items| block immediately before |begin_|.
724 ExpandCapacityIfNecessary(inserted_items);
725 insert_end = begin();
726 begin_ =
727 (begin_ + buffer_.capacity() - inserted_items) % buffer_.capacity();
728 insert_cur = begin();
729 } else {
730 insert_cur = iterator(this, pos.index_);
731 MakeRoomFor(inserted_items, &insert_cur, &insert_end);
732 }
733
734 // Copy the items.
735 while (insert_cur < insert_end) {
736 new (&buffer_[insert_cur.index_]) T(*first);
737 ++insert_cur;
738 ++first;
739 }
740
741 IncrementGeneration();
742 }
743
744 // These all return an iterator to the inserted item. Existing iterators will
745 // be invalidated.
insert(const_iterator pos,const T & value)746 iterator insert(const_iterator pos, const T& value) {
747 return emplace(pos, value);
748 }
insert(const_iterator pos,T && value)749 iterator insert(const_iterator pos, T&& value) {
750 return emplace(pos, std::move(value));
751 }
752 template <class... Args>
emplace(const_iterator pos,Args &&...args)753 iterator emplace(const_iterator pos, Args&&... args) {
754 ValidateIterator(pos);
755
756 // Optimize insert at beginning which doesn't require shifting.
757 if (pos == cbegin()) {
758 emplace_front(std::forward<Args>(args)...);
759 return begin();
760 }
761
762 // Do this before we make the new iterators we return.
763 IncrementGeneration();
764
765 iterator insert_begin(this, pos.index_);
766 iterator insert_end;
767 MakeRoomFor(1, &insert_begin, &insert_end);
768 new (&buffer_[insert_begin.index_]) T(std::forward<Args>(args)...);
769
770 return insert_begin;
771 }
772
773 // Calling erase() won't automatically resize the buffer smaller like resize
774 // or the pop functions. Erase is slow and relatively uncommon, and for
775 // normal deque usage a pop will normally be done on a regular basis that
776 // will prevent excessive buffer usage over long periods of time. It's not
777 // worth having the extra code for every template instantiation of erase()
778 // to resize capacity downward to a new buffer.
erase(const_iterator pos)779 iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
erase(const_iterator first,const_iterator last)780 iterator erase(const_iterator first, const_iterator last) {
781 ValidateIterator(first);
782 ValidateIterator(last);
783
784 IncrementGeneration();
785
786 // First, call the destructor on the deleted items.
787 if (first.index_ == last.index_) {
788 // Nothing deleted. Need to return early to avoid falling through to
789 // moving items on top of themselves.
790 return iterator(this, first.index_);
791 } else if (first.index_ < last.index_) {
792 // Contiguous range.
793 buffer_.DestructRange(&buffer_[first.index_], &buffer_[last.index_]);
794 } else {
795 // Deleted range wraps around.
796 buffer_.DestructRange(&buffer_[first.index_],
797 &buffer_[buffer_.capacity()]);
798 buffer_.DestructRange(&buffer_[0], &buffer_[last.index_]);
799 }
800
801 if (first.index_ == begin_) {
802 // This deletion is from the beginning. Nothing needs to be copied, only
803 // begin_ needs to be updated.
804 begin_ = last.index_;
805 return iterator(this, last.index_);
806 }
807
808 // In an erase operation, the shifted items all move logically to the left,
809 // so move them from left-to-right.
810 iterator move_src(this, last.index_);
811 iterator move_src_end = end();
812 iterator move_dest(this, first.index_);
813 for (; move_src < move_src_end; move_src++, move_dest++) {
814 buffer_.MoveRange(&buffer_[move_src.index_],
815 &buffer_[move_src.index_ + 1],
816 &buffer_[move_dest.index_]);
817 }
818
819 end_ = move_dest.index_;
820
821 // Since we did not reallocate and only changed things after the erase
822 // element(s), the input iterator's index points to the thing following the
823 // deletion.
824 return iterator(this, first.index_);
825 }
826
827 // ---------------------------------------------------------------------------
828 // Begin/end operations.
829
push_front(const T & value)830 void push_front(const T& value) { emplace_front(value); }
push_front(T && value)831 void push_front(T&& value) { emplace_front(std::move(value)); }
832
push_back(const T & value)833 void push_back(const T& value) { emplace_back(value); }
push_back(T && value)834 void push_back(T&& value) { emplace_back(std::move(value)); }
835
836 template <class... Args>
emplace_front(Args &&...args)837 reference emplace_front(Args&&... args) {
838 ExpandCapacityIfNecessary(1);
839 if (begin_ == 0)
840 begin_ = buffer_.capacity() - 1;
841 else
842 begin_--;
843 IncrementGeneration();
844 new (&buffer_[begin_]) T(std::forward<Args>(args)...);
845 return front();
846 }
847
848 template <class... Args>
emplace_back(Args &&...args)849 reference emplace_back(Args&&... args) {
850 ExpandCapacityIfNecessary(1);
851 new (&buffer_[end_]) T(std::forward<Args>(args)...);
852 if (end_ == buffer_.capacity() - 1)
853 end_ = 0;
854 else
855 end_++;
856 IncrementGeneration();
857 return back();
858 }
859
pop_front()860 void pop_front() {
861 DCHECK(size());
862 buffer_.DestructRange(&buffer_[begin_], &buffer_[begin_ + 1]);
863 begin_++;
864 if (begin_ == buffer_.capacity())
865 begin_ = 0;
866
867 ShrinkCapacityIfNecessary();
868
869 // Technically popping will not invalidate any iterators since the
870 // underlying buffer will be stable. But in the future we may want to add a
871 // feature that resizes the buffer smaller if there is too much wasted
872 // space. This ensures we can make such a change safely.
873 IncrementGeneration();
874 }
pop_back()875 void pop_back() {
876 DCHECK(size());
877 if (end_ == 0)
878 end_ = buffer_.capacity() - 1;
879 else
880 end_--;
881 buffer_.DestructRange(&buffer_[end_], &buffer_[end_ + 1]);
882
883 ShrinkCapacityIfNecessary();
884
885 // See pop_front comment about why this is here.
886 IncrementGeneration();
887 }
888
889 // ---------------------------------------------------------------------------
890 // General operations.
891
swap(circular_deque & other)892 void swap(circular_deque& other) {
893 std::swap(buffer_, other.buffer_);
894 std::swap(begin_, other.begin_);
895 std::swap(end_, other.end_);
896 IncrementGeneration();
897 }
898
swap(circular_deque & lhs,circular_deque & rhs)899 friend void swap(circular_deque& lhs, circular_deque& rhs) { lhs.swap(rhs); }
900
901 private:
902 friend internal::circular_deque_iterator<T>;
903 friend internal::circular_deque_const_iterator<T>;
904
905 // Moves the items in the given circular buffer to the current one. The
906 // source is moved from so will become invalid. The destination buffer must
907 // have already been allocated with enough size.
MoveBuffer(VectorBuffer & from_buf,size_t from_begin,size_t from_end,VectorBuffer * to_buf,size_t * to_begin,size_t * to_end)908 static void MoveBuffer(VectorBuffer& from_buf,
909 size_t from_begin,
910 size_t from_end,
911 VectorBuffer* to_buf,
912 size_t* to_begin,
913 size_t* to_end) {
914 size_t from_capacity = from_buf.capacity();
915
916 *to_begin = 0;
917 if (from_begin < from_end) {
918 // Contiguous.
919 from_buf.MoveRange(&from_buf[from_begin], &from_buf[from_end],
920 to_buf->begin());
921 *to_end = from_end - from_begin;
922 } else if (from_begin > from_end) {
923 // Discontiguous, copy the right side to the beginning of the new buffer.
924 from_buf.MoveRange(&from_buf[from_begin], &from_buf[from_capacity],
925 to_buf->begin());
926 size_t right_size = from_capacity - from_begin;
927 // Append the left side.
928 from_buf.MoveRange(&from_buf[0], &from_buf[from_end],
929 &(*to_buf)[right_size]);
930 *to_end = right_size + from_end;
931 } else {
932 // No items.
933 *to_end = 0;
934 }
935 }
936
937 // Expands the buffer size. This assumes the size is larger than the
938 // number of elements in the vector (it won't call delete on anything).
SetCapacityTo(size_t new_capacity)939 void SetCapacityTo(size_t new_capacity) {
940 // Use the capacity + 1 as the internal buffer size to differentiate
941 // empty and full (see definition of buffer_ below).
942 VectorBuffer new_buffer(new_capacity + 1);
943 MoveBuffer(buffer_, begin_, end_, &new_buffer, &begin_, &end_);
944 buffer_ = std::move(new_buffer);
945 }
ExpandCapacityIfNecessary(size_t additional_elts)946 void ExpandCapacityIfNecessary(size_t additional_elts) {
947 size_t min_new_capacity = size() + additional_elts;
948 if (capacity() >= min_new_capacity)
949 return; // Already enough room.
950
951 min_new_capacity =
952 std::max(min_new_capacity, internal::kCircularBufferInitialCapacity);
953
954 // std::vector always grows by at least 50%. WTF::Deque grows by at least
955 // 25%. We expect queue workloads to generally stay at a similar size and
956 // grow less than a vector might, so use 25%.
957 size_t new_capacity =
958 std::max(min_new_capacity, capacity() + capacity() / 4);
959 SetCapacityTo(new_capacity);
960 }
961
ShrinkCapacityIfNecessary()962 void ShrinkCapacityIfNecessary() {
963 // Don't auto-shrink below this size.
964 if (capacity() <= internal::kCircularBufferInitialCapacity)
965 return;
966
967 // Shrink when 100% of the size() is wasted.
968 size_t sz = size();
969 size_t empty_spaces = capacity() - sz;
970 if (empty_spaces < sz)
971 return;
972
973 // Leave 1/4 the size as free capacity, not going below the initial
974 // capacity.
975 size_t new_capacity =
976 std::max(internal::kCircularBufferInitialCapacity, sz + sz / 4);
977 if (new_capacity < capacity()) {
978 // Count extra item to convert to internal capacity.
979 SetCapacityTo(new_capacity);
980 }
981 }
982
983 // Backend for clear() but does not resize the internal buffer.
ClearRetainCapacity()984 void ClearRetainCapacity() {
985 // This can't resize(0) because that requires a default constructor to
986 // compile, which not all contained classes may implement.
987 DestructRange(begin_, end_);
988 begin_ = 0;
989 end_ = 0;
990 IncrementGeneration();
991 }
992
993 // Calls destructors for the given begin->end indices. The indices may wrap
994 // around. The buffer is not resized, and the begin_ and end_ members are
995 // not changed.
DestructRange(size_t begin,size_t end)996 void DestructRange(size_t begin, size_t end) {
997 if (end == begin) {
998 return;
999 } else if (end > begin) {
1000 buffer_.DestructRange(&buffer_[begin], &buffer_[end]);
1001 } else {
1002 buffer_.DestructRange(&buffer_[begin], &buffer_[buffer_.capacity()]);
1003 buffer_.DestructRange(&buffer_[0], &buffer_[end]);
1004 }
1005 }
1006
1007 // Makes room for |count| items starting at |*insert_begin|. Since iterators
1008 // are not stable across buffer resizes, |*insert_begin| will be updated to
1009 // point to the beginning of the newly opened position in the new array (it's
1010 // in/out), and the end of the newly opened position (it's out-only).
MakeRoomFor(size_t count,iterator * insert_begin,iterator * insert_end)1011 void MakeRoomFor(size_t count, iterator* insert_begin, iterator* insert_end) {
1012 if (count == 0) {
1013 *insert_end = *insert_begin;
1014 return;
1015 }
1016
1017 // The offset from the beginning will be stable across reallocations.
1018 size_t begin_offset = insert_begin->OffsetFromBegin();
1019 ExpandCapacityIfNecessary(count);
1020
1021 insert_begin->index_ = (begin_ + begin_offset) % buffer_.capacity();
1022 *insert_end =
1023 iterator(this, (insert_begin->index_ + count) % buffer_.capacity());
1024
1025 // Update the new end and prepare the iterators for copying.
1026 iterator src = end();
1027 end_ = (end_ + count) % buffer_.capacity();
1028 iterator dest = end();
1029
1030 // Move the elements. This will always involve shifting logically to the
1031 // right, so move in a right-to-left order.
1032 while (true) {
1033 if (src == *insert_begin)
1034 break;
1035 --src;
1036 --dest;
1037 buffer_.MoveRange(&buffer_[src.index_], &buffer_[src.index_ + 1],
1038 &buffer_[dest.index_]);
1039 }
1040 }
1041
1042 #if DCHECK_IS_ON()
1043 // Asserts the given index is dereferenceable. The index is an index into the
1044 // buffer, not an index used by operator[] or at() which will be offsets from
1045 // begin.
CheckValidIndex(size_t i)1046 void CheckValidIndex(size_t i) const {
1047 if (begin_ <= end_)
1048 DCHECK(i >= begin_ && i < end_);
1049 else
1050 DCHECK((i >= begin_ && i < buffer_.capacity()) || i < end_);
1051 }
1052
1053 // Asserts the given index is either dereferenceable or points to end().
CheckValidIndexOrEnd(size_t i)1054 void CheckValidIndexOrEnd(size_t i) const {
1055 if (i != end_)
1056 CheckValidIndex(i);
1057 }
1058
ValidateIterator(const const_iterator & i)1059 void ValidateIterator(const const_iterator& i) const {
1060 DCHECK(i.parent_deque_ == this);
1061 i.CheckUnstableUsage();
1062 }
1063
1064 // See generation_ below.
IncrementGeneration()1065 void IncrementGeneration() { generation_++; }
1066 #else
1067 // No-op versions of these functions for release builds.
CheckValidIndex(size_t)1068 void CheckValidIndex(size_t) const {}
CheckValidIndexOrEnd(size_t)1069 void CheckValidIndexOrEnd(size_t) const {}
ValidateIterator(const const_iterator & i)1070 void ValidateIterator(const const_iterator& i) const {}
IncrementGeneration()1071 void IncrementGeneration() {}
1072 #endif
1073
1074 // Danger, the buffer_.capacity() is the "internal capacity" which is
1075 // capacity() + 1 since there is an extra item to indicate the end. Otherwise
1076 // being completely empty and completely full are indistinguishable (begin ==
1077 // end). We could add a separate flag to avoid it, but that adds significant
1078 // extra complexity since every computation will have to check for it. Always
1079 // keeping one extra unused element in the buffer makes iterator computations
1080 // much simpler.
1081 //
1082 // Container internal code will want to use buffer_.capacity() for offset
1083 // computations rather than capacity().
1084 VectorBuffer buffer_;
1085 size_type begin_ = 0;
1086 size_type end_ = 0;
1087
1088 #if DCHECK_IS_ON()
1089 // Incremented every time a modification is made that could affect iterator
1090 // invalidations.
1091 uint64_t generation_ = 0;
1092 #endif
1093 };
1094
1095 // Implementations of base::Erase[If] (see base/stl_util.h).
1096 template <class T, class Value>
Erase(circular_deque<T> & container,const Value & value)1097 void Erase(circular_deque<T>& container, const Value& value) {
1098 container.erase(std::remove(container.begin(), container.end(), value),
1099 container.end());
1100 }
1101
1102 template <class T, class Predicate>
EraseIf(circular_deque<T> & container,Predicate pred)1103 void EraseIf(circular_deque<T>& container, Predicate pred) {
1104 container.erase(std::remove_if(container.begin(), container.end(), pred),
1105 container.end());
1106 }
1107
1108 } // namespace base
1109
1110 #endif // BASE_CONTAINERS_CIRCULAR_DEQUE_H_
1111