shineworld 73 Posted November 22, 2022 Hi all, what is the fastest way to compare two vars of the TIntegerDynArray type? Thank you in advance for your suggestions. Share this post Link to post
David Heffernan 2345 Posted November 22, 2022 First compare their length then do a CompareMem if the lengths are equal Share this post Link to post
shineworld 73 Posted November 22, 2022 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; Share this post Link to post
David Heffernan 2345 Posted November 22, 2022 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. Share this post Link to post
shineworld 73 Posted November 22, 2022 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; Share this post Link to post
David Heffernan 2345 Posted November 22, 2022 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. Share this post Link to post
David Heffernan 2345 Posted November 22, 2022 48 minutes ago, shineworld said: TIntegerDynArray Any reason why you aren't using TArray<Integer>? Share this post Link to post
shineworld 73 Posted November 22, 2022 (edited) 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 November 22, 2022 by shineworld Share this post Link to post
David Heffernan 2345 Posted November 22, 2022 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 Share this post Link to post
Remy Lebeau 1397 Posted November 22, 2022 (edited) 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 November 22, 2022 by Remy Lebeau 1 Share this post Link to post
David Heffernan 2345 Posted November 23, 2022 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. Share this post Link to post
Fr0sT.Brutal 900 Posted November 23, 2022 Guys you're saving on matches. CompareMem will eat all these nano-optimizations. Share this post Link to post