function IsAnagram_BrunoK(const S1, S2: String; IgnoreSpaces: Boolean = True;
ExceptionOnError: Boolean = False): Boolean;
const
cCold: boolean = True; // WarmUp done -> cCold = False
cArIndexStr: shortstring = ''; // Holder for indexes by character
cFlagArraySize = ((2 + 128 - 32 - (Ord('z') - Ord('a') + 1)) *
SizeOf(SmallInt) + (SizeOf(SizeInt) - 1) div
(SizeOf(SizeInt) div 2));
cFlagArraySizeInt = (cFlagArraySize * 2) div SizeOf(SizeInt);
var
vcArIndex: array[0..High(Byte)] of byte absolute cArIndexStr;
procedure WarmUp;
var
i, j: integer;
begin
FillDWord(vcArIndex, SizeOf(vcArIndex) div SizeOf(DWord), 0); // Init array
vcArIndex[0] := 0; // Invalid character counter
vcArIndex[1] := 1; // Dead characters
j := 2;
for i := Ord(' ') to 128 - 1 do
if (i < Ord('a')) or (i > Ord('z')) then begin
vcArIndex[i] := j;
Inc(j);
end
else
vcArIndex[i] := vcArIndex[i - (Ord('a') - Ord('A'))];
cCold := False;
end;
procedure Error(const Where: string; AtPos: SizeInt); noreturn;
begin
raise ERangeError.CreateFmt('IsAnagram_bk: illegal character in %s at position %d',
[Where, AtPos]);
end;
type
TFreq = array[0..cFlagArraySizeInt - 1] of SizeInt; // Trick from bart
var
F1: array[0..cFlagArraySizeInt - 1] of SizeInt;
F1SI: array[0..cFlagArraySize - 1] of SmallInt absolute F1;
i: integer;
j: integer;
vpIndex: PSmallInt;
pb, pe: PByte;
begin
if cCold then
WarmUp;
F1 := Default(TFreq); // Init array // Sligth speed improvement
vcArIndex[Ord(' ')] := 2;
if IgnoreSpaces then
vcArIndex[Ord(' ')] := 1; // Send them to dead char
{ Increase counts for S1 }
{ for i := 1 to Length(S1) do begin replace with while and pointers }
pb := PByte(S1);
pe := pb+Length(S1);
while pb<pe do begin // Tiny improvement with pointers
// j := Ord(S1[i]);
j := pb^;
vpIndex := @F1SI[vcArIndex[j]];
Inc(vpIndex^);
if vpIndex<>@F1SI[0] then begin
inc(pb);
Continue;
end;
{ Invalid charater }
Result := False;
if ExceptionOnError then
Error('S1', i);
Exit;
end;
F1SI[1] := High(SmallInt); // Do not fail due to deadchar's
{ Decrease counts for S2 }
for i := 1 to Length(S2) do begin // No improvement with pointers
j := byte(S2[i]);
vpIndex := @F1SI[vcArIndex[j]];
Dec(vpIndex^);
if vpIndex^ >= 0 then // All is well, processs next character
Continue;
{ Invalid character or more counter become negative }
Result := False;
if ExceptionOnError and (vpIndex = @F1SI[0]) then
Error('S2', i);
Exit;
end;
F1SI[1] := 0; // Ignore dead characters
for i := 0 to cFlagArraySizeInt - 1 do
if F1[i] <> 0 then
Exit(False);
Result := True;
end;