TStringBuilder.Append calls SetLength on each and every call. And SetLength contains a try-except block that is always activated.

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

Comments

  1. min/max is clearly premature optimization here: not the biggest bottleneck, for sure! ;)

    ReplyDelete
  2. Not a huge bottleneck, but measurable.
    I've optimized just about everything I could find. Including eliminating the hidden nil checks on Value when calling move. Also length and capacity now read directly from the field instead of through a getter. The original was basically death by needlepricks, thus every individual change is only a small optimization. Only together do they add up to a serious %.

    ReplyDelete

Post a Comment