Jedoch wenn dieses Array 1 Mio überschreitet muss es als Ringpuffer weiterarbeiten,
also 0 löschen und alle anderen Werte nachschieben,
Ist zwar schon eine Weile her, aber ich kann mich noch erinnern, daß wir früher, wo Speicherzugriffe noch länger dauerten, einen Ringbuffer so implementiert haben, daß eben keine Daten verschoben werden mussten. Dazu wurde ein Array mit der Größe des Ringbuffers initialisiert und die Daten ganz normal über einen Indexzähler eingelesen. Erreicht der Zähler nun das Ende des Buffers wird er einfach wieder an den Anfang gesetzt und ein Merker gesetzt, der sagt, daß der Ringbuffer voll ist. Ab jetzt markiert der Zähler somit den Anfang des Ringbuffers. Daher auch der Name: man betrachtet die Daten wie einen Ring, auf dem man nur den Index verschiebt.
Will man nun die Daten des Ringbuffers lesen, unterscheidet man einen vollen und einen nicht-vollen Ringbuffer. Beim nicht-vollen wird ganz normal vom Anfang des Arrays bis zum Eintrag
Zähler-1 gelesen. Beim vollen Ringbuffer liest man vom Zähler bis zum Ende des Arrays und hängt dann noch die Werte vom Anfang des Arrays bis zum Eintrag
Zähler-1 dran.
Mit dieser Technik wird zwar das Auslesen des Ringbuffers etwas aufwändiger, aber das Anfügen eines neuen Wertes geht rattenschnell, da nicht jedesmal das ganze Array verschoben werden muss.
Eine einfache Implementation, die für diesen Zweck ausreichen müsste, ware in etwa sowas (nicht komplett durchgetestet!):
Delphi-Quellcode:
unit uRingBuffer;
interface
type
TRingBuffer<T> =
class
private
FData: TArray<T>;
FFull: Boolean;
FIndex: Integer;
function CalcIndex(Value: Integer): Integer;
function GetCount: Integer;
function GetSize: Integer;
public
constructor Create(ASize: Integer);
procedure AddValue(
const AValue: T);
function GetValue(AIndex: Integer): T;
function GetValues(AIndex, ACount: Integer): TArray<T>;
property Count: Integer
read GetCount;
property Size: Integer
read GetSize;
end;
implementation
constructor TRingBuffer<T>.Create(ASize: Integer);
begin
inherited Create;
SetLength(FData, ASize);
FIndex := 0;
FFull := false;
end;
procedure TRingBuffer<T>.AddValue(
const AValue: T);
begin
FData[FIndex] := AValue;
Inc(FIndex);
if FIndex > High(FData)
then begin
FIndex := 0;
FFull := true;
end;
end;
function TRingBuffer<T>.GetValue(AIndex: Integer): T;
begin
Result := FData[CalcIndex(AIndex)];
end;
function TRingBuffer<T>.GetValues(AIndex, ACount: Integer): TArray<T>;
var
idx: Integer;
I: Integer;
begin
Assert(AIndex + ACount <= Count, '
buffer has not enough elements');
SetLength(Result, ACount);
idx := CalcIndex(AIndex);
for I := 0
to ACount - 1
do begin
Result[I] := FData[idx];
Inc(idx);
if idx > High(FData)
then begin
idx := 0;
end;
end;
end;
function TRingBuffer<T>.CalcIndex(Value: Integer): Integer;
begin
Result := Value;
if FFull
then begin
Result := Result + FIndex;
if Result > High(FData)
then begin
Result := Result - Size;
end;
end;
end;
function TRingBuffer<T>.GetCount: Integer;
begin
if FFull
then begin
Result := Size;
end
else begin
Result := FIndex;
end;
end;
function TRingBuffer<T>.GetSize: Integer;
begin
Result := Length(FData);
end;
end.