#pragma once
#include<vector>
#include<string>
class Buffer
{
public:
static const size_t kCheapPrepend = 8;
static const size_t kInitiaSize = 1024;
explicit Buffer(size_t initialSize = kInitiaSize)
: buffer_(kCheapPrepend+kInitiaSize)
, readerIndex_(kCheapPrepend)
, writerIndex_(kCheapPrepend)
{}
size_t readableBytes() const
{
return writerIndex_-readerIndex_;
}
size_t writableBytes() const
{
return buffer_.size()-writerIndex_;
}
size_t prependableBytes() const
{
return readerIndex_;
}
const char* peek() const
{
return begin()+readerIndex_;
}
void retrieve(size_t len)
{
if(len<readableBytes())
{
readerIndex_+=len;
}
else
{
retrieveAll();
}
}
void retrieveAll()
{
readerIndex_=writerIndex_=kCheapPrepend;
}
std::string retrieveAllAsString()
{
return retrieveAsString(readableBytes());
}
std::string retrieveAsString(size_t len)
{
std::string result(peek(),len);
retrieve(len);
return result;
}
void ensuerWriteableBytes(size_t len)
{
if(writableBytes()<len)
{
makeSpace(len);
}
}
void append(const char*data,size_t len)
{
ensuerWriteableBytes(len);
std::copy(data,data+len,beginWrite());
writerIndex_+=len;
}
char* beginWrite()
{
return begin()+writerIndex_;
}
const char* beginWrite()const
{
return begin()+writerIndex_;
}
ssize_t readFd(int fd,int *saveErrno);
ssize_t writeFd(int fd,int*saveErrno);
private:
char* begin()
{
return &*buffer_.begin();
}
const char* begin() const
{
return &*buffer_.begin();
}
void makeSpace(size_t len)
{
if(writableBytes() + prependableBytes()<len + kCheapPrepend)
{
buffer_.resize(writerIndex_+len);
}
else
{
size_t readable = readableBytes();
std::copy(begin()+readableBytes(),
begin()+writerIndex_,
begin()+kCheapPrepend);
readerIndex_=kCheapPrepend;
writerIndex_=kCheapPrepend+readable;
}
}
std::vector<char> buffer_;
size_t readerIndex_;
size_t writerIndex_;
};
#include "Buffer.h"
#include <errno.h>
#include <sys/uio.h>
#include <unistd.h>
ssize_t Buffer::readFd(int fd, int* saveErrno)
{
char extrabuf[65536] = {0};
struct iovec vec[2];
const size_t writable = writableBytes();
vec[0].iov_base = begin() + writerIndex_;
vec[0].iov_len = writable;
vec[1].iov_base = extrabuf;
vec[1].iov_len = sizeof extrabuf;
const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1;
const ssize_t n = ::readv(fd, vec, iovcnt);
if (n < 0)
{
*saveErrno = errno;
}
else if (n <= writable)
{
writerIndex_ += n;
}
else
{
writerIndex_ = buffer_.size();
append(extrabuf, n - writable);
}
return n;
}
ssize_t Buffer::writeFd(int fd, int* saveErrno)
{
ssize_t n = ::write(fd, peek(), readableBytes());
if (n < 0)
{
*saveErrno = errno;
}
return n;
}