#pragma once
#include <corecrt_memory.h>
#include <list>
#include <mutex>
#define BLOCK_BUFFER_SIZE 4096
#define INIT_BLOCK_SIZE 2
class CBlock
{
public:
CBlock() :
_headOffset(0),
_tailOffset(0)
{}
~CBlock() {}
static CBlock* create()
{
return new CBlock;
}
void destroy()
{
delete this;
}
int write(char* buffer, int size)
{
int remaindSize = getRemaindSize();
int copySize = size > remaindSize ? remaindSize : size;
memcpy(_buffer + _tailOffset, buffer, copySize);
return copySize;
}
int read(char* buffer, int size)
{
int useSize = getUseSize();
int copySize = size > useSize ? useSize : size;
memcpy(buffer,_buffer + _headOffset , copySize);
return copySize;
}
int getUseSize()
{
return _tailOffset - _headOffset;
}
int getRemaindSize()
{
return BLOCK_BUFFER_SIZE - _tailOffset;
}
bool empty()
{
return _headOffset == _tailOffset;
}
bool full()
{
return _tailOffset >= BLOCK_BUFFER_SIZE;
}
void clear()
{
_headOffset = 0;
_tailOffset = 0;
}
void setHeadOffset(int offset)
{
_headOffset += offset;
}
void setTailOffset(int offset)
{
_tailOffset += offset;
}
private:
int _headOffset;
int _tailOffset;
char _buffer[BLOCK_BUFFER_SIZE];
};
class CBlockBuffer
{
public:
CBlockBuffer(int initSize = INIT_BLOCK_SIZE);
~CBlockBuffer();
static CBlockBuffer* create()
{
return new CBlockBuffer;
}
void destroy();
int write(char* buffer,int totalSize);
int read(char* buffer, int totalSize);
int readNotMove(char* buffer, int totalSize);
void reset();
std::mutex& getMutex() { return _mx; }
int getUseSize() { return m_useSize; }
private:
CBlock* allocBlock();
private:
std::list<CBlock*> m_useBlockList;
std::list<CBlock*> m_freeBlockList;
int m_useSize;
std::mutex _mx;
};
#include "BlockBuffer.h"
CBlockBuffer::CBlockBuffer(int initSize)
:m_useSize(0)
{
m_useBlockList.clear();
m_freeBlockList.clear();
for (int index = 0 ;index < initSize; ++index)
{
CBlock* block = CBlock::create();
if (block)
{
m_freeBlockList.push_back(block);
}
}
}
void CBlockBuffer::destroy()
{
while (!m_useBlockList.empty())
{
CBlock* tmp = m_useBlockList.front();
if (tmp)
{
delete tmp;
}
m_useBlockList.pop_front();
}
m_useBlockList.clear();
while (!m_freeBlockList.empty())
{
CBlock* tmp = m_freeBlockList.front();
if (tmp)
{
delete tmp;
}
m_freeBlockList.pop_front();
}
m_freeBlockList.clear();
}
CBlockBuffer::~CBlockBuffer()
{
destroy();
}
CBlock* CBlockBuffer::allocBlock()
{
if (m_freeBlockList.empty())
{
return CBlock::create();
}
else
{
CBlock* tmp = m_freeBlockList.front();
m_freeBlockList.pop_front();
m_freeBlockList.clear();
return tmp;
}
}
int CBlockBuffer::write(char* buffer, int totalSize)
{
int lastSize = totalSize;
//寫入到最後一個block
if (!m_useBlockList.empty())
{
CBlock* tmp = m_useBlockList.back();
if (tmp)
{
int writeSize = tmp->write(buffer, lastSize);
tmp->setTailOffset(writeSize);
lastSize -= writeSize;
buffer += writeSize;
}
}
//沒寫完就申請一個block繼續寫入
while (lastSize > 0)
{
CBlock* tmp = allocBlock();
if (tmp )
{
int writeSize = tmp->write(buffer, lastSize);
tmp->setTailOffset(writeSize);
lastSize -= writeSize;
buffer += writeSize;
m_useBlockList.push_back(tmp);
}
else
{
break;
}
}
m_useSize += (totalSize - lastSize);
return totalSize - lastSize;
}
int CBlockBuffer::readNotMove(char* buffer, int totalSize)
{
int lastSize = totalSize;
while (lastSize > 0)
{
if (m_useBlockList.empty())
{
break;
}
CBlock* tmp = m_useBlockList.front();
if (tmp)
{
int readSize = tmp->read(buffer, lastSize);
lastSize -= readSize;
buffer += readSize;
if (tmp->empty())
{
tmp->clear();
m_useBlockList.pop_front();
m_freeBlockList.push_back(tmp);
}
}
}
return totalSize - lastSize;
}
int CBlockBuffer::read(char* buffer, int totalSize)
{
int lastSize = totalSize;
while (lastSize > 0)
{
if (m_useBlockList.empty())
{
break;
}
CBlock* tmp = m_useBlockList.front();
if (tmp)
{
int readSize = tmp->read(buffer, lastSize);
tmp->setHeadOffset(readSize);
lastSize -= readSize;
buffer += readSize;
if (tmp->empty())
{
tmp->clear();
m_useBlockList.pop_front();
m_freeBlockList.push_back(tmp);
}
}
}
m_useSize -= (totalSize - lastSize);
return totalSize - lastSize;
}
void CBlockBuffer::reset()
{
while (!m_useBlockList.empty())
{
CBlock* tmp = m_useBlockList.front();
if (tmp)
{
tmp->clear();
m_freeBlockList.push_back(tmp);
}
m_useBlockList.pop_front();
}
m_useBlockList.clear();
m_useSize = 0;
}