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