#pragma once #include #include #include #include /** * @brief 固定容量的环形缓冲区 * * 容量在编译期固定且必须为 2 的幂;head/tail 为无符号整数,下标通过 % Capacity 取模。 * 满时继续 push 会覆盖最旧元素。接口风格与 std::deque 类似(front/back/pop_front)。 * * @tparam T 元素类型 * @tparam Capacity 缓冲区容量,必须大于 0 且为 2 的幂 */ template 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 m_data; /**< 底层存储,大小为 Capacity */ size_t m_head = 0; /**< 最旧元素的下标 */ size_t m_tail = 0; /**< 下一个写入位置(尾后) */ size_t m_size = 0; /**< 当前元素个数 */ };