1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_CONTAINERS_RING_BUFFER_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_RING_BUFFER_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <stddef.h> 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard Worker #include "base/check.h" 11*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ref.h" 12*6777b538SAndroid Build Coastguard Worker 13*6777b538SAndroid Build Coastguard Worker namespace base { 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard Worker // base::RingBuffer uses a fixed-size array, unlike base::circular_deque and 16*6777b538SAndroid Build Coastguard Worker // std::deque, and so, one can access only the last |kSize| elements. Also, you 17*6777b538SAndroid Build Coastguard Worker // can add elements to the front and read/modify random elements, but cannot 18*6777b538SAndroid Build Coastguard Worker // remove elements from the back. Therefore, it does not have a |Size| method, 19*6777b538SAndroid Build Coastguard Worker // only |BufferSize|, which is a constant, and |CurrentIndex|, which is the 20*6777b538SAndroid Build Coastguard Worker // number of elements added so far. 21*6777b538SAndroid Build Coastguard Worker // 22*6777b538SAndroid Build Coastguard Worker // If the above is sufficient for your use case, base::RingBuffer should be more 23*6777b538SAndroid Build Coastguard Worker // efficient than base::circular_deque. 24*6777b538SAndroid Build Coastguard Worker template <typename T, size_t kSize> 25*6777b538SAndroid Build Coastguard Worker class RingBuffer { 26*6777b538SAndroid Build Coastguard Worker public: RingBuffer()27*6777b538SAndroid Build Coastguard Worker RingBuffer() : current_index_(0) {} 28*6777b538SAndroid Build Coastguard Worker RingBuffer(const RingBuffer&) = delete; 29*6777b538SAndroid Build Coastguard Worker RingBuffer& operator=(const RingBuffer&) = delete; 30*6777b538SAndroid Build Coastguard Worker BufferSize()31*6777b538SAndroid Build Coastguard Worker size_t BufferSize() const { return kSize; } 32*6777b538SAndroid Build Coastguard Worker CurrentIndex()33*6777b538SAndroid Build Coastguard Worker size_t CurrentIndex() const { return current_index_; } 34*6777b538SAndroid Build Coastguard Worker 35*6777b538SAndroid Build Coastguard Worker // Returns true if a value was saved to index |n|. IsFilledIndex(size_t n)36*6777b538SAndroid Build Coastguard Worker bool IsFilledIndex(size_t n) const { 37*6777b538SAndroid Build Coastguard Worker return IsFilledIndexByBufferIndex(BufferIndex(n)); 38*6777b538SAndroid Build Coastguard Worker } 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard Worker // Returns the element at index |n| (% |kSize|). 41*6777b538SAndroid Build Coastguard Worker // 42*6777b538SAndroid Build Coastguard Worker // n = 0 returns the oldest value and 43*6777b538SAndroid Build Coastguard Worker // n = bufferSize() - 1 returns the most recent value. ReadBuffer(size_t n)44*6777b538SAndroid Build Coastguard Worker const T& ReadBuffer(size_t n) const { 45*6777b538SAndroid Build Coastguard Worker const size_t buffer_index = BufferIndex(n); 46*6777b538SAndroid Build Coastguard Worker CHECK(IsFilledIndexByBufferIndex(buffer_index)); 47*6777b538SAndroid Build Coastguard Worker return buffer_[buffer_index]; 48*6777b538SAndroid Build Coastguard Worker } 49*6777b538SAndroid Build Coastguard Worker MutableReadBuffer(size_t n)50*6777b538SAndroid Build Coastguard Worker T* MutableReadBuffer(size_t n) { 51*6777b538SAndroid Build Coastguard Worker const size_t buffer_index = BufferIndex(n); 52*6777b538SAndroid Build Coastguard Worker CHECK(IsFilledIndexByBufferIndex(buffer_index)); 53*6777b538SAndroid Build Coastguard Worker return &buffer_[buffer_index]; 54*6777b538SAndroid Build Coastguard Worker } 55*6777b538SAndroid Build Coastguard Worker SaveToBuffer(const T & value)56*6777b538SAndroid Build Coastguard Worker void SaveToBuffer(const T& value) { 57*6777b538SAndroid Build Coastguard Worker buffer_[BufferIndex(0)] = value; 58*6777b538SAndroid Build Coastguard Worker current_index_++; 59*6777b538SAndroid Build Coastguard Worker } 60*6777b538SAndroid Build Coastguard Worker Clear()61*6777b538SAndroid Build Coastguard Worker void Clear() { current_index_ = 0; } 62*6777b538SAndroid Build Coastguard Worker 63*6777b538SAndroid Build Coastguard Worker // Iterator has const access to the RingBuffer it got retrieved from. 64*6777b538SAndroid Build Coastguard Worker class Iterator { 65*6777b538SAndroid Build Coastguard Worker public: index()66*6777b538SAndroid Build Coastguard Worker size_t index() const { return index_; } 67*6777b538SAndroid Build Coastguard Worker 68*6777b538SAndroid Build Coastguard Worker const T* operator->() const { return &buffer_->ReadBuffer(index_); } 69*6777b538SAndroid Build Coastguard Worker const T* operator*() const { return &buffer_->ReadBuffer(index_); } 70*6777b538SAndroid Build Coastguard Worker 71*6777b538SAndroid Build Coastguard Worker Iterator& operator++() { 72*6777b538SAndroid Build Coastguard Worker index_++; 73*6777b538SAndroid Build Coastguard Worker if (index_ == kSize) 74*6777b538SAndroid Build Coastguard Worker out_of_range_ = true; 75*6777b538SAndroid Build Coastguard Worker return *this; 76*6777b538SAndroid Build Coastguard Worker } 77*6777b538SAndroid Build Coastguard Worker 78*6777b538SAndroid Build Coastguard Worker Iterator& operator--() { 79*6777b538SAndroid Build Coastguard Worker if (index_ == 0) 80*6777b538SAndroid Build Coastguard Worker out_of_range_ = true; 81*6777b538SAndroid Build Coastguard Worker index_--; 82*6777b538SAndroid Build Coastguard Worker return *this; 83*6777b538SAndroid Build Coastguard Worker } 84*6777b538SAndroid Build Coastguard Worker 85*6777b538SAndroid Build Coastguard Worker operator bool() const { 86*6777b538SAndroid Build Coastguard Worker return !out_of_range_ && buffer_->IsFilledIndex(index_); 87*6777b538SAndroid Build Coastguard Worker } 88*6777b538SAndroid Build Coastguard Worker 89*6777b538SAndroid Build Coastguard Worker private: Iterator(const RingBuffer<T,kSize> & buffer,size_t index)90*6777b538SAndroid Build Coastguard Worker Iterator(const RingBuffer<T, kSize>& buffer, size_t index) 91*6777b538SAndroid Build Coastguard Worker : buffer_(buffer), index_(index), out_of_range_(false) {} 92*6777b538SAndroid Build Coastguard Worker 93*6777b538SAndroid Build Coastguard Worker const raw_ref<const RingBuffer<T, kSize>> buffer_; 94*6777b538SAndroid Build Coastguard Worker size_t index_; 95*6777b538SAndroid Build Coastguard Worker bool out_of_range_; 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker friend class RingBuffer<T, kSize>; 98*6777b538SAndroid Build Coastguard Worker }; 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker // Returns an Iterator pointing to the oldest value in the buffer. 101*6777b538SAndroid Build Coastguard Worker // Example usage (iterate from oldest to newest value): 102*6777b538SAndroid Build Coastguard Worker // for (RingBuffer<T, kSize>::Iterator it = ring_buffer.Begin(); it; ++it) {} Begin()103*6777b538SAndroid Build Coastguard Worker Iterator Begin() const { 104*6777b538SAndroid Build Coastguard Worker if (current_index_ < kSize) 105*6777b538SAndroid Build Coastguard Worker return Iterator(*this, kSize - current_index_); 106*6777b538SAndroid Build Coastguard Worker return Iterator(*this, 0); 107*6777b538SAndroid Build Coastguard Worker } 108*6777b538SAndroid Build Coastguard Worker 109*6777b538SAndroid Build Coastguard Worker // Returns an Iterator pointing to the newest value in the buffer. 110*6777b538SAndroid Build Coastguard Worker // Example usage (iterate backwards from newest to oldest value): 111*6777b538SAndroid Build Coastguard Worker // for (RingBuffer<T, kSize>::Iterator it = ring_buffer.End(); it; --it) {} End()112*6777b538SAndroid Build Coastguard Worker Iterator End() const { return Iterator(*this, kSize - 1); } 113*6777b538SAndroid Build Coastguard Worker 114*6777b538SAndroid Build Coastguard Worker private: BufferIndex(size_t n)115*6777b538SAndroid Build Coastguard Worker inline size_t BufferIndex(size_t n) const { 116*6777b538SAndroid Build Coastguard Worker return (current_index_ + n) % kSize; 117*6777b538SAndroid Build Coastguard Worker } 118*6777b538SAndroid Build Coastguard Worker 119*6777b538SAndroid Build Coastguard Worker // This specialization of |IsFilledIndex| is a micro-optimization that enables 120*6777b538SAndroid Build Coastguard Worker // us to do e.g. `CHECK(IsFilledIndex(n))` without calling |BufferIndex| 121*6777b538SAndroid Build Coastguard Worker // twice. Since |BufferIndex| involves a % operation, it's not quite free at a 122*6777b538SAndroid Build Coastguard Worker // micro-scale. IsFilledIndexByBufferIndex(size_t buffer_index)123*6777b538SAndroid Build Coastguard Worker inline bool IsFilledIndexByBufferIndex(size_t buffer_index) const { 124*6777b538SAndroid Build Coastguard Worker return buffer_index < current_index_; 125*6777b538SAndroid Build Coastguard Worker } 126*6777b538SAndroid Build Coastguard Worker 127*6777b538SAndroid Build Coastguard Worker T buffer_[kSize]; 128*6777b538SAndroid Build Coastguard Worker size_t current_index_; 129*6777b538SAndroid Build Coastguard Worker }; 130*6777b538SAndroid Build Coastguard Worker 131*6777b538SAndroid Build Coastguard Worker } // namespace base 132*6777b538SAndroid Build Coastguard Worker 133*6777b538SAndroid Build Coastguard Worker #endif // BASE_CONTAINERS_RING_BUFFER_H_ 134