Wednesday, November 17, 2004

Fast String Append in Delphi

I don't normally put code in this blog, but bear with me on this one, it's a good one!

I needed to append a lot of strings together really quickly; I was sitting in a loop, getting strings from another function, and appending them to a result string. These strings weren't small, and the loop was going round 20,000 times; the operation took 10 minutes. Blah. There must be a better way.

I built the class below, and implemented using it. Now it takes about 2 seconds. Fantastic!

It's a simple thing, but pretty damned useful if you are building up big XML as I was.

Here it is:



TFastStringAppend = class
private
arrchar: Array of Char;
flength: integer;
fcapacity: integer;
function GetResultString: string;
public
constructor create;
procedure Append(astr: String);
property ResultString: string read GetResultString;
end;

{ TFastStringAppend }

procedure TFastStringAppend.Append(astr: String);
var
newlength: integer;
begin
newlength := flength + length(astr);
if newlength > fcapacity then
begin
fcapacity := round(newlength * 1.5);
setlength(arrchar, fcapacity + 1);
end;

strpcopy(@arrchar[flength], astr);
flength := newlength;
arrchar[flength] := char(0);
end;

constructor TFastStringAppend.create;
begin
setlength(arrchar, 1);
arrchar[0] := char(0);
flength := 0;
fcapacity := 0;
end;

function TFastStringAppend.GetResultString: string;
begin
result := pchar(@arrchar[0]);
end;



You use it as follows:



function GetAReallyBigString: string;
var
fsa: TFastStringAppend;
begin
try
fsa := TFastStringAppend.create;
// fsa is initialised holding the empty string
for t := 0 to 19999 do
begin
// function SomeFunkyString(i: integer): string;
fsa.Append(SomeFunkyString(t));
end;
// and here's the mighty result string!
result := fsa.ResultString;
finally
FreeAndNil(fsa.free); // FreeAndNil is in Sysutils
end;
end;


2 Comments:

At 10:46 AM, Blogger Jon Roder said...

Nice one. Should have a positive effect on memory allocation / fragmentation also. Can I recommend you add a fillfactor property to the class (replacing the static 1.5 value), that way when you know you are going to put heaps of stuff in there, you can reduce the number of memory reallocations.

 
At 10:57 AM, Blogger Unknown said...

Yes, that'd be a nice extension. I leave it as an exercise to the reader :-)

 

Post a Comment

<< Home