From 644b3fa8fda7a3ceaf6a2e77a2c77f52385210ce Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Wed, 27 Aug 2025 15:15:47 +0200 Subject: [PATCH] Vector type --- Src/Data/Myc.Data.Types.RTTI.pas | 50 ++++ Src/Data/Myc.Data.Types.Records.pas | 25 +- Src/Data/Myc.Data.Types.Vector.pas | 403 ++++++++++++++++++++++++++++ Src/Data/Myc.Data.Types.pas | 160 ++++++++++- 4 files changed, 634 insertions(+), 4 deletions(-) create mode 100644 Src/Data/Myc.Data.Types.Vector.pas diff --git a/Src/Data/Myc.Data.Types.RTTI.pas b/Src/Data/Myc.Data.Types.RTTI.pas index 2bf78d6..d7ec75d 100644 --- a/Src/Data/Myc.Data.Types.RTTI.pas +++ b/Src/Data/Myc.Data.Types.RTTI.pas @@ -12,11 +12,61 @@ type function AsTValue: TValue; end; +function RttiTypeToDataType(rttiType: TRttiType): TDataType; + implementation uses + System.TypInfo, 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; + 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; + 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 } function TValueHelper.AsTValue: TValue; diff --git a/Src/Data/Myc.Data.Types.Records.pas b/Src/Data/Myc.Data.Types.Records.pas index 3927889..a3f9744 100644 --- a/Src/Data/Myc.Data.Types.Records.pas +++ b/Src/Data/Myc.Data.Types.Records.pas @@ -38,17 +38,23 @@ type class constructor CreateClass; class destructor DestroyClass; + // Factory method to get a cached or new record type instance. class function GetInstance(const AFields: TArray): 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: IDataRecordType; overload; static; + function CreateValue(const AItems: array of IDataValue): IDataRecordValue; end; implementation uses - System.SyncObjs; + System.SyncObjs, + System.Rtti, + Myc.Data.Types.RTTI; type // Implements the record data value. @@ -324,6 +330,23 @@ begin Result := GetInstance(tFields); end; +class function TImplDataRecordType.GetInstance: 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); var i: Integer; diff --git a/Src/Data/Myc.Data.Types.Vector.pas b/Src/Data/Myc.Data.Types.Vector.pas new file mode 100644 index 0000000..c92a31c --- /dev/null +++ b/Src/Data/Myc.Data.Types.Vector.pas @@ -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; + + 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; + 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.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. diff --git a/Src/Data/Myc.Data.Types.pas b/Src/Data/Myc.Data.Types.pas index d127b69..1ac17bb 100644 --- a/Src/Data/Myc.Data.Types.pas +++ b/Src/Data/Myc.Data.Types.pas @@ -6,7 +6,7 @@ uses System.SysUtils; 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 {$region 'private'} @@ -189,6 +189,27 @@ type property ElementType: IDataType read GetElementType; 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 type TValue = record @@ -207,6 +228,7 @@ type function AsRecord: IDataRecordValue; inline; function AsTuple: IDataTupleValue; inline; function AsArray: IDataArrayValue; inline; + function AsVector: IDataVectorValue; inline; function AsEnum: IDataEnumValue; inline; function AsMethod: IDataMethodValue; inline; function AsVoid: IDataVoidValue; inline; @@ -479,6 +501,36 @@ type property ElementType: IDataType read GetElementType; 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 type 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.TTuple): 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 class function Void: TDataType.TVoid; static; inline; @@ -541,8 +594,10 @@ type class function Tuple: TDataType.TTuple; static; inline; class function MethodOf(const AArgType, AResultType: IDataType): TDataType.TMethod; 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): TDataType.TRecord; overload; static; class function RecordOf(const Fields: array of TDataRecordField): TDataType.TRecord; overload; static; + class function RecordOf: TDataType.TRecord; overload; static; class function EnumOf(const AName: string; const AIdentifiers: array of string): TDataType.TEnum; static; function AsOrdinal: TDataType.TOrdinal; inline; @@ -553,6 +608,7 @@ type function AsRecord: TDataType.TRecord; inline; function AsTuple: TDataType.TTuple; inline; function AsArray: TDataType.TArray; inline; + function AsVector: TDataType.TVector; inline; function AsEnum: TDataType.TEnum; inline; function AsMethod: TDataType.TMethod; inline; @@ -572,6 +628,7 @@ uses Myc.Data.Types.Timestamp, Myc.Data.Types.Decimal, Myc.Data.Types.Arrays, + Myc.Data.Types.Vector, Myc.Data.Types.Records, Myc.Data.Types.Tuple, Myc.Data.Types.Enum, @@ -1264,6 +1321,75 @@ begin Result := A.FArrayType; 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 } constructor TDataType.Create(const ADataType: IDataType); @@ -1330,16 +1456,19 @@ end; class function TDataType.RecordOf(const Fields: TArray): TDataType.TRecord; begin - // The TImplDataRecordType now manages its own instances. Result.Create(TImplDataRecordType.GetInstance(Fields)); end; class function TDataType.RecordOf(const Fields: array of TDataRecordField): TDataType.TRecord; begin - // The TImplDataRecordType now manages its own instances. Result.Create(TImplDataRecordType.GetInstance(Fields)); end; +class function TDataType.RecordOf: TDataType.TRecord; +begin + Result.Create(TImplDataRecordType.GetInstance); +end; + class function TDataType.Text: TDataType.TText; begin Result.Create(TImplDataTextType.Singleton); @@ -1355,6 +1484,12 @@ begin Result.Create(TImplDataTupleType.Singleton); 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; begin Result.Create(TImplDataVoidType.Singleton); @@ -1375,6 +1510,11 @@ begin Result.FDataType := A.FArrayType; 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; begin Result.FDataType := A.FDecimalType; @@ -1503,6 +1643,13 @@ begin Result := IDataTupleValue(FDataValue); 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; begin if (FDataValue.DataType.Kind <> dkVoid) then @@ -1598,4 +1745,11 @@ begin Result.Create(IDataTupleType(FDataType)); end; +function TDataType.AsVector: TDataType.TVector; +begin + if (FDataType.Kind <> dkVector) then + raise EInvalidCast.Create('Vector expected'); + Result.Create(IDataVectorType(FDataType)); +end; + end.