106 lines
3.4 KiB
C++
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
|