circular_buffer

本文介绍了如何使用Boost库中的Circular Buffer来实现定长的旋转容器。通过实例演示了Circular Buffer的基本操作,如插入、删除元素及访问容器中的最新和最早元素。

 

编程有时需要使用定长的容器(fixed size container)。实现旋转容器可以像下面这样:

std::vector<T> vec(size);
vec[i % size] = newelem;

 

但boost的circular_buffer提供更多功能,我们不需要重复造轮子了(DRY):

#include <boost/circular_buffer.hpp>

    boost::circular_buffer<int> cb(3);

    // Insert threee elements into the buffer.
    cb.push_back(1);
    std::cout << "1 inserted, size:" << cb.size() << endl;
    std::cout << "latest is " << cb[cb.size() - 1] << endl;

    cb.push_back(2);
    std::cout << "2 inserted, size:" << cb.size() << endl;
    std::cout << "latest is " << cb[cb.size()-1] << endl;

    cb.push_back(3);
    std::cout << "3 inserted, size:" << cb.size() << endl;
    std::cout << "latest is " << cb[cb.size()-1] << endl;

    int a = cb[0];  // a == 1
    int b = cb[1];  // b == 2
    int c = cb[2];  // c == 3

    std::cout << "1st is" << a << endl;
    std::cout << "2nd is" << b << endl;

    // The buffer is full now, so pushing subsequent
    // elements will overwrite the front-most elements.

    cb.push_back(4);  // Overwrite 1 with 4.
    std::cout << "4 inserted, size:" << cb.size() << endl;
    std::cout << "latest is " << cb[cb.size()-1] << endl;

    cb.push_back(5);  // Overwrite 2 with 5.
    std::cout << "5 inserted, size:" << cb.size() << endl;
    std::cout << "latest is " << cb[cb.size()-1] << endl;

    // The buffer now contains 3, 4 and 5.
    a = cb[0];  // a == 3
    b = cb[1];  // b == 4
    c = cb[2];  // c == 5
    std::cout << "1st is" << a << endl;


    cb.pop_back();  // 5 is removed.
    cb.pop_front(); // 3 is removed.
    std::cout << "head and tail removed, size:" << cb.size() << endl;
    std::cout << "latest is " << cb[cb.size() - 1] << endl;
    // Leaving only one element with value = 4.
    int d = cb[0];  // d == 4

 

转载于:https://www.cnblogs.com/scottgu/p/4259447.html

#include "circular_buffer.h" #include <stdlib.h> // malloc/free 函数声明 #include <string.h> // memcpy 函数声明 /** * @brief 初始化循环缓冲区 * * @param size 缓冲区大小(字节) * @return 成功返回缓冲区指针,失败返回NULL * * @note 缓冲区大小建议为2的幂次以优化模运算 * @warning 使用完缓冲区后必须调用 circular_buffer_destroy() 释放资源 */ circular_buffer_t* circular_buffer_init(size_t size) { circular_buffer_t* cb = malloc(sizeof(circular_buffer_t)); if (!cb) return NULL; cb->buffer = malloc(size); if (!cb->buffer) { free(cb); return NULL; } cb->size = size; cb->head = 0; cb->tail = 0; cb->count = 0; return cb; } /** * @brief 销毁循环缓冲区 * * @param cb 要销毁的缓冲区指针 * * @note 释放分配的内存资源 * @warning 不要对同一缓冲区重复调用此函数 */ void circular_buffer_destroy(circular_buffer_t* cb) { if (cb) { free(cb->buffer); free(cb); } } /** * @brief 重置缓冲区到初始状态 * * @param cb 要重置的缓冲区指针 * * @note 保持缓冲区内存分配状态,仅重置读写指针和数据量 */ void circular_buffer_reset(circular_buffer_t* cb) { cb->head = 0; cb->tail = 0; cb->count = 0; } /** * @brief 向缓冲区写入数据 * * @param cb 循环缓冲区指针 * @param data 要写入的数据指针 * @param len 要写入的数据长度(字节) * @return 实际写入的数据长度(字节) * * @note 如果写入长度超过缓冲区大小,自动丢弃超出部分 * @note 支持数据回绕处理(自动处理缓冲区边界) */ size_t circular_buffer_write(circular_buffer_t* cb, const uint8_t* data, size_t len) { if (!cb || !data || len == 0) return 0; size_t actual_write = 0; // 如果数据量超过缓冲区大小,只写入最后size字节 if (len > cb->size) { data += (len - cb->size); len = cb->size; } // 计算实际可写入量 actual_write = (len <= (cb->size - cb->count)) ? len : (cb->size - cb->count); // 分两种情况写入:是否跨越缓冲区边界 if (actual_write > 0) { // 计算到缓冲区末尾的连续空间 size_t to_end = cb->size - cb->head; if (to_end >= actual_write) { // 不需要回绕 memcpy(cb->buffer + cb->head, data, actual_write); cb->head = (cb->head + actual_write) % cb->size; } else { // 需要回绕 memcpy(cb->buffer + cb->head, data, to_end); memcpy(cb->buffer, data + to_end, actual_write - to_end); cb->head = actual_write - to_end; } cb->count += actual_write; } return actual_write; } /** * @brief 从缓冲区读取数据 * * @param cb 循环缓冲区指针 * @param data 用于存储读取数据的缓冲区 * @param len 请求读取的数据长度(字节) * @return 实际读取的数据长度(字节) * * @note 支持数据回绕处理(自动处理缓冲区边界) */ size_t circular_buffer_read(circular_buffer_t* cb, uint8_t* data, size_t len) { if (!cb || !data || len == 0 || cb->count == 0) return 0; size_t actual_read = (len <= cb->count) ? len : cb->count; // 计算到缓冲区末尾的连续数据 size_t to_end = cb->size - cb->tail; if (to_end >= actual_read) { // 不需要回绕 memcpy(data, cb->buffer + cb->tail, actual_read); cb->tail = (cb->tail + actual_read) % cb->size; } else { // 需要回绕 memcpy(data, cb->buffer + cb->tail, to_end); memcpy(data + to_end, cb->buffer, actual_read - to_end); cb->tail = actual_read - to_end; } cb->count -= actual_read; return actual_read; } /** * @brief 查看缓冲区数据(不移动指针) * * @param cb 循环缓冲区指针 * @param data 用于存储查看数据的缓冲区 * @param len 请求查看的数据长度(字节) * @return 实际查看的数据长度(字节) * * @note 用于预览数据而不改变缓冲区状态 */ size_t circular_buffer_peek(circular_buffer_t* cb, uint8_t* data, size_t len) { if (!cb || !data || len == 0 || cb->count == 0) return 0; size_t actual_peek = (len <= cb->count) ? len : cb->count; // 计算到缓冲区末尾的连续数据 size_t to_end = cb->size - cb->tail; if (to_end >= actual_peek) { memcpy(data, cb->buffer + cb->tail, actual_peek); } else { memcpy(data, cb->buffer + cb->tail, to_end); memcpy(data + to_end, cb->buffer, actual_peek - to_end); } return actual_peek; } /** * @brief 获取缓冲区可用空间 * * @param cb 循环缓冲区指针 * @return 可用空间大小(字节) */ size_t circular_buffer_available_space(circular_buffer_t* cb) { return cb->size - cb->count; } /** * @brief 获取缓冲区当前数据量 * * @param cb 循环缓冲区指针 * @return 当前数据量(字节) */ size_t circular_buffer_available_data(circular_buffer_t* cb) { return cb->count; } /** * @brief 检查缓冲区是否为空 * * @param cb 循环缓冲区指针 * @return true表示为空,false表示非空 */ bool circular_buffer_is_empty(circular_buffer_t* cb) { return cb->count == 0; } /** * @brief 检查缓冲区是否已满 * * @param cb 循环缓冲区指针 * @return true表示已满,false表示未满 */ bool circular_buffer_is_full(circular_buffer_t* cb) { return cb->count == cb->size; } #ifndef CIRCULAR_BUFFER_H #define CIRCULAR_BUFFER_H #include <stdint.h> // 标准整数类型定义 #include <stdbool.h> // 布尔类型定义 #include <stddef.h> // size_t 类型定义 #ifdef __cplusplus extern "C" { #endif /** * @brief 循环缓冲区结构体 * * 该结构体实现了线程不安全的环形缓冲区,支持基本的数据读写操作。 * 使用前必须通过 circular_buffer_init() 初始化。 */ typedef struct { uint8_t* buffer; /**< 数据存储缓冲区指针 */ size_t size; /**< 缓冲区总容量(字节) */ size_t head; /**< 数据写入位置索引(0-based) */ size_t tail; /**< 数据读取位置索引(0-based) */ size_t count; /**< 当前缓冲区中数据量(字节) */ } circular_buffer_t; /** * @brief 初始化循环缓冲区 * * @param size 缓冲区大小(字节) * @return 成功返回缓冲区指针,失败返回NULL */ circular_buffer_t* circular_buffer_init(size_t size); /** * @brief 销毁循环缓冲区 * * @param cb 要销毁的缓冲区指针 */ void circular_buffer_destroy(circular_buffer_t* cb); /** * @brief 重置缓冲区到初始状态 * * @param cb 要重置的缓冲区指针 */ void circular_buffer_reset(circular_buffer_t* cb); /** * @brief 向缓冲区写入数据 * * @param cb 循环缓冲区指针 * @param data 要写入的数据指针 * @param len 要写入的数据长度(字节) * @return 实际写入的数据长度(字节) */ size_t circular_buffer_write(circular_buffer_t* cb, const uint8_t* data, size_t len); /** * @brief 从缓冲区读取数据 * * @param cb 循环缓冲区指针 * @param data 用于存储读取数据的缓冲区 * @param len 请求读取的数据长度(字节) * @return 实际读取的数据长度(字节) */ size_t circular_buffer_read(circular_buffer_t* cb, uint8_t* data, size_t len); /** * @brief 查看缓冲区数据(不移动读指针) * * @param cb 循环缓冲区指针 * @param data 用于存储查看数据的缓冲区 * @param len 请求查看的数据长度(字节) * @return 实际查看的数据长度(字节) */ size_t circular_buffer_peek(circular_buffer_t* cb, uint8_t* data, size_t len); /** * @brief 获取缓冲区可用空间 * * @param cb 循环缓冲区指针 * @return 可用空间大小(字节) */ size_t circular_buffer_available_space(circular_buffer_t* cb); /** * @brief 获取缓冲区当前数据量 * * @param cb 循环缓冲区指针 * @return 当前数据量(字节) */ size_t circular_buffer_available_data(circular_buffer_t* cb); /** * @brief 检查缓冲区是否为空 * * @param cb 循环缓冲区指针 * @return true表示为空,false表示非空 */ bool circular_buffer_is_empty(circular_buffer_t* cb); /** * @brief 检查缓冲区是否已满 * * @param cb 循环缓冲区指针 * @return true表示已满,false表示未满 */ bool circular_buffer_is_full(circular_buffer_t* cb); #ifdef __cplusplus } #endif #endif // CIRCULAR_BUFFER_H 兼容该库来实现
07-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值