Files
kwa.fr/sdi_toolBox_1.0.x/toolBox/sdi_toolBox/generic/circularBuffer.h
2026-03-12 16:31:18 +01:00

106 lines
3.4 KiB
C++

/*
{{copyright}}
*/
/*
{{version}}
*/
/*
{{license}}
*/
#pragma once
#include <array>
#include <cstdint>
#include <optional>
namespace sdi_toolBox::generic
{
//--------------------------------------------------------------
template<class T, size_t BUFFER_SIZE>
class CircularBuffer final
{
public:
CircularBuffer() = default; // Constructor
~CircularBuffer() = default; // Destructor
CircularBuffer(const CircularBuffer &other) = delete; // Copy constructor
CircularBuffer(CircularBuffer &&other) noexcept = delete; // Move constructor
CircularBuffer &operator=(const CircularBuffer &other) = delete; // Copy assignment
CircularBuffer &operator=(CircularBuffer &&other) noexcept = delete; // Move assignment
bool push(const T &item); // Add an element to the buffer
std::optional<T> pop(); // Retrieve an element from the buffer
bool isEmpty() const; // Check if the buffer is empty
bool isFull() const; // Check if the buffer is full
size_t size() const; // Get the current number of elements
protected:
std::array<T, BUFFER_SIZE> m_buffer;
volatile size_t m_head = 0; // Index for the next write (push)
volatile size_t m_tail = 0; // Index for the next read (pop)
volatile size_t m_size = 0; // Current number of elements stored
};
//--------------------------------------------------------------
//--------------------------------------------------------------
/* Add an element to the buffer */
template<class T, size_t BUFFER_SIZE>
inline bool CircularBuffer<T, BUFFER_SIZE>::push(const T &item)
{
if (isFull())
return false; // Buffer is full
// Write the item at the current head position
m_buffer[m_head] = item;
// Move head pointer, wrapping around using modulo
m_head = (m_head + 1) % BUFFER_SIZE;
// Increase the current size of the data in the buffer
m_size = m_size + 1;
return true;
}
//--------------------------------------------------------------
/* Retrieve an element from the buffer */
template<class T, size_t BUFFER_SIZE>
inline std::optional<T> CircularBuffer<T, BUFFER_SIZE>::pop()
{
if (isEmpty())
return {}; // Buffer is empty, cannot pop
// Read (copy) the item at the current tail position
T item = m_buffer[m_tail];
// Move tail pointer, wrapping around using modulo
m_tail = (m_tail + 1) % BUFFER_SIZE;
// Decrease the current size of the data in the buffer
m_size = m_size - 1;
return item;
}
//--------------------------------------------------------------
/* Check if the buffer is empty */
template<class T, size_t BUFFER_SIZE>
inline bool CircularBuffer<T, BUFFER_SIZE>::isEmpty() const
{
return m_size == 0;
}
//--------------------------------------------------------------
/* Check if the buffer is full */
template<class T, size_t BUFFER_SIZE>
inline bool CircularBuffer<T, BUFFER_SIZE>::isFull() const
{
return m_size == BUFFER_SIZE;
}
//--------------------------------------------------------------
/* Get the current number of elements */
template<class T, size_t BUFFER_SIZE>
inline size_t CircularBuffer<T, BUFFER_SIZE>::size() const
{
return m_size;
}
//--------------------------------------------------------------
} // namespace sdi_toolBox::generic