You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
4.7 KiB
C

1 month ago
#pragma once
#include <vector>
#include <cstddef>
#include <utility>
#include <cassert>
/**
* @brief
*
* 2 head/tail % Capacity
* push std::deque front/back/pop_front
*
* @tparam T
* @tparam Capacity 0 2
*/
template<typename T, size_t Capacity>
class RingBuffer
{
static_assert(Capacity > 0 && (Capacity & (Capacity - 1)) == 0, "RingBuffer capacity must be a power of 2");
public:
/** @brief 默认构造,内部缓冲区预分配 Capacity 个元素。 */
RingBuffer() : m_data(Capacity) {}
/**
* @brief
* @param value
* @note
*/
void push(const T& value)
{
if (m_size == Capacity)
{
m_head = (m_head + 1) % Capacity;
}
else
{
++m_size;
}
m_data[m_tail] = value;
m_tail = (m_tail + 1) % Capacity;
}
/**
* @brief
* @param value
* @note
*/
void push(T&& value)
{
if (m_size == Capacity)
{
m_head = (m_head + 1) % Capacity;
}
else
{
++m_size;
}
m_data[m_tail] = std::move(value);
m_tail = (m_tail + 1) % Capacity;
}
/**
* @brief
* @return const
* @pre !empty()
*/
const T& front() const
{
assert(!empty() && "RingBuffer::front() on empty buffer");
return m_data[m_head];
}
/**
* @brief
* @return const
* @pre !empty()
*/
T& front()
{
assert(!empty() && "RingBuffer::front() on empty buffer");
return m_data[m_head];
}
/**
* @brief
* @return const
* @pre !empty()
*/
const T& back() const
{
assert(!empty() && "RingBuffer::back() on empty buffer");
return m_data[(m_tail + Capacity - 1) % Capacity];
}
/**
* @brief
* @return const
* @pre !empty()
*/
T& back()
{
assert(!empty() && "RingBuffer::back() on empty buffer");
return m_data[(m_tail + Capacity - 1) % Capacity];
}
/**
* @brief
* @param i 0 size()-1
* @return i const
* @pre i < size()
*/
const T& operator[](size_t i) const
{
assert(i < m_size && "RingBuffer::operator[] index out of range");
return m_data[(m_head + i) % Capacity];
}
/**
* @brief
* @param i 0 size()-1
* @return i const
* @pre i < size()
*/
T& operator[](size_t i)
{
assert(i < m_size && "RingBuffer::operator[] index out of range");
return m_data[(m_head + i) % Capacity];
}
/**
* @brief
* @note
*/
void pop_front()
{
if (empty())
return;
m_head = (m_head + 1) % Capacity;
--m_size;
}
/**
* @brief push
*/
void clear()
{
m_head = 0;
m_tail = 0;
m_size = 0;
}
/**
* @brief value
* @param value T operator==
* @return true false
* @note 线 O(size())
*/
bool contains(const T& value) const
{
for (size_t i = 0; i < m_size; ++i)
{
size_t idx = (m_head + i) % Capacity;
if (m_data[idx] == value)
{
return true;
}
}
return false;
}
/** @brief 当前元素个数 */
size_t size() const
{
return m_size;
}
/** @brief 缓冲区容量(编译期常量)。 */
size_t capacity() const
{
return Capacity;
}
/** @brief 是否为空(无元素)。 */
bool empty() const
{
return m_size == 0;
}
/** @brief 是否已满(元素个数等于容量)。 */
bool full() const
{
return m_size == Capacity;
}
private:
std::vector<T> m_data; /**< 底层存储,大小为 Capacity */
size_t m_head = 0; /**< 最旧元素的下标 */
size_t m_tail = 0; /**< 下一个写入位置(尾后) */
size_t m_size = 0; /**< 当前元素个数 */
};