瀏覽代碼

* TutlReadBufferStream => TutlPagedBufferStream, offers the same functionality for reading *and* writing

master
Martok 10 年之前
父節點
當前提交
80546477e7
共有 1 個檔案被更改,包括 100 行新增 和 65 行删除
  1. +100
    -65
      uutlStreamHelper.pas

+ 100
- 65
uutlStreamHelper.pas 查看文件

@@ -11,7 +11,7 @@ unit uutlStreamHelper;
interface

uses
Classes, Contnrs, syncobjs;
SysUtils, Classes, Contnrs, syncobjs;

type
TutlFourCC = string[4];
@@ -72,21 +72,23 @@ type
procedure WriteLine(A: AnsiString);
end;

{ TutlReadBufferStream }
{ TutlPagedBufferStream }

TutlReadBufferStream = class(TStream)
TutlPagedBufferStream = class(TOwnerStream)
public const
DEFAULT_BUFLEN = 4096*16;
private
FBaseStream: TStream;
FBuffer: Pointer;
FBufferValid: boolean;
FBufferStart, FBufferLen, FBufferAvail: Int64;
FPosition: int64;
FOwnsStream: Boolean;
FVirtualSize, FVirtualPosition: Int64;
FBuffer: TBytes;
FBufferStart: Int64;
FBufferModified: boolean;
protected
function GetSize: Int64; override;
procedure SetSize(const NewSize: Int64); override;
procedure ReMapBuffer;
procedure FlushBuffer;
public
constructor Create(const BaseStream: TStream; const BufferSize: Cardinal; const aOwnsStream: Boolean = false);
constructor Create(const BaseStream: TStream; const BufferSize: Cardinal = DEFAULT_BUFLEN; const aOwnsStream: Boolean = false);
destructor Destroy; override;
function Read(var Buffer; Count: Integer): Integer; override;
function Write(const Buffer; Count: Integer): Integer; override;
@@ -138,7 +140,7 @@ type

implementation

uses SysUtils,RtlConsts, uutlExceptions;
uses RtlConsts, uutlExceptions, Math;

type
TPositionData = class
@@ -378,96 +380,129 @@ begin
WriteAnsiBytes(A + sLineBreak);
end;

{ TutlReadBufferStream }
{ TutlPagedBufferStream }

constructor TutlReadBufferStream.Create(const BaseStream: TStream; const BufferSize: Cardinal;
constructor TutlPagedBufferStream.Create(const BaseStream: TStream; const BufferSize: Cardinal;
const aOwnsStream: Boolean);
begin
inherited Create;
FBaseStream:= BaseStream;
FBufferLen:= BufferSize;
FBuffer:= GetMemory(FBufferLen);
FOwnsStream := aOwnsStream;
FPosition:= 0;
inherited Create(BaseStream);
SourceOwner:= aOwnsStream;
SetLength(FBuffer, BufferSize);
FVirtualPosition:= 0;
FVirtualSize:= Source.Size;
FBufferStart:= -1;
ReMapBuffer;
end;

destructor TutlReadBufferStream.Destroy;
destructor TutlPagedBufferStream.Destroy;
begin
FBufferValid:= false;
if (FOwnsStream) then
FBaseStream.Free;
FreeMemory(FBuffer);
FlushBuffer;
SetLength(FBuffer, 0);
inherited;
end;

function TutlReadBufferStream.Seek(Offset: Integer; Origin: Word): Integer;
function TutlPagedBufferStream.Seek(Offset: Integer; Origin: Word): Integer;
begin
case Origin of
soFromBeginning: FPosition := Offset;
soFromCurrent: Inc(FPosition, Offset);
soFromEnd: FPosition := Size + Offset;
end;
Result := FPosition;
soFromBeginning: FVirtualPosition := Offset;
soFromCurrent: Inc(FVirtualPosition, Offset);
soFromEnd: FVirtualPosition := Size + Offset;
end;
ReMapBuffer;
Result := FVirtualPosition;
end;

function TutlReadBufferStream.GetSize: Int64;
function TutlPagedBufferStream.GetSize: Int64;
begin
Result:= FBaseStream.Size;
Result:= FVirtualSize;
end;

procedure TutlReadBufferStream.SetSize(const NewSize: Int64);
procedure TutlPagedBufferStream.SetSize(const NewSize: Int64);
begin
FBaseStream.Size:= NewSize;
FVirtualSize:= NewSize;
Source.Size:= NewSize;
if Position > FVirtualSize then
Position:= FVirtualSize;
end;

function TutlReadBufferStream.Write(const Buffer; Count: Integer): Integer;
function TutlPagedBufferStream.Write(const Buffer; Count: Integer): Integer;
var
bw, c: Int64;
bp: Pointer;
begin
FBufferValid:= false;
FBaseStream.Position:= FPosition;
Result:= FBaseStream.Write(Buffer, Count);
FPosition:= FBaseStream.Position;
bw:= 0;
bp:= @Buffer;
while (bw < Count) do begin
ReMapBuffer;
// Wie viel Daten können wir schreiben?
c:= Min(Count - bw, Length(FBuffer) - (FVirtualPosition-FBufferStart));

// das schreiben und buffer weiterschieben
Move(bp^, FBuffer[FVirtualPosition-FBufferStart], c);
Inc(Bp, c);
Inc(bw, c);
Inc(FVirtualPosition, c);
if FVirtualPosition > FVirtualSize then
FVirtualSize:= FVirtualPosition;
end;
if bw > 0 then
FBufferModified:= true;
Result:= bw;
end;

function TutlReadBufferStream.Read(var Buffer; Count: Integer): Integer;
function TutlPagedBufferStream.Read(var Buffer; Count: Integer): Integer;
var
rp, br, c: Int64;
br, c: Int64;
bp: Pointer;
begin
br:= 0;
bp:= @Buffer;
while (br < Count) and (FPosition<Size) do begin
// Welches Buffer-Segment wird gesucht?
rp:= (FPosition div FBufferLen) * FBufferLen;
// ist das das aktuelle?
if not FBufferValid or (FBufferStart <> rp) then begin
// Segment holen
FBaseStream.Position:= rp;
FBufferAvail:= FBaseStream.Read(FBuffer^, FBufferLen);
FBufferStart:= rp;
FBufferValid:= true;
end;

while (br < Count) and (FVirtualPosition<FVirtualSize) do begin
ReMapBuffer;
// Wie viel Daten daraus brauchen wir bzw. können wir kriegen?
c:= Count - br;
if c > FBufferAvail - (FPosition-FBufferStart) then
c:= FBufferAvail - (FPosition-FBufferStart);
c:= Min(Min(Count - br, Length(FBuffer) - (FVirtualPosition-FBufferStart)), FVirtualSize - FVirtualPosition);

// das rausholen und buffer weiterschieben
{$IFDEF FPC}
// FPC: kein Cast, direkt mit Pointer in richtiger Größe rechnen
Move(Pointer(FBuffer + (FPosition-FBufferStart))^, bp^, c);
Move(FBuffer[FVirtualPosition-FBufferStart], bp^, c);
Inc(Bp, c);
{$ELSE}
// Delphi ist eh nur i386, also fix 32bit
Move(Pointer(Cardinal(FBuffer) + (FPosition-FBufferStart))^, bp^, c);
Inc(Cardinal(Bp), c);
{$ENDIF}
Inc(br, c);
Inc(FPosition, c);
Inc(FVirtualPosition, c);
end;
Result:= br;
end;

procedure TutlPagedBufferStream.ReMapBuffer;
var
newbs: Int64;
inbuf: Int64;
begin
// Welches Buffer-Segment wird gesucht?
newbs:= (FVirtualPosition div Length(FBuffer)) * Length(FBuffer);
// ist das das aktuelle?
if FBufferStart <> newbs then begin
FlushBuffer;
// Segment holen
Source.Position:= newbs;
inbuf:= Min(Length(FBuffer), FVirtualSize - newbs);
Source.ReadBuffer(FBuffer[0], inbuf);
FBufferStart:= newbs;
FBufferModified:= false;
end;
end;

procedure TutlPagedBufferStream.FlushBuffer;
var
towrite: Int64;
begin
if not FBufferModified then
// Nothing to do
Exit;

Source.Position:= FBufferStart;
towrite:= Min(Length(FBuffer), FVirtualSize - FBufferStart);
Source.WriteBuffer(FBuffer[0], towrite);
end;

{ TutlFIFOStream }

constructor TutlFIFOStream.Create(const aLockFree: boolean);


Loading…
取消
儲存