IComparer<T> = interface
function Compare(const AItem1, AItem2:T):Boolean;
end;
{Such declaration is REQUIERED, cuz TPairList is inherited from TList, so pair comparers should work for TList too}
IPairComparer<TKey, TValue> = interface(IComparer<TPair<TKey, TValue>>)
{Can be implemented via QueryInterface() - GUID is needed to be provided then,
but it's slow - I don't like to use it for internal interfaces}
function GetKeyComparer:IComparer<TKey>;
function GetValueComparer:IComparer<TValue>;
function GetPairKeyComparer:IPairComparer<TKey, TValue>;
function GetPairValueComparer:IPairComparer<TKey, TValue>;
end;
{Just aliases for the same interface - should work, but causes weird behavior, I described above.
It's not even bug - it's unforeseen situation. Delphi simply assumes, that if they're inherited from the same interface -
then implementation of this interface should be the same for all 3. And this is completely wrong.}
IPairKeyComparer<TKey, TValue> = interface(IPairComparer<TKey, TValue>);
IPairValueComparer<TKey, TValue> = interface(IPairComparer<TKey, TValue>);
TAbstractPairComparer<TKey, TValue> = class(TInterfacedObject, IPairComparer<TKey, TValue>,
IComparer<TKey>, IComparer<TValue>,
IPairKeyComparer<TKey, TValue>, IPairValueComparer<TKey, TValue>)
protected
function Compare(const AItem1, AItem2:TPair<TKey, TValue>):Boolean;virtual;abstract;
function ComparePairKey(const AItem1, AItem2:TPair<TKey, TValue>):Boolean;virtual;abstract;
function ComparePairValue(const AItem1, AItem2:TPair<TKey, TValue>):Boolean;virtual;abstract;
{Following lines don't work properly - work, only when current unit is being rebuilt}
function IPairComparer<TKey, TValue>.Compare = Compare;
function IPairKeyComparer<TKey, TValue>.Compare = ComparePairKey;
function IPairValueComparer<TKey, TValue>.Compare = ComparePairValue;
public
function GetPairKeyComparer:IPairComparer<TKey, TValue>;
function GetPairValueComparer:IPairComparer<TKey, TValue>;
end;
function TAbstractPairComparer<TKey, TValue>.GetPairKeyComparer:IPairComparer<TKey, TValue>;
var Temp:IPairKeyComparer<TKey, TValue>;
begin
{Crutch: "as" doesn't work, when no GUID is specified,
cuz "as" and "is" are just syntax sugar for QueryInterface()
and direct cast isn't handled properly by compiler.
We don't want to use QueryInterface(), cuz it's slow.}
Temp := Self;
Result := IPairComparer<TKey, TValue>(Temp);
end;
function TAbstractPairComparer<TKey, TValue>.GetPairValueComparer:IPairComparer<TKey, TValue>;
var Temp:IPairValueComparer<TKey, TValue>;
begin
{Crutch: "as" doesn't work, when no GUID is specified,
cuz "as" and "is" are just syntax sugar for QueryInterface()
and direct cast isn't handled properly by compiler.
We don't want to use QueryInterface(), cuz it's slow.}
Temp := Self;
Result := IPairComparer<TKey, TValue>(Temp);
end;