Vector type
This commit is contained in:
@@ -12,11 +12,61 @@ type
|
|||||||
function AsTValue: TValue;
|
function AsTValue: TValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function RttiTypeToDataType(rttiType: TRttiType): TDataType;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
System.TypInfo,
|
||||||
System.Math;
|
System.Math;
|
||||||
|
|
||||||
|
// Recursively converts a TRttiType to an IDataType.
|
||||||
|
function RttiTypeToDataType(rttiType: TRttiType): TDataType;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
// Convert an RTTI type representation to its corresponding IDataType.
|
||||||
|
case rttiType.TypeKind of
|
||||||
|
tkInteger, tkInt64, tkChar, tkWChar: Result := TDataType.Ordinal;
|
||||||
|
tkFloat:
|
||||||
|
if (rttiType.Handle = TypeInfo(TDateTime)) then
|
||||||
|
Result := TDataType.Timestamp
|
||||||
|
else
|
||||||
|
Result := TDataType.Float;
|
||||||
|
tkString, tkWideString, tkUString: Result := TDataType.Text;
|
||||||
|
tkEnumeration:
|
||||||
|
begin
|
||||||
|
var enumType := rttiType as TRttiEnumerationType;
|
||||||
|
var names := enumType.GetNames;
|
||||||
|
var identifiers: TArray<string>;
|
||||||
|
SetLength(identifiers, Length(names));
|
||||||
|
for i := 0 to High(names) do
|
||||||
|
identifiers[i] := names[i];
|
||||||
|
Result := TDataType.EnumOf(enumType.Name, identifiers);
|
||||||
|
end;
|
||||||
|
tkDynArray:
|
||||||
|
begin
|
||||||
|
var arrayType := rttiType as TRttiDynamicArrayType;
|
||||||
|
Result := TDataType.ArrayOf(RttiTypeToDataType(arrayType.ElementType));
|
||||||
|
end;
|
||||||
|
tkRecord:
|
||||||
|
begin
|
||||||
|
var recordType := rttiType as TRttiRecordType;
|
||||||
|
var fields := recordType.GetFields;
|
||||||
|
var recordFields: TArray<TDataRecordField>;
|
||||||
|
SetLength(recordFields, Length(fields));
|
||||||
|
for i := 0 to High(fields) do
|
||||||
|
recordFields[i] := TDataRecordField.Create(fields[i].Name, RttiTypeToDataType(fields[i].FieldType));
|
||||||
|
Result := TDataType.RecordOf(recordFields);
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
// Raise an exception for unsupported types.
|
||||||
|
raise ENotSupportedException.CreateFmt(
|
||||||
|
'Type "%s" (Kind: %s) is not supported for RTTI-based record creation.',
|
||||||
|
[rttiType.Name, GetEnumName(TypeInfo(TTypeKind), Ord(rttiType.TypeKind))]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TValueHelper }
|
{ TValueHelper }
|
||||||
|
|
||||||
function TValueHelper.AsTValue: TValue;
|
function TValueHelper.AsTValue: TValue;
|
||||||
|
|||||||
@@ -38,17 +38,23 @@ type
|
|||||||
|
|
||||||
class constructor CreateClass;
|
class constructor CreateClass;
|
||||||
class destructor DestroyClass;
|
class destructor DestroyClass;
|
||||||
|
|
||||||
// Factory method to get a cached or new record type instance.
|
// 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: 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
|
||||||
|
class function GetInstance<T>: IDataRecordType; overload; static;
|
||||||
|
|
||||||
function CreateValue(const AItems: array of IDataValue): IDataRecordValue;
|
function CreateValue(const AItems: array of IDataValue): IDataRecordValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
System.SyncObjs;
|
System.SyncObjs,
|
||||||
|
System.Rtti,
|
||||||
|
Myc.Data.Types.RTTI;
|
||||||
|
|
||||||
type
|
type
|
||||||
// Implements the record data value.
|
// Implements the record data value.
|
||||||
@@ -324,6 +330,23 @@ begin
|
|||||||
Result := GetInstance(tFields);
|
Result := GetInstance(tFields);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TImplDataRecordType.GetInstance<T>: IDataRecordType;
|
||||||
|
var
|
||||||
|
ctx: TRttiContext;
|
||||||
|
rttiType: TRttiType;
|
||||||
|
begin
|
||||||
|
// Create an RTTI context to introspect the type T.
|
||||||
|
ctx := TRttiContext.Create;
|
||||||
|
rttiType := ctx.GetType(TypeInfo(T));
|
||||||
|
|
||||||
|
// The generic parameter T must be a record.
|
||||||
|
if not (rttiType is TRttiRecordType) then
|
||||||
|
raise EArgumentException.Create('Generic parameter T must be a record type.');
|
||||||
|
|
||||||
|
// Delegate the conversion from RTTI type to IDataType to the helper function.
|
||||||
|
Result := RttiTypeToDataType(rttiType).AsRecord;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TImplDataRecordType.Create(const AFields: array of TDataRecordField);
|
constructor TImplDataRecordType.Create(const AFields: array of TDataRecordField);
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
|
|||||||
@@ -0,0 +1,403 @@
|
|||||||
|
unit Myc.Data.Types.Vector;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.Generics.Collections,
|
||||||
|
Myc.Data.Types;
|
||||||
|
|
||||||
|
type
|
||||||
|
// Implements the IDataVectorType interface.
|
||||||
|
TImplDataVectorType = class(TInterfacedObject, IDataType, IDataVectorType)
|
||||||
|
private
|
||||||
|
// Registry for singleton type instances.
|
||||||
|
class var
|
||||||
|
FVectorTypeRegistry: TDictionary<String, IDataVectorType>;
|
||||||
|
|
||||||
|
FElementType: IDataType;
|
||||||
|
FElementCount: Integer;
|
||||||
|
FName: string;
|
||||||
|
function GetName: String;
|
||||||
|
function GetKind: TDataKind;
|
||||||
|
function GetElementType: IDataType;
|
||||||
|
function GetElementCount: Integer;
|
||||||
|
function CreateValue(const AItems: array of IDataValue): IDataVectorValue;
|
||||||
|
|
||||||
|
class constructor Create;
|
||||||
|
class destructor Destroy;
|
||||||
|
public
|
||||||
|
constructor Create(const AElementType: IDataType; const AElementCount: Integer);
|
||||||
|
|
||||||
|
// Gets a cached or new instance for the given element type and count.
|
||||||
|
class function GetInstance(const AElementType: IDataType; const AElementCount: Integer): IDataVectorType; static;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.SysUtils;
|
||||||
|
|
||||||
|
type
|
||||||
|
// Implements a generic vector value for N > 4 elements.
|
||||||
|
TImplDataVectorValue = class(TInterfacedObject, IDataVectorValue)
|
||||||
|
private
|
||||||
|
FDataType: IDataVectorType;
|
||||||
|
FItems: TArray<IDataValue>;
|
||||||
|
function GetDataType: IDataType;
|
||||||
|
function GetAsString: string;
|
||||||
|
function GetElementCount: Integer;
|
||||||
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
|
public
|
||||||
|
constructor Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Optimized implementation for a vector with 1 element.
|
||||||
|
TImplDataVectorValue1 = class(TInterfacedObject, IDataValue, IDataVectorValue)
|
||||||
|
private
|
||||||
|
FDataType: IDataVectorType;
|
||||||
|
FItem0: IDataValue;
|
||||||
|
function GetDataType: IDataType;
|
||||||
|
function GetAsString: string;
|
||||||
|
function GetElementCount: Integer;
|
||||||
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
|
public
|
||||||
|
constructor Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Optimized implementation for a vector with 2 elements.
|
||||||
|
TImplDataVectorValue2 = class(TInterfacedObject, IDataValue, IDataVectorValue)
|
||||||
|
private
|
||||||
|
FDataType: IDataVectorType;
|
||||||
|
FItem0, FItem1: IDataValue;
|
||||||
|
function GetDataType: IDataType;
|
||||||
|
function GetAsString: string;
|
||||||
|
function GetElementCount: Integer;
|
||||||
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
|
public
|
||||||
|
constructor Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Optimized implementation for a vector with 3 elements.
|
||||||
|
TImplDataVectorValue3 = class(TInterfacedObject, IDataValue, IDataVectorValue)
|
||||||
|
private
|
||||||
|
FDataType: IDataVectorType;
|
||||||
|
FItem0, FItem1, FItem2: IDataValue;
|
||||||
|
function GetDataType: IDataType;
|
||||||
|
function GetAsString: string;
|
||||||
|
function GetElementCount: Integer;
|
||||||
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
|
public
|
||||||
|
constructor Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Optimized implementation for a vector with 4 elements.
|
||||||
|
TImplDataVectorValue4 = class(TInterfacedObject, IDataValue, IDataVectorValue)
|
||||||
|
private
|
||||||
|
FDataType: IDataVectorType;
|
||||||
|
FItem0, FItem1, FItem2, FItem3: IDataValue;
|
||||||
|
function GetDataType: IDataType;
|
||||||
|
function GetAsString: string;
|
||||||
|
function GetElementCount: Integer;
|
||||||
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
|
public
|
||||||
|
constructor Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TImplDataVectorValue }
|
||||||
|
|
||||||
|
constructor TImplDataVectorValue.Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
|
SetLength(FItems, Length(AItems));
|
||||||
|
for i := 0 to High(FItems) do
|
||||||
|
FItems[i] := AItems[i];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue.GetAsString: string;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
sb: TStringBuilder;
|
||||||
|
begin
|
||||||
|
sb := TStringBuilder.Create;
|
||||||
|
try
|
||||||
|
sb.Append('(');
|
||||||
|
for i := 0 to High(FItems) do
|
||||||
|
begin
|
||||||
|
if (i > 0) then
|
||||||
|
sb.Append(', ');
|
||||||
|
sb.Append(FItems[i].AsString);
|
||||||
|
end;
|
||||||
|
sb.Append(')');
|
||||||
|
Result := sb.ToString;
|
||||||
|
finally
|
||||||
|
sb.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue.GetDataType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := FDataType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue.GetElementCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := Length(FItems);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue.GetItem(Idx: Integer): IDataValue;
|
||||||
|
begin
|
||||||
|
Result := FItems[Idx];
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TImplDataVectorValue1 }
|
||||||
|
|
||||||
|
constructor TImplDataVectorValue1.Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
|
FItem0 := AItems[0];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue1.GetAsString: string;
|
||||||
|
begin
|
||||||
|
Result := '(' + FItem0.AsString + ')';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue1.GetDataType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := FDataType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue1.GetElementCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue1.GetItem(Idx: Integer): IDataValue;
|
||||||
|
begin
|
||||||
|
case Idx of
|
||||||
|
0: Result := FItem0;
|
||||||
|
else
|
||||||
|
raise EArgumentException.Create('Index out of bounds');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TImplDataVectorValue2 }
|
||||||
|
|
||||||
|
constructor TImplDataVectorValue2.Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
|
FItem0 := AItems[0];
|
||||||
|
FItem1 := AItems[1];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue2.GetAsString: string;
|
||||||
|
begin
|
||||||
|
Result := '(' + FItem0.AsString + ', ' + FItem1.AsString + ')';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue2.GetDataType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := FDataType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue2.GetElementCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue2.GetItem(Idx: Integer): IDataValue;
|
||||||
|
begin
|
||||||
|
case Idx of
|
||||||
|
0: Result := FItem0;
|
||||||
|
1: Result := FItem1;
|
||||||
|
else
|
||||||
|
raise EArgumentException.Create('Index out of bounds');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TImplDataVectorValue3 }
|
||||||
|
|
||||||
|
constructor TImplDataVectorValue3.Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
|
FItem0 := AItems[0];
|
||||||
|
FItem1 := AItems[1];
|
||||||
|
FItem2 := AItems[2];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue3.GetAsString: string;
|
||||||
|
begin
|
||||||
|
Result := '(' + FItem0.AsString + ', ' + FItem1.AsString + ', ' + FItem2.AsString + ')';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue3.GetDataType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := FDataType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue3.GetElementCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := 3;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue3.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;
|
||||||
|
|
||||||
|
{ TImplDataVectorValue4 }
|
||||||
|
|
||||||
|
constructor TImplDataVectorValue4.Create(const ADataType: IDataVectorType; const AItems: array of IDataValue);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FDataType := ADataType;
|
||||||
|
FItem0 := AItems[0];
|
||||||
|
FItem1 := AItems[1];
|
||||||
|
FItem2 := AItems[2];
|
||||||
|
FItem3 := AItems[3];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue4.GetAsString: string;
|
||||||
|
begin
|
||||||
|
Result := '(' + FItem0.AsString + ', ' + FItem1.AsString + ', ' + FItem2.AsString + ', ' + FItem3.AsString + ')';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue4.GetDataType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := FDataType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue4.GetElementCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := 4;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorValue4.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;
|
||||||
|
|
||||||
|
{ TImplDataVectorType }
|
||||||
|
|
||||||
|
class constructor TImplDataVectorType.Create;
|
||||||
|
begin
|
||||||
|
// Initialize the class-level type registry.
|
||||||
|
FVectorTypeRegistry := TDictionary<String, IDataVectorType>.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class destructor TImplDataVectorType.Destroy;
|
||||||
|
begin
|
||||||
|
// Free the class-level type registry.
|
||||||
|
FVectorTypeRegistry.Free;
|
||||||
|
FVectorTypeRegistry := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TImplDataVectorType.Create(const AElementType: IDataType; const AElementCount: Integer);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
if (AElementCount <= 0) then
|
||||||
|
raise EArgumentException.Create('Element count must be greater than zero.');
|
||||||
|
|
||||||
|
FElementType := AElementType;
|
||||||
|
FElementCount := AElementCount;
|
||||||
|
FName := Format('Vector<%s>[%d]', [FElementType.Name, FElementCount]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorType.CreateValue(const AItems: array of IDataValue): IDataVectorValue;
|
||||||
|
var
|
||||||
|
item: IDataValue;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
// Validate that the number of items matches the vector's element count.
|
||||||
|
if (Length(AItems) <> FElementCount) then
|
||||||
|
raise EArgumentException
|
||||||
|
.CreateFmt('Invalid number of elements for vector. Expected %d, but got %d.', [FElementCount, Length(AItems)]);
|
||||||
|
|
||||||
|
// Validate that all items match the element type of this vector type.
|
||||||
|
i := 0;
|
||||||
|
for item in AItems do
|
||||||
|
begin
|
||||||
|
if (item.DataType <> FElementType) then
|
||||||
|
raise EArgumentException.CreateFmt(
|
||||||
|
'Invalid data type for item at index %d. Expected ''%s'', but got ''%s''.',
|
||||||
|
[i, FElementType.Name, item.DataType.Name]);
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use optimized implementations for vectors with 1-4 elements.
|
||||||
|
case FElementCount of
|
||||||
|
1: Result := TImplDataVectorValue1.Create(Self, AItems);
|
||||||
|
2: Result := TImplDataVectorValue2.Create(Self, AItems);
|
||||||
|
3: Result := TImplDataVectorValue3.Create(Self, AItems);
|
||||||
|
4: Result := TImplDataVectorValue4.Create(Self, AItems);
|
||||||
|
else
|
||||||
|
// Use the generic implementation for vectors with more than 4 elements.
|
||||||
|
Result := TImplDataVectorValue.Create(Self, AItems);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorType.GetElementCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := FElementCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorType.GetElementType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := FElementType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorType.GetKind: TDataKind;
|
||||||
|
begin
|
||||||
|
Result := dkVector;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TImplDataVectorType.GetName: String;
|
||||||
|
begin
|
||||||
|
Result := FName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TImplDataVectorType.GetInstance(const AElementType: IDataType; const AElementCount: Integer): IDataVectorType;
|
||||||
|
var
|
||||||
|
key: string;
|
||||||
|
begin
|
||||||
|
if (AElementCount <= 0) then
|
||||||
|
raise EArgumentException.Create('Element count must be greater than zero.');
|
||||||
|
|
||||||
|
if not Assigned(AElementType) then
|
||||||
|
raise EArgumentException.Create('Cannot create a vector type with a nil element type.');
|
||||||
|
|
||||||
|
// Generate a unique key for the dictionary. Using a separator that is unlikely in a type name.
|
||||||
|
key := AElementType.Name + '|' + AElementCount.ToString;
|
||||||
|
|
||||||
|
TMonitor.Enter(FVectorTypeRegistry);
|
||||||
|
try
|
||||||
|
if not FVectorTypeRegistry.TryGetValue(key, Result) then
|
||||||
|
begin
|
||||||
|
Result := TImplDataVectorType.Create(AElementType, AElementCount);
|
||||||
|
FVectorTypeRegistry.Add(key, Result);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
TMonitor.Exit(FVectorTypeRegistry);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
+157
-3
@@ -6,7 +6,7 @@ uses
|
|||||||
System.SysUtils;
|
System.SysUtils;
|
||||||
|
|
||||||
type
|
type
|
||||||
TDataKind = (dkVoid, dkOrdinal, dkFloat, dkText, dkTimestamp, dkDecimal, dkRecord, dkTuple, dkArray, dkEnum, dkMethod);
|
TDataKind = (dkVoid, dkOrdinal, dkFloat, dkText, dkTimestamp, dkDecimal, dkRecord, dkTuple, dkArray, dkVector, dkEnum, dkMethod);
|
||||||
|
|
||||||
IDataType = interface
|
IDataType = interface
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -189,6 +189,27 @@ type
|
|||||||
property ElementType: IDataType read GetElementType;
|
property ElementType: IDataType read GetElementType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Represents a fixed-size vector of data values.
|
||||||
|
IDataVectorValue = interface(IDataValue)
|
||||||
|
{$region 'private'}
|
||||||
|
function GetElementCount: Integer;
|
||||||
|
function GetItem(Idx: Integer): IDataValue;
|
||||||
|
{$endregion}
|
||||||
|
property ElementCount: Integer read GetElementCount;
|
||||||
|
property Items[Idx: Integer]: IDataValue read GetItem; default;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Represents the type of a fixed-size vector.
|
||||||
|
IDataVectorType = interface(IDataType)
|
||||||
|
{$region 'private'}
|
||||||
|
function GetElementType: IDataType;
|
||||||
|
function GetElementCount: Integer;
|
||||||
|
{$endregion}
|
||||||
|
function CreateValue(const AItems: array of IDataValue): IDataVectorValue;
|
||||||
|
property ElementType: IDataType read GetElementType;
|
||||||
|
property ElementCount: Integer read GetElementCount;
|
||||||
|
end;
|
||||||
|
|
||||||
TDataType = record
|
TDataType = record
|
||||||
type
|
type
|
||||||
TValue = record
|
TValue = record
|
||||||
@@ -207,6 +228,7 @@ type
|
|||||||
function AsRecord: IDataRecordValue; inline;
|
function AsRecord: IDataRecordValue; inline;
|
||||||
function AsTuple: IDataTupleValue; inline;
|
function AsTuple: IDataTupleValue; inline;
|
||||||
function AsArray: IDataArrayValue; inline;
|
function AsArray: IDataArrayValue; inline;
|
||||||
|
function AsVector: IDataVectorValue; inline;
|
||||||
function AsEnum: IDataEnumValue; inline;
|
function AsEnum: IDataEnumValue; inline;
|
||||||
function AsMethod: IDataMethodValue; inline;
|
function AsMethod: IDataMethodValue; inline;
|
||||||
function AsVoid: IDataVoidValue; inline;
|
function AsVoid: IDataVoidValue; inline;
|
||||||
@@ -479,6 +501,36 @@ type
|
|||||||
property ElementType: IDataType read GetElementType;
|
property ElementType: IDataType read GetElementType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TVector = record
|
||||||
|
type
|
||||||
|
TValue = record
|
||||||
|
private
|
||||||
|
FVectorValue: IDataVectorValue;
|
||||||
|
function GetDataType: TDataType.TVector;
|
||||||
|
function GetItems(Idx: Integer): TDataType.TValue; inline;
|
||||||
|
function GetElementCount: Integer; inline;
|
||||||
|
public
|
||||||
|
constructor Create(const AVectorValue: IDataVectorValue);
|
||||||
|
class operator Implicit(const A: IDataVectorValue): TDataType.TVector.TValue; overload; inline;
|
||||||
|
class operator Implicit(const A: TDataType.TVector.TValue): IDataVectorValue; overload; inline;
|
||||||
|
class operator Implicit(const A: TDataType.TVector.TValue): TDataType.TValue; overload; inline;
|
||||||
|
property ElementCount: Integer read GetElementCount;
|
||||||
|
property Items[Idx: Integer]: TDataType.TValue read GetItems; default;
|
||||||
|
property DataType: TDataType.TVector read GetDataType;
|
||||||
|
end;
|
||||||
|
private
|
||||||
|
FVectorType: IDataVectorType;
|
||||||
|
function GetElementType: IDataType; inline;
|
||||||
|
function GetElementCount: Integer; inline;
|
||||||
|
public
|
||||||
|
constructor Create(const AVectorType: IDataVectorType);
|
||||||
|
class operator Implicit(const A: IDataVectorType): TDataType.TVector; overload; inline;
|
||||||
|
class operator Implicit(const A: TDataType.TVector): IDataVectorType; overload; inline;
|
||||||
|
function CreateValue(const AItems: array of IDataValue): TDataType.TVector.TValue;
|
||||||
|
property ElementType: IDataType read GetElementType;
|
||||||
|
property ElementCount: Integer read GetElementCount;
|
||||||
|
end;
|
||||||
|
|
||||||
TMethod = record
|
TMethod = record
|
||||||
type
|
type
|
||||||
TProc = reference to function(const AValue: TDataType.TValue): TDataType.TValue;
|
TProc = reference to function(const AValue: TDataType.TValue): TDataType.TValue;
|
||||||
@@ -530,6 +582,7 @@ type
|
|||||||
class operator Implicit(const A: TDataType.TRecord): TDataType; overload; inline;
|
class operator Implicit(const A: TDataType.TRecord): TDataType; overload; inline;
|
||||||
class operator Implicit(const A: TDataType.TTuple): TDataType; overload; inline;
|
class operator Implicit(const A: TDataType.TTuple): TDataType; overload; inline;
|
||||||
class operator Implicit(const A: TDataType.TArray): TDataType; overload; inline;
|
class operator Implicit(const A: TDataType.TArray): TDataType; overload; inline;
|
||||||
|
class operator Implicit(const A: TDataType.TVector): TDataType; overload; inline;
|
||||||
|
|
||||||
// Type factories
|
// Type factories
|
||||||
class function Void: TDataType.TVoid; static; inline;
|
class function Void: TDataType.TVoid; static; inline;
|
||||||
@@ -541,8 +594,10 @@ type
|
|||||||
class function Tuple: TDataType.TTuple; static; inline;
|
class function Tuple: TDataType.TTuple; static; inline;
|
||||||
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 RecordOf(const Fields: TArray<TDataRecordField>): TDataType.TRecord; overload; 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 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;
|
||||||
|
|
||||||
function AsOrdinal: TDataType.TOrdinal; inline;
|
function AsOrdinal: TDataType.TOrdinal; inline;
|
||||||
@@ -553,6 +608,7 @@ type
|
|||||||
function AsRecord: TDataType.TRecord; inline;
|
function AsRecord: TDataType.TRecord; inline;
|
||||||
function AsTuple: TDataType.TTuple; inline;
|
function AsTuple: TDataType.TTuple; inline;
|
||||||
function AsArray: TDataType.TArray; inline;
|
function AsArray: TDataType.TArray; inline;
|
||||||
|
function AsVector: TDataType.TVector; inline;
|
||||||
function AsEnum: TDataType.TEnum; inline;
|
function AsEnum: TDataType.TEnum; inline;
|
||||||
function AsMethod: TDataType.TMethod; inline;
|
function AsMethod: TDataType.TMethod; inline;
|
||||||
|
|
||||||
@@ -572,6 +628,7 @@ uses
|
|||||||
Myc.Data.Types.Timestamp,
|
Myc.Data.Types.Timestamp,
|
||||||
Myc.Data.Types.Decimal,
|
Myc.Data.Types.Decimal,
|
||||||
Myc.Data.Types.Arrays,
|
Myc.Data.Types.Arrays,
|
||||||
|
Myc.Data.Types.Vector,
|
||||||
Myc.Data.Types.Records,
|
Myc.Data.Types.Records,
|
||||||
Myc.Data.Types.Tuple,
|
Myc.Data.Types.Tuple,
|
||||||
Myc.Data.Types.Enum,
|
Myc.Data.Types.Enum,
|
||||||
@@ -1264,6 +1321,75 @@ begin
|
|||||||
Result := A.FArrayType;
|
Result := A.FArrayType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TDataType.TVector.TValue }
|
||||||
|
|
||||||
|
constructor TDataType.TVector.TValue.Create(const AVectorValue: IDataVectorValue);
|
||||||
|
begin
|
||||||
|
FVectorValue := AVectorValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataType.TVector.TValue.GetDataType: TDataType.TVector;
|
||||||
|
begin
|
||||||
|
Result := IDataVectorType(FVectorValue.DataType);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataType.TVector.TValue.GetElementCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := FVectorValue.ElementCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataType.TVector.TValue.GetItems(Idx: Integer): TDataType.TValue;
|
||||||
|
begin
|
||||||
|
Result.Create(FVectorValue.Items[Idx]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class operator TDataType.TVector.TValue.Implicit(const A: IDataVectorValue): TDataType.TVector.TValue;
|
||||||
|
begin
|
||||||
|
Result.FVectorValue := A;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class operator TDataType.TVector.TValue.Implicit(const A: TDataType.TVector.TValue): IDataVectorValue;
|
||||||
|
begin
|
||||||
|
Result := A.FVectorValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class operator TDataType.TVector.TValue.Implicit(const A: TDataType.TVector.TValue): TDataType.TValue;
|
||||||
|
begin
|
||||||
|
Result.Create(A.FVectorValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDataType.TVector }
|
||||||
|
|
||||||
|
constructor TDataType.TVector.Create(const AVectorType: IDataVectorType);
|
||||||
|
begin
|
||||||
|
FVectorType := AVectorType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataType.TVector.CreateValue(const AItems: array of IDataValue): TDataType.TVector.TValue;
|
||||||
|
begin
|
||||||
|
Result.Create(FVectorType.CreateValue(AItems));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataType.TVector.GetElementCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := FVectorType.ElementCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataType.TVector.GetElementType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := FVectorType.ElementType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class operator TDataType.TVector.Implicit(const A: IDataVectorType): TDataType.TVector;
|
||||||
|
begin
|
||||||
|
Result.FVectorType := A;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class operator TDataType.TVector.Implicit(const A: TDataType.TVector): IDataVectorType;
|
||||||
|
begin
|
||||||
|
Result := A.FVectorType;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TDataType }
|
{ TDataType }
|
||||||
|
|
||||||
constructor TDataType.Create(const ADataType: IDataType);
|
constructor TDataType.Create(const ADataType: IDataType);
|
||||||
@@ -1330,16 +1456,19 @@ end;
|
|||||||
|
|
||||||
class function TDataType.RecordOf(const Fields: TArray<TDataRecordField>): TDataType.TRecord;
|
class function TDataType.RecordOf(const Fields: TArray<TDataRecordField>): TDataType.TRecord;
|
||||||
begin
|
begin
|
||||||
// The TImplDataRecordType now manages its own instances.
|
|
||||||
Result.Create(TImplDataRecordType.GetInstance(Fields));
|
Result.Create(TImplDataRecordType.GetInstance(Fields));
|
||||||
end;
|
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
|
||||||
// The TImplDataRecordType now manages its own instances.
|
|
||||||
Result.Create(TImplDataRecordType.GetInstance(Fields));
|
Result.Create(TImplDataRecordType.GetInstance(Fields));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TDataType.RecordOf<T>: TDataType.TRecord;
|
||||||
|
begin
|
||||||
|
Result.Create(TImplDataRecordType.GetInstance<T>);
|
||||||
|
end;
|
||||||
|
|
||||||
class function TDataType.Text: TDataType.TText;
|
class function TDataType.Text: TDataType.TText;
|
||||||
begin
|
begin
|
||||||
Result.Create(TImplDataTextType.Singleton);
|
Result.Create(TImplDataTextType.Singleton);
|
||||||
@@ -1355,6 +1484,12 @@ begin
|
|||||||
Result.Create(TImplDataTupleType.Singleton);
|
Result.Create(TImplDataTupleType.Singleton);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TDataType.VectorOf(const AElementType: IDataType; const AElementCount: Integer): TDataType.TVector;
|
||||||
|
begin
|
||||||
|
// The TImplDataVectorType now manages its own instances.
|
||||||
|
Result.Create(TImplDataVectorType.GetInstance(AElementType, AElementCount));
|
||||||
|
end;
|
||||||
|
|
||||||
class function TDataType.Void: TDataType.TVoid;
|
class function TDataType.Void: TDataType.TVoid;
|
||||||
begin
|
begin
|
||||||
Result.Create(TImplDataVoidType.Singleton);
|
Result.Create(TImplDataVoidType.Singleton);
|
||||||
@@ -1375,6 +1510,11 @@ begin
|
|||||||
Result.FDataType := A.FArrayType;
|
Result.FDataType := A.FArrayType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class operator TDataType.Implicit(const A: TDataType.TVector): TDataType;
|
||||||
|
begin
|
||||||
|
Result.FDataType := A.FVectorType;
|
||||||
|
end;
|
||||||
|
|
||||||
class operator TDataType.Implicit(const A: TDataType.TDecimal): TDataType;
|
class operator TDataType.Implicit(const A: TDataType.TDecimal): TDataType;
|
||||||
begin
|
begin
|
||||||
Result.FDataType := A.FDecimalType;
|
Result.FDataType := A.FDecimalType;
|
||||||
@@ -1503,6 +1643,13 @@ begin
|
|||||||
Result := IDataTupleValue(FDataValue);
|
Result := IDataTupleValue(FDataValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDataType.TValue.AsVector: IDataVectorValue;
|
||||||
|
begin
|
||||||
|
if (FDataValue.DataType.Kind <> dkVector) then
|
||||||
|
raise EInvalidCast.Create('Vector expected');
|
||||||
|
Result := IDataVectorValue(FDataValue);
|
||||||
|
end;
|
||||||
|
|
||||||
function TDataType.TValue.AsVoid: IDataVoidValue;
|
function TDataType.TValue.AsVoid: IDataVoidValue;
|
||||||
begin
|
begin
|
||||||
if (FDataValue.DataType.Kind <> dkVoid) then
|
if (FDataValue.DataType.Kind <> dkVoid) then
|
||||||
@@ -1598,4 +1745,11 @@ begin
|
|||||||
Result.Create(IDataTupleType(FDataType));
|
Result.Create(IDataTupleType(FDataType));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDataType.AsVector: TDataType.TVector;
|
||||||
|
begin
|
||||||
|
if (FDataType.Kind <> dkVector) then
|
||||||
|
raise EInvalidCast.Create('Vector expected');
|
||||||
|
Result.Create(IDataVectorType(FDataType));
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
Reference in New Issue
Block a user