目录
缓冲区功能分析
缓冲区空间分配策略分析
数据设计和函数介绍
完整代码
接口介绍
个人主页:东洛的克莱斯韦克-CSDN博客
缓冲区功能分析
1.可以向缓冲区写入数据
2.可用从缓冲区读取数据
3.可用窥探数据——把数据拷贝给上层,但缓冲区数据不减少
4.可以读取一行——以\n \r\n \r 结尾算一行
5.可以获取缓冲区可读数据的大小
6.可以清空缓冲区,数据
缓冲区空间分配策略分析
空间划分:
缓冲区初始值为1024个字节,用两个下标(分别是读下标和写下标)把空间分为三段。
第一段:0下标到读下标(左闭右开),这段为剩余空间
第二段:读下标到写下标(左闭右开),这段为可读数据
第三段:写下标到空间末尾(左闭右开),这段为剩余空间
扩容策略:
1.写入数据的大小小于等于第三段空间,直接写入
2.写入的数据的大小小于等于第一段空间大小加第三段空间大小,把可读数据拷贝到空间的开头,在写入数据
3,写入的数据大小大于等于第一段空间大小加第三段空间大小,直接扩容,然后在第三段写入数据。
上述策略中的第二点,是为了不让空间一直扩容,扩容很大概率都是异地扩容,也需要拷贝,这是有代价的。
数据设计和函数介绍
底层的容器用std::vector<char>类型。两个下标用uint64_t类型
【C++】详解STL容器之一的 vector_c++ vector扩容缩容-CSDN博客
std::vector<char> _buff; //缓冲区uint64_t _read_pos; //读下标uint64_t _write_pos; //写下标
拷贝数据用std::copy,第一个参数:从哪里拷贝的起始地址,第二个参数:从哪里拷贝的末尾地址,第三参数:从拷贝到哪里的起始地址。
查找字符用C语言的strchr,第一个参数:一段空间的起始地址,第二个参数:要查找字符的ASCII,找到了返回字符的地址,失败返回nullptr
完整代码
#include <vector>
#include <cstdint>
#include <assert.h>
#include <algorithm>
#include <string>
#include <iostream>
#include <cstring>#define BUFF_MAX_SIZE 1024 //容器大小的初始值class Buff{private:std::vector<char> _buff; //缓冲区uint64_t _read_pos; //读下标uint64_t _write_pos; //写下标private://获取容器起始地址char* GetInitPos(){ return &( *_buff.begin()); }//获取读位置地址char* GetReadPos(){ return GetInitPos() + _read_pos; }//获取写位置地址char* GetWritePos(){ return GetInitPos() + _write_pos; }//缓冲区读位置之后有多少空闲空间,把空间分为了三段,第一段uint64_t FirstParagraphV(){ return _read_pos; }//可读数据大小,第二段uint64_t SecondParagraphV(){ return _write_pos - _read_pos; }//缓冲区写位置之前有多少空闲空间,第三段uint64_t ThirdParagraphV(){ return _buff.capacity() - _write_pos; }//读偏移移动void MoveReadPos(uint64_t len){assert(len <= SecondParagraphV());_read_pos += len;}//写偏移移动void MoveWritePos(uint64_t len){assert(len <= ThirdParagraphV());_write_pos += len;}//确保足够空间void EnsureSpaceEnough(uint64_t len){if (len <= ThirdParagraphV()){return;} else if ( len <= FirstParagraphV() + ThirdParagraphV()){std::copy(GetReadPos(), GetWritePos(), GetInitPos());_write_pos = SecondParagraphV();_read_pos = 0;}else{ _buff.reserve(_buff.capacity() + len); }}public://构造Buff():_read_pos(0), _write_pos(0), _buff(BUFF_MAX_SIZE){ }//可读数据大小]uint64_t ReadSize(){ return SecondParagraphV(); }//写入数据void Write(const char* date, uint64_t len){EnsureSpaceEnough(len); //确保空间足够std::copy(date, date + len, GetWritePos()); //写入数据MoveWritePos(len); //移动下标}void Write(const std::string& date, uint64_t len){ Write(&date[0], len); }void Write(Buff& date, uint64_t len){ Write(date.GetReadPos(), len); }//窥探数据void pry(char* buf, uint64_t len){assert(len <= SecondParagraphV());std::copy(GetReadPos(), GetReadPos() + len, buf);}void pry(std::string& buf, uint64_t len){ pry(&(*buf.begin()), len); }void pry(Buff& buf, uint64_t len){ pry(buf.GetWritePos(), len); }//读取数据void Read(char* buf, uint64_t len){assert(len <= SecondParagraphV());std::copy(GetReadPos(), GetReadPos() + len, buf);MoveReadPos(len);}void Read(std::string& buf, uint64_t len){ Read(&(*buf.begin()), len); }void Read(Buff& buf, uint64_t len){ Read(buf.GetWritePos(), len); }//读取一行bool ReadLen(std::string& str){//\n \r\n /rchar c = '\n';char* pos_ptr = strchr(GetInitPos(), c);if (nullptr == pos_ptr){c = '\r';pos_ptr = strchr(GetInitPos(), c);if (nullptr == pos_ptr){return false;}else{std::copy(GetInitPos(), pos_ptr, &(*str.begin()));MoveReadPos(pos_ptr - GetInitPos());return true;} return false;}else{std::copy(GetInitPos(), pos_ptr, &(*str.begin()));MoveReadPos(pos_ptr - GetInitPos()); return true;}}//清空缓冲区void Clear(){_read_pos = 0;_write_pos = 0;}
};
接口介绍
ReadSize:获取缓冲区可读数据的大小
Write:向缓冲区写入数据,第一个参数是从哪里写入,可以是char* std::string Buff,第二个参数是写入数据的大小
pry:从缓冲区窥探数据,第一个参数是把数据读到哪里,可以是char* std::string Buff,第二个参数是写入数据的大小
Read:从缓冲区读取数据,第一个参数是把数据读到哪里,可以是char* std::string Buff,第二个参数是写入数据的大小
ReadLen:从缓冲区读取一行
Clear:清理缓冲区