16d528ed9Sopenharmony_ci// Copyright 2017 The Chromium Authors. All rights reserved. 26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 36d528ed9Sopenharmony_ci// found in the LICENSE file. 46d528ed9Sopenharmony_ci 56d528ed9Sopenharmony_ci#ifndef BASE_CONTAINERS_CIRCULAR_DEQUE_H_ 66d528ed9Sopenharmony_ci#define BASE_CONTAINERS_CIRCULAR_DEQUE_H_ 76d528ed9Sopenharmony_ci 86d528ed9Sopenharmony_ci#include <algorithm> 96d528ed9Sopenharmony_ci#include <cstddef> 106d528ed9Sopenharmony_ci#include <iterator> 116d528ed9Sopenharmony_ci#include <type_traits> 126d528ed9Sopenharmony_ci#include <utility> 136d528ed9Sopenharmony_ci 146d528ed9Sopenharmony_ci#include "base/containers/vector_buffer.h" 156d528ed9Sopenharmony_ci#include "base/logging.h" 166d528ed9Sopenharmony_ci#include "base/template_util.h" 176d528ed9Sopenharmony_ci 186d528ed9Sopenharmony_ci// base::circular_deque is similar to std::deque. Unlike std::deque, the 196d528ed9Sopenharmony_ci// storage is provided in a flat circular buffer conceptually similar to a 206d528ed9Sopenharmony_ci// vector. The beginning and end will wrap around as necessary so that 216d528ed9Sopenharmony_ci// pushes and pops will be constant time as long as a capacity expansion is 226d528ed9Sopenharmony_ci// not required. 236d528ed9Sopenharmony_ci// 246d528ed9Sopenharmony_ci// The API should be identical to std::deque with the following differences: 256d528ed9Sopenharmony_ci// 266d528ed9Sopenharmony_ci// - ITERATORS ARE NOT STABLE. Mutating the container will invalidate all 276d528ed9Sopenharmony_ci// iterators. 286d528ed9Sopenharmony_ci// 296d528ed9Sopenharmony_ci// - Insertions may resize the vector and so are not constant time (std::deque 306d528ed9Sopenharmony_ci// guarantees constant time for insertions at the ends). 316d528ed9Sopenharmony_ci// 326d528ed9Sopenharmony_ci// - Container-wide comparisons are not implemented. If you want to compare 336d528ed9Sopenharmony_ci// two containers, use an algorithm so the expensive iteration is explicit. 346d528ed9Sopenharmony_ci// 356d528ed9Sopenharmony_ci// If you want a similar container with only a queue API, use base::queue in 366d528ed9Sopenharmony_ci// base/containers/queue.h. 376d528ed9Sopenharmony_ci// 386d528ed9Sopenharmony_ci// Constructors: 396d528ed9Sopenharmony_ci// circular_deque(); 406d528ed9Sopenharmony_ci// circular_deque(size_t count); 416d528ed9Sopenharmony_ci// circular_deque(size_t count, const T& value); 426d528ed9Sopenharmony_ci// circular_deque(InputIterator first, InputIterator last); 436d528ed9Sopenharmony_ci// circular_deque(const circular_deque&); 446d528ed9Sopenharmony_ci// circular_deque(circular_deque&&); 456d528ed9Sopenharmony_ci// circular_deque(std::initializer_list<value_type>); 466d528ed9Sopenharmony_ci// 476d528ed9Sopenharmony_ci// Assignment functions: 486d528ed9Sopenharmony_ci// circular_deque& operator=(const circular_deque&); 496d528ed9Sopenharmony_ci// circular_deque& operator=(circular_deque&&); 506d528ed9Sopenharmony_ci// circular_deque& operator=(std::initializer_list<T>); 516d528ed9Sopenharmony_ci// void assign(size_t count, const T& value); 526d528ed9Sopenharmony_ci// void assign(InputIterator first, InputIterator last); 536d528ed9Sopenharmony_ci// void assign(std::initializer_list<T> value); 546d528ed9Sopenharmony_ci// 556d528ed9Sopenharmony_ci// Random accessors: 566d528ed9Sopenharmony_ci// T& at(size_t); 576d528ed9Sopenharmony_ci// const T& at(size_t) const; 586d528ed9Sopenharmony_ci// T& operator[](size_t); 596d528ed9Sopenharmony_ci// const T& operator[](size_t) const; 606d528ed9Sopenharmony_ci// 616d528ed9Sopenharmony_ci// End accessors: 626d528ed9Sopenharmony_ci// T& front(); 636d528ed9Sopenharmony_ci// const T& front() const; 646d528ed9Sopenharmony_ci// T& back(); 656d528ed9Sopenharmony_ci// const T& back() const; 666d528ed9Sopenharmony_ci// 676d528ed9Sopenharmony_ci// Iterator functions: 686d528ed9Sopenharmony_ci// iterator begin(); 696d528ed9Sopenharmony_ci// const_iterator begin() const; 706d528ed9Sopenharmony_ci// const_iterator cbegin() const; 716d528ed9Sopenharmony_ci// iterator end(); 726d528ed9Sopenharmony_ci// const_iterator end() const; 736d528ed9Sopenharmony_ci// const_iterator cend() const; 746d528ed9Sopenharmony_ci// reverse_iterator rbegin(); 756d528ed9Sopenharmony_ci// const_reverse_iterator rbegin() const; 766d528ed9Sopenharmony_ci// const_reverse_iterator crbegin() const; 776d528ed9Sopenharmony_ci// reverse_iterator rend(); 786d528ed9Sopenharmony_ci// const_reverse_iterator rend() const; 796d528ed9Sopenharmony_ci// const_reverse_iterator crend() const; 806d528ed9Sopenharmony_ci// 816d528ed9Sopenharmony_ci// Memory management: 826d528ed9Sopenharmony_ci// void reserve(size_t); // SEE IMPLEMENTATION FOR SOME GOTCHAS. 836d528ed9Sopenharmony_ci// size_t capacity() const; 846d528ed9Sopenharmony_ci// void shrink_to_fit(); 856d528ed9Sopenharmony_ci// 866d528ed9Sopenharmony_ci// Size management: 876d528ed9Sopenharmony_ci// void clear(); 886d528ed9Sopenharmony_ci// bool empty() const; 896d528ed9Sopenharmony_ci// size_t size() const; 906d528ed9Sopenharmony_ci// void resize(size_t); 916d528ed9Sopenharmony_ci// void resize(size_t count, const T& value); 926d528ed9Sopenharmony_ci// 936d528ed9Sopenharmony_ci// Positional insert and erase: 946d528ed9Sopenharmony_ci// void insert(const_iterator pos, size_type count, const T& value); 956d528ed9Sopenharmony_ci// void insert(const_iterator pos, 966d528ed9Sopenharmony_ci// InputIterator first, InputIterator last); 976d528ed9Sopenharmony_ci// iterator insert(const_iterator pos, const T& value); 986d528ed9Sopenharmony_ci// iterator insert(const_iterator pos, T&& value); 996d528ed9Sopenharmony_ci// iterator emplace(const_iterator pos, Args&&... args); 1006d528ed9Sopenharmony_ci// iterator erase(const_iterator pos); 1016d528ed9Sopenharmony_ci// iterator erase(const_iterator first, const_iterator last); 1026d528ed9Sopenharmony_ci// 1036d528ed9Sopenharmony_ci// End insert and erase: 1046d528ed9Sopenharmony_ci// void push_front(const T&); 1056d528ed9Sopenharmony_ci// void push_front(T&&); 1066d528ed9Sopenharmony_ci// void push_back(const T&); 1076d528ed9Sopenharmony_ci// void push_back(T&&); 1086d528ed9Sopenharmony_ci// T& emplace_front(Args&&...); 1096d528ed9Sopenharmony_ci// T& emplace_back(Args&&...); 1106d528ed9Sopenharmony_ci// void pop_front(); 1116d528ed9Sopenharmony_ci// void pop_back(); 1126d528ed9Sopenharmony_ci// 1136d528ed9Sopenharmony_ci// General: 1146d528ed9Sopenharmony_ci// void swap(circular_deque&); 1156d528ed9Sopenharmony_ci 1166d528ed9Sopenharmony_cinamespace base { 1176d528ed9Sopenharmony_ci 1186d528ed9Sopenharmony_citemplate <class T> 1196d528ed9Sopenharmony_ciclass circular_deque; 1206d528ed9Sopenharmony_ci 1216d528ed9Sopenharmony_cinamespace internal { 1226d528ed9Sopenharmony_ci 1236d528ed9Sopenharmony_ci// Start allocating nonempty buffers with this many entries. This is the 1246d528ed9Sopenharmony_ci// external capacity so the internal buffer will be one larger (= 4) which is 1256d528ed9Sopenharmony_ci// more even for the allocator. See the descriptions of internal vs. external 1266d528ed9Sopenharmony_ci// capacity on the comment above the buffer_ variable below. 1276d528ed9Sopenharmony_ciconstexpr size_t kCircularBufferInitialCapacity = 3; 1286d528ed9Sopenharmony_ci 1296d528ed9Sopenharmony_citemplate <typename T> 1306d528ed9Sopenharmony_ciclass circular_deque_const_iterator { 1316d528ed9Sopenharmony_ci public: 1326d528ed9Sopenharmony_ci using difference_type = std::ptrdiff_t; 1336d528ed9Sopenharmony_ci using value_type = T; 1346d528ed9Sopenharmony_ci using pointer = const T*; 1356d528ed9Sopenharmony_ci using reference = const T&; 1366d528ed9Sopenharmony_ci using iterator_category = std::random_access_iterator_tag; 1376d528ed9Sopenharmony_ci 1386d528ed9Sopenharmony_ci circular_deque_const_iterator() : parent_deque_(nullptr), index_(0) { 1396d528ed9Sopenharmony_ci#if DCHECK_IS_ON() 1406d528ed9Sopenharmony_ci created_generation_ = 0; 1416d528ed9Sopenharmony_ci#endif // DCHECK_IS_ON() 1426d528ed9Sopenharmony_ci } 1436d528ed9Sopenharmony_ci 1446d528ed9Sopenharmony_ci // Dereferencing. 1456d528ed9Sopenharmony_ci const T& operator*() const { 1466d528ed9Sopenharmony_ci CheckUnstableUsage(); 1476d528ed9Sopenharmony_ci parent_deque_->CheckValidIndex(index_); 1486d528ed9Sopenharmony_ci return parent_deque_->buffer_[index_]; 1496d528ed9Sopenharmony_ci } 1506d528ed9Sopenharmony_ci const T* operator->() const { 1516d528ed9Sopenharmony_ci CheckUnstableUsage(); 1526d528ed9Sopenharmony_ci parent_deque_->CheckValidIndex(index_); 1536d528ed9Sopenharmony_ci return &parent_deque_->buffer_[index_]; 1546d528ed9Sopenharmony_ci } 1556d528ed9Sopenharmony_ci const value_type& operator[](difference_type i) const { return *(*this + i); } 1566d528ed9Sopenharmony_ci 1576d528ed9Sopenharmony_ci // Increment and decrement. 1586d528ed9Sopenharmony_ci circular_deque_const_iterator& operator++() { 1596d528ed9Sopenharmony_ci Increment(); 1606d528ed9Sopenharmony_ci return *this; 1616d528ed9Sopenharmony_ci } 1626d528ed9Sopenharmony_ci circular_deque_const_iterator operator++(int) { 1636d528ed9Sopenharmony_ci circular_deque_const_iterator ret = *this; 1646d528ed9Sopenharmony_ci Increment(); 1656d528ed9Sopenharmony_ci return ret; 1666d528ed9Sopenharmony_ci } 1676d528ed9Sopenharmony_ci circular_deque_const_iterator& operator--() { 1686d528ed9Sopenharmony_ci Decrement(); 1696d528ed9Sopenharmony_ci return *this; 1706d528ed9Sopenharmony_ci } 1716d528ed9Sopenharmony_ci circular_deque_const_iterator operator--(int) { 1726d528ed9Sopenharmony_ci circular_deque_const_iterator ret = *this; 1736d528ed9Sopenharmony_ci Decrement(); 1746d528ed9Sopenharmony_ci return ret; 1756d528ed9Sopenharmony_ci } 1766d528ed9Sopenharmony_ci 1776d528ed9Sopenharmony_ci // Random access mutation. 1786d528ed9Sopenharmony_ci friend circular_deque_const_iterator operator+( 1796d528ed9Sopenharmony_ci const circular_deque_const_iterator& iter, 1806d528ed9Sopenharmony_ci difference_type offset) { 1816d528ed9Sopenharmony_ci circular_deque_const_iterator ret = iter; 1826d528ed9Sopenharmony_ci ret.Add(offset); 1836d528ed9Sopenharmony_ci return ret; 1846d528ed9Sopenharmony_ci } 1856d528ed9Sopenharmony_ci circular_deque_const_iterator& operator+=(difference_type offset) { 1866d528ed9Sopenharmony_ci Add(offset); 1876d528ed9Sopenharmony_ci return *this; 1886d528ed9Sopenharmony_ci } 1896d528ed9Sopenharmony_ci friend circular_deque_const_iterator operator-( 1906d528ed9Sopenharmony_ci const circular_deque_const_iterator& iter, 1916d528ed9Sopenharmony_ci difference_type offset) { 1926d528ed9Sopenharmony_ci circular_deque_const_iterator ret = iter; 1936d528ed9Sopenharmony_ci ret.Add(-offset); 1946d528ed9Sopenharmony_ci return ret; 1956d528ed9Sopenharmony_ci } 1966d528ed9Sopenharmony_ci circular_deque_const_iterator& operator-=(difference_type offset) { 1976d528ed9Sopenharmony_ci Add(-offset); 1986d528ed9Sopenharmony_ci return *this; 1996d528ed9Sopenharmony_ci } 2006d528ed9Sopenharmony_ci 2016d528ed9Sopenharmony_ci friend std::ptrdiff_t operator-(const circular_deque_const_iterator& lhs, 2026d528ed9Sopenharmony_ci const circular_deque_const_iterator& rhs) { 2036d528ed9Sopenharmony_ci lhs.CheckComparable(rhs); 2046d528ed9Sopenharmony_ci return lhs.OffsetFromBegin() - rhs.OffsetFromBegin(); 2056d528ed9Sopenharmony_ci } 2066d528ed9Sopenharmony_ci 2076d528ed9Sopenharmony_ci // Comparisons. 2086d528ed9Sopenharmony_ci friend bool operator==(const circular_deque_const_iterator& lhs, 2096d528ed9Sopenharmony_ci const circular_deque_const_iterator& rhs) { 2106d528ed9Sopenharmony_ci lhs.CheckComparable(rhs); 2116d528ed9Sopenharmony_ci return lhs.index_ == rhs.index_; 2126d528ed9Sopenharmony_ci } 2136d528ed9Sopenharmony_ci friend bool operator!=(const circular_deque_const_iterator& lhs, 2146d528ed9Sopenharmony_ci const circular_deque_const_iterator& rhs) { 2156d528ed9Sopenharmony_ci return !(lhs == rhs); 2166d528ed9Sopenharmony_ci } 2176d528ed9Sopenharmony_ci friend bool operator<(const circular_deque_const_iterator& lhs, 2186d528ed9Sopenharmony_ci const circular_deque_const_iterator& rhs) { 2196d528ed9Sopenharmony_ci lhs.CheckComparable(rhs); 2206d528ed9Sopenharmony_ci return lhs.OffsetFromBegin() < rhs.OffsetFromBegin(); 2216d528ed9Sopenharmony_ci } 2226d528ed9Sopenharmony_ci friend bool operator<=(const circular_deque_const_iterator& lhs, 2236d528ed9Sopenharmony_ci const circular_deque_const_iterator& rhs) { 2246d528ed9Sopenharmony_ci return !(lhs > rhs); 2256d528ed9Sopenharmony_ci } 2266d528ed9Sopenharmony_ci friend bool operator>(const circular_deque_const_iterator& lhs, 2276d528ed9Sopenharmony_ci const circular_deque_const_iterator& rhs) { 2286d528ed9Sopenharmony_ci lhs.CheckComparable(rhs); 2296d528ed9Sopenharmony_ci return lhs.OffsetFromBegin() > rhs.OffsetFromBegin(); 2306d528ed9Sopenharmony_ci } 2316d528ed9Sopenharmony_ci friend bool operator>=(const circular_deque_const_iterator& lhs, 2326d528ed9Sopenharmony_ci const circular_deque_const_iterator& rhs) { 2336d528ed9Sopenharmony_ci return !(lhs < rhs); 2346d528ed9Sopenharmony_ci } 2356d528ed9Sopenharmony_ci 2366d528ed9Sopenharmony_ci protected: 2376d528ed9Sopenharmony_ci friend class circular_deque<T>; 2386d528ed9Sopenharmony_ci 2396d528ed9Sopenharmony_ci circular_deque_const_iterator(const circular_deque<T>* parent, size_t index) 2406d528ed9Sopenharmony_ci : parent_deque_(parent), index_(index) { 2416d528ed9Sopenharmony_ci#if DCHECK_IS_ON() 2426d528ed9Sopenharmony_ci created_generation_ = parent->generation_; 2436d528ed9Sopenharmony_ci#endif // DCHECK_IS_ON() 2446d528ed9Sopenharmony_ci } 2456d528ed9Sopenharmony_ci 2466d528ed9Sopenharmony_ci // Returns the offset from the beginning index of the buffer to the current 2476d528ed9Sopenharmony_ci // item. 2486d528ed9Sopenharmony_ci size_t OffsetFromBegin() const { 2496d528ed9Sopenharmony_ci if (index_ >= parent_deque_->begin_) 2506d528ed9Sopenharmony_ci return index_ - parent_deque_->begin_; // On the same side as begin. 2516d528ed9Sopenharmony_ci return parent_deque_->buffer_.capacity() - parent_deque_->begin_ + index_; 2526d528ed9Sopenharmony_ci } 2536d528ed9Sopenharmony_ci 2546d528ed9Sopenharmony_ci // Most uses will be ++ and -- so use a simplified implementation. 2556d528ed9Sopenharmony_ci void Increment() { 2566d528ed9Sopenharmony_ci CheckUnstableUsage(); 2576d528ed9Sopenharmony_ci parent_deque_->CheckValidIndex(index_); 2586d528ed9Sopenharmony_ci index_++; 2596d528ed9Sopenharmony_ci if (index_ == parent_deque_->buffer_.capacity()) 2606d528ed9Sopenharmony_ci index_ = 0; 2616d528ed9Sopenharmony_ci } 2626d528ed9Sopenharmony_ci void Decrement() { 2636d528ed9Sopenharmony_ci CheckUnstableUsage(); 2646d528ed9Sopenharmony_ci parent_deque_->CheckValidIndexOrEnd(index_); 2656d528ed9Sopenharmony_ci if (index_ == 0) 2666d528ed9Sopenharmony_ci index_ = parent_deque_->buffer_.capacity() - 1; 2676d528ed9Sopenharmony_ci else 2686d528ed9Sopenharmony_ci index_--; 2696d528ed9Sopenharmony_ci } 2706d528ed9Sopenharmony_ci void Add(difference_type delta) { 2716d528ed9Sopenharmony_ci CheckUnstableUsage(); 2726d528ed9Sopenharmony_ci#if DCHECK_IS_ON() 2736d528ed9Sopenharmony_ci if (delta <= 0) 2746d528ed9Sopenharmony_ci parent_deque_->CheckValidIndexOrEnd(index_); 2756d528ed9Sopenharmony_ci else 2766d528ed9Sopenharmony_ci parent_deque_->CheckValidIndex(index_); 2776d528ed9Sopenharmony_ci#endif 2786d528ed9Sopenharmony_ci // It should be valid to add 0 to any iterator, even if the container is 2796d528ed9Sopenharmony_ci // empty and the iterator points to end(). The modulo below will divide 2806d528ed9Sopenharmony_ci // by 0 if the buffer capacity is empty, so it's important to check for 2816d528ed9Sopenharmony_ci // this case explicitly. 2826d528ed9Sopenharmony_ci if (delta == 0) 2836d528ed9Sopenharmony_ci return; 2846d528ed9Sopenharmony_ci 2856d528ed9Sopenharmony_ci difference_type new_offset = OffsetFromBegin() + delta; 2866d528ed9Sopenharmony_ci DCHECK(new_offset >= 0 && 2876d528ed9Sopenharmony_ci new_offset <= static_cast<difference_type>(parent_deque_->size())); 2886d528ed9Sopenharmony_ci index_ = (new_offset + parent_deque_->begin_) % 2896d528ed9Sopenharmony_ci parent_deque_->buffer_.capacity(); 2906d528ed9Sopenharmony_ci } 2916d528ed9Sopenharmony_ci 2926d528ed9Sopenharmony_ci#if DCHECK_IS_ON() 2936d528ed9Sopenharmony_ci void CheckUnstableUsage() const { 2946d528ed9Sopenharmony_ci DCHECK(parent_deque_); 2956d528ed9Sopenharmony_ci // Since circular_deque doesn't guarantee stability, any attempt to 2966d528ed9Sopenharmony_ci // dereference this iterator after a mutation (i.e. the generation doesn't 2976d528ed9Sopenharmony_ci // match the original) in the container is illegal. 2986d528ed9Sopenharmony_ci DCHECK_EQ(created_generation_, parent_deque_->generation_) 2996d528ed9Sopenharmony_ci << "circular_deque iterator dereferenced after mutation."; 3006d528ed9Sopenharmony_ci } 3016d528ed9Sopenharmony_ci void CheckComparable(const circular_deque_const_iterator& other) const { 3026d528ed9Sopenharmony_ci DCHECK_EQ(parent_deque_, other.parent_deque_); 3036d528ed9Sopenharmony_ci // Since circular_deque doesn't guarantee stability, two iterators that 3046d528ed9Sopenharmony_ci // are compared must have been generated without mutating the container. 3056d528ed9Sopenharmony_ci // If this fires, the container was mutated between generating the two 3066d528ed9Sopenharmony_ci // iterators being compared. 3076d528ed9Sopenharmony_ci DCHECK_EQ(created_generation_, other.created_generation_); 3086d528ed9Sopenharmony_ci } 3096d528ed9Sopenharmony_ci#else 3106d528ed9Sopenharmony_ci inline void CheckUnstableUsage() const {} 3116d528ed9Sopenharmony_ci inline void CheckComparable(const circular_deque_const_iterator&) const {} 3126d528ed9Sopenharmony_ci#endif // DCHECK_IS_ON() 3136d528ed9Sopenharmony_ci 3146d528ed9Sopenharmony_ci const circular_deque<T>* parent_deque_; 3156d528ed9Sopenharmony_ci size_t index_; 3166d528ed9Sopenharmony_ci 3176d528ed9Sopenharmony_ci#if DCHECK_IS_ON() 3186d528ed9Sopenharmony_ci // The generation of the parent deque when this iterator was created. The 3196d528ed9Sopenharmony_ci // container will update the generation for every modification so we can 3206d528ed9Sopenharmony_ci // test if the container was modified by comparing them. 3216d528ed9Sopenharmony_ci uint64_t created_generation_; 3226d528ed9Sopenharmony_ci#endif // DCHECK_IS_ON() 3236d528ed9Sopenharmony_ci}; 3246d528ed9Sopenharmony_ci 3256d528ed9Sopenharmony_citemplate <typename T> 3266d528ed9Sopenharmony_ciclass circular_deque_iterator : public circular_deque_const_iterator<T> { 3276d528ed9Sopenharmony_ci using base = circular_deque_const_iterator<T>; 3286d528ed9Sopenharmony_ci 3296d528ed9Sopenharmony_ci public: 3306d528ed9Sopenharmony_ci friend class circular_deque<T>; 3316d528ed9Sopenharmony_ci 3326d528ed9Sopenharmony_ci using difference_type = std::ptrdiff_t; 3336d528ed9Sopenharmony_ci using value_type = T; 3346d528ed9Sopenharmony_ci using pointer = T*; 3356d528ed9Sopenharmony_ci using reference = T&; 3366d528ed9Sopenharmony_ci using iterator_category = std::random_access_iterator_tag; 3376d528ed9Sopenharmony_ci 3386d528ed9Sopenharmony_ci // Expose the base class' constructor. 3396d528ed9Sopenharmony_ci circular_deque_iterator() : circular_deque_const_iterator<T>() {} 3406d528ed9Sopenharmony_ci 3416d528ed9Sopenharmony_ci // Dereferencing. 3426d528ed9Sopenharmony_ci T& operator*() const { return const_cast<T&>(base::operator*()); } 3436d528ed9Sopenharmony_ci T* operator->() const { return const_cast<T*>(base::operator->()); } 3446d528ed9Sopenharmony_ci T& operator[](difference_type i) { 3456d528ed9Sopenharmony_ci return const_cast<T&>(base::operator[](i)); 3466d528ed9Sopenharmony_ci } 3476d528ed9Sopenharmony_ci 3486d528ed9Sopenharmony_ci // Random access mutation. 3496d528ed9Sopenharmony_ci friend circular_deque_iterator operator+(const circular_deque_iterator& iter, 3506d528ed9Sopenharmony_ci difference_type offset) { 3516d528ed9Sopenharmony_ci circular_deque_iterator ret = iter; 3526d528ed9Sopenharmony_ci ret.Add(offset); 3536d528ed9Sopenharmony_ci return ret; 3546d528ed9Sopenharmony_ci } 3556d528ed9Sopenharmony_ci circular_deque_iterator& operator+=(difference_type offset) { 3566d528ed9Sopenharmony_ci base::Add(offset); 3576d528ed9Sopenharmony_ci return *this; 3586d528ed9Sopenharmony_ci } 3596d528ed9Sopenharmony_ci friend circular_deque_iterator operator-(const circular_deque_iterator& iter, 3606d528ed9Sopenharmony_ci difference_type offset) { 3616d528ed9Sopenharmony_ci circular_deque_iterator ret = iter; 3626d528ed9Sopenharmony_ci ret.Add(-offset); 3636d528ed9Sopenharmony_ci return ret; 3646d528ed9Sopenharmony_ci } 3656d528ed9Sopenharmony_ci circular_deque_iterator& operator-=(difference_type offset) { 3666d528ed9Sopenharmony_ci base::Add(-offset); 3676d528ed9Sopenharmony_ci return *this; 3686d528ed9Sopenharmony_ci } 3696d528ed9Sopenharmony_ci 3706d528ed9Sopenharmony_ci // Increment and decrement. 3716d528ed9Sopenharmony_ci circular_deque_iterator& operator++() { 3726d528ed9Sopenharmony_ci base::Increment(); 3736d528ed9Sopenharmony_ci return *this; 3746d528ed9Sopenharmony_ci } 3756d528ed9Sopenharmony_ci circular_deque_iterator operator++(int) { 3766d528ed9Sopenharmony_ci circular_deque_iterator ret = *this; 3776d528ed9Sopenharmony_ci base::Increment(); 3786d528ed9Sopenharmony_ci return ret; 3796d528ed9Sopenharmony_ci } 3806d528ed9Sopenharmony_ci circular_deque_iterator& operator--() { 3816d528ed9Sopenharmony_ci base::Decrement(); 3826d528ed9Sopenharmony_ci return *this; 3836d528ed9Sopenharmony_ci } 3846d528ed9Sopenharmony_ci circular_deque_iterator operator--(int) { 3856d528ed9Sopenharmony_ci circular_deque_iterator ret = *this; 3866d528ed9Sopenharmony_ci base::Decrement(); 3876d528ed9Sopenharmony_ci return ret; 3886d528ed9Sopenharmony_ci } 3896d528ed9Sopenharmony_ci 3906d528ed9Sopenharmony_ci private: 3916d528ed9Sopenharmony_ci circular_deque_iterator(const circular_deque<T>* parent, size_t index) 3926d528ed9Sopenharmony_ci : circular_deque_const_iterator<T>(parent, index) {} 3936d528ed9Sopenharmony_ci}; 3946d528ed9Sopenharmony_ci 3956d528ed9Sopenharmony_ci} // namespace internal 3966d528ed9Sopenharmony_ci 3976d528ed9Sopenharmony_citemplate <typename T> 3986d528ed9Sopenharmony_ciclass circular_deque { 3996d528ed9Sopenharmony_ci private: 4006d528ed9Sopenharmony_ci using VectorBuffer = internal::VectorBuffer<T>; 4016d528ed9Sopenharmony_ci 4026d528ed9Sopenharmony_ci public: 4036d528ed9Sopenharmony_ci using value_type = T; 4046d528ed9Sopenharmony_ci using size_type = std::size_t; 4056d528ed9Sopenharmony_ci using difference_type = std::ptrdiff_t; 4066d528ed9Sopenharmony_ci using reference = value_type&; 4076d528ed9Sopenharmony_ci using const_reference = const value_type&; 4086d528ed9Sopenharmony_ci using pointer = value_type*; 4096d528ed9Sopenharmony_ci using const_pointer = const value_type*; 4106d528ed9Sopenharmony_ci 4116d528ed9Sopenharmony_ci using iterator = internal::circular_deque_iterator<T>; 4126d528ed9Sopenharmony_ci using const_iterator = internal::circular_deque_const_iterator<T>; 4136d528ed9Sopenharmony_ci using reverse_iterator = std::reverse_iterator<iterator>; 4146d528ed9Sopenharmony_ci using const_reverse_iterator = std::reverse_iterator<const_iterator>; 4156d528ed9Sopenharmony_ci 4166d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 4176d528ed9Sopenharmony_ci // Constructor 4186d528ed9Sopenharmony_ci 4196d528ed9Sopenharmony_ci constexpr circular_deque() = default; 4206d528ed9Sopenharmony_ci 4216d528ed9Sopenharmony_ci // Constructs with |count| copies of |value| or default constructed version. 4226d528ed9Sopenharmony_ci circular_deque(size_type count) { resize(count); } 4236d528ed9Sopenharmony_ci circular_deque(size_type count, const T& value) { resize(count, value); } 4246d528ed9Sopenharmony_ci 4256d528ed9Sopenharmony_ci // Range constructor. 4266d528ed9Sopenharmony_ci template <class InputIterator> 4276d528ed9Sopenharmony_ci circular_deque(InputIterator first, InputIterator last) { 4286d528ed9Sopenharmony_ci assign(first, last); 4296d528ed9Sopenharmony_ci } 4306d528ed9Sopenharmony_ci 4316d528ed9Sopenharmony_ci // Copy/move. 4326d528ed9Sopenharmony_ci circular_deque(const circular_deque& other) : buffer_(other.size() + 1) { 4336d528ed9Sopenharmony_ci assign(other.begin(), other.end()); 4346d528ed9Sopenharmony_ci } 4356d528ed9Sopenharmony_ci circular_deque(circular_deque&& other) noexcept 4366d528ed9Sopenharmony_ci : buffer_(std::move(other.buffer_)), 4376d528ed9Sopenharmony_ci begin_(other.begin_), 4386d528ed9Sopenharmony_ci end_(other.end_) { 4396d528ed9Sopenharmony_ci other.begin_ = 0; 4406d528ed9Sopenharmony_ci other.end_ = 0; 4416d528ed9Sopenharmony_ci } 4426d528ed9Sopenharmony_ci 4436d528ed9Sopenharmony_ci circular_deque(std::initializer_list<value_type> init) { assign(init); } 4446d528ed9Sopenharmony_ci 4456d528ed9Sopenharmony_ci ~circular_deque() { DestructRange(begin_, end_); } 4466d528ed9Sopenharmony_ci 4476d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 4486d528ed9Sopenharmony_ci // Assignments. 4496d528ed9Sopenharmony_ci // 4506d528ed9Sopenharmony_ci // All of these may invalidate iterators and references. 4516d528ed9Sopenharmony_ci 4526d528ed9Sopenharmony_ci circular_deque& operator=(const circular_deque& other) { 4536d528ed9Sopenharmony_ci if (&other == this) 4546d528ed9Sopenharmony_ci return *this; 4556d528ed9Sopenharmony_ci 4566d528ed9Sopenharmony_ci reserve(other.size()); 4576d528ed9Sopenharmony_ci assign(other.begin(), other.end()); 4586d528ed9Sopenharmony_ci return *this; 4596d528ed9Sopenharmony_ci } 4606d528ed9Sopenharmony_ci circular_deque& operator=(circular_deque&& other) noexcept { 4616d528ed9Sopenharmony_ci if (&other == this) 4626d528ed9Sopenharmony_ci return *this; 4636d528ed9Sopenharmony_ci 4646d528ed9Sopenharmony_ci // We're about to overwrite the buffer, so don't free it in clear to 4656d528ed9Sopenharmony_ci // avoid doing it twice. 4666d528ed9Sopenharmony_ci ClearRetainCapacity(); 4676d528ed9Sopenharmony_ci buffer_ = std::move(other.buffer_); 4686d528ed9Sopenharmony_ci begin_ = other.begin_; 4696d528ed9Sopenharmony_ci end_ = other.end_; 4706d528ed9Sopenharmony_ci 4716d528ed9Sopenharmony_ci other.begin_ = 0; 4726d528ed9Sopenharmony_ci other.end_ = 0; 4736d528ed9Sopenharmony_ci 4746d528ed9Sopenharmony_ci IncrementGeneration(); 4756d528ed9Sopenharmony_ci return *this; 4766d528ed9Sopenharmony_ci } 4776d528ed9Sopenharmony_ci circular_deque& operator=(std::initializer_list<value_type> ilist) { 4786d528ed9Sopenharmony_ci reserve(ilist.size()); 4796d528ed9Sopenharmony_ci assign(std::begin(ilist), std::end(ilist)); 4806d528ed9Sopenharmony_ci return *this; 4816d528ed9Sopenharmony_ci } 4826d528ed9Sopenharmony_ci 4836d528ed9Sopenharmony_ci void assign(size_type count, const value_type& value) { 4846d528ed9Sopenharmony_ci ClearRetainCapacity(); 4856d528ed9Sopenharmony_ci reserve(count); 4866d528ed9Sopenharmony_ci for (size_t i = 0; i < count; i++) 4876d528ed9Sopenharmony_ci emplace_back(value); 4886d528ed9Sopenharmony_ci IncrementGeneration(); 4896d528ed9Sopenharmony_ci } 4906d528ed9Sopenharmony_ci 4916d528ed9Sopenharmony_ci // This variant should be enabled only when InputIterator is an iterator. 4926d528ed9Sopenharmony_ci template <typename InputIterator> 4936d528ed9Sopenharmony_ci typename std::enable_if<::base::internal::is_iterator<InputIterator>::value, 4946d528ed9Sopenharmony_ci void>::type 4956d528ed9Sopenharmony_ci assign(InputIterator first, InputIterator last) { 4966d528ed9Sopenharmony_ci // Possible future enhancement, dispatch on iterator tag type. For forward 4976d528ed9Sopenharmony_ci // iterators we can use std::difference to preallocate the space required 4986d528ed9Sopenharmony_ci // and only do one copy. 4996d528ed9Sopenharmony_ci ClearRetainCapacity(); 5006d528ed9Sopenharmony_ci for (; first != last; ++first) 5016d528ed9Sopenharmony_ci emplace_back(*first); 5026d528ed9Sopenharmony_ci IncrementGeneration(); 5036d528ed9Sopenharmony_ci } 5046d528ed9Sopenharmony_ci 5056d528ed9Sopenharmony_ci void assign(std::initializer_list<value_type> value) { 5066d528ed9Sopenharmony_ci reserve(std::distance(value.begin(), value.end())); 5076d528ed9Sopenharmony_ci assign(value.begin(), value.end()); 5086d528ed9Sopenharmony_ci } 5096d528ed9Sopenharmony_ci 5106d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 5116d528ed9Sopenharmony_ci // Accessors. 5126d528ed9Sopenharmony_ci // 5136d528ed9Sopenharmony_ci // Since this class assumes no exceptions, at() and operator[] are equivalent. 5146d528ed9Sopenharmony_ci 5156d528ed9Sopenharmony_ci const value_type& at(size_type i) const { 5166d528ed9Sopenharmony_ci DCHECK(i < size()); 5176d528ed9Sopenharmony_ci size_t right_size = buffer_.capacity() - begin_; 5186d528ed9Sopenharmony_ci if (begin_ <= end_ || i < right_size) 5196d528ed9Sopenharmony_ci return buffer_[begin_ + i]; 5206d528ed9Sopenharmony_ci return buffer_[i - right_size]; 5216d528ed9Sopenharmony_ci } 5226d528ed9Sopenharmony_ci value_type& at(size_type i) { 5236d528ed9Sopenharmony_ci return const_cast<value_type&>( 5246d528ed9Sopenharmony_ci const_cast<const circular_deque*>(this)->at(i)); 5256d528ed9Sopenharmony_ci } 5266d528ed9Sopenharmony_ci 5276d528ed9Sopenharmony_ci value_type& operator[](size_type i) { return at(i); } 5286d528ed9Sopenharmony_ci const value_type& operator[](size_type i) const { 5296d528ed9Sopenharmony_ci return const_cast<circular_deque*>(this)->at(i); 5306d528ed9Sopenharmony_ci } 5316d528ed9Sopenharmony_ci 5326d528ed9Sopenharmony_ci value_type& front() { 5336d528ed9Sopenharmony_ci DCHECK(!empty()); 5346d528ed9Sopenharmony_ci return buffer_[begin_]; 5356d528ed9Sopenharmony_ci } 5366d528ed9Sopenharmony_ci const value_type& front() const { 5376d528ed9Sopenharmony_ci DCHECK(!empty()); 5386d528ed9Sopenharmony_ci return buffer_[begin_]; 5396d528ed9Sopenharmony_ci } 5406d528ed9Sopenharmony_ci 5416d528ed9Sopenharmony_ci value_type& back() { 5426d528ed9Sopenharmony_ci DCHECK(!empty()); 5436d528ed9Sopenharmony_ci return *(--end()); 5446d528ed9Sopenharmony_ci } 5456d528ed9Sopenharmony_ci const value_type& back() const { 5466d528ed9Sopenharmony_ci DCHECK(!empty()); 5476d528ed9Sopenharmony_ci return *(--end()); 5486d528ed9Sopenharmony_ci } 5496d528ed9Sopenharmony_ci 5506d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 5516d528ed9Sopenharmony_ci // Iterators. 5526d528ed9Sopenharmony_ci 5536d528ed9Sopenharmony_ci iterator begin() { return iterator(this, begin_); } 5546d528ed9Sopenharmony_ci const_iterator begin() const { return const_iterator(this, begin_); } 5556d528ed9Sopenharmony_ci const_iterator cbegin() const { return const_iterator(this, begin_); } 5566d528ed9Sopenharmony_ci 5576d528ed9Sopenharmony_ci iterator end() { return iterator(this, end_); } 5586d528ed9Sopenharmony_ci const_iterator end() const { return const_iterator(this, end_); } 5596d528ed9Sopenharmony_ci const_iterator cend() const { return const_iterator(this, end_); } 5606d528ed9Sopenharmony_ci 5616d528ed9Sopenharmony_ci reverse_iterator rbegin() { return reverse_iterator(end()); } 5626d528ed9Sopenharmony_ci const_reverse_iterator rbegin() const { 5636d528ed9Sopenharmony_ci return const_reverse_iterator(end()); 5646d528ed9Sopenharmony_ci } 5656d528ed9Sopenharmony_ci const_reverse_iterator crbegin() const { return rbegin(); } 5666d528ed9Sopenharmony_ci 5676d528ed9Sopenharmony_ci reverse_iterator rend() { return reverse_iterator(begin()); } 5686d528ed9Sopenharmony_ci const_reverse_iterator rend() const { 5696d528ed9Sopenharmony_ci return const_reverse_iterator(begin()); 5706d528ed9Sopenharmony_ci } 5716d528ed9Sopenharmony_ci const_reverse_iterator crend() const { return rend(); } 5726d528ed9Sopenharmony_ci 5736d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 5746d528ed9Sopenharmony_ci // Memory management. 5756d528ed9Sopenharmony_ci 5766d528ed9Sopenharmony_ci // IMPORTANT NOTE ON reserve(...): This class implements auto-shrinking of 5776d528ed9Sopenharmony_ci // the buffer when elements are deleted and there is "too much" wasted space. 5786d528ed9Sopenharmony_ci // So if you call reserve() with a large size in anticipation of pushing many 5796d528ed9Sopenharmony_ci // elements, but pop an element before the queue is full, the capacity you 5806d528ed9Sopenharmony_ci // reserved may be lost. 5816d528ed9Sopenharmony_ci // 5826d528ed9Sopenharmony_ci // As a result, it's only worthwhile to call reserve() when you're adding 5836d528ed9Sopenharmony_ci // many things at once with no intermediate operations. 5846d528ed9Sopenharmony_ci void reserve(size_type new_capacity) { 5856d528ed9Sopenharmony_ci if (new_capacity > capacity()) 5866d528ed9Sopenharmony_ci SetCapacityTo(new_capacity); 5876d528ed9Sopenharmony_ci } 5886d528ed9Sopenharmony_ci 5896d528ed9Sopenharmony_ci size_type capacity() const { 5906d528ed9Sopenharmony_ci // One item is wasted to indicate end(). 5916d528ed9Sopenharmony_ci return buffer_.capacity() == 0 ? 0 : buffer_.capacity() - 1; 5926d528ed9Sopenharmony_ci } 5936d528ed9Sopenharmony_ci 5946d528ed9Sopenharmony_ci void shrink_to_fit() { 5956d528ed9Sopenharmony_ci if (empty()) { 5966d528ed9Sopenharmony_ci // Optimize empty case to really delete everything if there was 5976d528ed9Sopenharmony_ci // something. 5986d528ed9Sopenharmony_ci if (buffer_.capacity()) 5996d528ed9Sopenharmony_ci buffer_ = VectorBuffer(); 6006d528ed9Sopenharmony_ci } else { 6016d528ed9Sopenharmony_ci SetCapacityTo(size()); 6026d528ed9Sopenharmony_ci } 6036d528ed9Sopenharmony_ci } 6046d528ed9Sopenharmony_ci 6056d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 6066d528ed9Sopenharmony_ci // Size management. 6076d528ed9Sopenharmony_ci 6086d528ed9Sopenharmony_ci // This will additionally reset the capacity() to 0. 6096d528ed9Sopenharmony_ci void clear() { 6106d528ed9Sopenharmony_ci // This can't resize(0) because that requires a default constructor to 6116d528ed9Sopenharmony_ci // compile, which not all contained classes may implement. 6126d528ed9Sopenharmony_ci ClearRetainCapacity(); 6136d528ed9Sopenharmony_ci buffer_ = VectorBuffer(); 6146d528ed9Sopenharmony_ci } 6156d528ed9Sopenharmony_ci 6166d528ed9Sopenharmony_ci bool empty() const { return begin_ == end_; } 6176d528ed9Sopenharmony_ci 6186d528ed9Sopenharmony_ci size_type size() const { 6196d528ed9Sopenharmony_ci if (begin_ <= end_) 6206d528ed9Sopenharmony_ci return end_ - begin_; 6216d528ed9Sopenharmony_ci return buffer_.capacity() - begin_ + end_; 6226d528ed9Sopenharmony_ci } 6236d528ed9Sopenharmony_ci 6246d528ed9Sopenharmony_ci // When reducing size, the elements are deleted from the end. When expanding 6256d528ed9Sopenharmony_ci // size, elements are added to the end with |value| or the default 6266d528ed9Sopenharmony_ci // constructed version. Even when using resize(count) to shrink, a default 6276d528ed9Sopenharmony_ci // constructor is required for the code to compile, even though it will not 6286d528ed9Sopenharmony_ci // be called. 6296d528ed9Sopenharmony_ci // 6306d528ed9Sopenharmony_ci // There are two versions rather than using a default value to avoid 6316d528ed9Sopenharmony_ci // creating a temporary when shrinking (when it's not needed). Plus if 6326d528ed9Sopenharmony_ci // the default constructor is desired when expanding usually just calling it 6336d528ed9Sopenharmony_ci // for each element is faster than making a default-constructed temporary and 6346d528ed9Sopenharmony_ci // copying it. 6356d528ed9Sopenharmony_ci void resize(size_type count) { 6366d528ed9Sopenharmony_ci // SEE BELOW VERSION if you change this. The code is mostly the same. 6376d528ed9Sopenharmony_ci if (count > size()) { 6386d528ed9Sopenharmony_ci // This could be slightly more efficient but expanding a queue with 6396d528ed9Sopenharmony_ci // identical elements is unusual and the extra computations of emplacing 6406d528ed9Sopenharmony_ci // one-by-one will typically be small relative to calling the constructor 6416d528ed9Sopenharmony_ci // for every item. 6426d528ed9Sopenharmony_ci ExpandCapacityIfNecessary(count - size()); 6436d528ed9Sopenharmony_ci while (size() < count) 6446d528ed9Sopenharmony_ci emplace_back(); 6456d528ed9Sopenharmony_ci } else if (count < size()) { 6466d528ed9Sopenharmony_ci size_t new_end = (begin_ + count) % buffer_.capacity(); 6476d528ed9Sopenharmony_ci DestructRange(new_end, end_); 6486d528ed9Sopenharmony_ci end_ = new_end; 6496d528ed9Sopenharmony_ci 6506d528ed9Sopenharmony_ci ShrinkCapacityIfNecessary(); 6516d528ed9Sopenharmony_ci } 6526d528ed9Sopenharmony_ci IncrementGeneration(); 6536d528ed9Sopenharmony_ci } 6546d528ed9Sopenharmony_ci void resize(size_type count, const value_type& value) { 6556d528ed9Sopenharmony_ci // SEE ABOVE VERSION if you change this. The code is mostly the same. 6566d528ed9Sopenharmony_ci if (count > size()) { 6576d528ed9Sopenharmony_ci ExpandCapacityIfNecessary(count - size()); 6586d528ed9Sopenharmony_ci while (size() < count) 6596d528ed9Sopenharmony_ci emplace_back(value); 6606d528ed9Sopenharmony_ci } else if (count < size()) { 6616d528ed9Sopenharmony_ci size_t new_end = (begin_ + count) % buffer_.capacity(); 6626d528ed9Sopenharmony_ci DestructRange(new_end, end_); 6636d528ed9Sopenharmony_ci end_ = new_end; 6646d528ed9Sopenharmony_ci 6656d528ed9Sopenharmony_ci ShrinkCapacityIfNecessary(); 6666d528ed9Sopenharmony_ci } 6676d528ed9Sopenharmony_ci IncrementGeneration(); 6686d528ed9Sopenharmony_ci } 6696d528ed9Sopenharmony_ci 6706d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 6716d528ed9Sopenharmony_ci // Insert and erase. 6726d528ed9Sopenharmony_ci // 6736d528ed9Sopenharmony_ci // Insertion and deletion in the middle is O(n) and invalidates all existing 6746d528ed9Sopenharmony_ci // iterators. 6756d528ed9Sopenharmony_ci // 6766d528ed9Sopenharmony_ci // The implementation of insert isn't optimized as much as it could be. If 6776d528ed9Sopenharmony_ci // the insertion requires that the buffer be grown, it will first be grown 6786d528ed9Sopenharmony_ci // and everything moved, and then the items will be inserted, potentially 6796d528ed9Sopenharmony_ci // moving some items twice. This simplifies the implementation substantially 6806d528ed9Sopenharmony_ci // and means less generated templatized code. Since this is an uncommon 6816d528ed9Sopenharmony_ci // operation for deques, and already relatively slow, it doesn't seem worth 6826d528ed9Sopenharmony_ci // the benefit to optimize this. 6836d528ed9Sopenharmony_ci 6846d528ed9Sopenharmony_ci void insert(const_iterator pos, size_type count, const T& value) { 6856d528ed9Sopenharmony_ci ValidateIterator(pos); 6866d528ed9Sopenharmony_ci 6876d528ed9Sopenharmony_ci // Optimize insert at the beginning. 6886d528ed9Sopenharmony_ci if (pos == begin()) { 6896d528ed9Sopenharmony_ci ExpandCapacityIfNecessary(count); 6906d528ed9Sopenharmony_ci for (size_t i = 0; i < count; i++) 6916d528ed9Sopenharmony_ci push_front(value); 6926d528ed9Sopenharmony_ci return; 6936d528ed9Sopenharmony_ci } 6946d528ed9Sopenharmony_ci 6956d528ed9Sopenharmony_ci iterator insert_cur(this, pos.index_); 6966d528ed9Sopenharmony_ci iterator insert_end; 6976d528ed9Sopenharmony_ci MakeRoomFor(count, &insert_cur, &insert_end); 6986d528ed9Sopenharmony_ci while (insert_cur < insert_end) { 6996d528ed9Sopenharmony_ci new (&buffer_[insert_cur.index_]) T(value); 7006d528ed9Sopenharmony_ci ++insert_cur; 7016d528ed9Sopenharmony_ci } 7026d528ed9Sopenharmony_ci 7036d528ed9Sopenharmony_ci IncrementGeneration(); 7046d528ed9Sopenharmony_ci } 7056d528ed9Sopenharmony_ci 7066d528ed9Sopenharmony_ci // This enable_if keeps this call from getting confused with the (pos, count, 7076d528ed9Sopenharmony_ci // value) version when value is an integer. 7086d528ed9Sopenharmony_ci template <class InputIterator> 7096d528ed9Sopenharmony_ci typename std::enable_if<::base::internal::is_iterator<InputIterator>::value, 7106d528ed9Sopenharmony_ci void>::type 7116d528ed9Sopenharmony_ci insert(const_iterator pos, InputIterator first, InputIterator last) { 7126d528ed9Sopenharmony_ci ValidateIterator(pos); 7136d528ed9Sopenharmony_ci 7146d528ed9Sopenharmony_ci size_t inserted_items = std::distance(first, last); 7156d528ed9Sopenharmony_ci if (inserted_items == 0) 7166d528ed9Sopenharmony_ci return; // Can divide by 0 when doing modulo below, so return early. 7176d528ed9Sopenharmony_ci 7186d528ed9Sopenharmony_ci // Make a hole to copy the items into. 7196d528ed9Sopenharmony_ci iterator insert_cur; 7206d528ed9Sopenharmony_ci iterator insert_end; 7216d528ed9Sopenharmony_ci if (pos == begin()) { 7226d528ed9Sopenharmony_ci // Optimize insert at the beginning, nothing needs to be shifted and the 7236d528ed9Sopenharmony_ci // hole is the |inserted_items| block immediately before |begin_|. 7246d528ed9Sopenharmony_ci ExpandCapacityIfNecessary(inserted_items); 7256d528ed9Sopenharmony_ci insert_end = begin(); 7266d528ed9Sopenharmony_ci begin_ = 7276d528ed9Sopenharmony_ci (begin_ + buffer_.capacity() - inserted_items) % buffer_.capacity(); 7286d528ed9Sopenharmony_ci insert_cur = begin(); 7296d528ed9Sopenharmony_ci } else { 7306d528ed9Sopenharmony_ci insert_cur = iterator(this, pos.index_); 7316d528ed9Sopenharmony_ci MakeRoomFor(inserted_items, &insert_cur, &insert_end); 7326d528ed9Sopenharmony_ci } 7336d528ed9Sopenharmony_ci 7346d528ed9Sopenharmony_ci // Copy the items. 7356d528ed9Sopenharmony_ci while (insert_cur < insert_end) { 7366d528ed9Sopenharmony_ci new (&buffer_[insert_cur.index_]) T(*first); 7376d528ed9Sopenharmony_ci ++insert_cur; 7386d528ed9Sopenharmony_ci ++first; 7396d528ed9Sopenharmony_ci } 7406d528ed9Sopenharmony_ci 7416d528ed9Sopenharmony_ci IncrementGeneration(); 7426d528ed9Sopenharmony_ci } 7436d528ed9Sopenharmony_ci 7446d528ed9Sopenharmony_ci // These all return an iterator to the inserted item. Existing iterators will 7456d528ed9Sopenharmony_ci // be invalidated. 7466d528ed9Sopenharmony_ci iterator insert(const_iterator pos, const T& value) { 7476d528ed9Sopenharmony_ci return emplace(pos, value); 7486d528ed9Sopenharmony_ci } 7496d528ed9Sopenharmony_ci iterator insert(const_iterator pos, T&& value) { 7506d528ed9Sopenharmony_ci return emplace(pos, std::move(value)); 7516d528ed9Sopenharmony_ci } 7526d528ed9Sopenharmony_ci template <class... Args> 7536d528ed9Sopenharmony_ci iterator emplace(const_iterator pos, Args&&... args) { 7546d528ed9Sopenharmony_ci ValidateIterator(pos); 7556d528ed9Sopenharmony_ci 7566d528ed9Sopenharmony_ci // Optimize insert at beginning which doesn't require shifting. 7576d528ed9Sopenharmony_ci if (pos == cbegin()) { 7586d528ed9Sopenharmony_ci emplace_front(std::forward<Args>(args)...); 7596d528ed9Sopenharmony_ci return begin(); 7606d528ed9Sopenharmony_ci } 7616d528ed9Sopenharmony_ci 7626d528ed9Sopenharmony_ci // Do this before we make the new iterators we return. 7636d528ed9Sopenharmony_ci IncrementGeneration(); 7646d528ed9Sopenharmony_ci 7656d528ed9Sopenharmony_ci iterator insert_begin(this, pos.index_); 7666d528ed9Sopenharmony_ci iterator insert_end; 7676d528ed9Sopenharmony_ci MakeRoomFor(1, &insert_begin, &insert_end); 7686d528ed9Sopenharmony_ci new (&buffer_[insert_begin.index_]) T(std::forward<Args>(args)...); 7696d528ed9Sopenharmony_ci 7706d528ed9Sopenharmony_ci return insert_begin; 7716d528ed9Sopenharmony_ci } 7726d528ed9Sopenharmony_ci 7736d528ed9Sopenharmony_ci // Calling erase() won't automatically resize the buffer smaller like resize 7746d528ed9Sopenharmony_ci // or the pop functions. Erase is slow and relatively uncommon, and for 7756d528ed9Sopenharmony_ci // normal deque usage a pop will normally be done on a regular basis that 7766d528ed9Sopenharmony_ci // will prevent excessive buffer usage over long periods of time. It's not 7776d528ed9Sopenharmony_ci // worth having the extra code for every template instantiation of erase() 7786d528ed9Sopenharmony_ci // to resize capacity downward to a new buffer. 7796d528ed9Sopenharmony_ci iterator erase(const_iterator pos) { return erase(pos, pos + 1); } 7806d528ed9Sopenharmony_ci iterator erase(const_iterator first, const_iterator last) { 7816d528ed9Sopenharmony_ci ValidateIterator(first); 7826d528ed9Sopenharmony_ci ValidateIterator(last); 7836d528ed9Sopenharmony_ci 7846d528ed9Sopenharmony_ci IncrementGeneration(); 7856d528ed9Sopenharmony_ci 7866d528ed9Sopenharmony_ci // First, call the destructor on the deleted items. 7876d528ed9Sopenharmony_ci if (first.index_ == last.index_) { 7886d528ed9Sopenharmony_ci // Nothing deleted. Need to return early to avoid falling through to 7896d528ed9Sopenharmony_ci // moving items on top of themselves. 7906d528ed9Sopenharmony_ci return iterator(this, first.index_); 7916d528ed9Sopenharmony_ci } else if (first.index_ < last.index_) { 7926d528ed9Sopenharmony_ci // Contiguous range. 7936d528ed9Sopenharmony_ci buffer_.DestructRange(&buffer_[first.index_], &buffer_[last.index_]); 7946d528ed9Sopenharmony_ci } else { 7956d528ed9Sopenharmony_ci // Deleted range wraps around. 7966d528ed9Sopenharmony_ci buffer_.DestructRange(&buffer_[first.index_], 7976d528ed9Sopenharmony_ci &buffer_[buffer_.capacity()]); 7986d528ed9Sopenharmony_ci buffer_.DestructRange(&buffer_[0], &buffer_[last.index_]); 7996d528ed9Sopenharmony_ci } 8006d528ed9Sopenharmony_ci 8016d528ed9Sopenharmony_ci if (first.index_ == begin_) { 8026d528ed9Sopenharmony_ci // This deletion is from the beginning. Nothing needs to be copied, only 8036d528ed9Sopenharmony_ci // begin_ needs to be updated. 8046d528ed9Sopenharmony_ci begin_ = last.index_; 8056d528ed9Sopenharmony_ci return iterator(this, last.index_); 8066d528ed9Sopenharmony_ci } 8076d528ed9Sopenharmony_ci 8086d528ed9Sopenharmony_ci // In an erase operation, the shifted items all move logically to the left, 8096d528ed9Sopenharmony_ci // so move them from left-to-right. 8106d528ed9Sopenharmony_ci iterator move_src(this, last.index_); 8116d528ed9Sopenharmony_ci iterator move_src_end = end(); 8126d528ed9Sopenharmony_ci iterator move_dest(this, first.index_); 8136d528ed9Sopenharmony_ci for (; move_src < move_src_end; move_src++, move_dest++) { 8146d528ed9Sopenharmony_ci buffer_.MoveRange(&buffer_[move_src.index_], 8156d528ed9Sopenharmony_ci &buffer_[move_src.index_ + 1], 8166d528ed9Sopenharmony_ci &buffer_[move_dest.index_]); 8176d528ed9Sopenharmony_ci } 8186d528ed9Sopenharmony_ci 8196d528ed9Sopenharmony_ci end_ = move_dest.index_; 8206d528ed9Sopenharmony_ci 8216d528ed9Sopenharmony_ci // Since we did not reallocate and only changed things after the erase 8226d528ed9Sopenharmony_ci // element(s), the input iterator's index points to the thing following the 8236d528ed9Sopenharmony_ci // deletion. 8246d528ed9Sopenharmony_ci return iterator(this, first.index_); 8256d528ed9Sopenharmony_ci } 8266d528ed9Sopenharmony_ci 8276d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 8286d528ed9Sopenharmony_ci // Begin/end operations. 8296d528ed9Sopenharmony_ci 8306d528ed9Sopenharmony_ci void push_front(const T& value) { emplace_front(value); } 8316d528ed9Sopenharmony_ci void push_front(T&& value) { emplace_front(std::move(value)); } 8326d528ed9Sopenharmony_ci 8336d528ed9Sopenharmony_ci void push_back(const T& value) { emplace_back(value); } 8346d528ed9Sopenharmony_ci void push_back(T&& value) { emplace_back(std::move(value)); } 8356d528ed9Sopenharmony_ci 8366d528ed9Sopenharmony_ci template <class... Args> 8376d528ed9Sopenharmony_ci reference emplace_front(Args&&... args) { 8386d528ed9Sopenharmony_ci ExpandCapacityIfNecessary(1); 8396d528ed9Sopenharmony_ci if (begin_ == 0) 8406d528ed9Sopenharmony_ci begin_ = buffer_.capacity() - 1; 8416d528ed9Sopenharmony_ci else 8426d528ed9Sopenharmony_ci begin_--; 8436d528ed9Sopenharmony_ci IncrementGeneration(); 8446d528ed9Sopenharmony_ci new (&buffer_[begin_]) T(std::forward<Args>(args)...); 8456d528ed9Sopenharmony_ci return front(); 8466d528ed9Sopenharmony_ci } 8476d528ed9Sopenharmony_ci 8486d528ed9Sopenharmony_ci template <class... Args> 8496d528ed9Sopenharmony_ci reference emplace_back(Args&&... args) { 8506d528ed9Sopenharmony_ci ExpandCapacityIfNecessary(1); 8516d528ed9Sopenharmony_ci new (&buffer_[end_]) T(std::forward<Args>(args)...); 8526d528ed9Sopenharmony_ci if (end_ == buffer_.capacity() - 1) 8536d528ed9Sopenharmony_ci end_ = 0; 8546d528ed9Sopenharmony_ci else 8556d528ed9Sopenharmony_ci end_++; 8566d528ed9Sopenharmony_ci IncrementGeneration(); 8576d528ed9Sopenharmony_ci return back(); 8586d528ed9Sopenharmony_ci } 8596d528ed9Sopenharmony_ci 8606d528ed9Sopenharmony_ci void pop_front() { 8616d528ed9Sopenharmony_ci DCHECK(size()); 8626d528ed9Sopenharmony_ci buffer_.DestructRange(&buffer_[begin_], &buffer_[begin_ + 1]); 8636d528ed9Sopenharmony_ci begin_++; 8646d528ed9Sopenharmony_ci if (begin_ == buffer_.capacity()) 8656d528ed9Sopenharmony_ci begin_ = 0; 8666d528ed9Sopenharmony_ci 8676d528ed9Sopenharmony_ci ShrinkCapacityIfNecessary(); 8686d528ed9Sopenharmony_ci 8696d528ed9Sopenharmony_ci // Technically popping will not invalidate any iterators since the 8706d528ed9Sopenharmony_ci // underlying buffer will be stable. But in the future we may want to add a 8716d528ed9Sopenharmony_ci // feature that resizes the buffer smaller if there is too much wasted 8726d528ed9Sopenharmony_ci // space. This ensures we can make such a change safely. 8736d528ed9Sopenharmony_ci IncrementGeneration(); 8746d528ed9Sopenharmony_ci } 8756d528ed9Sopenharmony_ci void pop_back() { 8766d528ed9Sopenharmony_ci DCHECK(size()); 8776d528ed9Sopenharmony_ci if (end_ == 0) 8786d528ed9Sopenharmony_ci end_ = buffer_.capacity() - 1; 8796d528ed9Sopenharmony_ci else 8806d528ed9Sopenharmony_ci end_--; 8816d528ed9Sopenharmony_ci buffer_.DestructRange(&buffer_[end_], &buffer_[end_ + 1]); 8826d528ed9Sopenharmony_ci 8836d528ed9Sopenharmony_ci ShrinkCapacityIfNecessary(); 8846d528ed9Sopenharmony_ci 8856d528ed9Sopenharmony_ci // See pop_front comment about why this is here. 8866d528ed9Sopenharmony_ci IncrementGeneration(); 8876d528ed9Sopenharmony_ci } 8886d528ed9Sopenharmony_ci 8896d528ed9Sopenharmony_ci // --------------------------------------------------------------------------- 8906d528ed9Sopenharmony_ci // General operations. 8916d528ed9Sopenharmony_ci 8926d528ed9Sopenharmony_ci void swap(circular_deque& other) { 8936d528ed9Sopenharmony_ci std::swap(buffer_, other.buffer_); 8946d528ed9Sopenharmony_ci std::swap(begin_, other.begin_); 8956d528ed9Sopenharmony_ci std::swap(end_, other.end_); 8966d528ed9Sopenharmony_ci IncrementGeneration(); 8976d528ed9Sopenharmony_ci } 8986d528ed9Sopenharmony_ci 8996d528ed9Sopenharmony_ci friend void swap(circular_deque& lhs, circular_deque& rhs) { lhs.swap(rhs); } 9006d528ed9Sopenharmony_ci 9016d528ed9Sopenharmony_ci private: 9026d528ed9Sopenharmony_ci friend internal::circular_deque_iterator<T>; 9036d528ed9Sopenharmony_ci friend internal::circular_deque_const_iterator<T>; 9046d528ed9Sopenharmony_ci 9056d528ed9Sopenharmony_ci // Moves the items in the given circular buffer to the current one. The 9066d528ed9Sopenharmony_ci // source is moved from so will become invalid. The destination buffer must 9076d528ed9Sopenharmony_ci // have already been allocated with enough size. 9086d528ed9Sopenharmony_ci static void MoveBuffer(VectorBuffer& from_buf, 9096d528ed9Sopenharmony_ci size_t from_begin, 9106d528ed9Sopenharmony_ci size_t from_end, 9116d528ed9Sopenharmony_ci VectorBuffer* to_buf, 9126d528ed9Sopenharmony_ci size_t* to_begin, 9136d528ed9Sopenharmony_ci size_t* to_end) { 9146d528ed9Sopenharmony_ci size_t from_capacity = from_buf.capacity(); 9156d528ed9Sopenharmony_ci 9166d528ed9Sopenharmony_ci *to_begin = 0; 9176d528ed9Sopenharmony_ci if (from_begin < from_end) { 9186d528ed9Sopenharmony_ci // Contiguous. 9196d528ed9Sopenharmony_ci from_buf.MoveRange(&from_buf[from_begin], &from_buf[from_end], 9206d528ed9Sopenharmony_ci to_buf->begin()); 9216d528ed9Sopenharmony_ci *to_end = from_end - from_begin; 9226d528ed9Sopenharmony_ci } else if (from_begin > from_end) { 9236d528ed9Sopenharmony_ci // Discontiguous, copy the right side to the beginning of the new buffer. 9246d528ed9Sopenharmony_ci from_buf.MoveRange(&from_buf[from_begin], &from_buf[from_capacity], 9256d528ed9Sopenharmony_ci to_buf->begin()); 9266d528ed9Sopenharmony_ci size_t right_size = from_capacity - from_begin; 9276d528ed9Sopenharmony_ci // Append the left side. 9286d528ed9Sopenharmony_ci from_buf.MoveRange(&from_buf[0], &from_buf[from_end], 9296d528ed9Sopenharmony_ci &(*to_buf)[right_size]); 9306d528ed9Sopenharmony_ci *to_end = right_size + from_end; 9316d528ed9Sopenharmony_ci } else { 9326d528ed9Sopenharmony_ci // No items. 9336d528ed9Sopenharmony_ci *to_end = 0; 9346d528ed9Sopenharmony_ci } 9356d528ed9Sopenharmony_ci } 9366d528ed9Sopenharmony_ci 9376d528ed9Sopenharmony_ci // Expands the buffer size. This assumes the size is larger than the 9386d528ed9Sopenharmony_ci // number of elements in the vector (it won't call delete on anything). 9396d528ed9Sopenharmony_ci void SetCapacityTo(size_t new_capacity) { 9406d528ed9Sopenharmony_ci // Use the capacity + 1 as the internal buffer size to differentiate 9416d528ed9Sopenharmony_ci // empty and full (see definition of buffer_ below). 9426d528ed9Sopenharmony_ci VectorBuffer new_buffer(new_capacity + 1); 9436d528ed9Sopenharmony_ci MoveBuffer(buffer_, begin_, end_, &new_buffer, &begin_, &end_); 9446d528ed9Sopenharmony_ci buffer_ = std::move(new_buffer); 9456d528ed9Sopenharmony_ci } 9466d528ed9Sopenharmony_ci void ExpandCapacityIfNecessary(size_t additional_elts) { 9476d528ed9Sopenharmony_ci size_t min_new_capacity = size() + additional_elts; 9486d528ed9Sopenharmony_ci if (capacity() >= min_new_capacity) 9496d528ed9Sopenharmony_ci return; // Already enough room. 9506d528ed9Sopenharmony_ci 9516d528ed9Sopenharmony_ci min_new_capacity = 9526d528ed9Sopenharmony_ci std::max(min_new_capacity, internal::kCircularBufferInitialCapacity); 9536d528ed9Sopenharmony_ci 9546d528ed9Sopenharmony_ci // std::vector always grows by at least 50%. WTF::Deque grows by at least 9556d528ed9Sopenharmony_ci // 25%. We expect queue workloads to generally stay at a similar size and 9566d528ed9Sopenharmony_ci // grow less than a vector might, so use 25%. 9576d528ed9Sopenharmony_ci size_t new_capacity = 9586d528ed9Sopenharmony_ci std::max(min_new_capacity, capacity() + capacity() / 4); 9596d528ed9Sopenharmony_ci SetCapacityTo(new_capacity); 9606d528ed9Sopenharmony_ci } 9616d528ed9Sopenharmony_ci 9626d528ed9Sopenharmony_ci void ShrinkCapacityIfNecessary() { 9636d528ed9Sopenharmony_ci // Don't auto-shrink below this size. 9646d528ed9Sopenharmony_ci if (capacity() <= internal::kCircularBufferInitialCapacity) 9656d528ed9Sopenharmony_ci return; 9666d528ed9Sopenharmony_ci 9676d528ed9Sopenharmony_ci // Shrink when 100% of the size() is wasted. 9686d528ed9Sopenharmony_ci size_t sz = size(); 9696d528ed9Sopenharmony_ci size_t empty_spaces = capacity() - sz; 9706d528ed9Sopenharmony_ci if (empty_spaces < sz) 9716d528ed9Sopenharmony_ci return; 9726d528ed9Sopenharmony_ci 9736d528ed9Sopenharmony_ci // Leave 1/4 the size as free capacity, not going below the initial 9746d528ed9Sopenharmony_ci // capacity. 9756d528ed9Sopenharmony_ci size_t new_capacity = 9766d528ed9Sopenharmony_ci std::max(internal::kCircularBufferInitialCapacity, sz + sz / 4); 9776d528ed9Sopenharmony_ci if (new_capacity < capacity()) { 9786d528ed9Sopenharmony_ci // Count extra item to convert to internal capacity. 9796d528ed9Sopenharmony_ci SetCapacityTo(new_capacity); 9806d528ed9Sopenharmony_ci } 9816d528ed9Sopenharmony_ci } 9826d528ed9Sopenharmony_ci 9836d528ed9Sopenharmony_ci // Backend for clear() but does not resize the internal buffer. 9846d528ed9Sopenharmony_ci void ClearRetainCapacity() { 9856d528ed9Sopenharmony_ci // This can't resize(0) because that requires a default constructor to 9866d528ed9Sopenharmony_ci // compile, which not all contained classes may implement. 9876d528ed9Sopenharmony_ci DestructRange(begin_, end_); 9886d528ed9Sopenharmony_ci begin_ = 0; 9896d528ed9Sopenharmony_ci end_ = 0; 9906d528ed9Sopenharmony_ci IncrementGeneration(); 9916d528ed9Sopenharmony_ci } 9926d528ed9Sopenharmony_ci 9936d528ed9Sopenharmony_ci // Calls destructors for the given begin->end indices. The indices may wrap 9946d528ed9Sopenharmony_ci // around. The buffer is not resized, and the begin_ and end_ members are 9956d528ed9Sopenharmony_ci // not changed. 9966d528ed9Sopenharmony_ci void DestructRange(size_t begin, size_t end) { 9976d528ed9Sopenharmony_ci if (end == begin) { 9986d528ed9Sopenharmony_ci return; 9996d528ed9Sopenharmony_ci } else if (end > begin) { 10006d528ed9Sopenharmony_ci buffer_.DestructRange(&buffer_[begin], &buffer_[end]); 10016d528ed9Sopenharmony_ci } else { 10026d528ed9Sopenharmony_ci buffer_.DestructRange(&buffer_[begin], &buffer_[buffer_.capacity()]); 10036d528ed9Sopenharmony_ci buffer_.DestructRange(&buffer_[0], &buffer_[end]); 10046d528ed9Sopenharmony_ci } 10056d528ed9Sopenharmony_ci } 10066d528ed9Sopenharmony_ci 10076d528ed9Sopenharmony_ci // Makes room for |count| items starting at |*insert_begin|. Since iterators 10086d528ed9Sopenharmony_ci // are not stable across buffer resizes, |*insert_begin| will be updated to 10096d528ed9Sopenharmony_ci // point to the beginning of the newly opened position in the new array (it's 10106d528ed9Sopenharmony_ci // in/out), and the end of the newly opened position (it's out-only). 10116d528ed9Sopenharmony_ci void MakeRoomFor(size_t count, iterator* insert_begin, iterator* insert_end) { 10126d528ed9Sopenharmony_ci if (count == 0) { 10136d528ed9Sopenharmony_ci *insert_end = *insert_begin; 10146d528ed9Sopenharmony_ci return; 10156d528ed9Sopenharmony_ci } 10166d528ed9Sopenharmony_ci 10176d528ed9Sopenharmony_ci // The offset from the beginning will be stable across reallocations. 10186d528ed9Sopenharmony_ci size_t begin_offset = insert_begin->OffsetFromBegin(); 10196d528ed9Sopenharmony_ci ExpandCapacityIfNecessary(count); 10206d528ed9Sopenharmony_ci 10216d528ed9Sopenharmony_ci insert_begin->index_ = (begin_ + begin_offset) % buffer_.capacity(); 10226d528ed9Sopenharmony_ci *insert_end = 10236d528ed9Sopenharmony_ci iterator(this, (insert_begin->index_ + count) % buffer_.capacity()); 10246d528ed9Sopenharmony_ci 10256d528ed9Sopenharmony_ci // Update the new end and prepare the iterators for copying. 10266d528ed9Sopenharmony_ci iterator src = end(); 10276d528ed9Sopenharmony_ci end_ = (end_ + count) % buffer_.capacity(); 10286d528ed9Sopenharmony_ci iterator dest = end(); 10296d528ed9Sopenharmony_ci 10306d528ed9Sopenharmony_ci // Move the elements. This will always involve shifting logically to the 10316d528ed9Sopenharmony_ci // right, so move in a right-to-left order. 10326d528ed9Sopenharmony_ci while (true) { 10336d528ed9Sopenharmony_ci if (src == *insert_begin) 10346d528ed9Sopenharmony_ci break; 10356d528ed9Sopenharmony_ci --src; 10366d528ed9Sopenharmony_ci --dest; 10376d528ed9Sopenharmony_ci buffer_.MoveRange(&buffer_[src.index_], &buffer_[src.index_ + 1], 10386d528ed9Sopenharmony_ci &buffer_[dest.index_]); 10396d528ed9Sopenharmony_ci } 10406d528ed9Sopenharmony_ci } 10416d528ed9Sopenharmony_ci 10426d528ed9Sopenharmony_ci#if DCHECK_IS_ON() 10436d528ed9Sopenharmony_ci // Asserts the given index is dereferenceable. The index is an index into the 10446d528ed9Sopenharmony_ci // buffer, not an index used by operator[] or at() which will be offsets from 10456d528ed9Sopenharmony_ci // begin. 10466d528ed9Sopenharmony_ci void CheckValidIndex(size_t i) const { 10476d528ed9Sopenharmony_ci if (begin_ <= end_) 10486d528ed9Sopenharmony_ci DCHECK(i >= begin_ && i < end_); 10496d528ed9Sopenharmony_ci else 10506d528ed9Sopenharmony_ci DCHECK((i >= begin_ && i < buffer_.capacity()) || i < end_); 10516d528ed9Sopenharmony_ci } 10526d528ed9Sopenharmony_ci 10536d528ed9Sopenharmony_ci // Asserts the given index is either dereferenceable or points to end(). 10546d528ed9Sopenharmony_ci void CheckValidIndexOrEnd(size_t i) const { 10556d528ed9Sopenharmony_ci if (i != end_) 10566d528ed9Sopenharmony_ci CheckValidIndex(i); 10576d528ed9Sopenharmony_ci } 10586d528ed9Sopenharmony_ci 10596d528ed9Sopenharmony_ci void ValidateIterator(const const_iterator& i) const { 10606d528ed9Sopenharmony_ci DCHECK(i.parent_deque_ == this); 10616d528ed9Sopenharmony_ci i.CheckUnstableUsage(); 10626d528ed9Sopenharmony_ci } 10636d528ed9Sopenharmony_ci 10646d528ed9Sopenharmony_ci // See generation_ below. 10656d528ed9Sopenharmony_ci void IncrementGeneration() { generation_++; } 10666d528ed9Sopenharmony_ci#else 10676d528ed9Sopenharmony_ci // No-op versions of these functions for release builds. 10686d528ed9Sopenharmony_ci void CheckValidIndex(size_t) const {} 10696d528ed9Sopenharmony_ci void CheckValidIndexOrEnd(size_t) const {} 10706d528ed9Sopenharmony_ci void ValidateIterator(const const_iterator& i) const {} 10716d528ed9Sopenharmony_ci void IncrementGeneration() {} 10726d528ed9Sopenharmony_ci#endif 10736d528ed9Sopenharmony_ci 10746d528ed9Sopenharmony_ci // Danger, the buffer_.capacity() is the "internal capacity" which is 10756d528ed9Sopenharmony_ci // capacity() + 1 since there is an extra item to indicate the end. Otherwise 10766d528ed9Sopenharmony_ci // being completely empty and completely full are indistinguishable (begin == 10776d528ed9Sopenharmony_ci // end). We could add a separate flag to avoid it, but that adds significant 10786d528ed9Sopenharmony_ci // extra complexity since every computation will have to check for it. Always 10796d528ed9Sopenharmony_ci // keeping one extra unused element in the buffer makes iterator computations 10806d528ed9Sopenharmony_ci // much simpler. 10816d528ed9Sopenharmony_ci // 10826d528ed9Sopenharmony_ci // Container internal code will want to use buffer_.capacity() for offset 10836d528ed9Sopenharmony_ci // computations rather than capacity(). 10846d528ed9Sopenharmony_ci VectorBuffer buffer_; 10856d528ed9Sopenharmony_ci size_type begin_ = 0; 10866d528ed9Sopenharmony_ci size_type end_ = 0; 10876d528ed9Sopenharmony_ci 10886d528ed9Sopenharmony_ci#if DCHECK_IS_ON() 10896d528ed9Sopenharmony_ci // Incremented every time a modification is made that could affect iterator 10906d528ed9Sopenharmony_ci // invalidations. 10916d528ed9Sopenharmony_ci uint64_t generation_ = 0; 10926d528ed9Sopenharmony_ci#endif 10936d528ed9Sopenharmony_ci}; 10946d528ed9Sopenharmony_ci 10956d528ed9Sopenharmony_ci// Implementations of base::Erase[If] (see base/stl_util.h). 10966d528ed9Sopenharmony_citemplate <class T, class Value> 10976d528ed9Sopenharmony_civoid Erase(circular_deque<T>& container, const Value& value) { 10986d528ed9Sopenharmony_ci container.erase(std::remove(container.begin(), container.end(), value), 10996d528ed9Sopenharmony_ci container.end()); 11006d528ed9Sopenharmony_ci} 11016d528ed9Sopenharmony_ci 11026d528ed9Sopenharmony_citemplate <class T, class Predicate> 11036d528ed9Sopenharmony_civoid EraseIf(circular_deque<T>& container, Predicate pred) { 11046d528ed9Sopenharmony_ci container.erase(std::remove_if(container.begin(), container.end(), pred), 11056d528ed9Sopenharmony_ci container.end()); 11066d528ed9Sopenharmony_ci} 11076d528ed9Sopenharmony_ci 11086d528ed9Sopenharmony_ci} // namespace base 11096d528ed9Sopenharmony_ci 11106d528ed9Sopenharmony_ci#endif // BASE_CONTAINERS_CIRCULAR_DEQUE_H_ 1111