Types added to Tuples
This commit is contained in:
+20
-14
@@ -162,14 +162,20 @@ type
|
|||||||
AOperator: TBinaryOperator;
|
AOperator: TBinaryOperator;
|
||||||
ARight: IExpressionNode
|
ARight: IExpressionNode
|
||||||
): IBinaryExpressionNode; static;
|
): IBinaryExpressionNode; static;
|
||||||
class function UnaryExpr(AOperator: TUnaryOperator; ARight: IExpressionNode): IUnaryExpressionNode; static;
|
class function UnaryExpr(const AOperator: TUnaryOperator; const ARight: IExpressionNode): IUnaryExpressionNode; static;
|
||||||
class function IfExpr(ACondition: IExpressionNode; AThenBranch, AElseBranch: IExpressionNode): IIfExpressionNode; static;
|
class function IfExpr(
|
||||||
class function LambdaExpr(const AParameters: array of IIdentifierNode; ABody: IAstNode): ILambdaExpressionNode; static;
|
const ACondition: IExpressionNode;
|
||||||
class function FunctionCall(ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode; static;
|
const AThenBranch, AElseBranch: IExpressionNode
|
||||||
|
): IIfExpressionNode; static;
|
||||||
|
class function LambdaExpr(const AParameters: array of IIdentifierNode; const ABody: IAstNode): ILambdaExpressionNode; static;
|
||||||
|
class function FunctionCall(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode; static;
|
||||||
// Statements
|
// Statements
|
||||||
class function Block(const AStatements: array of IStatementNode): IBlockStatementNode; static;
|
class function Block(const AStatements: array of IStatementNode): IBlockStatementNode; static;
|
||||||
class function VarDecl(AIdentifier: IIdentifierNode; AInitializer: IExpressionNode): IVariableDeclarationStatementNode; static;
|
class function VarDecl(
|
||||||
class function ExprStmt(AExpression: IExpressionNode): IExpressionStatementNode; static;
|
const AIdentifier: IIdentifierNode;
|
||||||
|
AInitializer: IExpressionNode
|
||||||
|
): IVariableDeclarationStatementNode; static;
|
||||||
|
class function ExprStmt(const AExpression: IExpressionNode): IExpressionStatementNode; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Manages the scope of execution, holding variables and their values.
|
// Manages the scope of execution, holding variables and their values.
|
||||||
@@ -188,7 +194,7 @@ type
|
|||||||
TEvaluatorVisitor = class(TInterfacedObject, IAstVisitor)
|
TEvaluatorVisitor = class(TInterfacedObject, IAstVisitor)
|
||||||
private
|
private
|
||||||
FScope: TExecutionScope;
|
FScope: TExecutionScope;
|
||||||
function IsTruthy(AValue: IDataValue): Boolean;
|
function IsTruthy(const AValue: IDataValue): Boolean;
|
||||||
public
|
public
|
||||||
constructor Create(AScope: TExecutionScope);
|
constructor Create(AScope: TExecutionScope);
|
||||||
// Expression visitors
|
// Expression visitors
|
||||||
@@ -335,17 +341,17 @@ begin
|
|||||||
Result := TBinaryExpressionNodeImpl.Create(ALeft, AOperator, ARight);
|
Result := TBinaryExpressionNodeImpl.Create(ALeft, AOperator, ARight);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.UnaryExpr(AOperator: TUnaryOperator; ARight: IExpressionNode): IUnaryExpressionNode;
|
class function TAst.UnaryExpr(const AOperator: TUnaryOperator; const ARight: IExpressionNode): IUnaryExpressionNode;
|
||||||
begin
|
begin
|
||||||
Result := TUnaryExpressionNodeImpl.Create(AOperator, ARight);
|
Result := TUnaryExpressionNodeImpl.Create(AOperator, ARight);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.IfExpr(ACondition: IExpressionNode; AThenBranch, AElseBranch: IExpressionNode): IIfExpressionNode;
|
class function TAst.IfExpr(const ACondition: IExpressionNode; const AThenBranch, AElseBranch: IExpressionNode): IIfExpressionNode;
|
||||||
begin
|
begin
|
||||||
Result := TIfExpressionNodeImpl.Create(ACondition, AThenBranch, AElseBranch);
|
Result := TIfExpressionNodeImpl.Create(ACondition, AThenBranch, AElseBranch);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.LambdaExpr(const AParameters: array of IIdentifierNode; ABody: IAstNode): ILambdaExpressionNode;
|
class function TAst.LambdaExpr(const AParameters: array of IIdentifierNode; const ABody: IAstNode): ILambdaExpressionNode;
|
||||||
var
|
var
|
||||||
paramList: TList<IIdentifierNode>;
|
paramList: TList<IIdentifierNode>;
|
||||||
param: IIdentifierNode;
|
param: IIdentifierNode;
|
||||||
@@ -356,7 +362,7 @@ begin
|
|||||||
Result := TLambdaExpressionNodeImpl.Create(paramList, ABody);
|
Result := TLambdaExpressionNodeImpl.Create(paramList, ABody);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.FunctionCall(ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode;
|
class function TAst.FunctionCall(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode;
|
||||||
var
|
var
|
||||||
argList: TList<IExpressionNode>;
|
argList: TList<IExpressionNode>;
|
||||||
arg: IExpressionNode;
|
arg: IExpressionNode;
|
||||||
@@ -378,12 +384,12 @@ begin
|
|||||||
Result := TBlockStatementNodeImpl.Create(stmtList);
|
Result := TBlockStatementNodeImpl.Create(stmtList);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.VarDecl(AIdentifier: IIdentifierNode; AInitializer: IExpressionNode): IVariableDeclarationStatementNode;
|
class function TAst.VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IExpressionNode): IVariableDeclarationStatementNode;
|
||||||
begin
|
begin
|
||||||
Result := TVariableDeclarationStatementNodeImpl.Create(AIdentifier, AInitializer);
|
Result := TVariableDeclarationStatementNodeImpl.Create(AIdentifier, AInitializer);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.ExprStmt(AExpression: IExpressionNode): IExpressionStatementNode;
|
class function TAst.ExprStmt(const AExpression: IExpressionNode): IExpressionStatementNode;
|
||||||
begin
|
begin
|
||||||
Result := TExpressionStatementNodeImpl.Create(AExpression);
|
Result := TExpressionStatementNodeImpl.Create(AExpression);
|
||||||
end;
|
end;
|
||||||
@@ -673,7 +679,7 @@ begin
|
|||||||
FScope := AScope;
|
FScope := AScope;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TEvaluatorVisitor.IsTruthy(AValue: IDataValue): Boolean;
|
function TEvaluatorVisitor.IsTruthy(const AValue: IDataValue): Boolean;
|
||||||
begin
|
begin
|
||||||
// Defines the language's concept of "truthiness".
|
// Defines the language's concept of "truthiness".
|
||||||
// For now, only ordinals can be conditions. 0 is false, everything else is true.
|
// For now, only ordinals can be conditions. 0 is false, everything else is true.
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ type
|
|||||||
class constructor CreateClass;
|
class constructor CreateClass;
|
||||||
class destructor DestroyClass;
|
class destructor DestroyClass;
|
||||||
|
|
||||||
// Factory method to get a cached or new record type instance.
|
|
||||||
class function GetInstance(const AFields: TArray<TDataRecordField>): IDataRecordType; overload; static;
|
|
||||||
class function GetInstance(const AFields: array of TDataRecordField): IDataRecordType; overload; static;
|
class function GetInstance(const AFields: array of TDataRecordField): IDataRecordType; overload; static;
|
||||||
|
|
||||||
// TODO Create a record ba analyzing the RTTI of T
|
// TODO Create a record ba analyzing the RTTI of T
|
||||||
@@ -302,16 +300,22 @@ begin
|
|||||||
FRecordTypeRegistry := nil;
|
FRecordTypeRegistry := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TImplDataRecordType.GetInstance(const AFields: TArray<TDataRecordField>): IDataRecordType;
|
class function TImplDataRecordType.GetInstance(const AFields: array of TDataRecordField): IDataRecordType;
|
||||||
var
|
var
|
||||||
|
tFields: TArray<TDataRecordField>;
|
||||||
|
i: Integer;
|
||||||
res: IDataRecordType;
|
res: IDataRecordType;
|
||||||
begin
|
begin
|
||||||
|
SetLength(tFields, Length(AFields));
|
||||||
|
for i := 0 to High(AFields) do
|
||||||
|
tFields[i] := AFields[i];
|
||||||
|
|
||||||
TMonitor.Enter(FRecordTypeRegistry);
|
TMonitor.Enter(FRecordTypeRegistry);
|
||||||
try
|
try
|
||||||
if not FRecordTypeRegistry.TryGetValue(AFields, res) then
|
if not FRecordTypeRegistry.TryGetValue(tFields, res) then
|
||||||
begin
|
begin
|
||||||
res := TImplDataRecordType.Create(AFields);
|
res := TImplDataRecordType.Create(tFields);
|
||||||
FRecordTypeRegistry.Add(AFields, res);
|
FRecordTypeRegistry.Add(tFields, res);
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
TMonitor.Exit(FRecordTypeRegistry);
|
TMonitor.Exit(FRecordTypeRegistry);
|
||||||
@@ -319,17 +323,6 @@ begin
|
|||||||
Result := res;
|
Result := res;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TImplDataRecordType.GetInstance(const AFields: array of TDataRecordField): IDataRecordType;
|
|
||||||
var
|
|
||||||
tFields: TArray<TDataRecordField>;
|
|
||||||
i: Integer;
|
|
||||||
begin
|
|
||||||
SetLength(tFields, Length(AFields));
|
|
||||||
for i := 0 to High(AFields) do
|
|
||||||
tFields[i] := AFields[i];
|
|
||||||
Result := GetInstance(tFields);
|
|
||||||
end;
|
|
||||||
|
|
||||||
class function TImplDataRecordType.GetInstance<T>: IDataRecordType;
|
class function TImplDataRecordType.GetInstance<T>: IDataRecordType;
|
||||||
var
|
var
|
||||||
ctx: TRttiContext;
|
ctx: TRttiContext;
|
||||||
|
|||||||
+226
-138
@@ -3,121 +3,283 @@ unit Myc.Data.Types.Tuple;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
System.Generics.Collections,
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
|
System.Generics.Defaults,
|
||||||
|
System.Hash,
|
||||||
Myc.Data.Types;
|
Myc.Data.Types;
|
||||||
|
|
||||||
type
|
type
|
||||||
// Implements the singleton tuple data type.
|
// Custom comparer for TArray<IDataType> to be used as a dictionary key.
|
||||||
|
TDataTupleTypeComparer = class(TInterfacedObject, IEqualityComparer<TArray<IDataType>>)
|
||||||
|
public
|
||||||
|
function Equals(const Left, Right: TArray<IDataType>): Boolean; reintroduce;
|
||||||
|
function GetHashCode(const Value: TArray<IDataType>): Integer; reintroduce;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Implements the tuple data type.
|
||||||
TImplDataTupleType = class(TInterfacedObject, IDataType, IDataTupleType)
|
TImplDataTupleType = class(TInterfacedObject, IDataType, IDataTupleType)
|
||||||
strict private
|
strict private
|
||||||
|
// Class-level registry to cache and reuse tuple type definitions.
|
||||||
class var
|
class var
|
||||||
FSingleton: IDataTupleType;
|
FTupleTypeRegistry: TDictionary<TArray<IDataType>, IDataTupleType>;
|
||||||
class constructor CreateClass;
|
|
||||||
private
|
private
|
||||||
|
FItemTypes: TArray<IDataType>;
|
||||||
|
FEmptyValue: IDataTupleValue; // Cached instance for zero-field tuples
|
||||||
function GetName: String;
|
function GetName: String;
|
||||||
function GetKind: TDataKind;
|
function GetKind: TDataKind;
|
||||||
public
|
|
||||||
function CreateValue(const AItems: array of IDataValue): IDataTupleValue;
|
function CreateValue(const AItems: array of IDataValue): IDataTupleValue;
|
||||||
class property Singleton: IDataTupleType read FSingleton;
|
function GetItemCount: Integer;
|
||||||
|
function GetItemType(Idx: Integer): IDataType;
|
||||||
|
public
|
||||||
|
constructor Create(const AItemTypes: TArray<IDataType>);
|
||||||
|
destructor Destroy; override;
|
||||||
|
|
||||||
|
class constructor CreateClass;
|
||||||
|
class destructor DestroyClass;
|
||||||
|
|
||||||
|
class function GetInstance(const AItemTypes: array of IDataType): IDataTupleType; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.SyncObjs,
|
||||||
|
System.Rtti;
|
||||||
|
|
||||||
type
|
type
|
||||||
// Implements the simple tuple data value.
|
// Implements the tuple data value.
|
||||||
TImplDataTupleValue = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
TImplDataTupleValue = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||||
private
|
private
|
||||||
|
FDataType: IDataTupleType;
|
||||||
FItems: TArray<IDataValue>;
|
FItems: TArray<IDataValue>;
|
||||||
function GetDataType: IDataType;
|
function GetDataType: IDataType;
|
||||||
function GetAsString: string;
|
function GetAsString: string;
|
||||||
function GetItemCount: Integer;
|
function GetItemCount: Integer;
|
||||||
function GetItem(Idx: Integer): IDataValue;
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
public
|
public
|
||||||
constructor Create(const AItems: array of IDataValue);
|
constructor Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Optimized singleton implementation for a tuple with 0 elements.
|
// Optimized implementation for a tuple with 0 fields.
|
||||||
TImplDataTupleValue0 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
TImplDataTupleValue0 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||||
strict private
|
|
||||||
class var
|
|
||||||
FSingleton: IDataTupleValue;
|
|
||||||
class constructor CreateClass;
|
|
||||||
private
|
private
|
||||||
|
FDataType: IDataTupleType;
|
||||||
function GetDataType: IDataType;
|
function GetDataType: IDataType;
|
||||||
function GetAsString: string;
|
function GetAsString: string;
|
||||||
function GetItemCount: Integer;
|
function GetItemCount: Integer;
|
||||||
function GetItem(Idx: Integer): IDataValue;
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
public
|
public
|
||||||
class property Singleton: IDataTupleValue read FSingleton;
|
constructor Create(const ADataType: IDataTupleType);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Optimized implementation for a tuple with 1 element.
|
// Optimized implementation for a tuple with 1 field.
|
||||||
TImplDataTupleValue1 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
TImplDataTupleValue1 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||||
private
|
private
|
||||||
|
FDataType: IDataTupleType;
|
||||||
FItem0: IDataValue;
|
FItem0: IDataValue;
|
||||||
function GetDataType: IDataType;
|
function GetDataType: IDataType;
|
||||||
function GetAsString: string;
|
function GetAsString: string;
|
||||||
function GetItemCount: Integer;
|
function GetItemCount: Integer;
|
||||||
function GetItem(Idx: Integer): IDataValue;
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
public
|
public
|
||||||
constructor Create(const AItems: array of IDataValue);
|
constructor Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Optimized implementation for a tuple with 2 elements.
|
// Optimized implementation for a tuple with 2 fields.
|
||||||
TImplDataTupleValue2 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
TImplDataTupleValue2 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||||
private
|
private
|
||||||
|
FDataType: IDataTupleType;
|
||||||
FItem0, FItem1: IDataValue;
|
FItem0, FItem1: IDataValue;
|
||||||
function GetDataType: IDataType;
|
function GetDataType: IDataType;
|
||||||
function GetAsString: string;
|
function GetAsString: string;
|
||||||
function GetItemCount: Integer;
|
function GetItemCount: Integer;
|
||||||
function GetItem(Idx: Integer): IDataValue;
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
public
|
public
|
||||||
constructor Create(const AItems: array of IDataValue);
|
constructor Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Optimized implementation for a tuple with 3 elements.
|
// Optimized implementation for a tuple with 3 fields.
|
||||||
TImplDataTupleValue3 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
TImplDataTupleValue3 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||||
private
|
private
|
||||||
|
FDataType: IDataTupleType;
|
||||||
FItem0, FItem1, FItem2: IDataValue;
|
FItem0, FItem1, FItem2: IDataValue;
|
||||||
function GetDataType: IDataType;
|
function GetDataType: IDataType;
|
||||||
function GetAsString: string;
|
function GetAsString: string;
|
||||||
function GetItemCount: Integer;
|
function GetItemCount: Integer;
|
||||||
function GetItem(Idx: Integer): IDataValue;
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
public
|
public
|
||||||
constructor Create(const AItems: array of IDataValue);
|
constructor Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Optimized implementation for a tuple with 4 elements.
|
// Optimized implementation for a tuple with 4 fields.
|
||||||
TImplDataTupleValue4 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
TImplDataTupleValue4 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||||
private
|
private
|
||||||
|
FDataType: IDataTupleType;
|
||||||
FItem0, FItem1, FItem2, FItem3: IDataValue;
|
FItem0, FItem1, FItem2, FItem3: IDataValue;
|
||||||
function GetDataType: IDataType;
|
function GetDataType: IDataType;
|
||||||
function GetAsString: string;
|
function GetAsString: string;
|
||||||
function GetItemCount: Integer;
|
function GetItemCount: Integer;
|
||||||
function GetItem(Idx: Integer): IDataValue;
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
public
|
public
|
||||||
constructor Create(const AItems: array of IDataValue);
|
constructor Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Optimized implementation for a tuple with 5 elements.
|
{ TDataTupleTypeComparer }
|
||||||
TImplDataTupleValue5 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
|
||||||
private
|
function TDataTupleTypeComparer.Equals(const Left, Right: TArray<IDataType>): Boolean;
|
||||||
FItem0, FItem1, FItem2, FItem3, FItem4: IDataValue;
|
var
|
||||||
function GetDataType: IDataType;
|
i: Integer;
|
||||||
function GetAsString: string;
|
begin
|
||||||
function GetItemCount: Integer;
|
if (Length(Left) <> Length(Right)) then
|
||||||
function GetItem(Idx: Integer): IDataValue;
|
exit(False);
|
||||||
public
|
|
||||||
constructor Create(const AItems: array of IDataValue);
|
for i := 0 to High(Left) do
|
||||||
|
begin
|
||||||
|
// Compare by interface reference.
|
||||||
|
// It's safe because all IDataType instances are managed by GetInstance singletons.
|
||||||
|
if (Left[i] <> Right[i]) then
|
||||||
|
exit(False);
|
||||||
end;
|
end;
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TImplDataTupleValue (generic implementation for N > 5 elements) }
|
function TDataTupleTypeComparer.GetHashCode(const Value: TArray<IDataType>): Integer;
|
||||||
|
var
|
||||||
|
dataType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
for dataType in Value do
|
||||||
|
begin
|
||||||
|
// Use the hash of the interface's memory address.
|
||||||
|
// This is safe and fast due to the singleton pattern for types.
|
||||||
|
Result := Integer(PPointer(@dataType)^) xor Result;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TImplDataTupleValue.Create(const AItems: array of IDataValue);
|
{ TImplDataTupleType }
|
||||||
|
|
||||||
|
class constructor TImplDataTupleType.CreateClass;
|
||||||
|
begin
|
||||||
|
// Initialize the global registry for tuple types.
|
||||||
|
FTupleTypeRegistry := TDictionary<TArray<IDataType>, IDataTupleType>.Create(TDataTupleTypeComparer.Create);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class destructor TImplDataTupleType.DestroyClass;
|
||||||
|
begin
|
||||||
|
FTupleTypeRegistry.Free;
|
||||||
|
FTupleTypeRegistry := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TImplDataTupleType.Create(const AItemTypes: TArray<IDataType>);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FItemTypes := AItemTypes;
|
||||||
|
|
||||||
|
// Pre-create the singleton value instance if this is a zero-field tuple.
|
||||||
|
if (Length(FItemTypes) = 0) then
|
||||||
|
FEmptyValue := TImplDataTupleValue0.Create(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TImplDataTupleType.Destroy;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataTupleType.CreateValue(const AItems: array of IDataValue): IDataTupleValue;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if (Length(AItems) <> Length(FItemTypes)) then
|
||||||
|
raise EArgumentException
|
||||||
|
.CreateFmt('Invalid number of items for this tuple type. Expected %d, but got %d.', [Length(FItemTypes), Length(AItems)]);
|
||||||
|
|
||||||
|
for i := 0 to High(AItems) do
|
||||||
|
if not Assigned(AItems[i]) or (AItems[i].DataType <> FItemTypes[i]) then
|
||||||
|
raise EArgumentException.CreateFmt(
|
||||||
|
'Invalid data type for item at index %d. Expected %s, but got %s.',
|
||||||
|
[i, FItemTypes[i].Name, AItems[i].DataType.Name]);
|
||||||
|
|
||||||
|
// Use optimized implementations for tuples with 0, 1, 2, 3, or 4 fields.
|
||||||
|
case Length(FItemTypes) of
|
||||||
|
0: Result := FEmptyValue; // Return the pre-cached instance.
|
||||||
|
1: Result := TImplDataTupleValue1.Create(Self, AItems);
|
||||||
|
2: Result := TImplDataTupleValue2.Create(Self, AItems);
|
||||||
|
3: Result := TImplDataTupleValue3.Create(Self, AItems);
|
||||||
|
4: Result := TImplDataTupleValue4.Create(Self, AItems);
|
||||||
|
else
|
||||||
|
// Use the generic implementation for tuples with more than 4 fields.
|
||||||
|
Result := TImplDataTupleValue.Create(Self, AItems);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TImplDataTupleType.GetInstance(const AItemTypes: array of IDataType): IDataTupleType;
|
||||||
|
var
|
||||||
|
tItems: TArray<IDataType>;
|
||||||
|
i: Integer;
|
||||||
|
res: IDataTupleType;
|
||||||
|
begin
|
||||||
|
SetLength(tItems, Length(AItemTypes));
|
||||||
|
for i := 0 to High(AItemTypes) do
|
||||||
|
tItems[i] := AItemTypes[i];
|
||||||
|
|
||||||
|
TMonitor.Enter(FTupleTypeRegistry);
|
||||||
|
try
|
||||||
|
if not FTupleTypeRegistry.TryGetValue(tItems, res) then
|
||||||
|
begin
|
||||||
|
res := TImplDataTupleType.Create(tItems);
|
||||||
|
FTupleTypeRegistry.Add(tItems, res);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
TMonitor.Exit(FTupleTypeRegistry);
|
||||||
|
end;
|
||||||
|
Result := res;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataTupleType.GetItemCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := Length(FItemTypes);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataTupleType.GetItemType(Idx: Integer): IDataType;
|
||||||
|
begin
|
||||||
|
Result := FItemTypes[Idx];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataTupleType.GetName: String;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
sb: TStringBuilder;
|
||||||
|
begin
|
||||||
|
sb := TStringBuilder.Create;
|
||||||
|
try
|
||||||
|
sb.Append('Tuple<');
|
||||||
|
for i := 0 to High(FItemTypes) do
|
||||||
|
begin
|
||||||
|
sb.Append(FItemTypes[i].Name);
|
||||||
|
if (i < High(FItemTypes)) then
|
||||||
|
sb.Append(', ');
|
||||||
|
end;
|
||||||
|
sb.Append('>');
|
||||||
|
Result := sb.ToString;
|
||||||
|
finally
|
||||||
|
sb.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataTupleType.GetKind: TDataKind;
|
||||||
|
begin
|
||||||
|
Result := dkTuple;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TImplDataTupleValue (generic implementation for N > 4 fields) }
|
||||||
|
|
||||||
|
constructor TImplDataTupleValue.Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
SetLength(FItems, Length(AItems));
|
SetLength(FItems, Length(AItems));
|
||||||
for i := 0 to High(AItems) do
|
for i := 0 to High(AItems) do
|
||||||
FItems[i] := AItems[i];
|
FItems[i] := AItems[i];
|
||||||
@@ -125,7 +287,7 @@ end;
|
|||||||
|
|
||||||
function TImplDataTupleValue.GetDataType: IDataType;
|
function TImplDataTupleValue.GetDataType: IDataType;
|
||||||
begin
|
begin
|
||||||
Result := TImplDataTupleType.Singleton;
|
Result := FDataType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue.GetAsString: string;
|
function TImplDataTupleValue.GetAsString: string;
|
||||||
@@ -161,9 +323,10 @@ end;
|
|||||||
|
|
||||||
{ TImplDataTupleValue0 }
|
{ TImplDataTupleValue0 }
|
||||||
|
|
||||||
class constructor TImplDataTupleValue0.CreateClass;
|
constructor TImplDataTupleValue0.Create(const ADataType: IDataTupleType);
|
||||||
begin
|
begin
|
||||||
FSingleton := TImplDataTupleValue0.Create;
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue0.GetAsString: string;
|
function TImplDataTupleValue0.GetAsString: string;
|
||||||
@@ -173,7 +336,7 @@ end;
|
|||||||
|
|
||||||
function TImplDataTupleValue0.GetDataType: IDataType;
|
function TImplDataTupleValue0.GetDataType: IDataType;
|
||||||
begin
|
begin
|
||||||
Result := TImplDataTupleType.Singleton;
|
Result := FDataType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue0.GetItem(Idx: Integer): IDataValue;
|
function TImplDataTupleValue0.GetItem(Idx: Integer): IDataValue;
|
||||||
@@ -188,20 +351,21 @@ end;
|
|||||||
|
|
||||||
{ TImplDataTupleValue1 }
|
{ TImplDataTupleValue1 }
|
||||||
|
|
||||||
constructor TImplDataTupleValue1.Create(const AItems: array of IDataValue);
|
constructor TImplDataTupleValue1.Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
FItem0 := AItems[0];
|
FItem0 := AItems[0];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue1.GetAsString: string;
|
function TImplDataTupleValue1.GetAsString: string;
|
||||||
begin
|
begin
|
||||||
Result := '(' + FItem0.AsString + ')';
|
Result := Format('(%s)', [FItem0.AsString]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue1.GetDataType: IDataType;
|
function TImplDataTupleValue1.GetDataType: IDataType;
|
||||||
begin
|
begin
|
||||||
Result := TImplDataTupleType.Singleton;
|
Result := FDataType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue1.GetItem(Idx: Integer): IDataValue;
|
function TImplDataTupleValue1.GetItem(Idx: Integer): IDataValue;
|
||||||
@@ -220,21 +384,34 @@ end;
|
|||||||
|
|
||||||
{ TImplDataTupleValue2 }
|
{ TImplDataTupleValue2 }
|
||||||
|
|
||||||
constructor TImplDataTupleValue2.Create(const AItems: array of IDataValue);
|
constructor TImplDataTupleValue2.Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
FItem0 := AItems[0];
|
FItem0 := AItems[0];
|
||||||
FItem1 := AItems[1];
|
FItem1 := AItems[1];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue2.GetAsString: string;
|
function TImplDataTupleValue2.GetAsString: string;
|
||||||
|
var
|
||||||
|
sb: TStringBuilder;
|
||||||
begin
|
begin
|
||||||
Result := '(' + FItem0.AsString + ', ' + FItem1.AsString + ')';
|
sb := TStringBuilder.Create;
|
||||||
|
try
|
||||||
|
sb.Append('(');
|
||||||
|
sb.Append(FItem0.AsString);
|
||||||
|
sb.Append(', ');
|
||||||
|
sb.Append(FItem1.AsString);
|
||||||
|
sb.Append(')');
|
||||||
|
Result := sb.ToString;
|
||||||
|
finally
|
||||||
|
sb.Free;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue2.GetDataType: IDataType;
|
function TImplDataTupleValue2.GetDataType: IDataType;
|
||||||
begin
|
begin
|
||||||
Result := TImplDataTupleType.Singleton;
|
Result := FDataType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue2.GetItem(Idx: Integer): IDataValue;
|
function TImplDataTupleValue2.GetItem(Idx: Integer): IDataValue;
|
||||||
@@ -254,9 +431,10 @@ end;
|
|||||||
|
|
||||||
{ TImplDataTupleValue3 }
|
{ TImplDataTupleValue3 }
|
||||||
|
|
||||||
constructor TImplDataTupleValue3.Create(const AItems: array of IDataValue);
|
constructor TImplDataTupleValue3.Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
FItem0 := AItems[0];
|
FItem0 := AItems[0];
|
||||||
FItem1 := AItems[1];
|
FItem1 := AItems[1];
|
||||||
FItem2 := AItems[2];
|
FItem2 := AItems[2];
|
||||||
@@ -283,7 +461,7 @@ end;
|
|||||||
|
|
||||||
function TImplDataTupleValue3.GetDataType: IDataType;
|
function TImplDataTupleValue3.GetDataType: IDataType;
|
||||||
begin
|
begin
|
||||||
Result := TImplDataTupleType.Singleton;
|
Result := FDataType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue3.GetItem(Idx: Integer): IDataValue;
|
function TImplDataTupleValue3.GetItem(Idx: Integer): IDataValue;
|
||||||
@@ -304,9 +482,10 @@ end;
|
|||||||
|
|
||||||
{ TImplDataTupleValue4 }
|
{ TImplDataTupleValue4 }
|
||||||
|
|
||||||
constructor TImplDataTupleValue4.Create(const AItems: array of IDataValue);
|
constructor TImplDataTupleValue4.Create(const ADataType: IDataTupleType; const AItems: array of IDataValue);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
FItem0 := AItems[0];
|
FItem0 := AItems[0];
|
||||||
FItem1 := AItems[1];
|
FItem1 := AItems[1];
|
||||||
FItem2 := AItems[2];
|
FItem2 := AItems[2];
|
||||||
@@ -336,7 +515,7 @@ end;
|
|||||||
|
|
||||||
function TImplDataTupleValue4.GetDataType: IDataType;
|
function TImplDataTupleValue4.GetDataType: IDataType;
|
||||||
begin
|
begin
|
||||||
Result := TImplDataTupleType.Singleton;
|
Result := FDataType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImplDataTupleValue4.GetItem(Idx: Integer): IDataValue;
|
function TImplDataTupleValue4.GetItem(Idx: Integer): IDataValue;
|
||||||
@@ -356,95 +535,4 @@ begin
|
|||||||
Result := 4;
|
Result := 4;
|
||||||
end;
|
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.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.
|
end.
|
||||||
|
|||||||
+28
-11
@@ -591,11 +591,11 @@ type
|
|||||||
class function Text: TDataType.TText; static; inline;
|
class function Text: TDataType.TText; static; inline;
|
||||||
class function Timestamp: TDataType.TTimestamp; static; inline;
|
class function Timestamp: TDataType.TTimestamp; static; inline;
|
||||||
class function DecimalOf(const AScale: Integer): TDataType.TDecimal; static;
|
class function DecimalOf(const AScale: Integer): TDataType.TDecimal; static;
|
||||||
class function Tuple: TDataType.TTuple; static; inline;
|
class function TupleOf(const AItemTypes: array of IDataType): TDataType.TTuple; overload; static;
|
||||||
|
class function TupleOf(const AItemValues: array of IDataValue): TDataType.TTuple.TValue; overload; static;
|
||||||
class function MethodOf(const AArgType, AResultType: IDataType): TDataType.TMethod; static;
|
class function MethodOf(const AArgType, AResultType: IDataType): TDataType.TMethod; static;
|
||||||
class function ArrayOf(const AElementType: IDataType): TDataType.TArray; static;
|
class function ArrayOf(const AElementType: IDataType): TDataType.TArray; static;
|
||||||
class function VectorOf(const AElementType: IDataType; const AElementCount: Integer): TDataType.TVector; static;
|
class function VectorOf(const AElementType: IDataType; const AElementCount: Integer): TDataType.TVector; static;
|
||||||
class function RecordOf(const Fields: TArray<TDataRecordField>): TDataType.TRecord; overload; static;
|
|
||||||
class function RecordOf(const Fields: array of TDataRecordField): TDataType.TRecord; overload; static;
|
class function RecordOf(const Fields: array of TDataRecordField): TDataType.TRecord; overload; static;
|
||||||
class function RecordOf<T>: TDataType.TRecord; overload; static;
|
class function RecordOf<T>: TDataType.TRecord; overload; static;
|
||||||
class function EnumOf(const AName: string; const AIdentifiers: array of string): TDataType.TEnum; static;
|
class function EnumOf(const AName: string; const AIdentifiers: array of string): TDataType.TEnum; static;
|
||||||
@@ -669,7 +669,7 @@ var
|
|||||||
scaleValue: Integer;
|
scaleValue: Integer;
|
||||||
begin
|
begin
|
||||||
scaleValue := GetDataType.Scale;
|
scaleValue := GetDataType.Scale;
|
||||||
if scaleValue > 0 then
|
if (scaleValue > 0) then
|
||||||
Result := FDecimalValue.Value / Power(10, scaleValue)
|
Result := FDecimalValue.Value / Power(10, scaleValue)
|
||||||
else
|
else
|
||||||
Result := FDecimalValue.Value;
|
Result := FDecimalValue.Value;
|
||||||
@@ -1031,7 +1031,7 @@ var
|
|||||||
idx: Integer;
|
idx: Integer;
|
||||||
begin
|
begin
|
||||||
idx := IndexOf(AIdentifier);
|
idx := IndexOf(AIdentifier);
|
||||||
if idx < 0 then
|
if (idx < 0) then
|
||||||
raise EArgumentException.CreateFmt('Unknown identifier: %s', [AIdentifier]);
|
raise EArgumentException.CreateFmt('Unknown identifier: %s', [AIdentifier]);
|
||||||
Result := CreateValue(idx);
|
Result := CreateValue(idx);
|
||||||
end;
|
end;
|
||||||
@@ -1454,11 +1454,6 @@ begin
|
|||||||
Result.Create(TImplDataOrdinalType.Singleton);
|
Result.Create(TImplDataOrdinalType.Singleton);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TDataType.RecordOf(const Fields: TArray<TDataRecordField>): TDataType.TRecord;
|
|
||||||
begin
|
|
||||||
Result.Create(TImplDataRecordType.GetInstance(Fields));
|
|
||||||
end;
|
|
||||||
|
|
||||||
class function TDataType.RecordOf(const Fields: array of TDataRecordField): TDataType.TRecord;
|
class function TDataType.RecordOf(const Fields: array of TDataRecordField): TDataType.TRecord;
|
||||||
begin
|
begin
|
||||||
Result.Create(TImplDataRecordType.GetInstance(Fields));
|
Result.Create(TImplDataRecordType.GetInstance(Fields));
|
||||||
@@ -1479,9 +1474,31 @@ begin
|
|||||||
Result.Create(TImplDataTimestampType.Singleton);
|
Result.Create(TImplDataTimestampType.Singleton);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TDataType.Tuple: TDataType.TTuple;
|
class function TDataType.TupleOf(const AItemTypes: array of IDataType): TDataType.TTuple;
|
||||||
|
var
|
||||||
|
tItems: TArray<IDataType>;
|
||||||
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
Result.Create(TImplDataTupleType.Singleton);
|
SetLength(tItems, Length(AItemTypes));
|
||||||
|
for i := 0 to High(AItemTypes) do
|
||||||
|
tItems[i] := AItemTypes[i];
|
||||||
|
|
||||||
|
// Use the instance manager to get a tuple type for the given element types.
|
||||||
|
Result.Create(TImplDataTupleType.GetInstance(tItems));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TDataType.TupleOf(const AItemValues: array of IDataValue): TDataType.TTuple.TValue;
|
||||||
|
var
|
||||||
|
tItems: TArray<IDataType>;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
SetLength(tItems, Length(AItemValues));
|
||||||
|
for i := 0 to High(AItemValues) do
|
||||||
|
tItems[i] := AItemValues[i].DataType;
|
||||||
|
|
||||||
|
var tTuple := TImplDataTupleType.GetInstance(tItems);
|
||||||
|
|
||||||
|
Result := tTuple.CreateValue(AItemValues);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TDataType.VectorOf(const AElementType: IDataType; const AElementCount: Integer): TDataType.TVector;
|
class function TDataType.VectorOf(const AElementType: IDataType; const AElementCount: Integer): TDataType.TVector;
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ begin
|
|||||||
floatValue := TDataType.Float.CreateValue(45.67);
|
floatValue := TDataType.Float.CreateValue(45.67);
|
||||||
|
|
||||||
// --- 2. Test Value Creation and basic properties ---
|
// --- 2. Test Value Creation and basic properties ---
|
||||||
tuple1 := TDataType.Tuple.CreateValue([intValue, floatValue]);
|
tuple1 := TDataType.TupleOf([intValue, floatValue]);
|
||||||
|
|
||||||
Assert.IsNotNull(IDataTupleValue(tuple1), 'Tuple value should be created');
|
Assert.IsNotNull(IDataTupleValue(tuple1), 'Tuple value should be created');
|
||||||
Assert.AreEqual(2, tuple1.ItemCount, 'ItemCount should be on the value');
|
Assert.AreEqual(2, tuple1.ItemCount, 'ItemCount should be on the value');
|
||||||
@@ -181,8 +181,8 @@ begin
|
|||||||
|
|
||||||
// --- 3. Test Singleton Type Behavior ---
|
// --- 3. Test Singleton Type Behavior ---
|
||||||
// Create more tuples with different structures
|
// Create more tuples with different structures
|
||||||
tuple2 := TDataType.Tuple.CreateValue([TDataType.Ordinal.CreateValue(99), TDataType.Float.CreateValue(1.1)]);
|
tuple2 := TDataType.TupleOf([TDataType.Ordinal.CreateValue(99), TDataType.Float.CreateValue(1.1)]);
|
||||||
tuple3 := TDataType.Tuple.CreateValue([intValue]);
|
tuple3 := TDataType.TupleOf([intValue]);
|
||||||
|
|
||||||
// Access the DataType via the underlying interface
|
// Access the DataType via the underlying interface
|
||||||
type1 := tuple1.DataType;
|
type1 := tuple1.DataType;
|
||||||
@@ -190,11 +190,7 @@ begin
|
|||||||
type3 := tuple3.DataType;
|
type3 := tuple3.DataType;
|
||||||
|
|
||||||
Assert.IsNotNull(type1, 'DataType interface should be accessible');
|
Assert.IsNotNull(type1, 'DataType interface should be accessible');
|
||||||
Assert.AreEqual('Tuple', type1.Name, 'The type name for all tuples should be Tuple');
|
Assert.AreEqual('Tuple<Integer, Float>', type1.Name, 'The type name for all tuples should be Tuple');
|
||||||
|
|
||||||
// The core test: All tuples, regardless of their content, must share the exact same singleton type object.
|
|
||||||
Assert.AreSame(type1, type2, 'All tuple types should be the same singleton instance');
|
|
||||||
Assert.AreSame(type1, type3, 'All tuple types should be the same singleton instance');
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMyTestObject.TestTuples_Generic;
|
procedure TMyTestObject.TestTuples_Generic;
|
||||||
@@ -204,7 +200,7 @@ var
|
|||||||
begin
|
begin
|
||||||
// Test the generic implementation for tuples with > 5 elements.
|
// Test the generic implementation for tuples with > 5 elements.
|
||||||
tupleValue :=
|
tupleValue :=
|
||||||
TDataType.Tuple.CreateValue(
|
TDataType.TupleOf(
|
||||||
[
|
[
|
||||||
TDataType.Ordinal.CreateValue(1),
|
TDataType.Ordinal.CreateValue(1),
|
||||||
TDataType.Ordinal.CreateValue(2),
|
TDataType.Ordinal.CreateValue(2),
|
||||||
@@ -542,7 +538,7 @@ begin
|
|||||||
Assert.AreEqual('<ID: 1, Name: Bob>', IDataValue(recordValue).AsString, 'Record AsString incorrect');
|
Assert.AreEqual('<ID: 1, Name: Bob>', IDataValue(recordValue).AsString, 'Record AsString incorrect');
|
||||||
|
|
||||||
// Tuple
|
// Tuple
|
||||||
tupleValue := TDataType.Tuple.CreateValue([TDataType.Ordinal.CreateValue(10), TDataType.Text.CreateValue('Tuple')]);
|
tupleValue := TDataType.TupleOf([TDataType.Ordinal.CreateValue(10), TDataType.Text.CreateValue('Tuple')]);
|
||||||
Assert.AreEqual('(10, Tuple)', IDataValue(tupleValue).AsString, 'Tuple AsString incorrect');
|
Assert.AreEqual('(10, Tuple)', IDataValue(tupleValue).AsString, 'Tuple AsString incorrect');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user