spicetools/util/circular_buffer.h

129 lines
2.4 KiB
C++

#pragma once
#include <cstdio>
#include <memory>
#include <vector>
template<class T>
class circular_buffer {
public:
explicit circular_buffer(size_t size) :
buf_(std::unique_ptr<T[]>(new T[size])),
size_(size) {
}
void put(T item) {
buf_[head_] = item;
head_ = (head_ + 1) % size_;
if (head_ == tail_) {
tail_ = (tail_ + 1) % size_;
}
}
void put_all(const T *items, int size) {
for (int i = 0; i < size; i++)
this->put(items[i]);
}
void put_all(std::vector<T> items) {
for (auto i : items)
this->put(i);
}
T get() {
if (empty()) {
return T();
}
// read data and advance the tail (we now have a free space)
auto val = buf_[tail_];
tail_ = (tail_ + 1) % size_;
return val;
}
std::vector<T> get_all() {
std::vector<T> contents;
contents.reserve(size());
while (!empty()) {
contents.push_back(get());
}
return contents;
}
T peek() {
if (empty()) {
return T();
}
// read data
return buf_[tail_];
}
T *peek_ptr() {
if (empty()) {
return nullptr;
}
// read data
return &buf_[tail_];
}
T peek(size_t pos) {
if (empty()) {
return T();
}
return buf_[(tail_ + pos) % size_];
}
T* peek_ptr(size_t pos) {
if (empty())
return nullptr;
return &buf_[(tail_ + pos) % size_];
}
std::vector<T> peek_all() {
const auto elements = size();
std::vector<T> contents;
contents.reserve(size());
for (size_t i = 0; i < elements; i++)
contents.push_back(peek(i));
return contents;
}
void reset() {
head_ = tail_;
}
bool empty() {
// if head and tail are equal, we are empty
return head_ == tail_;
}
bool full() {
// if tail is ahead the head by 1, we are full
return ((head_ + 1) % size_) == tail_;
}
size_t size() {
if (tail_ > head_)
return size_ + head_ - tail_;
else
return head_ - tail_;
}
private:
std::unique_ptr<T[]> buf_;
size_t head_ = 0;
size_t tail_ = 0;
size_t size_;
};