mirror of
https://github.com/jslightham/cpp-utils.git
synced 2026-03-09 18:12:26 +01:00
Add RingBuffer
This commit is contained in:
150
RingBuffer.h
Normal file
150
RingBuffer.h
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class RingBuffer {
|
||||||
|
public:
|
||||||
|
explicit RingBuffer(size_t capacity)
|
||||||
|
: m_buffer(capacity), m_capacity(capacity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(const T& item) {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
m_buffer[m_head] = item;
|
||||||
|
|
||||||
|
if (m_full) {
|
||||||
|
m_tail = (m_tail + 1) % m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_head = (m_head + 1) % m_capacity;
|
||||||
|
m_full = m_head == m_tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(T&& item) {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
m_buffer[m_head] = std::move(item);
|
||||||
|
|
||||||
|
if (m_full) {
|
||||||
|
m_tail = (m_tail + 1) % m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_head = (m_head + 1) % m_capacity;
|
||||||
|
m_full = m_head == m_tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<T> pop() {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
if (empty_locked()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
T value = std::move(m_buffer[m_tail]);
|
||||||
|
m_full = false;
|
||||||
|
m_tail = (m_tail + 1) % m_capacity;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<T> peek() const {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
if (empty_locked()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return m_buffer[m_tail];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<T> drain() {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
std::vector<T> out;
|
||||||
|
size_t count = size_locked();
|
||||||
|
out.reserve(count);
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx = m_tail;
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
out.push_back(std::move(m_buffer[idx]));
|
||||||
|
idx = (idx + 1) % m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_head = 0;
|
||||||
|
m_tail = 0;
|
||||||
|
m_full = false;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<T> peek_drain() {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
std::vector<T> out;
|
||||||
|
size_t count = size_locked();
|
||||||
|
out.reserve(count);
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx = m_tail;
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
out.push_back(m_buffer[idx]);
|
||||||
|
idx = (idx + 1) % m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
m_head = m_tail;
|
||||||
|
m_full = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
return empty_locked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool full() const {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
return m_full;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
return size_locked();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity() const {
|
||||||
|
return m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool empty_locked() const {
|
||||||
|
return (!m_full && (m_head == m_tail));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size_locked() const {
|
||||||
|
if (m_full) return m_capacity;
|
||||||
|
if (m_head >= m_tail) return m_head - m_tail;
|
||||||
|
return m_capacity + m_head - m_tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<T> m_buffer;
|
||||||
|
const size_t m_capacity;
|
||||||
|
|
||||||
|
size_t m_head = 0;
|
||||||
|
size_t m_tail = 0;
|
||||||
|
bool m_full = false;
|
||||||
|
|
||||||
|
// mutable allows const functions to modify/lock the mutex
|
||||||
|
mutable std::mutex m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user