北京做手机网站建设,高端品牌网站建设定位,分销软件有哪些,Wordpress 倒计时 代码文章目录 0. 引言1. 使用示例2. 流程图2.1 追加数据流程2.2 获取空闲块流程2.3 处理特殊字符流程2.4 释放块流程2.5 获取下一个使用块流程 3. 代码详解3.1 Block 结构体3.2 RingBuffer 类3.3 主要方法解析append 方法currentUsed 和 currentUsing 方法release 方法nextUsed 方法… 文章目录 0. 引言1. 使用示例2. 流程图2.1 追加数据流程2.2 获取空闲块流程2.3 处理特殊字符流程2.4 释放块流程2.5 获取下一个使用块流程 3. 代码详解3.1 Block 结构体3.2 RingBuffer 类3.3 主要方法解析append 方法currentUsed 和 currentUsing 方法release 方法nextUsed 方法 3.4 私有方法解析nextFree 方法checkSpecial 方法 4. 内存管理与拷贝控制5. 完整代码 0. 引言
本文将介绍一个解析串口数据的环形缓冲区使用’$‘或者’#分割串口消息。
主要设计考虑包括
内存管理选用内存块数组而不是选用一整块的内存读写指针的方式以减少读写数据时的资源竞争。使用原始指针手动分配和释放内存确保每个 Block 管理自己的缓冲区。 确保资源的安全转移。状态管理每个 Block 通过 status 成员变量表示其当前状态空闲、使用中或已使用。
1. 使用示例
以下是一个简单的使用示例展示如何创建 RingBuffer 实例、追加数据、访问当前使用的 Block 以及释放 Block。
#include ring_buffer.hppint main()
{try{// 创建一个包含10个Block的RingBufferRingBuffer ringBuffer(10);// 追加数据1const char* data1 Hello, World!;if (!ringBuffer.append(reinterpret_castconst uint8_t*(data1), std::strlen(data1))){std::cerr Failed to append data1.\n;}// 追加数据2包含特殊字符const char* data2 Special#Character;if (!ringBuffer.append(reinterpret_castconst uint8_t*(data2), std::strlen(data2))){std::cerr Failed to append data2.\n;}// 访问当前使用的Blockconst RingBuffer::Block usedBlock ringBuffer.currentUsed();std::cout Used Block Index: usedBlock.index , Written: usedBlock.written \n;// 访问当前正在写入的Blockconst RingBuffer::Block usingBlock ringBuffer.currentUsing();std::cout Using Block Index: usingBlock.index , Written: usingBlock.written \n;// 释放第一个BlockringBuffer.release(0);}catch (const std::exception ex){std::cerr Exception: ex.what() \n;}return 0;
}解析
创建 RingBuffer初始化一个包含10个 Block 的 RingBuffer 实例。追加数据 追加字符串 Hello, World!。追加包含特殊字符 # 的字符串 Special#Character触发数据分割逻辑。 访问 Block 获取并打印当前使用的 Block 的索引和已写入字节数。获取并打印当前正在写入的 Block 的索引和已写入字节数。 释放 Block释放第一个 Block将其状态标记为 BufFree 并重置已写入字节数。异常处理使用 try-catch 块捕获并处理可能抛出的异常确保程序的稳定性。
2. 流程图
2.1 追加数据流程
首先我们来看一下追加数据的整体流程。这是环形缓冲区的核心功能负责将新数据添加到缓冲区中。 #mermaid-svg-0EDuvhsXEJHv8I77 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-0EDuvhsXEJHv8I77 .error-icon{fill:#552222;}#mermaid-svg-0EDuvhsXEJHv8I77 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0EDuvhsXEJHv8I77 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-0EDuvhsXEJHv8I77 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0EDuvhsXEJHv8I77 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0EDuvhsXEJHv8I77 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0EDuvhsXEJHv8I77 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0EDuvhsXEJHv8I77 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0EDuvhsXEJHv8I77 .marker.cross{stroke:#333333;}#mermaid-svg-0EDuvhsXEJHv8I77 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0EDuvhsXEJHv8I77 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0EDuvhsXEJHv8I77 .cluster-label text{fill:#333;}#mermaid-svg-0EDuvhsXEJHv8I77 .cluster-label span{color:#333;}#mermaid-svg-0EDuvhsXEJHv8I77 .label text,#mermaid-svg-0EDuvhsXEJHv8I77 span{fill:#333;color:#333;}#mermaid-svg-0EDuvhsXEJHv8I77 .node rect,#mermaid-svg-0EDuvhsXEJHv8I77 .node circle,#mermaid-svg-0EDuvhsXEJHv8I77 .node ellipse,#mermaid-svg-0EDuvhsXEJHv8I77 .node polygon,#mermaid-svg-0EDuvhsXEJHv8I77 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0EDuvhsXEJHv8I77 .node .label{text-align:center;}#mermaid-svg-0EDuvhsXEJHv8I77 .node.clickable{cursor:pointer;}#mermaid-svg-0EDuvhsXEJHv8I77 .arrowheadPath{fill:#333333;}#mermaid-svg-0EDuvhsXEJHv8I77 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0EDuvhsXEJHv8I77 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0EDuvhsXEJHv8I77 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-0EDuvhsXEJHv8I77 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-0EDuvhsXEJHv8I77 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0EDuvhsXEJHv8I77 .cluster text{fill:#333;}#mermaid-svg-0EDuvhsXEJHv8I77 .cluster span{color:#333;}#mermaid-svg-0EDuvhsXEJHv8I77 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0EDuvhsXEJHv8I77 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 长度超过 长度合适 有足够空间且状态为BufUsing 无足够空间或状态不符 获取成功 获取失败 开始 验证数据长度 输出错误信息 检查当前块空间和状态 数据复制到当前块 尝试获取下一个空闲块 设置新块状态为BufUsing 输出错误信息 结束 流程图解析
开始数据追加操作的起点。验证数据长度检查待追加的数据是否超过单个块的大小BlockSize。 长度超过输出错误信息终止操作。长度合适继续下一步。 检查当前块空间和状态判断当前块是否有足够的空间且状态为BufUsing使用中。 有足够空间且状态正确将数据复制到当前块。无足够空间或状态不符尝试获取下一个空闲块。 尝试获取下一个空闲块 获取成功设置新块的状态为BufUsing继续数据追加。获取失败输出错误信息终止操作。 结束数据追加流程结束。
2.2 获取空闲块流程
当当前块空间不足或状态不符时需要获取下一个空闲块。以下流程图展示了获取空闲块的具体步骤。
flowchart TDA[开始] -- B[检查当前块状态]B -- |状态为BufFree| C[可以使用当前块]B -- |状态不为BufFree| D[检查是否允许重试]D -- |允许重试| E[返回失败]D -- |不允许重试| F[标记当前块为BufUsed]F -- G[检查是否到达缓冲区末尾]G -- |是| H[回绕到第一个块]G -- |否| I[移动到下一个块]H -- J[检查块是否为空]I -- JJ -- |块为空| K[成功获取空闲块]J -- |块不为空| L[输出警告返回失败]C -- KK -- M[结束]L -- ME -- M流程图解析
开始获取空闲块操作的起点。检查当前块状态判断当前块是否为空闲状态BufFree。 状态为BufFree可以直接使用当前块。状态不为BufFree进一步检查是否允许重试。 检查是否允许重试 允许重试直接返回失败不进行进一步操作。不允许重试将当前块标记为BufUsed表示已被使用。 标记当前块为BufUsed更新当前块的状态。检查是否到达缓冲区末尾 是回绕到缓冲区的第一个块。否移动到下一个块。 检查块是否为空判断目标块是否为空闲状态。 块为空成功获取空闲块。块不为空输出警告信息返回失败。 结束获取空闲块流程结束。
2.3 处理特殊字符流程
在追加数据过程中如果数据中包含特殊字符如#或$需要对数据进行分割处理。以下流程图展示了处理特殊字符的具体步骤。 #mermaid-svg-L7yxcU6Cl5vOi6gh {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-L7yxcU6Cl5vOi6gh .error-icon{fill:#552222;}#mermaid-svg-L7yxcU6Cl5vOi6gh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-L7yxcU6Cl5vOi6gh .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-L7yxcU6Cl5vOi6gh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-L7yxcU6Cl5vOi6gh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-L7yxcU6Cl5vOi6gh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-L7yxcU6Cl5vOi6gh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-L7yxcU6Cl5vOi6gh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-L7yxcU6Cl5vOi6gh .marker.cross{stroke:#333333;}#mermaid-svg-L7yxcU6Cl5vOi6gh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-L7yxcU6Cl5vOi6gh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-L7yxcU6Cl5vOi6gh .cluster-label text{fill:#333;}#mermaid-svg-L7yxcU6Cl5vOi6gh .cluster-label span{color:#333;}#mermaid-svg-L7yxcU6Cl5vOi6gh .label text,#mermaid-svg-L7yxcU6Cl5vOi6gh span{fill:#333;color:#333;}#mermaid-svg-L7yxcU6Cl5vOi6gh .node rect,#mermaid-svg-L7yxcU6Cl5vOi6gh .node circle,#mermaid-svg-L7yxcU6Cl5vOi6gh .node ellipse,#mermaid-svg-L7yxcU6Cl5vOi6gh .node polygon,#mermaid-svg-L7yxcU6Cl5vOi6gh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-L7yxcU6Cl5vOi6gh .node .label{text-align:center;}#mermaid-svg-L7yxcU6Cl5vOi6gh .node.clickable{cursor:pointer;}#mermaid-svg-L7yxcU6Cl5vOi6gh .arrowheadPath{fill:#333333;}#mermaid-svg-L7yxcU6Cl5vOi6gh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-L7yxcU6Cl5vOi6gh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-L7yxcU6Cl5vOi6gh .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-L7yxcU6Cl5vOi6gh .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-L7yxcU6Cl5vOi6gh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-L7yxcU6Cl5vOi6gh .cluster text{fill:#333;}#mermaid-svg-L7yxcU6Cl5vOi6gh .cluster span{color:#333;}#mermaid-svg-L7yxcU6Cl5vOi6gh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-L7yxcU6Cl5vOi6gh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 不包含 包含 获取成功 获取失败 有 无 开始 检查数据中是否包含特殊字符 复制整个数据到当前块 复制特殊字符前的数据到当前块 尝试获取新块 设置新块状态为BufUsing 输出错误信息 复制特殊字符到新块 检查是否有剩余数据 复制剩余数据到新块 结束 流程图解析
开始处理特殊字符操作的起点。检查数据中是否包含特殊字符扫描数据是否包含#或$。 不包含直接将整个数据复制到当前块。包含将特殊字符前的数据复制到当前块。 复制特殊字符前的数据到当前块部分数据复制到当前块。尝试获取新块 获取成功设置新块状态为BufUsing。获取失败输出错误信息终止操作。 设置新块状态为BufUsing更新新块的状态。复制特殊字符到新块将特殊字符复制到新块。检查是否有剩余数据 有将剩余数据复制到新块。无结束操作。 结束处理特殊字符流程结束。
2.4 释放块流程
当某个块的数据被处理完毕后需要将其释放以便后续数据的追加。以下流程图展示了释放块的具体步骤。 #mermaid-svg-eXtKMTz6sMIMEfO5 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-eXtKMTz6sMIMEfO5 .error-icon{fill:#552222;}#mermaid-svg-eXtKMTz6sMIMEfO5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eXtKMTz6sMIMEfO5 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-eXtKMTz6sMIMEfO5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eXtKMTz6sMIMEfO5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eXtKMTz6sMIMEfO5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eXtKMTz6sMIMEfO5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eXtKMTz6sMIMEfO5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eXtKMTz6sMIMEfO5 .marker.cross{stroke:#333333;}#mermaid-svg-eXtKMTz6sMIMEfO5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eXtKMTz6sMIMEfO5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eXtKMTz6sMIMEfO5 .cluster-label text{fill:#333;}#mermaid-svg-eXtKMTz6sMIMEfO5 .cluster-label span{color:#333;}#mermaid-svg-eXtKMTz6sMIMEfO5 .label text,#mermaid-svg-eXtKMTz6sMIMEfO5 span{fill:#333;color:#333;}#mermaid-svg-eXtKMTz6sMIMEfO5 .node rect,#mermaid-svg-eXtKMTz6sMIMEfO5 .node circle,#mermaid-svg-eXtKMTz6sMIMEfO5 .node ellipse,#mermaid-svg-eXtKMTz6sMIMEfO5 .node polygon,#mermaid-svg-eXtKMTz6sMIMEfO5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eXtKMTz6sMIMEfO5 .node .label{text-align:center;}#mermaid-svg-eXtKMTz6sMIMEfO5 .node.clickable{cursor:pointer;}#mermaid-svg-eXtKMTz6sMIMEfO5 .arrowheadPath{fill:#333333;}#mermaid-svg-eXtKMTz6sMIMEfO5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eXtKMTz6sMIMEfO5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eXtKMTz6sMIMEfO5 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-eXtKMTz6sMIMEfO5 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-eXtKMTz6sMIMEfO5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eXtKMTz6sMIMEfO5 .cluster text{fill:#333;}#mermaid-svg-eXtKMTz6sMIMEfO5 .cluster span{color:#333;}#mermaid-svg-eXtKMTz6sMIMEfO5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eXtKMTz6sMIMEfO5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 有效 无效 开始 检查块索引是否有效 重置写入字节数 设置块状态为BufFree 结束 输出错误信息 流程图解析
开始释放块操作的起点。检查块索引是否有效验证要释放的块索引是否在有效范围内。 有效继续释放流程。无效输出错误信息终止操作。 重置写入字节数将块中的written成员变量重置为0。设置块状态为BufFree将块的状态更新为BufFree表示该块已空闲。结束释放块流程结束。
2.5 获取下一个使用块流程
在某些情况下需要获取下一个已经使用的块。以下流程图展示了获取下一个使用块的具体步骤。 #mermaid-svg-YiAWu2pLRILcHgNK {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-YiAWu2pLRILcHgNK .error-icon{fill:#552222;}#mermaid-svg-YiAWu2pLRILcHgNK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YiAWu2pLRILcHgNK .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-YiAWu2pLRILcHgNK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YiAWu2pLRILcHgNK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YiAWu2pLRILcHgNK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YiAWu2pLRILcHgNK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YiAWu2pLRILcHgNK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YiAWu2pLRILcHgNK .marker.cross{stroke:#333333;}#mermaid-svg-YiAWu2pLRILcHgNK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YiAWu2pLRILcHgNK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YiAWu2pLRILcHgNK .cluster-label text{fill:#333;}#mermaid-svg-YiAWu2pLRILcHgNK .cluster-label span{color:#333;}#mermaid-svg-YiAWu2pLRILcHgNK .label text,#mermaid-svg-YiAWu2pLRILcHgNK span{fill:#333;color:#333;}#mermaid-svg-YiAWu2pLRILcHgNK .node rect,#mermaid-svg-YiAWu2pLRILcHgNK .node circle,#mermaid-svg-YiAWu2pLRILcHgNK .node ellipse,#mermaid-svg-YiAWu2pLRILcHgNK .node polygon,#mermaid-svg-YiAWu2pLRILcHgNK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YiAWu2pLRILcHgNK .node .label{text-align:center;}#mermaid-svg-YiAWu2pLRILcHgNK .node.clickable{cursor:pointer;}#mermaid-svg-YiAWu2pLRILcHgNK .arrowheadPath{fill:#333333;}#mermaid-svg-YiAWu2pLRILcHgNK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YiAWu2pLRILcHgNK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YiAWu2pLRILcHgNK .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-YiAWu2pLRILcHgNK .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-YiAWu2pLRILcHgNK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YiAWu2pLRILcHgNK .cluster text{fill:#333;}#mermaid-svg-YiAWu2pLRILcHgNK .cluster span{color:#333;}#mermaid-svg-YiAWu2pLRILcHgNK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YiAWu2pLRILcHgNK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 状态为BufUsed 状态不为BufUsed 是 否 状态为BufUsed 状态不为BufUsed 状态为BufUsed 状态不为BufUsed 开始 检查当前使用块的状态 返回当前使用块的索引 检查是否到达缓冲区末尾 检查第一个块的状态 检查下一个块的状态 更新使用块索引为0 返回-1 更新使用块索引为下一个块 返回使用块的索引 结束 流程图解析
开始获取下一个使用块操作的起点。检查当前使用块的状态判断当前indexUsed_指向的块是否为BufUsed状态。 状态为BufUsed返回当前使用块的索引。状态不为BufUsed继续检查是否需要回绕。 检查是否到达缓冲区末尾 是检查第一个块的状态。否检查下一个块的状态。 检查第一个块的状态 状态为BufUsed更新indexUsed_为0返回索引。状态不为BufUsed返回-1表示没有找到下一个使用块。 检查下一个块的状态 状态为BufUsed更新indexUsed_为下一个块的索引返回索引。状态不为BufUsed返回-1表示没有找到下一个使用块。 结束获取下一个使用块流程结束。
3. 代码详解
下面我们将逐步解析 RingBuffer 类的实现理解其内部工作机制。
3.1 Block 结构体
struct Block
{uint8_t* buf; /// Buffer to store data.int8_t status; /// Status of the block (free, using, or used).int32_t index; /// Index of the block within the ring buffer.uint32_t written; /// Number of bytes written to the block./*** brief Constructs a Block with a pre-allocated buffer.** Initializes the buffer and sets default values for other members.*/Block() : buf(new uint8_t[BlockSize]), status(BufFree), index(-1), written(0){// Initialize buffer to zero (optional)std::memset(buf, 0, BlockSize);}/*** brief Destructor to deallocate the buffer.*/~Block() { delete[] buf; }// Delete copy constructor and copy assignment operator to prevent shallow copies.Block(const Block) delete;Block operator(const Block) delete;// Define move constructor and move assignment operator for safe transfers.Block(Block other) noexcept : buf(other.buf), status(other.status), index(other.index), written(other.written){other.buf nullptr;other.status BufFree;other.index -1;other.written 0;}Block operator(Block other) noexcept{if (this ! other){delete[] buf;buf other.buf;status other.status;index other.index;written other.written;other.buf nullptr;other.status BufFree;other.index -1;other.written 0;}return *this;}static constexpr uint32_t BlockSize 256; /// Size of each block in bytes.static constexpr int8_t BufFree 0; /// Indicates the block is free.static constexpr int8_t BufUsing 1; /// Indicates the block is currently in use.static constexpr int8_t BufUsed 2; /// Indicates the block has been used.
};解析 成员变量 uint8_t* buf指向数据缓冲区的原始指针。int8_t status表示 Block 的当前状态BufFree空闲、BufUsing使用中、BufUsed已使用。int32_t indexBlock 在 RingBuffer 中的索引。uint32_t written已写入 Block 的字节数。 构造函数与析构函数 构造函数中使用 new 分配固定大小的缓冲区并初始化其他成员变量。析构函数中使用 delete[] 释放缓冲区内存。 拷贝控制 拷贝构造函数和拷贝赋值运算符被删除防止浅拷贝带来的内存管理问题。移动构造函数和移动赋值运算符 被定义允许 Block 实例的资源安全转移。
3.2 RingBuffer 类
class RingBuffer
{public:// Block 结构体定义.../*** brief Constructs a RingBuffer with a specified number of blocks.** param num The number of blocks in the ring buffer. Defaults to 1000.*/explicit RingBuffer(uint32_t num 1000) : blocks_(num), blockNum_(num), index_(0), indexUsed_(-1){// Initialize each blocks index.for (uint32_t i 0; i blocks_.size(); i){blocks_[i].index static_castint32_t(i);}// Set the first blocks status to using.if (!blocks_.empty()){blocks_[0].status Block::BufUsing;}}/*** brief Destructor to deallocate all blocks.*/~RingBuffer() default; // Blocks are automatically destroyed, and their destructors handle buffer deallocation.// Delete copy constructor and copy assignment operator to prevent shallow copies.RingBuffer(const RingBuffer) delete;RingBuffer operator(const RingBuffer) delete;// Define move constructor and move assignment operator for safe transfers.RingBuffer(RingBuffer other) noexcept: blocks_(std::move(other.blocks_)),blockNum_(other.blockNum_),index_(other.index_),indexUsed_(other.indexUsed_){other.blockNum_ 0;other.index_ 0;other.indexUsed_ -1;}RingBuffer operator(RingBuffer other) noexcept{if (this ! other){blocks_ std::move(other.blocks_);blockNum_ other.blockNum_;index_ other.index_;indexUsed_ other.indexUsed_;other.blockNum_ 0;other.index_ 0;other.indexUsed_ -1;}return *this;}// append 方法定义...// currentUsed 和 currentUsing 方法定义...// release 方法定义...// nextUsed 方法定义...private:// nextFree 和 checkSpecial 方法定义...std::vectorBlock blocks_; /// Vector of blocks managed by the ring buffer.int32_t index_ 0; /// Current index for writing data.int32_t blockNum_ 0; /// Total number of blocks in the ring buffer.int32_t indexUsed_ -1; /// Index of the currently used block.
};解析 成员变量 std::vectorBlock blocks_存储所有 Block 的容器。int32_t index_当前用于写入数据的 Block 索引。int32_t blockNum_环形缓冲区中 Block 的总数。int32_t indexUsed_当前正在使用的 Block 索引初始化为 -1 表示无 Block 被使用。 构造函数与析构函数 构造函数中初始化 blocks_ 向量并为每个 Block 设置其索引。默认情况下第一个 Block 的状态设置为 BufUsing表示其已被使用。析构函数使用默认实现依赖于 Block 的析构函数自动释放内存。 拷贝控制 拷贝构造函数和拷贝赋值运算符被删除防止浅拷贝导致的资源管理问题。移动构造函数和移动赋值运算符 被定义允许 RingBuffer 实例的资源安全转移。
3.3 主要方法解析
append 方法
/*** brief Appends data to the ring buffer.** This method attempts to append the provided data to the current block.* If theres insufficient space or a retry is requested, it tries to acquire the next free block.* It also handles splitting data when special characters are encountered.** param buf Pointer to the data to append.* param length Length of the data in bytes.* param retry Flag indicating whether to retry acquiring a free block.* return True if the data was successfully appended; false otherwise.*/
bool append(const uint8_t* buf, uint32_t length, bool retry false)
{// Validate that the data length does not exceed block size.if (length Block::BlockSize){std::cerr Error: Length length exceeds block size Block::BlockSize .\n;return false;}// Check if the current block has enough space and is in the correct status.if (!retry blocks_[index_].written length Block::BlockSize){if (blocks_[index_].status ! Block::BufUsing){std::cerr Error: Current block status is not BufUsing.\n;return false;}}else{// Attempt to acquire the next free block.if (!nextFree(retry)){// If acquiring a free block fails, ensure the current block status is correct.if (blocks_[index_].status ! Block::BufUsed){std::cerr Error: Current block status is not BufUsed.\n;}return false;}// Update the status of the newly acquired block.blocks_[index_].status Block::BufUsing;}// If the current block is empty, copy the entire buffer.if (blocks_[index_].written 0){std::memcpy(blocks_[index_].buf blocks_[index_].written, buf, length);blocks_[index_].written length;}else{// Check for special characters in the buffer.int specialIdx checkSpecial(buf, length);if (specialIdx -1){// No special characters found; attempt to copy the entire buffer.if (blocks_[index_].written length Block::BlockSize){std::cerr Error: Not enough space to append data without special character.\n;return false;}std::memcpy(blocks_[index_].buf blocks_[index_].written, buf, length);blocks_[index_].written length;}else{// Special character found; split the data at the special character.if (blocks_[index_].written specialIdx Block::BlockSize){std::cerr Error: Not enough space to copy data before special character.\n;return false;}// Copy data up to the special character.std::memcpy(blocks_[index_].buf blocks_[index_].written, buf, specialIdx);blocks_[index_].written specialIdx;// Attempt to acquire a new free block for the special character.if (!nextFree(retry)){if (blocks_[index_].status ! Block::BufUsed){std::cerr Error: Current block status is not BufUsed after finding special character.\n;}return false;}// Update the status and reset the write position for the new block.blocks_[index_].status Block::BufUsing;blocks_[index_].written 0;// Copy the special character to the new block.blocks_[index_].buf[blocks_[index_].written] buf[specialIdx];// If there is remaining data after the special character, copy it to the new block.if (static_castuint32_t(specialIdx 1) length){uint32_t remainingLength length - specialIdx - 1;if (remainingLength Block::BlockSize - blocks_[index_].written){std::cerr Error: Not enough space to copy remaining data after special character.\n;return false;}std::memcpy(blocks_[index_].buf blocks_[index_].written, buf specialIdx 1, remainingLength);blocks_[index_].written remainingLength;}}}return true;
}解析
功能向环形缓冲区追加数据。步骤 长度校验确保待追加的数据长度不超过单个 Block 的大小。空间与状态检查检查当前 Block 是否有足够的空间以及其状态是否为 BufUsing。获取新块如果当前块空间不足或请求重试尝试获取下一个空闲块。数据复制 如果当前块为空直接复制整个数据。如果当前块已有数据检查数据中是否包含特殊字符# 或 $。 无特殊字符直接复制数据。有特殊字符在特殊字符处分割数据分别复制到当前块和新获取的块中。
currentUsed 和 currentUsing 方法
/*** brief Retrieves the currently used block.** return A constant reference to the currently used block.* throws std::out_of_range if the indexUsed_ is invalid.*/
const Block currentUsed() const
{if (indexUsed_ 0 static_castsize_t(indexUsed_) blocks_.size()){return blocks_[indexUsed_];}throw std::out_of_range(currentUsed(): indexUsed_ is out of range.);
}/*** brief Retrieves the block that is currently being used for writing.** return A constant reference to the block currently in use.* throws std::out_of_range if the index_ is invalid.*/
const Block currentUsing() const
{if (static_castsize_t(index_) blocks_.size()){return blocks_[index_];}throw std::out_of_range(currentUsing(): index_ is out of range.);
}解析
功能 currentUsed()获取当前正在使用的 Block。currentUsing()获取当前用于写入的 Block。 实现 通过索引 indexUsed_ 和 index_ 访问 blocks_ 向量中的相应 Block。添加了边界检查若索引无效抛出 std::out_of_range 异常防止访问越界。
release 方法
/*** brief Releases a block, marking it as free and resetting its written bytes.** param idx The index of the block to release.*/
void release(uint32_t idx)
{if (idx blocks_.size()){blocks_[idx].written 0;blocks_[idx].status Block::BufFree;}else{std::cerr Error: Release index idx is out of bounds.\n;}
}解析
功能释放指定索引的 Block将其状态标记为 BufFree 并重置已写入字节数。实现 检查索引是否在有效范围内。更新 Block 的 written 和 status 成员。
nextUsed 方法
/*** brief Retrieves the next used blocks index.** return The index of the next used block, or -1 if no such block exists.*/
int32_t nextUsed()
{// Check if the current used index is valid and marked as used.if (indexUsed_ 0 static_castsize_t(indexUsed_) blocks_.size() blocks_[indexUsed_].status Block::BufUsed){return indexUsed_;}// Handle wrapping around to the beginning of the ring buffer.if (indexUsed_ static_castint32_t(blockNum_) - 1){if (!blocks_.empty() blocks_[0].status Block::BufUsed){indexUsed_ 0;return indexUsed_;}else{return -1;}}else{// Check the next block in sequence.if ((indexUsed_ 1) static_castint32_t(blockNum_) blocks_[indexUsed_ 1].status Block::BufUsed){indexUsed_ 1;return indexUsed_;}else{return -1;}}
}解析
功能获取下一个已使用的 Block 的索引。实现 检查当前 indexUsed_ 是否指向一个已使用的 Block。如果在缓冲区末尾尝试回绕到起始位置。否则检查下一个 Block 是否已使用。若未找到则返回 -1。
3.4 私有方法解析
nextFree 方法
/*** brief Attempts to acquire the next free block in the ring buffer.** param retry Flag indicating whether to retry acquiring a free block.* return True if a free block was successfully acquired; false otherwise.*/
bool nextFree(bool retry false)
{// If the current block is free, it can be used.if (blocks_[index_].status Block::BufFree){return true;}else{// If retry is requested and the block is not free, do not attempt further.if (retry){return false;}}// Mark the current block as used since it cannot be reused immediately.blocks_[index_].status Block::BufUsed;// Handle wrapping around to the first block.if (index_ static_castint32_t(blockNum_) - 1){index_ 0;if (blocks_[index_].status ! Block::BufFree){std::cerr Warning: Block 0 is not free.\n;return false;}}else{// Move to the next block in the sequence.index_ 1;if (index_ static_castint32_t(blockNum_)){std::cerr Error: Index exceeded block number.\n;return false;}if (blocks_[index_].status ! Block::BufFree){std::cerr Warning: Block index_ is not free.\n;return false;}}return true;
}解析
功能尝试获取下一个空闲的 Block。实现 检查当前 Block 是否为空闲状态。若不为空闲且不允许重试标记当前 Block 为已使用并尝试下一个 Block。添加了回绕逻辑确保环形缓冲区的循环特性。在获取失败时输出警告或错误信息。
checkSpecial 方法
/*** brief Checks for the presence of special characters in the buffer.** This method scans the buffer for # or $ characters.** param buf Pointer to the buffer to check.* param length Length of the buffer in bytes.* return The index of the first special character found; -1 if none are found.*/
int checkSpecial(const uint8_t* buf, uint32_t length) const
{for (uint32_t i 0; i length; i){if (buf[i] # || buf[i] $){return static_castint(i);}}return -1;
}解析
功能检查缓冲区中是否存在特殊字符# 或 $。实现 遍历缓冲区数据查找特殊字符。若找到返回其索引否则返回 -1。
4. 内存管理与拷贝控制
在本实现中内存管理 和 拷贝控制 是确保 RingBuffer 类安全高效运行的关键因素。 原始指针管理内存 每个 Block 使用 new 分配固定大小的缓冲区并在析构函数中使用 delete[] 释放。这种手动管理内存的方法需要开发者确保在所有情况下都正确分配和释放资源避免内存泄漏或重复释放。 拷贝控制 通过 删除拷贝构造函数和拷贝赋值运算符防止 Block 和 RingBuffer 实例被浅拷贝避免多个实例指向同一内存区域。移动构造函数和移动赋值运算符 的实现允许资源的安全转移提高类的灵活性。
5. 完整代码 /*** brief A ring buffer implementation for managing fixed-size memory blocks without using smart pointers.*/
class RingBuffer
{public:/*** brief Represents a single block within the ring buffer.*/struct Block{uint8_t* buf; /// Buffer to store data.int8_t status; /// Status of the block (free, using, or used).int32_t index; /// Index of the block within the ring buffer.uint32_t written; /// Number of bytes written to the block./*** brief Constructs a Block with a pre-allocated buffer.** Initializes the buffer and sets default values for other members.*/Block() : buf(new uint8_t[BlockSize]), status(BufFree), index(-1), written(0){// Initialize buffer to zero (optional)std::memset(buf, 0, BlockSize);}/*** brief Destructor to deallocate the buffer.*/~Block() { delete[] buf; }// Delete copy constructor and copy assignment operator to prevent shallow copies.Block(const Block) delete;Block operator(const Block) delete;// Define move constructor and move assignment operator for safe transfers.Block(Block other) noexcept : buf(other.buf), status(other.status), index(other.index), written(other.written){other.buf nullptr;other.status BufFree;other.index -1;other.written 0;}Block operator(Block other) noexcept{if (this ! other){delete[] buf;buf other.buf;status other.status;index other.index;written other.written;other.buf nullptr;other.status BufFree;other.index -1;other.written 0;}return *this;}static constexpr uint32_t BlockSize 256; /// Size of each block in bytes.static constexpr int8_t BufFree 0; /// Indicates the block is free.static constexpr int8_t BufUsing 1; /// Indicates the block is currently in use.static constexpr int8_t BufUsed 2; /// Indicates the block has been used.};/*** brief Constructs a RingBuffer with a specified number of blocks.** param num The number of blocks in the ring buffer. Defaults to 1000.*/explicit RingBuffer(uint32_t num 1000) : blocks_(num), blockNum_(num), index_(0), indexUsed_(-1){// Initialize each blocks index.for (uint32_t i 0; i blocks_.size(); i){blocks_[i].index static_castint32_t(i);}// Set the first blocks status to using.if (!blocks_.empty()){blocks_[0].status Block::BufUsing;}}/*** brief Destructor to deallocate all blocks.*/~RingBuffer() default; // Blocks are automatically destroyed, and their destructors handle buffer deallocation.// Delete copy constructor and copy assignment operator to prevent shallow copies.RingBuffer(const RingBuffer) delete;RingBuffer operator(const RingBuffer) delete;// Define move constructor and move assignment operator for safe transfers.RingBuffer(RingBuffer other) noexcept: blocks_(std::move(other.blocks_)),blockNum_(other.blockNum_),index_(other.index_),indexUsed_(other.indexUsed_){other.blockNum_ 0;other.index_ 0;other.indexUsed_ -1;}RingBuffer operator(RingBuffer other) noexcept{if (this ! other){blocks_ std::move(other.blocks_);blockNum_ other.blockNum_;index_ other.index_;indexUsed_ other.indexUsed_;other.blockNum_ 0;other.index_ 0;other.indexUsed_ -1;}return *this;}/*** brief Appends data to the ring buffer.** This method attempts to append the provided data to the current block.* If theres insufficient space or a retry is requested, it tries to acquire the next free block.* It also handles splitting data when special characters are encountered.** param buf Pointer to the data to append.* param length Length of the data in bytes.* param retry Flag indicating whether to retry acquiring a free block.* return True if the data was successfully appended; false otherwise.*/bool append(const uint8_t* buf, uint32_t length, bool retry false){// Validate that the data length does not exceed block size.if (length Block::BlockSize){std::cerr Error: Length length exceeds block size Block::BlockSize .\n;return false;}// Check if the current block has enough space and is in the correct status.if (!retry blocks_[index_].written length Block::BlockSize){if (blocks_[index_].status ! Block::BufUsing){std::cerr Error: Current block status is not BufUsing.\n;return false;}}else{// Attempt to acquire the next free block.if (!nextFree(retry)){// If acquiring a free block fails, ensure the current block status is correct.if (blocks_[index_].status ! Block::BufUsed){std::cerr Error: Current block status is not BufUsed.\n;}return false;}// Update the status of the newly acquired block.blocks_[index_].status Block::BufUsing;}// If the current block is empty, copy the entire buffer.if (blocks_[index_].written 0){std::memcpy(blocks_[index_].buf blocks_[index_].written, buf, length);blocks_[index_].written length;}else{// Check for special characters in the buffer.int specialIdx checkSpecial(buf, length);if (specialIdx -1){// No special characters found; attempt to copy the entire buffer.if (blocks_[index_].written length Block::BlockSize){std::cerr Error: Not enough space to append data without special character.\n;return false;}std::memcpy(blocks_[index_].buf blocks_[index_].written, buf, length);blocks_[index_].written length;}else{// Special character found; split the data at the special character.if (blocks_[index_].written specialIdx Block::BlockSize){std::cerr Error: Not enough space to copy data before special character.\n;return false;}// Copy data up to the special character.std::memcpy(blocks_[index_].buf blocks_[index_].written, buf, specialIdx);blocks_[index_].written specialIdx;// Attempt to acquire a new free block for the special character.if (!nextFree(retry)){if (blocks_[index_].status ! Block::BufUsed){std::cerr Error: Current block status is not BufUsed after finding special character.\n;}return false;}// Update the status and reset the write position for the new block.blocks_[index_].status Block::BufUsing;blocks_[index_].written 0;// Copy the special character to the new block.blocks_[index_].buf[blocks_[index_].written] buf[specialIdx];// If there is remaining data after the special character, copy it to the new block.if (static_castuint32_t(specialIdx 1) length){uint32_t remainingLength length - specialIdx - 1;if (remainingLength Block::BlockSize - blocks_[index_].written){std::cerr Error: Not enough space to copy remaining data after special character.\n;return false;}std::memcpy(blocks_[index_].buf blocks_[index_].written, buf specialIdx 1, remainingLength);blocks_[index_].written remainingLength;}}}return true;}/*** brief Retrieves the currently used block.** return A constant reference to the currently used block.* throws std::out_of_range if the indexUsed_ is invalid.*/const Block currentUsed() const{if (indexUsed_ 0 static_castsize_t(indexUsed_) blocks_.size()){return blocks_[indexUsed_];}throw std::out_of_range(currentUsed(): indexUsed_ is out of range.);}/*** brief Retrieves the block that is currently being used for writing.** return A constant reference to the block currently in use.* throws std::out_of_range if the index_ is invalid.*/const Block currentUsing() const{if (static_castsize_t(index_) blocks_.size()){return blocks_[index_];}throw std::out_of_range(currentUsing(): index_ is out of range.);}/*** brief Releases a block, marking it as free and resetting its written bytes.** param idx The index of the block to release.*/void release(uint32_t idx){if (idx blocks_.size()){blocks_[idx].written 0;blocks_[idx].status Block::BufFree;}else{std::cerr Error: Release index idx is out of bounds.\n;}}/*** brief Retrieves the next used blocks index.** return The index of the next used block, or -1 if no such block exists.*/int32_t nextUsed(){// Check if the current used index is valid and marked as used.if (indexUsed_ 0 static_castsize_t(indexUsed_) blocks_.size() blocks_[indexUsed_].status Block::BufUsed){return indexUsed_;}// Handle wrapping around to the beginning of the ring buffer.if (indexUsed_ static_castint32_t(blockNum_) - 1){if (!blocks_.empty() blocks_[0].status Block::BufUsed){indexUsed_ 0;return indexUsed_;}else{return -1;}}else{// Check the next block in sequence.if ((indexUsed_ 1) static_castint32_t(blockNum_) blocks_[indexUsed_ 1].status Block::BufUsed){indexUsed_ 1;return indexUsed_;}else{return -1;}}}private:/*** brief Attempts to acquire the next free block in the ring buffer.** param retry Flag indicating whether to retry acquiring a free block.* return True if a free block was successfully acquired; false otherwise.*/bool nextFree(bool retry false){// If the current block is free, it can be used.if (blocks_[index_].status Block::BufFree){return true;}else{// If retry is requested and the block is not free, do not attempt further.if (retry){return false;}}// Mark the current block as used since it cannot be reused immediately.blocks_[index_].status Block::BufUsed;// Handle wrapping around to the first block.if (index_ static_castint32_t(blockNum_) - 1){index_ 0;if (blocks_[index_].status ! Block::BufFree){std::cerr Warning: Block 0 is not free.\n;return false;}}else{// Move to the next block in the sequence.index_ 1;if (index_ static_castint32_t(blockNum_)){std::cerr Error: Index exceeded block number.\n;return false;}if (blocks_[index_].status ! Block::BufFree){std::cerr Warning: Block index_ is not free.\n;return false;}}return true;}/*** brief Checks for the presence of special characters in the buffer.** This method scans the buffer for # or $ characters.** param buf Pointer to the buffer to check.* param length Length of the buffer in bytes.* return The index of the first special character found; -1 if none are found.*/int checkSpecial(const uint8_t* buf, uint32_t length) const{for (uint32_t i 0; i length; i){if (buf[i] # || buf[i] $){return static_castint(i);}}return -1;}std::vectorBlock blocks_; /// Vector of blocks managed by the ring buffer.int32_t index_ 0; /// Current index for writing data.int32_t blockNum_ 0; /// Total number of blocks in the ring buffer.int32_t indexUsed_ -1; /// Index of the currently used block.
};