From 14e8973c318b6d4c62201c0e3f70b56864896992 Mon Sep 17 00:00:00 2001 From: Johnathon Slightham Date: Tue, 17 Feb 2026 11:01:29 -0500 Subject: [PATCH] Add RingBuffer --- RingBuffer.h | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 RingBuffer.h diff --git a/RingBuffer.h b/RingBuffer.h new file mode 100644 index 0000000..59c38a8 --- /dev/null +++ b/RingBuffer.h @@ -0,0 +1,150 @@ +#include +#include +#include + +template +class RingBuffer { +public: + explicit RingBuffer(size_t capacity) + : m_buffer(capacity), m_capacity(capacity) { + } + + void push(const T& item) { + std::lock_guard 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 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 pop() { + std::lock_guard 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 peek() const { + std::lock_guard lock(m_mutex); + if (empty_locked()) { + return std::nullopt; + } + return m_buffer[m_tail]; + } + + std::vector drain() { + std::lock_guard lock(m_mutex); + + std::vector 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 peek_drain() { + std::lock_guard lock(m_mutex); + + std::vector 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 lock(m_mutex); + m_head = m_tail; + m_full = false; + } + + bool empty() const { + std::lock_guard lock(m_mutex); + return empty_locked(); + } + + bool full() const { + std::lock_guard lock(m_mutex); + return m_full; + } + + size_t size() const { + std::lock_guard 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 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; +}; +