Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is CompareMem suitable for comparing two arrays for equality?

I need to compare if all items of a given array are the same.

For now, I have the following code:

Type
  TD = array [0..1] of TDateTime;

var A: TD;
    B: TD;
begin
  A[0] := Date-1;   A[1] := Date+1;
  B[0] := Date-1;   B[1] := Date+1;

  if CompareMem(@A, @B, SizeOf(TD)) then
    Showmessage('Equals')
  else
    Showmessage('Differ');

This is working fine but as CompareMem is written in assembly I'm not able (yet) to understand what it does.

Is CompareMem a valid way to do what I want? Also, I would like to know if will work to every data types like string, integer, etc.

like image 598
EProgrammerNotFound Avatar asked Jun 18 '13 17:06

EProgrammerNotFound


2 Answers

This is not written in assembly... Comparing memory is valid if all the memory is filled with array items without gaps. Generally it would work if

1) All array memory is filled with data without gaps (gap may contain garbage and cause false negative).

1.1. this should be enforced by packed array keyword, if compiler would not ignore it

1.2 this should happen if SizeOf(A[1]) is 2,4,8,16 etc

But you better cover this by unit tests using FillChar with different patterns - they would imitate garbage, then manual filling of array elements with matching values, then checking with CompareMem that elements wiped all the pre-filled garbage.

2) Array elements only contain simple value types, not reference types.

Char, integer, double, short string, fixed-size array or record made of those - are simple types.

All other strings, pointers, objects, interfaces, dynamic and open arrays - are merely pointers to the external data, and can not be compared "by memory"

You may read about http://docwiki.embarcadero.com/Libraries/XE2/en/System.Finalize for more hints. Assembler implementation of procedures/functions would also be good topic, as it would cover binary representations of different Delphi data types

like image 168
Arioch 'The Avatar answered Nov 03 '22 01:11

Arioch 'The


CompareMem simply performs a byte by byte comparison. There are two main ways in which CompareMem fails to be valid for equality testing by value:

  1. The types being tested contain padding.
  2. The types being tested are or contain reference types.

You are asking about arrays. Since arrays are always packed, they contain no padding. Since you are comparing the array values, the question can focus on the elements of the array.

Value comparison of arrays will be an appropriate thing to do if and only if the array elements are value types that contain no padding bytes and contain no reference types.

This is the case for all simple value types.

For records, you need to check whether or not the record contains reference types. This must be a recursive check. Does the record contain records that contain reference types, and so on. And then you must look for padding. As soon as you find padding, the use of CompareMem is not appropriate.

like image 32
David Heffernan Avatar answered Nov 03 '22 00:11

David Heffernan