Many new features! Have to be used.

This commit is contained in:
meffi@lab313.ru
2014-02-17 23:30:50 +00:00
commit b84a8264a2
22 changed files with 16228 additions and 0 deletions

309
units/sdStreams.pas Normal file
View File

@@ -0,0 +1,309 @@
{ sdStreams.pas
- TsdFastMemStream with improved capacity setting
- TsdStringStream
- TsdBufferWriter
Author: Nils Haeck M.Sc.
copyright (c) 2002 - 2011 SimDesign BV (www.simdesign.nl)
}
unit sdStreams;
{$ifdef lcl}{$MODE Delphi}{$endif}
{$define simdesign.inc}
interface
uses
Classes, SysUtils, sdDebug;
type
// TsdFastMemStream deals differently with capacity compared to a normal
// TMemoryStream; it increases the capacity with the natural growing function
// (fibonacci) each time, and has an initial capacity of $1000. The initial
// capacity is configurable with the create parameter.
TsdFastMemStream = class(TStream)
private
FMemory: Pointer;
FPosition: longint;
FFib1: longint;
FCapacity: longint;
FSize: longint;
protected
procedure SetCapacity(Value: longint);
procedure SetSize(NewSize: Longint); override;
public
constructor Create(InitialCapacity: longint = $1000);
destructor Destroy; override;
procedure Clear;
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
function Seek(Offset: Longint; Origin: Word): Longint; override;
procedure LoadFromFile(AFilename: string);
procedure LoadFromStream(Stream: TStream);
procedure SaveToFile(AFilename: string);
procedure SaveToStream(Stream: TStream);
property Memory: Pointer read FMemory;
property Size: longint read FSize write SetSize;
end;
// Delphi's implementation of TStringStream is severely flawed, it does a SetLength
// on each write, which slows down everything to a crawl. This implementation over-
// comes this issue.
TsdStringStream = class(TsdFastMemStream)
public
constructor Create(const S: Utf8String);
function DataString: Utf8String;
end;
// TsdBufferWriter is a buffered stream that takes another stream (ASource)
// and writes only buffer-wise to it, and writes to the stream are first
// done to the buffer. This stream type can only support writing.
TsdBufferWriter = class(TsdFastMemStream)
private
FSource: TStream;
FChunkSize: integer;
FRawBuffer: array of byte;
FRawPosition: Integer;
protected
procedure WriteChunk(Count: integer);
public
// Create the buffered writer stream by passing the destination stream in ASource,
// this destination stream must already be initialized.
constructor Create(ASource: TStream; AChunkSize: integer);
destructor Destroy; override;
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
end;
implementation
{ TsdFastMemStream }
procedure TsdFastMemStream.Clear;
begin
SetCapacity(0);
FSize := 0;
FPosition := 0;
end;
constructor TsdFastMemStream.Create(InitialCapacity: Integer);
begin
inherited Create;
FFib1 := InitialCapacity div 2;
FCapacity := InitialCapacity;
if FFib1 < 4 then
FFib1 := 4;
if FCapacity < 4 then
FCapacity := 4;
ReallocMem(FMemory, FCapacity);
end;
destructor TsdFastMemStream.Destroy;
begin
ReallocMem(FMemory, 0);
inherited;
end;
procedure TsdFastMemStream.LoadFromFile(AFilename: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure TsdFastMemStream.LoadFromStream(Stream: TStream);
var
Count: Longint;
begin
Stream.Position := 0;
Count := Stream.Size;
SetSize(Count);
if Count <> 0 then Stream.ReadBuffer(FMemory^, Count);
end;
function TsdFastMemStream.Read(var Buffer; Count: Integer): Longint;
begin
if (FPosition >= 0) and (Count >= 0) then
begin
Result := FSize - FPosition;
if Result > 0 then
begin
if Result > Count then
Result := Count;
Move(Pointer(Longint(FMemory) + FPosition)^, Buffer, Result);
Inc(FPosition, Result);
Exit;
end;
end;
Result := 0;
end;
procedure TsdFastMemStream.SaveToFile(AFilename: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(AFileName, fmCreate);
try
SaveToStream(Stream);
finally
Stream.Free;
end;
end;
procedure TsdFastMemStream.SaveToStream(Stream: TStream);
begin
if FSize <> 0 then Stream.WriteBuffer(FMemory^, FSize);
end;
function TsdFastMemStream.Seek(Offset: Integer; Origin: Word): Longint;
begin
case Origin of
soFromBeginning: FPosition := Offset;
soFromCurrent: Inc(FPosition, Offset);
soFromEnd: FPosition := FSize + Offset;
end;
Result := FPosition;
end;
procedure TsdFastMemStream.SetCapacity(Value: longint);
// Fibonacci 0,1,1,2,3,5,8,... FCapacity is Fib2.
// Fibonacci is a natural growing function where
// 0 + 1 = 1; 1 + 1 = 2; 1 + 2 = 3; 2 + 3 = 5; etc
var
Fib3: longint;
begin
while FCapacity < Value do
begin
Fib3 := FFib1 + FCapacity;
FFib1 := FCapacity;
FCapacity := Fib3;
end;
ReallocMem(FMemory, FCapacity);
end;
procedure TsdFastMemStream.SetSize(NewSize: longint);
var
OldPosition: Longint;
begin
OldPosition := FPosition;
SetCapacity(NewSize);
FSize := NewSize;
if OldPosition > NewSize then
Seek(0, soFromEnd);
end;
function TsdFastMemStream.Write(const Buffer; Count: Integer): Longint;
var
NewPos: Longint;
begin
if (FPosition >= 0) and (Count >= 0) then
begin
NewPos := FPosition + Count;
if NewPos > 0 then
begin
if NewPos > FSize then
begin
if NewPos > FCapacity then
SetCapacity(NewPos);
FSize := NewPos;
end;
System.Move(Buffer, Pointer(Longint(FMemory) + FPosition)^, Count);
FPosition := NewPos;
Result := Count;
Exit;
end;
end;
Result := 0;
end;
{ TsdStringStream }
constructor TsdStringStream.Create(const S: Utf8String);
begin
inherited Create;
SetSize(length(S));
if Size > 0 then
begin
Write(S[1], Size);
Position := 0;
end;
end;
function TsdStringStream.DataString: Utf8String;
begin
SetLength(Result, Size);
if Size > 0 then
begin
Position := 0;
Read(Result[1], length(Result));
end;
end;
{ TsdBufferWriter }
constructor TsdBufferWriter.Create(ASource: TStream; AChunkSize: integer);
begin
inherited Create;
FSource := ASource;
FChunkSize := AChunkSize;
SetLength(FRawBuffer, FChunkSize);
end;
destructor TsdBufferWriter.Destroy;
begin
// write the last chunk, if any
WriteChunk(FRawPosition);
// free the rawbuffer
SetLength(FRawBuffer, 0);
inherited;
end;
function TsdBufferWriter.Read(var Buffer; Count: Integer): Longint;
begin
// not implemented
raise Exception.Create('not implemented');
end;
function TsdBufferWriter.Write(const Buffer; Count: Integer): Longint;
var
Idx, Siz: integer;
begin
// index in the source buffer
Idx := 0;
// remaining size
Siz := Count;
// surplus
while FRawPosition + Siz >= FChunkSize do
begin
Move(TByteArray(Buffer)[Idx], FRawBuffer[FRawPosition], FChunkSize - FRawPosition);
WriteChunk(FChunkSize);
dec(Siz, FChunkSize - FRawPosition);
inc(Idx, FChunkSize - FRawPosition);
FRawPosition := 0;
end;
// copy the raw buffer
Move(TByteArray(Buffer)[Idx], FRawBuffer[FRawPosition], Siz);
inc(FRawPosition, Siz);
Result := Count;
end;
procedure TsdBufferWriter.WriteChunk(Count: integer);
begin
if Count > 0 then
begin
FSource.WriteBuffer(FRawBuffer[0], Count);
end;
end;
end.