program project1;
{$mode objfpc}
{$longstrings on}
{$modeswitch advancedrecords}
uses Variants, Generics.Collections, SysUtils, Generics.Defaults, Generics.Hashes;
type TRecord = packed record
FID: NativeUInt;
FKey: String;
constructor Create (AID: NativeUInt; AKey: String);
class operator = (a: TRecord; b: TRecord): Boolean;
end;
constructor TRecord.Create (AID: NativeUInt; AKey: String);
begin
FID := AID;
FKey := UpperCase (AKey);
end;
class operator TRecord.= (a: TRecord; b: TRecord): Boolean;
begin
Exit ((a.FID = b.FID) and (a.FKey = b.FKey));
end;
type TMyComparer = class (TInterfacedObject, specialize IEqualityComparer<TRecord>)
function Equals (constref aLeft, aRight: TRecord): Boolean;
function GetHashCode (constref aValue: TRecord): UInt32;
end;
function TMyComparer.Equals (constref aLeft, aRight: TRecord): Boolean;
begin
Result := (aLeft = aRight);
end;
function TMyComparer.GetHashCode(constref aValue: TRecord): UInt32;
var
p: Pointer = NIL;
l: NativeUInt;
begin
l := Length (AValue.FKey) + SizeOf (AValue.FID) + 1;
GetMem (p, l);
try
FillChar (p^, l, 0);
Move (AValue.FID, p^, SizeOf (AValue.FID));
StrPLCopy (p+SizeOf(AValue.FID), AValue.FKey, Length (AValue.FKey));
Exit (SimpleChecksumHash (p, l));
finally
FreeMem (p, l);
end;
end;
var
Dict: specialize TDictionary<TRecord,Variant>;
i: specialize TPair<TRecord,Variant>;
begin
Dict := specialize TDictionary<TRecord,Variant>.Create (TMyComparer.Create);
Dict.Add (TRecord.Create (1, 'test'), 1);
for i in Dict do Writeln (i.Key.FID, #9, i.Key.FKey, #9, i.Value);
Writeln (Dict.ContainsKey (TRecord.Create (1, 'test')));
// ^^^ TRUE
Writeln (Dict.ContainsKey (TRecord.Create (1, 'TEST')));
// ^^^ TRUE
Writeln (Dict.ContainsKey (TRecord.Create (1, 'text')));
// ^^^ FALSE
Writeln (Dict.ContainsKey (TRecord.Create (2, 'TEST')));
// ^^^ FALSE
Dict.Free;
end.