目录

2.实现思想

2.4.简单实现

3.memXXX接口

3.1.memcpy — 内存拷贝

3.2.memmove — 内存移动

3.3.memset — 内存填充

3.4.memchr — 内存查找

3.5.memcmp — 内存比较

4.std::copy -- 范围拷贝


1.模块概述

Buffer 模块是一个基于线性内存空间的缓冲区组件,用于临时存储数据按序取出数据

它通过读写偏移量机制,避免了频繁的数据搬移,同时能够自动处理空间不足的情况

2.实现思想

2.1.内存模型

采用 std::vector<char> 作为底层内存空间,其内部是一块连续的线性内存

string不能够处理\0,所以不采用

2.2.缓冲区核心要素

要素 说明
默认空间大小 缓冲区初始容量,默认为 1024 字节
读偏移量 _reader_idx 标记当前读取位置的相对偏移量
写偏移量 _writer_idx 标记当前写入位置的相对偏移量

偏移量是相对于缓冲区起始地址的相对值,而非绝对内存地址

2.3.数据操作思想

(1)写入数据流程

  1. 从当前写偏移位置开始写入
  2. 检查尾部空闲空间是否足够:足够,直接写入;不足,检查总空闲空间(尾部 + 头部)是否足够(足够:将现有数据搬移到缓冲区起始位置,整理碎片空间;不足:对缓冲区进行扩容)
  3. 写入成功后,写偏移量向后移动

(2)读取数据流程

  1. 从当前读偏移位置开始读取
  2. 可读数据大小 = 写偏移量 - 读偏移量
  3. 读取后,读偏移量向后移动

2.4.简单实现

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

#define BUFFER_DEFAULT_SIZE 1024

class Buffer
{
private:
    std::vector<char> _buffer;//缓冲区
    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* WritePosition() { return Begin() + _writer_idx; }

    //获取当前读取起始地址
    char* ReadPosition() { return Begin() + _reader_idx; }

    //获取末尾空间大小---写偏移之后的空间大小
    uint64_t TailIdleSize() { return _buffer.size() - _writer_idx; }

    //获取头部空间大小---读偏移之前的空间大小
    uint64_t FrontIdleSize() { return _reader_idx; }

    //获取可读数据大小              前闭后开
    uint64_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)
    {
        // 情况1:尾部空间足够,直接返回
        if (len <= TailIdleSize()) {
            return;
        }
        
        uint64_t readable = ReadableSize();
        
        // 情况2:尾部空间不足,但总空闲空间足够(需要整理碎片)
        if (len <= TailIdleSize() + FrontIdleSize()) {
            // 将可读数据移动到缓冲区起始位置
            std::memmove(Begin(), ReadPosition(), readable);
            _reader_idx = 0;
            _writer_idx = readable;
        }
        // 情况3:总空闲空间也不够,需要扩容
        else {
            // 先整理碎片到起始位置,再扩容
            if (_reader_idx > 0) {
                std::memmove(Begin(), ReadPosition(), readable);
                _reader_idx = 0;
                _writer_idx = readable;
            }
            // 扩容到至少能容纳 (readable + len) 字节
            _buffer.resize(readable + len);
        }
    }

    //写入数据
    void Write(const void* data, uint64_t len)
    {
        EnsureWriteSpace(len);
        const char* d = (const char*)data;
        std::copy(d, d + len, WritePosition());
    }

    //移动偏移量
    void WriteAndPush(const void* buf, uint64_t len)
    {
        Write(buf, len);
        MoveWriteOffset(len);
    }

    //复用逻辑
    void WriteString(const std::string& data) { Write(data.c_str(), data.size()); }

    void WriteStringAndPush(const std::string& data)
    {
        WriteString(data);
        MoveWriteOffset(data.size());
    }

    void WriteBuffer(Buffer& data) { Write(data.ReadPosition(), data.ReadableSize()); }

    void WriteBufferAndPush(Buffer& data)
    {
        WriteBuffer(data);
        MoveWriteOffset(data.ReadableSize());
    }


    //读取数据
    void Read(void* buffer, uint64_t len)
    {
        assert(len <= ReadableSize());
        std::copy(ReadPosition(), ReadPosition() + len, (char*)buffer);
    }

    //移动偏移量
    void ReadAndPop(void* buf, uint64_t len)
    {
        Read(buf, len);
        MoveReadOffset(len);
    }

    //强调复用逻辑
    std::string ReadAsString(uint64_t len)
    {
        assert(len <= ReadableSize());
        return  std::string(ReadPosition(), len);
    }

    std::string ReadAsStringAndPop(uint64_t len)
    {
        std::string ret = ReadAsString(len);
        MoveReadOffset(len);

        return ret;
    }

    //查找换行符
    char* FindCRLF()
    {
        char* res = (char*)memchr(ReadPosition(), '\n', ReadableSize());

        return res;
    }

    //针对ASCII字符有效
    std::string Getline()
    {
        char* pos = FindCRLF();
        if(pos == nullptr) return "";

        return ReadAsString(pos - ReadPosition() + 1);
    }

    std::string GetlineAndPop()
    {
        std::string ret = Getline();
        MoveReadOffset(ret.size());

        return ret;
    }

    //清空缓冲区
    void Clear() { _writer_idx = _reader_idx = 0; }
};

3.memXXX接口

3.1.memcpy — 内存拷贝

项目 说明
函数原型 void* memcpy(void* dest, const void* src, size_t n);
头文件 <cstring>
功能 从 src 复制 n 个字节到 dest
参数 dest: 目标地址
src: 源地址
n: 拷贝字节数
返回值 返回 dest 指针
安全性  不安全。若 dest 和 src 内存重叠,行为未定义
适用场景 两块不重叠内存的拷贝,例如缓冲区读写、结构体复制
性能 极快,编译器通常做极致优化
示例 memcpy(write_pos, data, len);

3.2.memmove — 内存移动

项目 说明
函数原型 void* memmove(void* dest, const void* src, size_t n);
头文件 <cstring>
功能 从 src 复制 n 个字节到 dest
参数 dest: 目标地址
src: 源地址
n: 拷贝字节数
返回值 返回 dest 指针
安全性 安全。允许 dest 和 src 内存重叠,内部会判断重叠方向并选择合适拷贝顺序
适用场景 同一块内存内数据的搬移,例如整理碎片、删除中间元素
性能 略慢于 memcpy(因为有重叠判断),但差距极小
示例 memmove(buf, buf + reader_idx, readable);

3.3.memset — 内存填充

项目 说明
函数原型 void* memset(void* str, int c, size_t n);
头文件 <cstring>
功能 将 str 指向内存的前 n 个字节设置为值 c
参数 str: 目标地址
c: 要设置的值(以 int 传入,实际转为 unsigned char
n: 填充字节数
返回值 返回 str 指针
安全性 安全。但需确保 n 不超出有效内存范围
适用场景 初始化内存为 0、填充固定值、清除敏感数据
性能 极快,通常会使用 CPU 特殊指令优化
示例 memset(&obj, 0, sizeof(obj));

3.4.memchr — 内存查找

项目 说明
函数原型 void* memchr(const void* str, int c, size_t n);
头文件 <cstring>
功能 在 str 指向的前 n 个字节中查找字符 c 的首次出现
参数 str: 搜索起始地址
c: 要查找的字符
n: 搜索范围(字节数)
返回值 找到:返回指向该字节的指针
未找到:返回 nullptr
安全性 安全。不会越界访问超出 n 的内存
适用场景 查找分隔符(如 \n)、定位特定标记字节
性能 线性扫描,中等速度。查找大块数据时性能不如专有算法
示例 memchr(buf + read_idx, '\n', readable_size);

3.5.memcmp — 内存比较

项目 说明
函数原型 int memcmp(const void* ptr1, const void* ptr2, size_t n);
头文件 <cstring>
功能 比较 ptr1 和 ptr2 指向的前 n 个字节
参数 ptr1: 第一块内存
ptr2: 第二块内存
n: 比较字节数
返回值 <0ptr1 小于 ptr2
0:相等
>0ptr1 大于 ptr2
安全性 安全。比较前 n 个字节,不会越界
适用场景 二进制数据比较、检查数据是否相同
性能 逐字节比较,大块数据可考虑先比较首字节或哈希
示例 memcmp(buf1, buf2, 16);

memcpy 本身不会检查边界,如果长度不正确,就会发生越界,导致未定义行为

4.std::copy -- 范围拷贝

项目 说明
函数原型 template<class InputIt, class OutputIt> OutputIt std::copy(InputIt first, InputIt last, OutputIt d_first);
头文件 <algorithm>
功能 将 [first, last) 范围内的元素拷贝到以 d_first 为起点的目标区域
参数 first: 源范围起始迭代器
last: 源范围结束迭代器(不包含)
d_first: 目标范围起始迭代器
返回值 指向目标范围最后一个被拷贝元素的下一个位置的迭代器
底层实现 对平凡可复制类型(如 char),编译器通常会优化为 memmove
安全性 若目标范围与源范围重叠且 d_first 在 [first, last) 内,行为未定义
类型安全 编译期检查,无需手动计算字节数,自动推导类型大小
泛型支持 适用于任何满足输入/输出迭代器概念的类型,不仅限于 char*
适用场景 C++ 风格代码,泛型编程,非平凡类型对象的拷贝
性能 平凡类型:与 memmove 相当;非平凡类型:触发赋值运算符,可能较慢
示例 std::copy(d, d + len, WritePosition());

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐