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