字符读写缓冲区封装
功能需求:
- 对一个文件描述符进行读写操作,需要可自动调整大小的缓冲区
实现思路:
- 容器:std::vector buff
- 操作:
- 维护读写两个指针记录当前读写位置,
- 扩容:若写指针达到当前buff尾,且数据未读完
- 缩减:每次操作完成,重置缓冲区
头文件
#ifndef BUFFER_H
#define BUFFER_H
#include <cstring>
#include <iostream>
#include <unistd.h>
#include <sys/uio.h>
#include <vector>
#include <atomic>
#include <assert.h>
class Buffer {
public:
Buffer(int initBuffSize = 1024);
~Buffer() = default;
size_t WritableBytes() const;
size_t ReadableBytes() const ;
size_t PrependableBytes() const;
const char* Peek() const;
void EnsureWriteable(size_t len);
void HasWritten(size_t len);
void Retrieve(size_t len);
void RetrieveUntil(const char* end);
void RetrieveAll() ;
std::string RetrieveAllToStr();
const char* BeginWriteConst() const;
char* BeginWrite();
void Append(const std::string& str);
void Append(const char* str, size_t len);
void Append(const void* data, size_t len);
void Append(const Buffer& buff);
ssize_t ReadFd(int fd, int* Errno);
ssize_t WriteFd(int fd, int* Errno);
private:
char* BeginPtr_();
const char* BeginPtr_() const;
void MakeSpace_(size_t len);
std::vector<char> buffer_;
std::atomic<std::size_t> readPos_;
std::atomic<std::size_t> writePos_;
};
#endif
源文件
#include "buffer.h"
Buffer::Buffer(int initBuffSize) : buffer_(initBuffSize), readPos_(0), writePos_(0) {}
size_t Buffer::ReadableBytes() const {
return writePos_ - readPos_;
}
size_t Buffer::WritableBytes() const {
return buffer_.size() - writePos_;
}
size_t Buffer::PrependableBytes() const {
return readPos_;
}
const char* Buffer::Peek() const {
return BeginPtr_() + readPos_;
}
void Buffer::Retrieve(size_t len) {
assert(len <= ReadableBytes());
readPos_ += len;
}
void Buffer::RetrieveUntil(const char* end) {
assert(Peek() <= end );
Retrieve(end - Peek());
}
void Buffer::RetrieveAll() {
bzero(&buffer_[0], buffer_.size());
readPos_ = 0;
writePos_ = 0;
}
std::string Buffer::RetrieveAllToStr() {
std::string str(Peek(), ReadableBytes());
RetrieveAll();
return str;
}
const char* Buffer::BeginWriteConst() const {
return BeginPtr_() + writePos_;
}
char* Buffer::BeginWrite() {
return BeginPtr_() + writePos_;
}
void Buffer::HasWritten(size_t len) {
writePos_ += len;
}
void Buffer::Append(const std::string& str) {
Append(str.data(), str.length());
}
void Buffer::Append(const void* data, size_t len) {
assert(data);
Append(static_cast<const char*>(data), len);
}
void Buffer::Append(const char* str, size_t len) {
assert(str);
EnsureWriteable(len);
std::copy(str, str + len, BeginWrite());
HasWritten(len);
}
void Buffer::Append(const Buffer& buff) {
Append(buff.Peek(), buff.ReadableBytes());
}
void Buffer::EnsureWriteable(size_t len) {
if(WritableBytes() < len) {
MakeSpace_(len);
}
assert(WritableBytes() >= len);
}
ssize_t Buffer::ReadFd(int fd, int* saveErrno) {
char buff[65535];
struct iovec iov[2];
const size_t writable = WritableBytes();
iov[0].iov_base = BeginPtr_() + writePos_;
iov[0].iov_len = writable;
iov[1].iov_base = buff;
iov[1].iov_len = sizeof(buff);
const ssize_t len = readv(fd, iov, 2);
if(len < 0) {
*saveErrno = errno;
}
else if(static_cast<size_t>(len) <= writable) {
writePos_ += len;
}
else {
writePos_ = buffer_.size();
Append(buff, len - writable);
}
return len;
}
ssize_t Buffer::WriteFd(int fd, int* saveErrno) {
size_t readSize = ReadableBytes();
ssize_t len = write(fd, Peek(), readSize);
if(len < 0) {
*saveErrno = errno;
return len;
}
readPos_ += len;
return len;
}
char* Buffer::BeginPtr_() {
return &*buffer_.begin();
}
const char* Buffer::BeginPtr_() const {
return &*buffer_.begin();
}
void Buffer::MakeSpace_(size_t len) {
if(WritableBytes() + PrependableBytes() < len) {
buffer_.resize(writePos_ + len + 1);
}
else {
size_t readable = ReadableBytes();
std::copy(BeginPtr_() + readPos_, BeginPtr_() + writePos_, BeginPtr_());
readPos_ = 0;
writePos_ = readPos_ + readable;
assert(readable == ReadableBytes());
}
}
测试代码1
#include "../buffer/buffer.h"
#include <sys/time.h>
#include <iostream>
int main()
{
Buffer buff_;
buff_.RetrieveAll();
buff_.Append("Hello world!",10);
buff_.Append("???",10);
buff_.Append("+++",10);
for(auto c : buff_.RetrieveAllToStr())
{
std::cout<<c<<"" ;
}
}
测试代码2
#include "../buffer/buffer.h"
#include <sys/time.h>
#include <iostream>
int main()
{
Buffer buff_;
buff_.RetrieveAll();
struct timeval now = {0, 0};
gettimeofday(&now, nullptr);
time_t tSec = now.tv_sec;
struct tm *sysTime = localtime(&tSec);
struct tm t = *sysTime;
int n = snprintf(buff_.BeginWrite(), 128, "%d-%02d-%02d %02d:%02d:%02d.%06ld ",
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
t.tm_hour, t.tm_min, t.tm_sec, now.tv_usec);
buff_.HasWritten(n);
buff_.Append("\n\0", 2);
for(auto c : buff_.RetrieveAllToStr())
{
std::cout<<c<<"";
}
}
引用
- 源代码:https://github.com/Aged-cat/WebServer