How can I extract a piece of PChar to a string?

During profiling, I came across a function that took quite a while, but basically came down to this very simple piece of code:

function GetSubstring(AInput: PChar; AStart, ASubstringLength: Integer): string;
begin
  Result := Copy(AInput, AStart, ASubstringLength);
end;

This function returns the expected substring, but it does not scale very well for longer inputs. I looked at the assembler code in the CPU view, and from what I can say (I usually do not work at the assembler level), it seems to be AInputimplicitly converted to a string before the call Copy.

But since at this point the length of the string / character array is unknown, the conversion code must go through the length PCharuntil it finds a null terminator. This explains the terrible scaling for longer inputs.

However, as the caller runs in length PChar, I initially thought I could just convert the method to use SetStringinstead.

function GetSubstring(AInput: PChar; AStart, ASubstringLength: Integer): string;
begin
  SetString(Result, AInput + AStart - 1, ASubstringLength);
end;

In addition to SetStringworking on the basis of zero (not on the basis of a single instance), it seems that there are several other trifles Copywith respect to checking their inputs, not all of which are documented (for example, any initial value less than 1 changes to 1). Thus, the naive implementation above does not always work as the original.

My goal is to maximize the replication of the procedure Copy, as this function is part of the library and has been widely used by my colleagues.

, , Copy. NB: 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).

+4
2

. , :

  • AInput .
  • AStart < 1.
  • AStart > FLength.
  • ASubstringLength < 0.
  • ASubstringLength + (AStart-1) > FLength.

1, . , PChar. , , AInput <> nil , , nil PChar.

2 5, 3 4. , AStart, , . , ASubstringLength. , , - , , .

, , . , . {$IFOPF D+} Assert . , , .

, , , - . , , .

+5

PChar string AInput + (AStart * SizeOf(PChar)) ASubstringLength * SizeOf(PChar) @Result, Result .

Move .

0

All Articles