Buffer缓冲区类设计实现

news2024/10/7 20:35:03

目录

类设计理念

类设计接口函数

类设计函数实现

测试

正常读取与写入

相同类型拷贝

扩容测试

按行读取


类设计理念

类设计接口函数

#include <vector>
#include <cstdint>

#define BUFFER_DEFAULT_SIZE 1024    // Buffer 默认起始大小
class Buffer
{
private:
    std::vector<char> _buffer; // 使用vector进行内存空间管理
    uint64_t _reader_idx;      // 读偏移
    uint64_t _writer_idx;      // 写偏移
public:
    Buffer() : _reader_idx(0), _writer_idx(0), _buffer(BUFFER_DEFAULT_SIZE) {}
    // 获取当前写入起始地址
    void *WirtePosition();
    // 获取当前读取起始地址
    void *ReadPosition();
    // 获取缓冲区末尾空闲空间大小--写偏移之后的空闲空间
    uint64_t TailIdleSize();
    // 获取缓冲区起始空闲空间大小--读偏移之前的空闲空间
    uint64_t HeadIdleSize();
    // 获取可读数据大小
    uint16_t ReadAbleSize();
    // 将读偏移向后移动
    void MoveReadOffset(uint64_t len);
    // 将写偏移向后移动
    void MoveWriteOffset(uint64_t len);
    // 确保可写空间足够(整体空闲空间够了就移动数据。否则就扩容)
    void EnsureWriteSpace(uint64_t len);
    // 写入数据
    void Write(void *data, uint64_t len);
    // 读取数据
    void Read(void *buf, uint64_t len);
    // 清空缓冲区
    void Clear();
};

类设计函数实现

#include <iostream>
#include <vector>
#include <cstdint>
#include <cassert>
#include <string>
#include <cstring>

#define BUFFER_DEFAULT_SIZE 1024 // Buffer 默认起始大小
class Buffer
{
private:
    std::vector<char> _buffer; // 使用vector进行内存空间管理
    uint64_t _reader_idx;      // 读偏移
    uint64_t _writer_idx;      // 写偏移
public:
    Buffer() : _reader_idx(0), _writer_idx(0), _buffer(BUFFER_DEFAULT_SIZE) {}
    char *Begin() { return &*_buffer.begin(); }
    // 获取当前写入起始地址
    char *WirtePosition() { return Begin() + _writer_idx; }
    // 获取当前读取起始地址
    char *ReadPosition() { return Begin() + _reader_idx; }
    // 获取缓冲区末尾空闲空间大小--写偏移之后的空闲空间, 总体空间大小减去写偏移
    uint64_t TailIdleSize() { return _buffer.size() - _writer_idx; }
    // 获取缓冲区起始空闲空间大小--读偏移之前的空闲空间
    uint64_t HeadIdleSize() { return _reader_idx; }
    // 获取可读数据大小 = 写偏移 - 读偏移
    uint16_t ReadAbleSize() { return _writer_idx - _reader_idx; };
    // 将读偏移向后移动
    void MoveReadOffset(uint64_t len)
    {
        // 向后移动的大小, 必须小于可读数据大小
        assert(len <= ReadAbleSize());
        _reader_idx += len;
    }
    // 将写偏移向后移动
    void MoveWriteOffset(uint64_t len)
    {
        // 向后移动的大小,必须小于当前后边的空闲空间大小
        assert(len <= TailIdleSize());
        _writer_idx += len;
    }
    // 确保可写空间足够(整体空闲空间够了就移动数据,否则就扩容)
    void EnsureWriteSpace(uint64_t len)
    {
        // 如果末尾空闲空间大小足够,直接返回
        if (len <= TailIdleSize())
        {
            return;
        }
        // 末尾空闲空间不够,则判断加上起始位置的空闲空间大小是否足够,够了就将数据移动到起始位置
        if (len <= TailIdleSize() + HeadIdleSize())
        {
            // 将数据移动到起始位置
            uint64_t rsz = ReadAbleSize();                            // 把当前数据大小先保存起来
            std::copy(ReadPosition(), ReadPosition() + rsz, Begin()); // 把可读数据拷贝到起始位置
            _reader_idx = 0;                                          // 将读偏移归0
            _writer_idx = rsz;                                        // 将写位置置为可读数据大小, 因为当前的可读数据大小就是写偏移量
        }
        else
        {
            // 总体空间不够,则需要扩容,不移动数据,直接给写偏移之后扩容足够空间即可
            _buffer.resize(_writer_idx + len);
        }
    }
    // 写入数据
    void Write(const void *data, uint64_t len)
    {
        // 1.保证有足够空间, 2.拷贝数据进去
        EnsureWriteSpace(len);
        const char *d = (const char *)data;
        std::copy(d, d + len, WirtePosition());
    }
    void WirteAndPush(const void *data, uint64_t len)
    {
        Write(data, len);
        MoveWriteOffset(len);
    }
    void WriteString(const std::string &data)
    {
        return Write(data.c_str(), data.size());
    }
    void WriteStringAndPush(const std::string &data)
    {
        WriteString(data);
        MoveWriteOffset(data.size());
    }
    void WriteBuffer(Buffer &data)
    {
        return Write(data.ReadPosition(), data.ReadAbleSize());
    }
    void WirteBufferAndPush(Buffer &data)
    {
        WriteBuffer(data);
        MoveWriteOffset(data.ReadAbleSize());
    }
    // 读取数据
    void Read(void *buf, uint64_t len)
    {
        // 要求获取的数据大小必须小于可读数据大小
        assert(len <= ReadAbleSize());
        std::copy(ReadPosition(), ReadPosition() + len, (char*)buf);
    }
    void ReadAndPop(void *buf, uint64_t len)
    {
        Read(buf, len);
        MoveReadOffset(len);
    }
    std::string ReadAsString(uint64_t len)
    {
        // 要求获取的数据大小必须小于可读数据大小
        assert(len <= ReadAbleSize());
        std::string str;
        str.resize(len);
        Read(&str[0], len); // 这里不直接用str.c_str()的原因是,这个的返回值是const类型
        return str;
    }
    std::string ReadAsStringAndPop(uint64_t len)
    {
        assert(len <= ReadAbleSize());
        std::string str = ReadAsString(len);
        MoveReadOffset(len);
        return str;
    }
    char *FindCRLF()
    {
        char *res = (char*)memchr(ReadPosition(), '\n', ReadAbleSize());
        return res;
    }
    //这种情况针对的是,通常获取一行数据
    std::string GetLine()
    {
        char *pos = FindCRLF();
        if(pos == nullptr)
            return "";
        // +1 是为了把换行字符也取出来
        return ReadAsString(pos - ReadPosition() + 1);
    }
    std::string GetLineAndPop()
    {
        std::string str = GetLine();
        MoveReadOffset(str.size());
        return str;
    }

    // 清空缓冲区
    void Clear()
    {
        // 只需要将偏移量归0即可
        _reader_idx = 0;
        _writer_idx = 0;
    }
};

测试

正常读取与写入

符合预期

相同类型拷贝

符合预期

扩容测试

符合预期

按行读取

程序正常退出,符合预期(不符合会死循环)

最后附上makefile

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1423396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis -- String 字符串, 计数命令,字符串操作

"学如逆水行舟&#xff0c;不进则退。" 目录 Redis的String字符串 常见命令 set get mget mset setnx setex psetex 计数命令 incr incrby decr decrby incrbyfloat 字符串操作 append getrange setrange strlen 小结 string内部编码 Redis…

全方面解析msvcp110.dll文件的修复教程,六个修复msvcp110.dll文件丢失问题的详细方法

msvcp110.dll是一个动态链接库文件&#xff0c;它是Microsoft Visual C 2012 Redistributable Package&#xff08;微软视觉C 2012重新分配包&#xff09;的一部分。这个文件主要包含了C标准库中的一些函数&#xff0c;特别是与内存管理、异常处理、字符串处理和数学计算相关的…

部署YUM仓库服务

一、yum仓库 1. yum简介 yum是一个基于RPM包&#xff08;是Red-Hat Package Manager红帽软件包管理器的缩写&#xff09;构建的软件更新机制&#xff0c;能够自动解决软件包之间的依赖关系。 为什么会有依赖关系的发生 因为linux本身就是以系统简洁为自身优势&#xff0c;所以…

动态gif制作方法是什么?一个网站在线制作

一般我们说的gif动图就是动态图片是一种图片格式。Gif动图就是由一帧一帧的静态画面合成一张有动态效果的图片。接下来。给大家讲一讲gif生成&#xff08;https://www.gif.cn/&#xff09;的方法吧&#xff01;很简单不需要下载软件&#xff0c;手机、pc均可操作&#xff0c;只…

Unity触发检测Trigger踩坑合集

正常状态 绿色方块&#xff1a;刚体碰撞盒检测触发碰撞脚本 蓝色方块&#xff1a;碰撞盒 检测脚本&#xff1a; 正常进出&#xff1a; 踩坑1 绿色方块&#xff1a;刚体碰撞盒检测触发碰撞脚本 蓝色方块&#xff1a;碰撞盒 保持绿色和蓝色方块的接触 对蓝色方块&#xff1a…

87.网游逆向分析与插件开发-物品使用-物品交换的逆向分析与C++封装

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;物品丢弃的逆向分析与C代码的封装-CSDN博客 码云地址&#xff08;ui显示角色数据 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本号&#xff1a;5222a6b1e5…

程序员的新风口,来了?

过去几年逐渐沉寂的程序员培训行业&#xff0c;现在重新热闹了起来。 作为一家IT培训机构的课程顾问&#xff0c;小娜发现&#xff0c;最近一段时间&#xff0c;咨询鸿蒙开发课程的人越来越多了&#xff0c;为了能够及时回复&#xff0c;我整理了一份话术&#xff0c;以便快速摸…

Qt Excel读写 - QXlsx的安装配置以及测试

Qt Excel读写 - QXlsx的安装配置以及测试 引言一、安装配置二、简单测试 引言 Qt无自带的库处理Excel 文件&#xff0c;但可通过QAxObject 借助COM接口进行Excel的读写1。亦可使用免费的开源第三方库&#xff1a;QXlsx&#xff0c;一个基于Qt库开发的用于读写Microsoft Excel文…

存储监控工具:监控存储区域网络(SAN)

从托管应用程序到提供大型多媒体服务&#xff0c;组织都依靠其 IT 基础架构来提供无与伦比的最终用户体验。为了提供这种卓越的体验&#xff0c;必须大大提高应用程序的可用性和性能。在许多其他挑战中&#xff0c;存储区域网络 &#xff08;SAN&#xff09; 正好用于应对这些挑…

Fiddler-02使用

文章目录 一、Fiddler的作用二、Fiddler抓取https请求三、Fiddler过滤请求1、案例一2、案例二3、过滤页面介绍4、总结 四、Fiddler删除数据五、Fiddler接口基础概述六、Fiddler请求响应报文详解1、请求2、响应 七、Fiddler定位前后端的问题八、Fiddler弱网测试方式一&#xff1…

(十六)串口UART

文章目录 UART简介传输数据帧和波特率定时器1作为串口1波特率发生器串口部分相关寄存器TMODAUXRPCONSCONSBUF 串口1工作模式1&#xff1a;8位UART&#xff0c;波特率可变总体工作原理如何简单接收一个字符和发送数据一步之遥的设置现象演示 UART简介 通用异步收发传输器(Unive…

程序员每天会阅读哪些技术网站来提升自己?

我有一个很特别的习惯……每周会固定一天去看一下接单网站上的高薪单子&#xff0c;不完全是为了接单&#xff0c;而是看现在稀缺的岗位是什么…… 其实很多程序员对外包接单都有误解&#xff0c;觉得外包接单平台上的项目都是一些边缘的、没人愿意干的项目&#xff0c;虽然这类…

好用的制造业项目管理工具推荐:提升生产效率与项目成功的关键利器

有什么好用的制造业项目管理工具&#xff1f;制造业作为传统行业&#xff0c;经常会采用项目制管理模式&#xff0c;项目管理对制造业的重要性不言而喻。2024年制造业企业面对国内依然激烈的竞争&#xff0c;想要进一步发展&#xff0c;不仅要对外谋取&#xff0c;也要对内优化…

【LLM多模态】Cogview3、DALL-E3、CogVLM、CogVideo模型

note 文章目录 noteVisualGLM-6B模型图生文&#xff1a;CogVLM-17B模型1. 模型架构2. 模型效果 文生图&#xff1a;CogView3模型DALL-E3模型CogVideo模型网易伏羲-丹青模型Reference VisualGLM-6B模型 VisualGLM 是一个依赖于具体语言模型的多模态模型&#xff0c;而CogVLM则是…

2024年【中级消防设施操作员(考前冲刺)】考试题及中级消防设施操作员(考前冲刺)考试报名

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 中级消防设施操作员&#xff08;考前冲刺&#xff09;考试题参考答案及中级消防设施操作员&#xff08;考前冲刺&#xff09;考试试题解析是安全生产模拟考试一点通题库老师及中级消防设施操作员&#xff08;考前冲刺…

[PHP]严格类型

PHP: 类型声明 - Manual

如何有效获取 Go 变量类型?探索多种方法

嗨&#xff0c;大家好&#xff01;本文是系列文章 Go 小技巧第九篇&#xff0c;系列文章查看&#xff1a;Go 语言小技巧。 文章目录 Go 的类型系统类型获取使用 fmt.Printf类型选择类型选择反射 reflect.TypeOf 其他注意点错误处理性能考量 总结 在 Python 中&#xff0c;可以使…

SpringBoot项目logback日志配置

Session 认证和 Token 认证 过滤器和拦截器 SpringBoot统一返回和统一异常处理 SpringBoot项目logback日志配置 程序运行出现错误时&#xff0c;第一时间想到的是甩锅还是日志&#xff1f;通过查看日志定位出问题的位置&#xff0c;才能更好的甩锅&#xff0c;今天就来学习…

Mastercam 2024 下载安装教程,流程简单,小白也能轻松搞定,附安装包和工具

前言 Mastercam是一款高效专业的实用型CAD/CAM设计辅助工具&#xff0c;集二维绘图、三维实体造型、曲面设计、体素拼合、数控编程、刀具路径模拟及真实感模拟等多种功能于一身&#xff0c;能够帮助用户轻松设计各种复杂的曲线、曲面零件、刀具路径等。 准备工作 1、Win10及…

Python爬虫:数据获取requests

1. 基本用法 1.1. 安装requests库 pip3 install requests 1.2. 发送HTTP请求 requests.request(method, url, **kwargs) 1.3. 发送GET请求 requests.get(url, paramsNone, **kwargs) 1.4. 发送POST请求 requests.post(url, dataNone, jsonNone, **kwargs) 1.5. 发送PU…