537 lines
14 KiB
ObjectPascal
537 lines
14 KiB
ObjectPascal
unit Myc.Data.Types.Tuple;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
Myc.Data.Types;
|
|
|
|
type
|
|
// Implements the singleton tuple data type.
|
|
TImplDataTupleType = class(TInterfacedObject, IDataType, IDataTupleType)
|
|
strict private
|
|
class var
|
|
FSingleton: IDataTupleType;
|
|
class constructor CreateClass;
|
|
private
|
|
function GetName: String;
|
|
function GetKind: TDataKind;
|
|
public
|
|
function CreateValue(const AItems: array of IDataValue): IDataTupleValue;
|
|
class property Singleton: IDataTupleType read FSingleton;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
System.Rtti;
|
|
|
|
type
|
|
// Implements the simple tuple data value.
|
|
TImplDataTupleValue = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
|
private
|
|
FItems: TArray<IDataValue>;
|
|
function GetDataType: IDataType;
|
|
function GetAsString: string;
|
|
function AsTValue: TValue;
|
|
function GetItemCount: Integer;
|
|
function GetItem(Idx: Integer): IDataValue;
|
|
public
|
|
constructor Create(const AItems: array of IDataValue);
|
|
end;
|
|
|
|
// Optimized singleton implementation for a tuple with 0 elements.
|
|
TImplDataTupleValue0 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
|
strict private
|
|
class var
|
|
FSingleton: IDataTupleValue;
|
|
FEmptyTValue: TValue;
|
|
class constructor CreateClass;
|
|
private
|
|
function GetDataType: IDataType;
|
|
function GetAsString: string;
|
|
function AsTValue: TValue;
|
|
function GetItemCount: Integer;
|
|
function GetItem(Idx: Integer): IDataValue;
|
|
public
|
|
class property Singleton: IDataTupleValue read FSingleton;
|
|
end;
|
|
|
|
// Optimized implementation for a tuple with 1 element.
|
|
TImplDataTupleValue1 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
|
private
|
|
FItem0: IDataValue;
|
|
function GetDataType: IDataType;
|
|
function GetAsString: string;
|
|
function AsTValue: TValue;
|
|
function GetItemCount: Integer;
|
|
function GetItem(Idx: Integer): IDataValue;
|
|
public
|
|
constructor Create(const AItems: array of IDataValue);
|
|
end;
|
|
|
|
// Optimized implementation for a tuple with 2 elements.
|
|
TImplDataTupleValue2 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
|
private
|
|
FItem0, FItem1: IDataValue;
|
|
function GetDataType: IDataType;
|
|
function GetAsString: string;
|
|
function AsTValue: TValue;
|
|
function GetItemCount: Integer;
|
|
function GetItem(Idx: Integer): IDataValue;
|
|
public
|
|
constructor Create(const AItems: array of IDataValue);
|
|
end;
|
|
|
|
// Optimized implementation for a tuple with 3 elements.
|
|
TImplDataTupleValue3 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
|
private
|
|
FItem0, FItem1, FItem2: IDataValue;
|
|
function GetDataType: IDataType;
|
|
function GetAsString: string;
|
|
function AsTValue: TValue;
|
|
function GetItemCount: Integer;
|
|
function GetItem(Idx: Integer): IDataValue;
|
|
public
|
|
constructor Create(const AItems: array of IDataValue);
|
|
end;
|
|
|
|
// Optimized implementation for a tuple with 4 elements.
|
|
TImplDataTupleValue4 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
|
private
|
|
FItem0, FItem1, FItem2, FItem3: IDataValue;
|
|
function GetDataType: IDataType;
|
|
function GetAsString: string;
|
|
function AsTValue: TValue;
|
|
function GetItemCount: Integer;
|
|
function GetItem(Idx: Integer): IDataValue;
|
|
public
|
|
constructor Create(const AItems: array of IDataValue);
|
|
end;
|
|
|
|
// Optimized implementation for a tuple with 5 elements.
|
|
TImplDataTupleValue5 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
|
private
|
|
FItem0, FItem1, FItem2, FItem3, FItem4: IDataValue;
|
|
function GetDataType: IDataType;
|
|
function GetAsString: string;
|
|
function AsTValue: TValue;
|
|
function GetItemCount: Integer;
|
|
function GetItem(Idx: Integer): IDataValue;
|
|
public
|
|
constructor Create(const AItems: array of IDataValue);
|
|
end;
|
|
|
|
{ TImplDataTupleValue (generic implementation for N > 5 elements) }
|
|
|
|
constructor TImplDataTupleValue.Create(const AItems: array of IDataValue);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inherited Create;
|
|
SetLength(FItems, Length(AItems));
|
|
for i := 0 to High(AItems) do
|
|
FItems[i] := AItems[i];
|
|
end;
|
|
|
|
function TImplDataTupleValue.GetDataType: IDataType;
|
|
begin
|
|
Result := TImplDataTupleType.Singleton;
|
|
end;
|
|
|
|
function TImplDataTupleValue.GetAsString: string;
|
|
var
|
|
sb: TStringBuilder;
|
|
i: Integer;
|
|
begin
|
|
sb := TStringBuilder.Create;
|
|
try
|
|
sb.Append('(');
|
|
for i := 0 to High(FItems) do
|
|
begin
|
|
sb.Append(FItems[i].AsString);
|
|
if (i < High(FItems)) then
|
|
sb.Append(', ');
|
|
end;
|
|
sb.Append(')');
|
|
Result := sb.ToString;
|
|
finally
|
|
sb.Free;
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue.AsTValue: TValue;
|
|
var
|
|
tvalueArray: TArray<TValue>;
|
|
i: Integer;
|
|
begin
|
|
SetLength(tvalueArray, Length(FItems));
|
|
for i := 0 to High(FItems) do
|
|
tvalueArray[i] := FItems[i].AsTValue;
|
|
Result := TValue.From<TArray<TValue>>(tvalueArray);
|
|
end;
|
|
|
|
function TImplDataTupleValue.GetItem(Idx: Integer): IDataValue;
|
|
begin
|
|
Result := FItems[Idx];
|
|
end;
|
|
|
|
function TImplDataTupleValue.GetItemCount: Integer;
|
|
begin
|
|
Result := Length(FItems);
|
|
end;
|
|
|
|
{ TImplDataTupleValue0 }
|
|
|
|
class constructor TImplDataTupleValue0.CreateClass;
|
|
var
|
|
emptyArray: TArray<TValue>;
|
|
begin
|
|
FSingleton := TImplDataTupleValue0.Create;
|
|
SetLength(emptyArray, 0);
|
|
FEmptyTValue := TValue.From<TArray<TValue>>(emptyArray);
|
|
end;
|
|
|
|
function TImplDataTupleValue0.GetAsString: string;
|
|
begin
|
|
Result := '()';
|
|
end;
|
|
|
|
function TImplDataTupleValue0.AsTValue: TValue;
|
|
begin
|
|
Result := FEmptyTValue;
|
|
end;
|
|
|
|
function TImplDataTupleValue0.GetDataType: IDataType;
|
|
begin
|
|
Result := TImplDataTupleType.Singleton;
|
|
end;
|
|
|
|
function TImplDataTupleValue0.GetItem(Idx: Integer): IDataValue;
|
|
begin
|
|
raise EArgumentException.Create('Index out of bounds');
|
|
end;
|
|
|
|
function TImplDataTupleValue0.GetItemCount: Integer;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
|
|
{ TImplDataTupleValue1 }
|
|
|
|
constructor TImplDataTupleValue1.Create(const AItems: array of IDataValue);
|
|
begin
|
|
inherited Create;
|
|
FItem0 := AItems[0];
|
|
end;
|
|
|
|
function TImplDataTupleValue1.GetAsString: string;
|
|
begin
|
|
Result := '(' + FItem0.AsString + ')';
|
|
end;
|
|
|
|
function TImplDataTupleValue1.AsTValue: TValue;
|
|
var
|
|
tvalueArray: TArray<TValue>;
|
|
begin
|
|
SetLength(tvalueArray, 1);
|
|
tvalueArray[0] := FItem0.AsTValue;
|
|
Result := TValue.From<TArray<TValue>>(tvalueArray);
|
|
end;
|
|
|
|
function TImplDataTupleValue1.GetDataType: IDataType;
|
|
begin
|
|
Result := TImplDataTupleType.Singleton;
|
|
end;
|
|
|
|
function TImplDataTupleValue1.GetItem(Idx: Integer): IDataValue;
|
|
begin
|
|
case Idx of
|
|
0: Result := FItem0;
|
|
else
|
|
raise EArgumentException.Create('Index out of bounds');
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue1.GetItemCount: Integer;
|
|
begin
|
|
Result := 1;
|
|
end;
|
|
|
|
{ TImplDataTupleValue2 }
|
|
|
|
constructor TImplDataTupleValue2.Create(const AItems: array of IDataValue);
|
|
begin
|
|
inherited Create;
|
|
FItem0 := AItems[0];
|
|
FItem1 := AItems[1];
|
|
end;
|
|
|
|
function TImplDataTupleValue2.GetAsString: string;
|
|
begin
|
|
Result := '(' + FItem0.AsString + ', ' + FItem1.AsString + ')';
|
|
end;
|
|
|
|
function TImplDataTupleValue2.AsTValue: TValue;
|
|
var
|
|
tvalueArray: TArray<TValue>;
|
|
begin
|
|
SetLength(tvalueArray, 2);
|
|
tvalueArray[0] := FItem0.AsTValue;
|
|
tvalueArray[1] := FItem1.AsTValue;
|
|
Result := TValue.From<TArray<TValue>>(tvalueArray);
|
|
end;
|
|
|
|
function TImplDataTupleValue2.GetDataType: IDataType;
|
|
begin
|
|
Result := TImplDataTupleType.Singleton;
|
|
end;
|
|
|
|
function TImplDataTupleValue2.GetItem(Idx: Integer): IDataValue;
|
|
begin
|
|
case Idx of
|
|
0: Result := FItem0;
|
|
1: Result := FItem1;
|
|
else
|
|
raise EArgumentException.Create('Index out of bounds');
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue2.GetItemCount: Integer;
|
|
begin
|
|
Result := 2;
|
|
end;
|
|
|
|
{ TImplDataTupleValue3 }
|
|
|
|
constructor TImplDataTupleValue3.Create(const AItems: array of IDataValue);
|
|
begin
|
|
inherited Create;
|
|
FItem0 := AItems[0];
|
|
FItem1 := AItems[1];
|
|
FItem2 := AItems[2];
|
|
end;
|
|
|
|
function TImplDataTupleValue3.GetAsString: string;
|
|
var
|
|
sb: TStringBuilder;
|
|
begin
|
|
sb := TStringBuilder.Create;
|
|
try
|
|
sb.Append('(');
|
|
sb.Append(FItem0.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem1.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem2.AsString);
|
|
sb.Append(')');
|
|
Result := sb.ToString;
|
|
finally
|
|
sb.Free;
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue3.AsTValue: TValue;
|
|
var
|
|
tvalueArray: TArray<TValue>;
|
|
begin
|
|
SetLength(tvalueArray, 3);
|
|
tvalueArray[0] := FItem0.AsTValue;
|
|
tvalueArray[1] := FItem1.AsTValue;
|
|
tvalueArray[2] := FItem2.AsTValue;
|
|
Result := TValue.From<TArray<TValue>>(tvalueArray);
|
|
end;
|
|
|
|
function TImplDataTupleValue3.GetDataType: IDataType;
|
|
begin
|
|
Result := TImplDataTupleType.Singleton;
|
|
end;
|
|
|
|
function TImplDataTupleValue3.GetItem(Idx: Integer): IDataValue;
|
|
begin
|
|
case Idx of
|
|
0: Result := FItem0;
|
|
1: Result := FItem1;
|
|
2: Result := FItem2;
|
|
else
|
|
raise EArgumentException.Create('Index out of bounds');
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue3.GetItemCount: Integer;
|
|
begin
|
|
Result := 3;
|
|
end;
|
|
|
|
{ TImplDataTupleValue4 }
|
|
|
|
constructor TImplDataTupleValue4.Create(const AItems: array of IDataValue);
|
|
begin
|
|
inherited Create;
|
|
FItem0 := AItems[0];
|
|
FItem1 := AItems[1];
|
|
FItem2 := AItems[2];
|
|
FItem3 := AItems[3];
|
|
end;
|
|
|
|
function TImplDataTupleValue4.GetAsString: string;
|
|
var
|
|
sb: TStringBuilder;
|
|
begin
|
|
sb := TStringBuilder.Create;
|
|
try
|
|
sb.Append('(');
|
|
sb.Append(FItem0.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem1.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem2.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem3.AsString);
|
|
sb.Append(')');
|
|
Result := sb.ToString;
|
|
finally
|
|
sb.Free;
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue4.AsTValue: TValue;
|
|
var
|
|
tvalueArray: TArray<TValue>;
|
|
begin
|
|
SetLength(tvalueArray, 4);
|
|
tvalueArray[0] := FItem0.AsTValue;
|
|
tvalueArray[1] := FItem1.AsTValue;
|
|
tvalueArray[2] := FItem2.AsTValue;
|
|
tvalueArray[3] := FItem3.AsTValue;
|
|
Result := TValue.From<TArray<TValue>>(tvalueArray);
|
|
end;
|
|
|
|
function TImplDataTupleValue4.GetDataType: IDataType;
|
|
begin
|
|
Result := TImplDataTupleType.Singleton;
|
|
end;
|
|
|
|
function TImplDataTupleValue4.GetItem(Idx: Integer): IDataValue;
|
|
begin
|
|
case Idx of
|
|
0: Result := FItem0;
|
|
1: Result := FItem1;
|
|
2: Result := FItem2;
|
|
3: Result := FItem3;
|
|
else
|
|
raise EArgumentException.Create('Index out of bounds');
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue4.GetItemCount: Integer;
|
|
begin
|
|
Result := 4;
|
|
end;
|
|
|
|
{ TImplDataTupleValue5 }
|
|
|
|
constructor TImplDataTupleValue5.Create(const AItems: array of IDataValue);
|
|
begin
|
|
inherited Create;
|
|
FItem0 := AItems[0];
|
|
FItem1 := AItems[1];
|
|
FItem2 := AItems[2];
|
|
FItem3 := AItems[3];
|
|
FItem4 := AItems[4];
|
|
end;
|
|
|
|
function TImplDataTupleValue5.GetAsString: string;
|
|
var
|
|
sb: TStringBuilder;
|
|
begin
|
|
sb := TStringBuilder.Create;
|
|
try
|
|
sb.Append('(');
|
|
sb.Append(FItem0.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem1.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem2.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem3.AsString);
|
|
sb.Append(', ');
|
|
sb.Append(FItem4.AsString);
|
|
sb.Append(')');
|
|
Result := sb.ToString;
|
|
finally
|
|
sb.Free;
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue5.AsTValue: TValue;
|
|
var
|
|
tvalueArray: TArray<TValue>;
|
|
begin
|
|
SetLength(tvalueArray, 5);
|
|
tvalueArray[0] := FItem0.AsTValue;
|
|
tvalueArray[1] := FItem1.AsTValue;
|
|
tvalueArray[2] := FItem2.AsTValue;
|
|
tvalueArray[3] := FItem3.AsTValue;
|
|
tvalueArray[4] := FItem4.AsTValue;
|
|
Result := TValue.From<TArray<TValue>>(tvalueArray);
|
|
end;
|
|
|
|
function TImplDataTupleValue5.GetDataType: IDataType;
|
|
begin
|
|
Result := TImplDataTupleType.Singleton;
|
|
end;
|
|
|
|
function TImplDataTupleValue5.GetItem(Idx: Integer): IDataValue;
|
|
begin
|
|
case Idx of
|
|
0: Result := FItem0;
|
|
1: Result := FItem1;
|
|
2: Result := FItem2;
|
|
3: Result := FItem3;
|
|
4: Result := FItem4;
|
|
else
|
|
raise EArgumentException.Create('Index out of bounds');
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleValue5.GetItemCount: Integer;
|
|
begin
|
|
Result := 5;
|
|
end;
|
|
|
|
{ TImplDataTupleType }
|
|
|
|
class constructor TImplDataTupleType.CreateClass;
|
|
begin
|
|
FSingleton := TImplDataTupleType.Create;
|
|
end;
|
|
|
|
function TImplDataTupleType.CreateValue(const AItems: array of IDataValue): IDataTupleValue;
|
|
begin
|
|
// Use optimized implementations for tuples with 0 to 5 elements.
|
|
case Length(AItems) of
|
|
0: Result := TImplDataTupleValue0.Singleton;
|
|
1: Result := TImplDataTupleValue1.Create(AItems);
|
|
2: Result := TImplDataTupleValue2.Create(AItems);
|
|
3: Result := TImplDataTupleValue3.Create(AItems);
|
|
4: Result := TImplDataTupleValue4.Create(AItems);
|
|
5: Result := TImplDataTupleValue5.Create(AItems);
|
|
else
|
|
// Use the generic implementation for tuples with more than 5 elements.
|
|
Result := TImplDataTupleValue.Create(AItems);
|
|
end;
|
|
end;
|
|
|
|
function TImplDataTupleType.GetName: String;
|
|
begin
|
|
Result := 'Tuple';
|
|
end;
|
|
|
|
function TImplDataTupleType.GetKind: TDataKind;
|
|
begin
|
|
Result := dkTuple;
|
|
end;
|
|
|
|
end.
|