Home | History | Annotate | Download | only in debug
      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:
     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