ring_buffer.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. #ifndef BASE_CONTAINERS_RING_BUFFER_H_
  5. #define BASE_CONTAINERS_RING_BUFFER_H_
  6. #include <stddef.h>
  7. #include "base/logging.h"
  8. #include "base/macros.h"
  9. namespace base {
  10. // base::RingBuffer uses a fixed-size array, unlike base::circular_deque and
  11. // std::deque, and so, one can access only the last |kSize| elements. Also, you
  12. // can add elements to the front and read/modify random elements, but cannot
  13. // remove elements from the back. Therefore, it does not have a |Size| method,
  14. // only |BufferSize|, which is a constant, and |CurrentIndex|, which is the
  15. // number of elements added so far.
  16. //
  17. // If the above is sufficient for your use case, base::RingBuffer should be more
  18. // efficient than base::circular_deque.
  19. template <typename T, size_t kSize>
  20. class RingBuffer {
  21. public:
  22. RingBuffer() : current_index_(0) {}
  23. size_t BufferSize() const { return kSize; }
  24. size_t CurrentIndex() const { return current_index_; }
  25. // Returns true if a value was saved to index |n|.
  26. bool IsFilledIndex(size_t n) const {
  27. return IsFilledIndexByBufferIndex(BufferIndex(n));
  28. }
  29. // Returns the element at index |n| (% |kSize|).
  30. //
  31. // n = 0 returns the oldest value and
  32. // n = bufferSize() - 1 returns the most recent value.
  33. const T& ReadBuffer(size_t n) const {
  34. const size_t buffer_index = BufferIndex(n);
  35. CHECK(IsFilledIndexByBufferIndex(buffer_index));
  36. return buffer_[buffer_index];
  37. }
  38. T* MutableReadBuffer(size_t n) {
  39. const size_t buffer_index = BufferIndex(n);
  40. CHECK(IsFilledIndexByBufferIndex(buffer_index));
  41. return &buffer_[buffer_index];
  42. }
  43. void SaveToBuffer(const T& value) {
  44. buffer_[BufferIndex(0)] = value;
  45. current_index_++;
  46. }
  47. void Clear() { current_index_ = 0; }
  48. // Iterator has const access to the RingBuffer it got retrieved from.
  49. class Iterator {
  50. public:
  51. size_t index() const { return index_; }
  52. const T* operator->() const { return &buffer_.ReadBuffer(index_); }
  53. const T* operator*() const { return &buffer_.ReadBuffer(index_); }
  54. Iterator& operator++() {
  55. index_++;
  56. if (index_ == kSize)
  57. out_of_range_ = true;
  58. return *this;
  59. }
  60. Iterator& operator--() {
  61. if (index_ == 0)
  62. out_of_range_ = true;
  63. index_--;
  64. return *this;
  65. }
  66. operator bool() const {
  67. return !out_of_range_ && buffer_.IsFilledIndex(index_);
  68. }
  69. private:
  70. Iterator(const RingBuffer<T, kSize>& buffer, size_t index)
  71. : buffer_(buffer), index_(index), out_of_range_(false) {}
  72. const RingBuffer<T, kSize>& buffer_;
  73. size_t index_;
  74. bool out_of_range_;
  75. friend class RingBuffer<T, kSize>;
  76. };
  77. // Returns an Iterator pointing to the oldest value in the buffer.
  78. // Example usage (iterate from oldest to newest value):
  79. // for (RingBuffer<T, kSize>::Iterator it = ring_buffer.Begin(); it; ++it) {}
  80. Iterator Begin() const {
  81. if (current_index_ < kSize)
  82. return Iterator(*this, kSize - current_index_);
  83. return Iterator(*this, 0);
  84. }
  85. // Returns an Iterator pointing to the newest value in the buffer.
  86. // Example usage (iterate backwards from newest to oldest value):
  87. // for (RingBuffer<T, kSize>::Iterator it = ring_buffer.End(); it; --it) {}
  88. Iterator End() const { return Iterator(*this, kSize - 1); }
  89. private:
  90. inline size_t BufferIndex(size_t n) const {
  91. return (current_index_ + n) % kSize;
  92. }
  93. // This specialization of |IsFilledIndex| is a micro-optimization that enables
  94. // us to do e.g. `CHECK(IsFilledIndex(n))` without calling |BufferIndex|
  95. // twice. Since |BufferIndex| involves a % operation, it's not quite free at a
  96. // micro-scale.
  97. inline bool IsFilledIndexByBufferIndex(size_t buffer_index) const {
  98. return buffer_index < current_index_;
  99. }
  100. T buffer_[kSize];
  101. size_t current_index_;
  102. DISALLOW_COPY_AND_ASSIGN(RingBuffer);
  103. };
  104. } // namespace base
  105. #endif // BASE_CONTAINERS_RING_BUFFER_H_