There appears to be a difference between the default sorting of a TPair when compiling under 32 bit vs 64 bit. Under 32 bit, the default sort behaves like it is sorting on the Key of the pair, under 64 bit, it looks to sort by the Value. Is this to be expected, or am I missing something ?
Tested using Delphi XE2, update 4. In a VCL application, drop a button, checkbox and listbox onto the screen, declare the following type
type TPairComparer = TComparer<TPair<integer,integer>>;
then place the code below in the button OnClick and run. Under 32 bit, using the default sort, the pairs are listed by key i.e. 1,2,3,4,5,6. Under 64 bit, the pairs are listed by value i.e. 2,5,6,7,8,9 and NOT by key.
To make the code work consistently across both platforms I have needed to specify my own comparer to force the sort by key on a 64 bit executable.
procedure TForm1.Button1Click(Sender: TObject);
var PriorityList : TList<TPair<Integer,integer>>;
Pair : TPair<integer,integer>;
PairComparer : IComparer<TPair<integer,integer>>;
iLoop : integer;
begin
PriorityList := TList<TPair<Integer,integer>>.Create;
PairComparer := TPairComparer.Construct(
function(const Left, Right: TPair<integer,integer>): Integer
begin
case Left.Key = Right.Key of
true : Result := 0;
else case Left.Key < Right.Key of
true : Result := -1;
else Result := +1;
end;
end;
end);
Pair.Key := 6;
Pair.Value := 6;
PriorityList.Add(Pair);
Pair.Key := 5;
Pair.Value := 5;
PriorityList.Add(Pair);
Pair.Key := 4;
Pair.Value := 8;
PriorityList.Add(Pair);
Pair.Key := 3;
Pair.Value := 9;
PriorityList.Add(Pair);
Pair.Key := 2;
Pair.Value := 7;
PriorityList.Add(Pair);
Pair.Key := 1;
Pair.Value := 2;
PriorityList.Add(Pair);
case Checkbox1.Checked of
true : PriorityList.Sort;
false : PriorityList.Sort(PairComparer);
end;
ListBox1.Clear;
for iLoop := 0 to PriorityList.Count-1 do
ListBox1.Items.Add(Format('Key : %d , Value : %d',[PriorityList[iLoop].Key,PriorityList[iLoop].Value]));
end;
The default comparer for such a type is pretty arbitrary. The compiler doesn't use any knowledge of the make up of the record. You've certainly not told it which member you want to be the primary sort key. So it is free to do what it wants.
In 32 bit the default comparer for an 8 byte record is implemented with a call to a CompareMem
-like function. So bytes are compared in increasing order of address. Thus the key is more significant.
Under 64 bit the default comparer treats the type as an unsigned 64 bit integer and so bytes are compared in decreasing address order, this being little endian. And so the value is more significant.
The pertinent code is in the implementation section of Generics.Defaults
:
function Comparer_Selector_Binary(info: PTypeInfo; size: Integer): Pointer;
begin
case size of
// NOTE: Little-endianness may cause counterintuitive results,
// but the results will at least be consistent.
1: Result := @Comparer_Instance_U1;
2: Result := @Comparer_Instance_U2;
4: Result := @Comparer_Instance_U4;
{$IFDEF CPUX64}
// 64-bit will pass const args in registers
8: Result := @Comparer_Instance_U8;
{$ENDIF}
else
Result := MakeInstance(@Comparer_Vtable_Binary, size);
end;
end;
The bottom line is that you need to supply a real comparer whenever you wish to sort records. Only built in numeric and string types have well defined ordered comparers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With