renderbug/lib/Figments/Ringbuf.h

100 lines
2.1 KiB
C++

#pragma once
#include <array>
/**
* A simple ring buffer structure
*/
template<typename T, int Size>
struct Ringbuf {
Ringbuf() : m_head(0), m_tail(0) {}
/**
* Clears the buffer's contents
*/
void clear() {
m_head = 0;
m_tail = 0;
}
/**
* Returns the value of the next available item, if available
*/
T peek(int offset) const {
const int nextHead = (m_head + offset) % Size;
return m_items[nextHead];
}
/**
* Removes and returns the next available item, if any.
*
* @return false if no data is available, true otherwise
*/
bool take(T& dest) {
if (m_head == m_tail) {
return false;
}
const int cur = m_head;
const int nextHead = (m_head + 1) % Size;
m_head = nextHead;
dest = m_items[cur];
return true;
}
/**
* Inserts an item into the buffer. If the buffer is full, the oldest item
* is overwritten.
*/
void insert(const T& src) {
const int cur = m_tail;
const int nextTail = (m_tail + 1) % Size;
if (nextTail == m_head) {
return;
} else {
m_tail = nextTail;
}
m_items[cur] = src;
}
/**
* Consumes the entire buffer and writes it to the given array.
*/
size_t write(T(&dest)[Size]) {
int i = 0;
size_t ret = 0;
while(take(dest[i])) {
i++;
ret += sizeof(T);
}
return ret;
}
/**
* Consumes the entire buffer and writes it to the given output
*/
size_t write(Print& stream) {
T val;
size_t ret = 0;
while(take(val)) {
stream.write(val);
}
return ret;
}
/**
* Returns how many items are available in the buffer
*/
size_t size() {
if (m_tail > m_head) {
return m_tail - m_head;
} else if (m_tail == m_head) {
return 0;
}
return m_tail + (Size - m_head);
}
private:
int m_head = 0;
int m_tail = 0;
std::array<T, Size> m_items;
};