📄 ucircularbuffer.pas
字号:
unit uCircularBuffer;
interface
uses
Windows, uCriticalSection;
type
TCircularBuffer = class
private
m_pBuffer : PByte;
m_nBufSize : Integer;
m_CirBufferLock: TCriticalSection;
m_HeadPos: Integer;
m_TailPos: Integer;
m_bThreadSafe: Boolean; //线程安全
published
property FThreadSafe: Boolean read m_bThreadSafe write m_bThreadSafe;
procedure SetEmpty; //重置Buffer
private
procedure Lock;
procedure UnLock;
function GetValidCount: Integer; //得到有效缓冲区大小(已占用)
procedure BufferResize; //Buffer增加
function IsOverFlowBuffer(nLen: Integer): Boolean; //要写入的长度是否溢出环形Buffer
function IsIndexOverFlow(nLen: Integer): Boolean; //索引是否溢出需要从0开始写数据
function HeadPosInc(nStep: Integer): Boolean; //移动m_HeadPos位置
public
procedure WriteCirBuffer(pBuffer: PChar; m_nBufLen: Integer); //向环形Buffer写入数据
procedure GetBufferData(pBuffer: PChar; m_nBufLen: Integer); //仅仅读出数据,并不移动环形Buffer指针
function ReadCirBuffer(pOutBuffer: PChar): Integer; //从环形Buffer读出数据(移动位置)
public
constructor Create(nSize: Integer);
destructor Destroy; override;
end;
implementation
uses SysUtils, uFileLogger;
constructor TCircularBuffer.Create(nSize: Integer);
begin
inherited Create;
m_bThreadSafe := FALSE;
m_nBufSize := nSize;
m_pBuffer := nil;
GetMem(m_pBuffer, m_nBufSize);
ZeroMemory(m_pBuffer, m_nBufSize);
m_HeadPos := 0;
m_TailPos := 0;
m_CirBufferLock := TCriticalSection.Create;
//_FileLogger.WriteLogMsg('原始数据:'+ m_pBuffer );
end;
destructor TCircularBuffer.Destroy;
begin
Lock;
FreeMem(m_pBuffer, m_nBufSize);
UnLock;
FreeAndNil(m_CirBufferLock);
inherited Destroy;
end;
procedure TCircularBuffer.Lock;
begin
if m_bThreadSafe then m_CirBufferLock.Lock;
end;
procedure TCircularBuffer.UnLock;
begin
if m_bThreadSafe then m_CirBufferLock.UnLock;
end;
procedure TCircularBuffer.SetEmpty;
begin
m_HeadPos := 0;
m_TailPos := 0;
end;
//得到有效缓冲区大小(已占用)
function TCircularBuffer.GetValidCount: Integer;
var
m_ValidCount: Integer;
begin
try
Lock;
m_ValidCount := m_TailPos - m_HeadPos; //尾部-头部
if ( m_ValidCount<0 ) then
m_ValidCount := m_nBufSize + m_ValidCount;
Result := m_ValidCount;
finally
UnLock;
end;
end;
//Buffer增加
procedure TCircularBuffer.BufferResize;
var
m_pNewBuffer: PByte;
m_nPrevBufSize: Integer;
begin
try
Lock;
//得到原环形Buffer大小
m_nPrevBufSize := m_nBufSize;
m_nBufSize := m_nBufSize shl 1;
//分配2倍大小缓冲
GetMem(m_pNewBuffer, m_nBufSize);
ZeroMemory(m_pNewBuffer, m_nBufSize);
//拷贝原数据到新分配的缓冲区位置
CopyMemory(Pointer(LongInt(m_pNewBuffer)),
Pointer(LongInt(m_pBuffer)),
m_nPrevBufSize);
//如果尾小于头,说明已经m_nBufSize之后从索引0开始到m_iTailPos之间是
//上一个环形Buffer的数据(mod之后),现在因为缓冲区变大,这部分数据应
//该放在真正的m_nPrevBufSize大小之后。
if (m_TailPos < m_HeadPos) then begin
//目的缓冲区位置:m_pNewBuffer+m_nPrevBufSize
CopyMemory( Pointer(LongInt(m_pNewBuffer)+m_nPrevBufSize),
Pointer(LongInt(m_pBuffer)),
m_TailPos );
//修改尾位置
m_TailPos := m_TailPos + m_nPrevBufSize;
end;
//释放原缓冲区数据
FreeMem(m_pBuffer, m_nPrevBufSize);
m_pBuffer := m_pNewBuffer;
{
_FileLogger.WriteLogMsg('BufferResize->数据:'+ m_pBuffer +
' 头位置:'+IntToStr(m_HeadPos)+
' 尾位置:'+IntToStr(m_TailPos)+
' 缓冲区大小:'+IntToStr(m_nBufSize));
}
finally
UnLock;
end;
end;
//要写入的长度是否溢出环形Buffer
function TCircularBuffer.IsOverFlowBuffer(nLen: Integer): Boolean;
begin
try
Lock;
Result := nLen>= m_nBufSize-GetValidCount();
finally
UnLock;
end;
end;
//索引是否溢出需要从0开始写数据
function TCircularBuffer.IsIndexOverFlow(nLen: Integer): Boolean;
begin
try
Lock;
Result := nLen + m_TailPos >= m_nBufSize;
finally
UnLock;
end;
end;
//移动m_HeadPos位置
function TCircularBuffer.HeadPosInc(nStep: Integer): Boolean;
begin
Result := FALSE;
if ( nStep<= GetValidCount ) then begin
m_HeadPos := m_HeadPos + nStep;
m_HeadPos := m_HeadPos mod m_nBufSize;
Result := m_HeadPos <> m_TailPos;
end;
end;
//向环形Buffer写入数据
procedure TCircularBuffer.WriteCirBuffer(pBuffer: PChar; m_nBufLen: Integer);
var
m_tmpBuffer: PChar;
m_nFirstCopySize: Integer;
m_nSecondCopySize: Integer;
begin
if m_nBufLen <= 0 then Exit;
try
Lock;
while IsOverFlowBuffer(m_nBufLen) do BufferResize;
if IsIndexOverFlow(m_nBufLen) then begin
//尾部需要拷贝的长度
m_nFirstCopySize := m_nBufSize - m_TailPos;
//头部需要拷贝的长度
m_nSecondCopySize := m_nBufLen - m_nFirstCopySize;
//拷贝到尾
CopyMemory( Pointer(LongInt(m_pBuffer)+m_TailPos),
Pointer(LongInt(pBuffer)),
m_nFirstCopySize );
if (m_nSecondCopySize>0) then begin
//拷贝到头
CopyMemory( Pointer(LongInt(m_pBuffer)),
Pointer(LongInt(pBuffer)+m_nFirstCopySize),
m_nSecondCopySize);
m_TailPos := m_nSecondCopySize;
end
else
m_TailPos := 0;
end
else
begin
//如果未溢出,直接把数据附加到尾部
CopyMemory( Pointer(LongInt(m_pBuffer)+m_TailPos),
Pointer(LongInt(pBuffer)),
m_nBufLen );
m_TailPos := m_TailPos + m_nBufLen;
end;
{
_FileLogger.WriteLogMsg('WriteCirBuffer->数据:'+ m_pBuffer +
' 写入数据:'+pBuffer+
' 头位置:'+IntToStr(m_HeadPos)+
' 尾位置:'+IntToStr(m_TailPos)+
' 缓冲区大小:'+IntToStr(m_nBufSize));
}
finally
UnLock;
end;
end;
//仅仅读出数据,并不移动环形Buffer指针
procedure TCircularBuffer.GetBufferData(pBuffer: PChar; m_nBufLen: Integer);
var
m_nFirstCopySize: Integer;
m_nSecondCopySize: Integer;
begin
if not ((m_nBufLen>0) and (m_nBufLen<=GetValidCount)) then Exit;
try
Lock;
//1 2 3 4 5 m_nBufSize = 5 m_HeadPos = 3 m_nBufLen =1时
//即长度在m_HeadPos之内的,可一次拷贝完整
//如果长度在(m_nBufSize - m_HeadPos)为
if (m_nBufLen < m_nBufSize - m_HeadPos) then begin
CopyMemory( Pointer(LongInt(pBuffer)),
Pointer(LongInt(m_pBuffer)+m_HeadPos),
m_nBufLen );
end
else
begin
//1 2 3 4 5 m_nBufSize = 5 m_HeadPos = 3 m_nBufLen =4时
m_nFirstCopySize := m_nBufSize - m_HeadPos;
m_nSecondCopySize := m_nBufLen - m_nFirstCopySize;
CopyMemory( Pointer(LongInt(pBuffer)),
Pointer(LongInt(m_pBuffer)+m_HeadPos),
m_nFirstCopySize );
if (m_nSecondCopySize>0) then begin
CopyMemory( Pointer(LongInt(pBuffer)+m_nFirstCopySize),
Pointer(LongInt(m_pBuffer)),
m_nSecondCopySize );
end;
end;
finally
UnLock;
end;
end;
//从环形Buffer读出数据(移动位置)
function TCircularBuffer.ReadCirBuffer(pOutBuffer: PChar): Integer;
var
m_VaildLen: Integer;
m_nFirstCopySize: Integer;
m_nSecondCopySize: Integer;
begin
try
Lock;
m_VaildLen := GetValidCount;
//有效数据>长度-头定位情况下,说明需要二次拷贝
if (m_VaildLen>(m_nBufSize - m_HeadPos)) then begin
//尾部需要拷贝的长度
m_nFirstCopySize := m_nBufSize - m_HeadPos;
//头部需要拷贝的长度
m_nSecondCopySize := m_TailPos;
//拷贝尾部数据
CopyMemory( Pointer(LongInt(pOutBuffer)),
Pointer(LongInt(m_pBuffer)+m_HeadPos),
m_nFirstCopySize );
if (m_nSecondCopySize>0) then begin
//拷贝头部数据
CopyMemory( Pointer(LongInt(pOutBuffer)+m_nFirstCopySize),
Pointer(LongInt(m_pBuffer)),
m_nSecondCopySize );
end;
//头部移动到相应位置
m_HeadPos := m_nSecondCopySize;
end
else
begin
CopyMemory( Pointer(LongInt(pOutBuffer)),
Pointer(LongInt(m_pBuffer)+m_HeadPos),
m_VaildLen );
m_HeadPos := m_HeadPos +m_VaildLen;
if (m_HeadPos = m_nBufSize) then m_HeadPos := 0;
end;
Result := m_VaildLen;
{
_FileLogger.WriteLogMsg('ReadCirBuffer->数据:'+ m_pBuffer +
' 读出数据:'+pOutBuffer+
' 头位置:'+IntToStr(m_HeadPos)+
' 尾位置:'+IntToStr(m_TailPos)+
' 缓冲区大小:'+IntToStr(m_nBufSize));
}
finally
UnLock;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -