⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ucircularbuffer.pas

📁 楠楠写的DBiocp例子都是源码
💻 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 + -