Revised by
Stefan Glienke
2a3fec6
| unit RecComparer;
interface
uses
Generics.Defaults;
type
TRecordEqualityComparer<T: record> = class(TEqualityComparer<T>)
private class var
EqualityComparer_Vtable: array[0..4] of Pointer;
EqualityComparer_Instance: Pointer;
Equals: function(const left, right: T): Boolean;
GetHashCode: function(Self: Pointer): Integer;
class function EqualsProxy(inst: Pointer; const left, right: T): Boolean; static;
class function GetHashCodeProxy(inst: Pointer; const value: T): Integer; static;
public
class constructor Create;
class function Default: IEqualityComparer<T>; static;
end;
function NopAddref(inst: Pointer): Integer; stdcall;
function NopRelease(inst: Pointer): Integer; stdcall;
function NopQueryInterface(inst: Pointer; const IID: TGUID; out Obj): HResult; stdcall;
implementation
uses
Rtti;
function NopAddref(inst: Pointer): Integer; stdcall;
begin
Result := -1;
end;
function NopRelease(inst: Pointer): Integer; stdcall;
begin
Result := -1;
end;
function NopQueryInterface(inst: Pointer; const IID: TGUID; out Obj): HResult; stdcall;
begin
Result := E_NOINTERFACE;
end;
{ TRecordEqualityComparer<T> }
class constructor TRecordEqualityComparer<T>.Create;
var
ctx: TRttiContext;
m: TRttiMethod;
p: Pointer;
begin
EqualityComparer_Vtable[0] := @NopQueryInterface;
EqualityComparer_Vtable[1] := @NopAddref;
EqualityComparer_Vtable[2] := @NopRelease;
EqualityComparer_Vtable[3] := @TRecordEqualityComparer<T>.EqualsProxy;
EqualityComparer_Vtable[4] := @TRecordEqualityComparer<T>.GetHashCodeProxy;
EqualityComparer_Instance := @EqualityComparer_Vtable;
m := ctx.GetType(TypeInfo(T)).GetMethod('&op_Equality');
if Assigned(m) then
Equals := m.CodeAddress;
m := ctx.GetType(TypeInfo(T)).GetMethod('GetHashCode');
if Assigned(m) then
GetHashCode := m.CodeAddress;
end;
class function TRecordEqualityComparer<T>.Default: IEqualityComparer<T>;
begin
Assert(GetTypeKind(T) = tkRecord);
Assert(Assigned(Equals));
IInterface(Result) := nil;
Pointer(Result) := @EqualityComparer_Instance;
end;
class function TRecordEqualityComparer<T>.EqualsProxy(inst: Pointer; const left,
right: T): Boolean;
begin
Result := Equals(left, right);
end;
class function TRecordEqualityComparer<T>.GetHashCodeProxy(inst: Pointer;
const value: T): Integer;
begin
Result := GetHashCode(@value);
end;
end.
|