Skip to content

Commit 32f3bd0

Browse files
twinn1013ansgarbecker
authored andcommitted
perf: avoid full string scans in StrEllipsis
UTF8Length and UTF8Copy walk every byte of the input, and StrEllipsis runs for each rendered grid cell, so large TEXT/BLOB values were fully scanned on every paint. Exit early when the byte count already proves there is nothing to cut, and resolve the left-hand cut position with UTF8CodepointToByteIndex, which only walks the first MaxLen codepoints. Output is unchanged - verified against the previous implementation with 10k randomized mixed ASCII/Korean/emoji strings plus boundary cases. Still cuts on UTF-8 codepoint boundaries.
1 parent 8befce3 commit 32f3bd0

1 file changed

Lines changed: 14 additions & 4 deletions

File tree

source/apphelpers.pas

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -535,18 +535,28 @@ function Explode(Separator, Text: String): TStringList;
535535
@return string
536536
}
537537
function StrEllipsis(const S: String; MaxLen: Integer; FromLeft: Boolean=True): String;
538+
var
539+
CutPos: PtrInt;
538540
begin
539541
// Truncate on UTF-8 codepoint boundaries, not raw bytes. A byte-wise cut (SetLength/Copy)
540542
// can split a multi-byte character and produce invalid UTF-8. On the Cocoa widgetset such a
541543
// string converts to a nil NSString, which crashes -[NSMenuItem initWithTitle:] when the
542544
// result is used as a menu caption (e.g. quick filter items).
543545
Result := S;
544-
if UTF8Length(Result) <= MaxLen then
546+
// A string with <= MaxLen bytes cannot contain more than MaxLen codepoints
547+
if Length(Result) <= MaxLen then
545548
Exit;
546-
if FromLeft then
547-
Result := UTF8Copy(Result, 1, MaxLen) + ''
548-
else
549+
if FromLeft then begin
550+
CutPos := UTF8CodepointToByteIndex(PChar(Result), Length(Result), MaxLen);
551+
if (CutPos < 0) or (CutPos >= Length(Result)) then
552+
Exit;
553+
SetLength(Result, CutPos);
554+
Result := Result + '';
555+
end else begin
556+
if UTF8Length(Result) <= MaxLen then
557+
Exit;
549558
Result := '' + UTF8Copy(Result, UTF8Length(Result) - MaxLen + 1, MaxLen);
559+
end;
550560
end;
551561

552562

0 commit comments

Comments
 (0)