Einzelnen Beitrag anzeigen

TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.079 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: TEdit + Steuerzeichen + XML = Exception

  Alt 3. Jul 2025, 12:50
Na gut, es würde alles noch ein bisschen schneller gehen, wenn man bis zum Maximum optimiert:

Code:
Debug Output: Original TStringBuilder: 53,99 ms Process Project1.exe (27340)
Debug Output: Optimiert mit PChar: 48,4411 ms Process Project1.exe (27340)
Debug Output: Direkter Zugriff: 27,047 ms Process Project1.exe (27340)
Debug Output: Direkter Zugriff 2: 16,019 ms Process Project1.exe (27340)
Debug Output: Direkter Zugriff 3: 12,4765 ms Process Project1.exe (27340)
Delphi-Quellcode:
function SanitizeXML_Original(const AValue: String): String;
var
  i: Integer;
  LChr: Char;
  LStrBldr: TStringBuilder;
begin
  LStrBldr := TStringBuilder.Create;
  try
    for i := 1 to Length(AValue) do
    begin
      LChr := AValue[i];
      if (LChr = #9) or (LChr = #10) or (LChr = #13) or
         ((LChr >= #32) and (LChr <= #$D7FF)) or
         ((LChr >= #$E000) and (LChr <= #$FFFD)) then
        LStrBldr.Append(LChr);
    end;
    Result := LStrBldr.ToString;
  finally
    LStrBldr.Free;
  end;
end;

function SanitizeXML_PChar(const AValue: String): String;
var
  Src, SrcEnd: PChar;
  LStrBldr: TStringBuilder;
  C: Char;
begin
  LStrBldr := TStringBuilder.Create(Length(AValue));
  try
    Src := PChar(AValue);
    SrcEnd := Src + Length(AValue);
    while Src < SrcEnd do
    begin
      C := Src^;
      if (C = #9) or (C = #10) or (C = #13) or
         ((C >= #32) and (C <= #$D7FF)) or
         ((C >= #$E000) and (C <= #$FFFD)) then
        LStrBldr.Append(C);
      Inc(Src);
    end;
    Result := LStrBldr.ToString;
  finally
    LStrBldr.Free;
  end;
end;

function SanitizeXML_Direct(const AValue: String): String;
var
  Src: PChar;
  Dest: PChar;
  Len, i: Integer;
  C: Char;
begin
  Len := Length(AValue);
  SetLength(Result, Len);
  Src := PChar(AValue);
  Dest := PChar(Result);

  for i := 0 to Len - 1 do
  begin
    C := Src[i];
    if (C = #9) or (C = #10) or (C = #13) or
       ((C >= #32) and (C <= #$D7FF)) or
       ((C >= #$E000) and (C <= #$FFFD)) then
    begin
      Dest^ := C;
      Inc(Dest);
    end;
  end;

  SetLength(Result, Dest - PChar(Result));
end;

function SanitizeXML_Direct_2(const AValue: String): String;
var
  Src: PChar;
  Dest: PChar;
  Len, i: Integer;
  C: Char;
begin
  Len := Length(AValue);
  SetLength(Result, Len);
  Src := PChar(AValue);
  Dest := PChar(Result);

  for i := 0 to Len - 1 do
  begin
    C := Src[i];
    case C of
      #9, #10, #13, #32..#$D7FF, #$E000..#$FFFD:
      begin
        Dest^ := C;
        Inc(Dest);
      end;
    end;
  end;

  SetLength(Result, Dest - PChar(Result));
end;

function SanitizeXML_Direct_3(const AValue: String): String;
var
  Src, SrcEnd, Dest: PChar;
  Len: Integer;
begin
  Len := Length(AValue);
  SetLength(Result, Len);
  Src := PChar(AValue);
  Dest := PChar(Result);
  SrcEnd := Src + Len;

  while Src < SrcEnd do
  begin
    case Src^ of
      #9, #10, #13,
      #32..#$D7FF,
      #$E000..#$FFFD:
      begin
        Dest^ := Src^;
        Inc(Dest);
      end;
    end;
    Inc(Src);
  end;

  SetLength(Result, Dest - PChar(Result));
end;

procedure RunBenchmark;
const
  Iterations = 1000;
var
  i: Integer;
  InputStr, ResultStr1, ResultStr2, ResultStr3, ResultStr4, ResultStr5: String;
  SW: TStopwatch;
begin
  // Beispiel-XML mit gültigen/ungültigen Zeichen
  InputStr := StringOfChar('A', 10000) + #0 + #1 + #2 + #3 + #4 + #5 + #6 + #7 +#8 + #$FFFF + StringOfChar('B', 10000);

  // Original
  SW := TStopwatch.StartNew;
  for i := 1 to Iterations do
    ResultStr1 := SanitizeXML_Original(InputStr);
  SW.Stop;
  OutputDebugString(PChar('Original TStringBuilder: ' + SW.Elapsed.TotalMilliseconds.ToString + ' ms'));

  // PChar + TStringBuilder
  SW := TStopwatch.StartNew;
  for i := 1 to Iterations do
    ResultStr2 := SanitizeXML_PChar(InputStr);
  SW.Stop;
  OutputDebugString(PChar('Optimiert mit PChar: ' + SW.Elapsed.TotalMilliseconds.ToString + ' ms'));

  // Direkte Speicherzugriffe
  SW := TStopwatch.StartNew;
  for i := 1 to Iterations do
    ResultStr3 := SanitizeXML_Direct(InputStr);
  SW.Stop;
  OutputDebugString(PChar('Direkter Zugriff: ' + SW.Elapsed.TotalMilliseconds.ToString + ' ms'));

  // Direkte Speicherzugriffe mit case-of
  SW := TStopwatch.StartNew;
  for i := 1 to Iterations do
    ResultStr4 := SanitizeXML_Direct_2(InputStr);
  SW.Stop;
  OutputDebugString(PChar('Direkter Zugriff 2: ' + SW.Elapsed.TotalMilliseconds.ToString + ' ms'));

  // Direkte Speicherzugriffe mit while statt for und mit case-of
  SW := TStopwatch.StartNew;
  for i := 1 to Iterations do
    ResultStr5 := SanitizeXML_Direct_3(InputStr);
  SW.Stop;
  OutputDebugString(PChar('Direkter Zugriff 3: ' + SW.Elapsed.TotalMilliseconds.ToString + ' ms'));
end;

Geändert von TiGü ( 3. Jul 2025 um 13:03 Uhr)
  Mit Zitat antworten Zitat