Delphi早期版本WideString的替代解决方案

    在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对比,结果如下:

分享到: