xref: /aosp_15_r20/external/libchrome/base/containers/ring_buffer.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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