blob: 18242411b9c7fcd7992b163c42078e183d026956 [file] [log] [blame]
#ifndef ANDROID_DVR_RING_BUFFER_H_
#define ANDROID_DVR_RING_BUFFER_H_
#include <utility>
#include <vector>
namespace android {
namespace dvr {
// A simple ring buffer implementation.
//
// A vector works but you either have to keep track of start_ and size_ yourself
// or erase() from the front which is inefficient.
//
// A deque works but the common usage pattern of Append() PopFront() Append()
// PopFront() looks like it allocates each time size goes from 0 --> 1, which we
// don't want. This class allocates only once.
template <typename T>
class RingBuffer {
public:
RingBuffer() { Reset(0); }
explicit RingBuffer(size_t capacity) { Reset(capacity); }
RingBuffer(const RingBuffer& other) = default;
RingBuffer(RingBuffer&& other) noexcept = default;
RingBuffer& operator=(const RingBuffer& other) = default;
RingBuffer& operator=(RingBuffer&& other) noexcept = default;
void Append(const T& val) {
if (IsFull())
PopFront();
Get(size_) = val;
size_++;
}
void Append(T&& val) {
if (IsFull())
PopFront();
Get(size_) = std::move(val);
size_++;
}
bool IsEmpty() const { return size_ == 0; }
bool IsFull() const { return size_ == buffer_.size(); }
size_t GetSize() const { return size_; }
size_t GetCapacity() const { return buffer_.size(); }
T& Get(size_t i) { return buffer_[(start_ + i) % buffer_.size()]; }
const T& Get(size_t i) const {
return buffer_[(start_ + i) % buffer_.size()];
}
const T& Back() const { return Get(size_ - 1); }
T& Back() { return Get(size_ - 1); }
const T& Front() const { return Get(0); }
T& Front() { return Get(0); }
void PopBack() {
if (size_ != 0) {
Get(size_ - 1) = T();
size_--;
}
}
void PopFront() {
if (size_ != 0) {
Get(0) = T();
start_ = (start_ + 1) % buffer_.size();
size_--;
}
}
void Clear() { Reset(GetCapacity()); }
void Reset(size_t capacity) {
start_ = size_ = 0;
buffer_.clear();
buffer_.resize(capacity);
}
private:
// Ideally we'd allocate our own memory and use placement new to instantiate
// instances of T instead of using a vector, but the vector is simpler.
std::vector<T> buffer_;
size_t start_, size_;
};
} // namespace dvr
} // namespace android
#endif // ANDROID_DVR_RING_BUFFER_H_