James Robinson | 646469d | 2014-10-03 15:33:28 -0700 | [diff] [blame] | 1 | // Copyright 2013 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 CC_DEBUG_RING_BUFFER_H_ |
| 6 | #define CC_DEBUG_RING_BUFFER_H_ |
| 7 | |
| 8 | #include "base/logging.h" |
| 9 | |
| 10 | namespace cc { |
| 11 | |
| 12 | template<typename T, size_t kSize> |
| 13 | class RingBuffer { |
| 14 | public: |
Benjamin Lerman | 5799890 | 2014-11-18 16:06:02 +0100 | [diff] [blame] | 15 | RingBuffer() : current_index_(0) {} |
James Robinson | 646469d | 2014-10-03 15:33:28 -0700 | [diff] [blame] | 16 | |
| 17 | size_t BufferSize() const { |
| 18 | return kSize; |
| 19 | } |
| 20 | |
| 21 | size_t CurrentIndex() const { |
| 22 | return current_index_; |
| 23 | } |
| 24 | |
| 25 | // tests if a value was saved to this index |
| 26 | bool IsFilledIndex(size_t n) const { |
| 27 | return BufferIndex(n) < current_index_; |
| 28 | } |
| 29 | |
| 30 | // n = 0 returns the oldest value and |
| 31 | // n = bufferSize() - 1 returns the most recent value. |
| 32 | const T& ReadBuffer(size_t n) const { |
| 33 | DCHECK(IsFilledIndex(n)); |
| 34 | return buffer_[BufferIndex(n)]; |
| 35 | } |
| 36 | |
| 37 | T* MutableReadBuffer(size_t n) { |
| 38 | DCHECK(IsFilledIndex(n)); |
| 39 | return &buffer_[BufferIndex(n)]; |
| 40 | } |
| 41 | |
| 42 | void SaveToBuffer(const T& value) { |
| 43 | buffer_[BufferIndex(0)] = value; |
| 44 | current_index_++; |
| 45 | } |
| 46 | |
| 47 | void Clear() { |
| 48 | current_index_ = 0; |
| 49 | } |
| 50 | |
| 51 | // Iterator has const access to the RingBuffer it got retrieved from. |
| 52 | class Iterator { |
| 53 | public: |
| 54 | size_t index() const { return index_; } |
| 55 | |
| 56 | const T* operator->() const { return &buffer_.ReadBuffer(index_); } |
| 57 | const T* operator*() const { return &buffer_.ReadBuffer(index_); } |
| 58 | |
| 59 | Iterator& operator++() { |
| 60 | index_++; |
| 61 | if (index_ == kSize) |
| 62 | out_of_range_ = true; |
| 63 | return *this; |
| 64 | } |
| 65 | |
| 66 | Iterator& operator--() { |
| 67 | if (index_ == 0) |
| 68 | out_of_range_ = true; |
| 69 | index_--; |
| 70 | return *this; |
| 71 | } |
| 72 | |
| 73 | operator bool() const { |
| 74 | return buffer_.IsFilledIndex(index_) && !out_of_range_; |
| 75 | } |
| 76 | |
| 77 | private: |
| 78 | Iterator(const RingBuffer<T, kSize>& buffer, size_t index) |
| 79 | : buffer_(buffer), |
| 80 | index_(index), |
| 81 | out_of_range_(false) { |
| 82 | } |
| 83 | |
| 84 | const RingBuffer<T, kSize>& buffer_; |
| 85 | size_t index_; |
| 86 | bool out_of_range_; |
| 87 | |
| 88 | friend class RingBuffer<T, kSize>; |
| 89 | }; |
| 90 | |
| 91 | // Returns an Iterator pointing to the oldest value in the buffer. |
| 92 | // Example usage (iterate from oldest to newest value): |
| 93 | // for (RingBuffer<T, kSize>::Iterator it = ring_buffer.Begin(); it; ++it) {} |
| 94 | Iterator Begin() const { |
| 95 | if (current_index_ < kSize) |
| 96 | return Iterator(*this, kSize - current_index_); |
| 97 | return Iterator(*this, 0); |
| 98 | } |
| 99 | |
| 100 | // Returns an Iterator pointing to the newest value in the buffer. |
| 101 | // Example usage (iterate backwards from newest to oldest value): |
| 102 | // for (RingBuffer<T, kSize>::Iterator it = ring_buffer.End(); it; --it) {} |
| 103 | Iterator End() const { |
| 104 | return Iterator(*this, kSize - 1); |
| 105 | } |
| 106 | |
| 107 | private: |
| 108 | inline size_t BufferIndex(size_t n) const { |
| 109 | return (current_index_ + n) % kSize; |
| 110 | } |
| 111 | |
| 112 | T buffer_[kSize]; |
| 113 | size_t current_index_; |
| 114 | |
| 115 | DISALLOW_COPY_AND_ASSIGN(RingBuffer); |
| 116 | }; |
| 117 | |
| 118 | } // namespace cc |
| 119 | |
| 120 | #endif // CC_DEBUG_RING_BUFFER_H_ |