プロファイリング中に、かなりの時間がかかる関数に出くわしましたが、基本的には次の非常に単純なコードに要約されます。
function GetSubstring(AInput: PChar; AStart, ASubstringLength: Integer): string;
begin
Result := Copy(AInput, AStart, ASubstringLength);
end;
この関数は予想される部分文字列を返しますが、長い入力に対してはうまくスケーリングしません。CPU ビューでアセンブラ コードを調べたところ、(私は通常、アセンブラ レベルで作業しているわけではありません) わかることから、 をAInput
呼び出す前に暗黙的に文字列に変換されているようCopy
です。
PChar
ただし、この時点では文字列/文字配列の長さは不明であるため、変換コードはnull ターミネータが見つかるまでその長さを移動する必要があります。これにより、より長い入力に対するひどいスケーリングが説明されます。
ただし、呼び出し元は の長さを渡すため、最初はメソッドを変換して代わりPChar
に使用できると考えていました。SetString
function GetSubstring(AInput: PChar; AStart, ASubstringLength: Integer): string;
begin
SetString(Result, AInput + AStart - 1, ASubstringLength);
end;
SetString
ゼロベース (コピーのように 1 ベースではない) の動作に加えてCopy
、入力の検証に関して他にも多くの小さなことが行われているようですが、そのすべてが文書化されているわけではありません (たとえば、1 未満の開始値が変更された場合) 1)に。したがって、上記の単純な実装は、常に元の実装として機能するとは限りません。
この関数はライブラリの一部であり、同僚によって広く使用されているため、私の目標はCopy
ルーチンを可能な限り複製することです。
次の実装がそれを達成するかどうか、または他の警告に注意する必要があるかどうか疑問に思っていますCopy
。注意:は、この関数が含まれるモジュール内の別の部分に由来するFLength
実際の長さです。AInput
この例では、他の部分を削除しました。
function GetSubstring(AInput: PChar; AStart, ASubstringLength: Integer): string;
begin
if (AInput = nil) then begin
Result := '';
end else begin
if (AStart < 1) then begin
AStart := 0;
end else begin
AStart := AStart - 1;
end;
if (ASubstringLength + AStart > FLength) then begin
ASubstringLength := FLength - AStart;
end;
SetString(Result, AInput + AStart, ASubstringLength);
end;
end;
私は Delphi 2006 を使用していますが、これは製品の他のバージョン (少なくとも非 Unicode のもの) とあまり変わらないと思います。