forked from mirrors/qmk_firmware
67 lines
1.2 KiB
C++
67 lines
1.2 KiB
C++
|
#pragma once
|
||
|
// A simple ringbuffer holding Size elements of type T
|
||
|
template <typename T, uint8_t Size>
|
||
|
class RingBuffer {
|
||
|
protected:
|
||
|
T buf_[Size];
|
||
|
uint8_t head_{0}, tail_{0};
|
||
|
public:
|
||
|
inline uint8_t nextPosition(uint8_t position) {
|
||
|
return (position + 1) % Size;
|
||
|
}
|
||
|
|
||
|
inline uint8_t prevPosition(uint8_t position) {
|
||
|
if (position == 0) {
|
||
|
return Size - 1;
|
||
|
}
|
||
|
return position - 1;
|
||
|
}
|
||
|
|
||
|
inline bool enqueue(const T &item) {
|
||
|
static_assert(Size > 1, "RingBuffer size must be > 1");
|
||
|
uint8_t next = nextPosition(head_);
|
||
|
if (next == tail_) {
|
||
|
// Full
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
buf_[head_] = item;
|
||
|
head_ = next;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
inline bool get(T &dest, bool commit = true) {
|
||
|
auto tail = tail_;
|
||
|
if (tail == head_) {
|
||
|
// No more data
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
dest = buf_[tail];
|
||
|
tail = nextPosition(tail);
|
||
|
|
||
|
if (commit) {
|
||
|
tail_ = tail;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
inline bool empty() const { return head_ == tail_; }
|
||
|
|
||
|
inline uint8_t size() const {
|
||
|
int diff = head_ - tail_;
|
||
|
if (diff >= 0) {
|
||
|
return diff;
|
||
|
}
|
||
|
return Size + diff;
|
||
|
}
|
||
|
|
||
|
inline T& front() {
|
||
|
return buf_[tail_];
|
||
|
}
|
||
|
|
||
|
inline bool peek(T &item) {
|
||
|
return get(item, false);
|
||
|
}
|
||
|
};
|