TStringBuilder.
TStringBuilder.Append calls SetLength on each and every call. And SetLength contains a try-except block that is always activated.
*Faulty code*
procedure TStringBuilder.SetLength(Value: Integer);
var
LOldLength: Integer;
begin
if Value < 0 then
raise ERangeError.CreateResFmt(@SParamIsNegative, ['Value']); // DO NOT LOCALIZE
if Value > MaxCapacity then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
LOldLength := FLength;
try
FLength := Value;
if FLength > Capacity then
ExpandCapacity;
except
on E: EOutOfMemory do
begin
FLength := LOldLength;
raise;
end;
end;
end;
*Improved code*
property Capacity: NativeUInt read FCapacity write SetCapacity;
procedure TStringBuilder.SetLength(Value: NativeUInt);
begin
if Value > Capacity then ExpandCapacity(Value);
FLength:= Value;
end;
procedure TStringBuilder.SetCapacity(Value: NativeUInt);
begin
if Value < Length then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
if Value > FMaxCapacity then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
System.SetLength(FData, Value);
FCapacity:= Value;
end;
Personally I'd remove the try entirely, I don't believe it's possible to recover from OoM, but with this simple change the TStringBuilder is much much faster.
Please vote for issue: https://quality.embarcadero.com/browse/RSP-19178
https://quality.embarcadero.com/browse/RSP-19178
*Faulty code*
procedure TStringBuilder.SetLength(Value: Integer);
var
LOldLength: Integer;
begin
if Value < 0 then
raise ERangeError.CreateResFmt(@SParamIsNegative, ['Value']); // DO NOT LOCALIZE
if Value > MaxCapacity then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
LOldLength := FLength;
try
FLength := Value;
if FLength > Capacity then
ExpandCapacity;
except
on E: EOutOfMemory do
begin
FLength := LOldLength;
raise;
end;
end;
end;
*Improved code*
property Capacity: NativeUInt read FCapacity write SetCapacity;
procedure TStringBuilder.SetLength(Value: NativeUInt);
begin
if Value > Capacity then ExpandCapacity(Value);
FLength:= Value;
end;
procedure TStringBuilder.SetCapacity(Value: NativeUInt);
begin
if Value < Length then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
if Value > FMaxCapacity then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
System.SetLength(FData, Value);
FCapacity:= Value;
end;
Personally I'd remove the try entirely, I don't believe it's possible to recover from OoM, but with this simple change the TStringBuilder is much much faster.
Please vote for issue: https://quality.embarcadero.com/browse/RSP-19178
https://quality.embarcadero.com/browse/RSP-19178
Comments
Post a Comment