mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-16 16:59:12 +02:00
* patch by Rika: avoid that capacity of TQueue grows to much for certain
usage patterns, resolves #39662
This commit is contained in:
parent
d748bb6630
commit
4c5fc2f958
@ -358,6 +358,7 @@ type
|
|||||||
constructor Create(AQueue: TQueue<T>);
|
constructor Create(AQueue: TQueue<T>);
|
||||||
end;
|
end;
|
||||||
protected
|
protected
|
||||||
|
function PrepareAddingItem: SizeInt; override;
|
||||||
function GetPtrEnumerator: TEnumerator<PT>; override;
|
function GetPtrEnumerator: TEnumerator<PT>; override;
|
||||||
protected
|
protected
|
||||||
// bug #24287 - workaround for generics type name conflict (Identifier not found)
|
// bug #24287 - workaround for generics type name conflict (Identifier not found)
|
||||||
@ -374,6 +375,7 @@ type
|
|||||||
function GetEnumerator: TEnumerator; reintroduce;
|
function GetEnumerator: TEnumerator; reintroduce;
|
||||||
private
|
private
|
||||||
FLow: SizeInt;
|
FLow: SizeInt;
|
||||||
|
procedure MoveToFront;
|
||||||
protected
|
protected
|
||||||
procedure SetCapacity(AValue: SizeInt); override;
|
procedure SetCapacity(AValue: SizeInt); override;
|
||||||
function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; override;
|
function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; override;
|
||||||
@ -2006,6 +2008,34 @@ end;
|
|||||||
|
|
||||||
{ TQueue<T> }
|
{ TQueue<T> }
|
||||||
|
|
||||||
|
function TQueue<T>.PrepareAddingItem: SizeInt;
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
result := FLength;
|
||||||
|
if result <= High(FItems) then
|
||||||
|
begin
|
||||||
|
FLength := result + 1;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if SizeUint(FLow) >= 4 + SizeUint(result) div 4 then
|
||||||
|
// If the empty space at the beginning is comparable to queue size, convert
|
||||||
|
//
|
||||||
|
// .......QQQQQQQQQ
|
||||||
|
// ↑FLow ↑FLength=length(FItems)
|
||||||
|
//
|
||||||
|
// to
|
||||||
|
//
|
||||||
|
// QQQQQQQQQ.......
|
||||||
|
// ↑FLow=0
|
||||||
|
//
|
||||||
|
// and retry the shortcut above.
|
||||||
|
MoveToFront
|
||||||
|
else
|
||||||
|
exit(inherited);
|
||||||
|
until false;
|
||||||
|
end;
|
||||||
|
|
||||||
function TQueue<T>.GetPtrEnumerator: TEnumerator<PT>;
|
function TQueue<T>.GetPtrEnumerator: TEnumerator<PT>;
|
||||||
begin
|
begin
|
||||||
Result := TPointersenumerator.Create(Self);
|
Result := TPointersenumerator.Create(Self);
|
||||||
@ -2037,6 +2067,21 @@ begin
|
|||||||
Notify(Result, ACollectionNotification);
|
Notify(Result, ACollectionNotification);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TQueue<T>.MoveToFront;
|
||||||
|
var
|
||||||
|
i: SizeInt;
|
||||||
|
begin
|
||||||
|
if FLength > FLow then
|
||||||
|
if IsManagedType(T) then
|
||||||
|
for i := 0 to FLength - FLow - 1 do
|
||||||
|
FItems[i] := FItems[FLow + i]
|
||||||
|
else
|
||||||
|
Move(FItems[FLow], FItems[0], (FLength - FLow) * SizeOf(T));
|
||||||
|
|
||||||
|
FLength := FLength - FLow;
|
||||||
|
FLow := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TQueue<T>.SetCapacity(AValue: SizeInt);
|
procedure TQueue<T>.SetCapacity(AValue: SizeInt);
|
||||||
begin
|
begin
|
||||||
if AValue < Count then
|
if AValue < Count then
|
||||||
@ -2045,15 +2090,8 @@ begin
|
|||||||
if AValue = FLength then
|
if AValue = FLength then
|
||||||
Exit;
|
Exit;
|
||||||
|
|
||||||
if (Count > 0) and (FLow > 0) then
|
MoveToFront;
|
||||||
begin
|
|
||||||
Move(FItems[FLow], FItems[0], Count * SizeOf(T));
|
|
||||||
FillChar(FItems[Count], (FLength - Count) * SizeOf(T), #0);
|
|
||||||
end;
|
|
||||||
|
|
||||||
SetLength(FItems, AValue);
|
SetLength(FItems, AValue);
|
||||||
FLength := Count;
|
|
||||||
FLow := 0;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TQueue<T>.GetCount: SizeInt;
|
function TQueue<T>.GetCount: SizeInt;
|
||||||
|
24
tests/webtbs/tw39662.pp
Normal file
24
tests/webtbs/tw39662.pp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
uses Generics.Collections;
|
||||||
|
|
||||||
|
var
|
||||||
|
Queue: specialize TQueue<Integer>;
|
||||||
|
I, J: Integer;
|
||||||
|
begin
|
||||||
|
Queue := specialize TQueue<Integer>.Create;
|
||||||
|
|
||||||
|
for I := 0 to 15 do
|
||||||
|
Queue.Enqueue(I);
|
||||||
|
for I := 1 to 10000 do
|
||||||
|
begin
|
||||||
|
for J := 1 to 15 do
|
||||||
|
Queue.Dequeue;
|
||||||
|
for J := 1 to 15 do
|
||||||
|
Queue.Enqueue(J);
|
||||||
|
end;
|
||||||
|
|
||||||
|
WriteLn(Queue.Capacity);
|
||||||
|
{ avoid too large capacities }
|
||||||
|
if Queue.Capacity>64 then
|
||||||
|
halt(1);
|
||||||
|
Queue.Free;
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user