| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CC_DEBUG_RING_BUFFER_H_ |
| #define CC_DEBUG_RING_BUFFER_H_ |
| |
| #include <stddef.h> |
| |
| #include "base/logging.h" |
| #include "base/macros.h" |
| |
| namespace cc { |
| |
| template<typename T, size_t kSize> |
| class RingBuffer { |
| public: |
| RingBuffer() : current_index_(0) {} |
| |
| size_t BufferSize() const { |
| return kSize; |
| } |
| |
| size_t CurrentIndex() const { |
| return current_index_; |
| } |
| |
| // tests if a value was saved to this index |
| bool IsFilledIndex(size_t n) const { |
| return BufferIndex(n) < current_index_; |
| } |
| |
| // n = 0 returns the oldest value and |
| // n = bufferSize() - 1 returns the most recent value. |
| const T& ReadBuffer(size_t n) const { |
| DCHECK(IsFilledIndex(n)); |
| return buffer_[BufferIndex(n)]; |
| } |
| |
| T* MutableReadBuffer(size_t n) { |
| DCHECK(IsFilledIndex(n)); |
| return &buffer_[BufferIndex(n)]; |
| } |
| |
| void SaveToBuffer(const T& value) { |
| buffer_[BufferIndex(0)] = value; |
| current_index_++; |
| } |
| |
| void Clear() { |
| current_index_ = 0; |
| } |
| |
| // Iterator has const access to the RingBuffer it got retrieved from. |
| class Iterator { |
| public: |
| size_t index() const { return index_; } |
| |
| const T* operator->() const { return &buffer_.ReadBuffer(index_); } |
| const T* operator*() const { return &buffer_.ReadBuffer(index_); } |
| |
| Iterator& operator++() { |
| index_++; |
| if (index_ == kSize) |
| out_of_range_ = true; |
| return *this; |
| } |
| |
| Iterator& operator--() { |
| if (index_ == 0) |
| out_of_range_ = true; |
| index_--; |
| return *this; |
| } |
| |
| operator bool() const { |
| return buffer_.IsFilledIndex(index_) && !out_of_range_; |
| } |
| |
| private: |
| Iterator(const RingBuffer<T, kSize>& buffer, size_t index) |
| : buffer_(buffer), |
| index_(index), |
| out_of_range_(false) { |
| } |
| |
| const RingBuffer<T, kSize>& buffer_; |
| size_t index_; |
| bool out_of_range_; |
| |
| friend class RingBuffer<T, kSize>; |
| }; |
| |
| // Returns an Iterator pointing to the oldest value in the buffer. |
| // Example usage (iterate from oldest to newest value): |
| // for (RingBuffer<T, kSize>::Iterator it = ring_buffer.Begin(); it; ++it) {} |
| Iterator Begin() const { |
| if (current_index_ < kSize) |
| return Iterator(*this, kSize - current_index_); |
| return Iterator(*this, 0); |
| } |
| |
| // Returns an Iterator pointing to the newest value in the buffer. |
| // Example usage (iterate backwards from newest to oldest value): |
| // for (RingBuffer<T, kSize>::Iterator it = ring_buffer.End(); it; --it) {} |
| Iterator End() const { |
| return Iterator(*this, kSize - 1); |
| } |
| |
| private: |
| inline size_t BufferIndex(size_t n) const { |
| return (current_index_ + n) % kSize; |
| } |
| |
| T buffer_[kSize]; |
| size_t current_index_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RingBuffer); |
| }; |
| |
| } // namespace cc |
| |
| #endif // CC_DEBUG_RING_BUFFER_H_ |