# Compare two TIntegerDynArray

## Recommended Posts

Hi all,

what is the fastest way to compare two vars of the TIntegerDynArray type?

First compare their length then do a CompareMem if the lengths are equal

That is what I've used....

```procedure TGCodeEditor.SetGCodeLinePoints(Value: TIntegerDynArray);
var
F: Boolean;
L: Integer;
begin
F := False;
L := Length(Value);
if (Length(FGCodeLinePoints) > 0) and (Length(FGCodeLinePoints) = L) then
F := CompareMem(@FGCodeLinePoints[0], @Value[0], Sizeof(Integer) * L);
FGCodeLinePoints := Value;
if not F then
Invalidate;
end;```

9 minutes ago, shineworld said:

That is what I've used....

```
procedure TGCodeEditor.SetGCodeLinePoints(Value: TIntegerDynArray);
var
F: Boolean;
L: Integer;
begin
F := False;
L := Length(Value);
if (Length(FGCodeLinePoints) > 0) and (Length(FGCodeLinePoints) = L) then
F := CompareMem(@FGCodeLinePoints[0], @Value[0], Sizeof(Integer) * L);
FGCodeLinePoints := Value;
if not F then
Invalidate;
end;```

Not much point having three calls to Length and in fact the zero length check can be skipped and rely on CompareMem to know what to do when passed a size of zero.

Some type like this?

PS: IsEqualIntegerDynArray placed in method just to test.

```procedure TGCodeEditor.SetGCodeLinePoints(Value: TIntegerDynArray);

function IsEqualIntegerDynArray(const A, B: TIntegerDynArray): Boolean;
begin
if Length(A) <> Length(B) then Exit(False);
Result := CompareMem(@A[0], @B[0], Sizeof(Integer) * Length(A));
end;

begin
if not IsEqualIntegerDynArray(FGCodeLinePoints, Value) then
begin
FGCodeLinePoints := Value;
Invalidate;
end;
end;```

1 minute ago, shineworld said:

Result﻿ := CompareMem(@A[0], @B[0], Sizeof(Integer) * Length(A));

This risks range check errors so I'd use Pointer(A)^ and similar for B. You could still save one of the lengths to a local to avoid getting it twice.

48 minutes ago, shineworld said:

TIntegerDynArray

Any reason why you aren't using TArray<Integer>?

Sincerely no reason.
I just thought that TIntegerDynArray is more performant than a generic.

In my defense or fault, I have not been a big user of generics until now.

Edited by shineworld

10 minutes ago, shineworld said:

Sincerely no reason.
I just thought that TIntegerDynArray is more performant than a generic.

In my defense or fault, I have not been a big user of generics until now.

Don't think performance is an issue with TArray<T> and using it makes you code better able to work with other generic code.

• 1

5 hours ago, shineworld said:

Some type like this?

PS: IsEqualIntegerDynArray placed in method just to test.

If there is any possibility that FGCodeLinePoints could be passed in to SetGCodeLinePoints() (eg: GCodeEditor1.GCodeLinePoints := GCodeEditor1.GCodeLinePoints;), then I would also add a pointer equality check as well, since dynamic arrays are implemented as ref-counted pinters, eg:

```procedure TGCodeEditor.SetGCodeLinePoints(Value: TIntegerDynArray);

function IsEqualIntegerDynArray(const A, B: TIntegerDynArray): Boolean;
var
L: Integer;
begin
if Pointer(A) = Pointer(B) then Exit(True); // <-- HERE
L := Length(A);
if L <> Length(B) then Exit(False);
Result := CompareMem(PInteger(A)^, PInteger(B)^, Sizeof(Integer) * L);
end;

begin
if not IsEqualIntegerDynArray(FGCodeLinePoints, Value) then
begin
FGCodeLinePoints := Value;
Invalidate;
end;
end;```
Edited by Remy Lebeau
• 1

6 hours ago, Remy Lebeau said:

If﻿ there is any possibility that FGCodeLinePoints could be passed in to SetGCodeLinePoints() (eg: GCodeEditor1.﻿GCodeLinePoints := GCodeEditor1.GCodeLinePoints;), then I would also add a pointer equality check as well﻿, since dynamic arrays are implemented as ref-counted pinters﻿, eg﻿:

I'd definitely remove the pointer check you just added. Surely that's just going to make things slower.

Guys you're saving on matches. CompareMem will eat all these nano-optimizations.