program TupleTest;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
IgnoreElm = record end;
Tuple<T1, T2> = record
{$REGION 'Implementation details'}
private
type
P1 = ^T1;
P2 = ^T2;
Tier = record
Ref1: P1;
Ref2: P2;
class operator LessThanOrEqual(const Dest: Tier; const Src: Tuple<T1, T2>): boolean; overload;
end;
private
class operator Implicit(const Value: Tuple<T1, T2>): Tuple<T1, IgnoreElm>;
class operator Implicit(const Value: Tuple<T1, T2>): Tuple<IgnoreElm, T2>;
{$ENDREGION}
public
Elm1: T1;
Elm2: T2;
end;
Tuple = record
public
class function From<T1, T2>(const Value1: T1; Value2: T2): Tuple<T1, T2>; static;
class function Tie<T1, T2>(var Elm1: T1; var Elm2: T2): Tuple<T1, T2>.Tier; overload; static;
class function Tie<T1>(var Elm1: T1; const Ignored2: IgnoreElm): Tuple<T1, IgnoreElm>.Tier; overload; static;
class function Tie<T2>(const Ignored1: IgnoreElm; var Elm2: T2): Tuple<IgnoreElm, T2>.Tier; overload; static;
end;
const
Ignore: IgnoreElm = ();
procedure Test;
var
tup: Tuple<integer, string>;
i: integer;
s: string;
begin
i := 123;
s := 'bar';
tup := Tuple.From<integer, string>(42, 'foo');
Tuple.Tie(Ignore, s) <= tup;
WriteLn(i, ', ', s); // 123, foo
end;
{ Tuple }
class function Tuple.From<T1, T2>(const Value1: T1; Value2: T2): Tuple<T1, T2>;
begin
result.Elm1 := Value1;
result.Elm2 := Value2;
end;
class function Tuple.Tie<T1, T2>(var Elm1: T1; var Elm2: T2): Tuple<T1, T2>.Tier;
begin
result.Ref1 := @Elm1;
result.Ref2 := @Elm2;
end;
class function Tuple.Tie<T1>(var Elm1: T1;
const Ignored2: IgnoreElm): Tuple<T1, IgnoreElm>.Tier;
begin
result.Ref1 := @Elm1;
result.Ref2 := nil;
end;
class function Tuple.Tie<T2>(const Ignored1: IgnoreElm;
var Elm2: T2): Tuple<IgnoreElm, T2>.Tier;
begin
result.Ref1 := nil;
result.Ref2 := @Elm2;
end;
{ Tuple<T1, T2>.Tier }
class operator Tuple<T1, T2>.Tier.LessThanOrEqual(const Dest: Tier;
const Src: Tuple<T1, T2>): boolean;
begin
if (TypeInfo(T1) <> TypeInfo(IgnoreElm)) then
Dest.Ref1^ := Src.Elm1;
if (TypeInfo(T2) <> TypeInfo(IgnoreElm)) then
Dest.Ref2^ := Src.Elm2;
result := True;
end;
{ Tuple<T1, T2> }
class operator Tuple<T1, T2>.Implicit(
const Value: Tuple<T1, T2>): Tuple<T1, IgnoreElm>;
begin
result.Elm1 := Value.Elm1;
end;
class operator Tuple<T1, T2>.Implicit(
const Value: Tuple<T1, T2>): Tuple<IgnoreElm, T2>;
begin
result.Elm2 := Value.Elm2;
end;
begin
Test;
ReadLn;
end.