在Delphi的早期版本中,并没有提供UnicodeString,而WideString缓慢的性能使许多使用宽字符串的应用性能不高。本文提供了一种方法,来优化早期的宽字符串速度。
【注意】本文并没有完整实现所有需要的方法,如果您有兴趣,自己实现剩下的部分吧。
我们知道WideString速度慢的一个重要原因是没有引用计数,因此,需要字符串的频率拷贝处理,造成系统性能低下,我们就从此入口,提升性能。
同时,由于WideString是内置类型,其分配和释放系统自动来决定,我们的实现也应达到这个要求。我们知道interface会自动管理计数器,而结构中的interface,Delphi也会自动管理生命周期,所以,下面的示例代码就是用了这样一个技巧,我们来看声明:
IQStringW=interface
procedure From(S:WideString);overload;
procedure From(p:PWideChar;len:NativeInt);overload;
function Copy:IQStringW;
function Data:PWideChar;
function Length:Integer;
end;
TQStringW=class(TInterfacedObject,IQStringW)
private
FData:array of WideChar;
public
procedure From(S:WideString);overload;
procedure From(p:PWideChar;len:NativeInt);overload;
function Copy:IQStringW;
function Data:PWideChar;
function Length:Integer;
end;
QStringW=record
private
Data:IQStringW;
public
class operator Implicit(const S:WideString):QStringW;
class operator Implicit(const p:PWideChar):QStringW;
class operator Implicit(const S:QStringW):PWideChar;
class operator Implicit(const S:QStringW):WideString;
function Copy:QStringW;
end;我们的QStringW是一个记录,内部唯一的数据成员Data是一个IQStringW接口,这样赋值时,记录将自动管理Data的引用计数,至于下面的一些重载,仅仅是演示,实际应用还需要重载更多的操作符,以方便操作。下面是实现的代码:
{ QStringW }
class operator QStringW.Implicit(const p: PWideChar): QStringW;
begin
Result.Data:=TQStringW.Create;
Result.Data.From(String(p));
end;
class operator QStringW.Implicit(const S: WideString): QStringW;
begin
Result.Data:=TQStringW.Create;
Result.Data.From(S);
end;
class operator QStringW.Implicit(const S: QStringW): WideString;
begin
if Assigned(S.Data) then
Result:=System.Copy(S.Data.Data,0,S.Data.Length)
else
SetLength(Result,0);
end;
class operator QStringW.Implicit(const S: QStringW): PWideChar;
begin
if Assigned(S.Data) then
Result:=S.Data.Data
else
Result:=nil;
end;
function QStringW.Copy: QStringW;
begin
if Assigned(Data) then
Result.Data:=Data.Copy
else
Result.Data:=nil;
end;
{ TQStringW }
function TQStringW.Copy: IQStringW;
var
AResult:TQStringW;
L:NativeInt;
begin
AResult:=TQStringW.Create;
L:=System.Length(FData);
SetLength(AResult.FData,L);
if L>0 then
Move(FData[0],AResult.FData[0],L shl 1);
Result:=AResult;
end;
function TQStringW.Data: PWideChar;
begin
Result:=PWideChar(@FData[0]);
end;
procedure TQStringW.From(S: WideString);
var
L:NativeInt;
begin
L:=System.Length(S);
SetLength(FData,L+1);
if L>0 then
Move(PWideChar(S)^,FData[0],L shl 1);
FData[L]:=#0;
end;
procedure TQStringW.From(p: PWideChar; len: NativeInt);
begin
if len<0 then
From(String(p))
else
begin
SetLength(FData,len+1);
if len>0 then
Move(p^,FData[0],len shl 1);
FData[len]:=#0;
end;
end;
function TQStringW.Length: Integer;
begin
Result:=System.Length(FData);
end;由于我们只实现了赋值操作值,那么我们对比下赋值的性能:
var
S,S1:QStringW;
WS,WS1:WideString;
U,US1:UnicodeString;
I: Integer;
T1,T2,T3:DWord;
begin
S:='Hello,world';
WS:='Hello,world';
U:='Hello,world';
T1:=GetTickCount;
for I := 0 to 1000000 do
S1:=S;
T1:=GetTickCount-T1;
T2:=GetTickCount;
for I := 0 to 1000000 do
WS1:=WS;
T2:=GetTickCount-T2;
T3:=GetTickCount;
for I := 0 to 1000000 do
US1:=U;
T3:=GetTickCount-T3;
ShowMessage('QStringW='+IntToStr(T1)+'ms,WideString='+IntToStr(T2)+'ms,UnicodeString='+IntToStr(T3)+'ms');
end;
为了对比Delphi2009后的UnicodeString性能,上面的测试代码在XE6 Update1上执行,并加入UnicodeString对比,结果如下:

