Generic indicator factory

This commit is contained in:
Michael Schimmel
2025-07-27 11:42:27 +02:00
parent 468adcf203
commit 86001b654f
2 changed files with 286 additions and 115 deletions
+117 -51
View File
@@ -32,10 +32,15 @@ type
constructor Create(const AName: string; AFieldType: TFieldType; ATypeInfo: PTypeInfo; AOffset: Integer);
procedure Copy(Src, Dst: Pointer);
function GetSize: Integer; inline;
function GetAlignedSize: Integer; inline;
public
class operator Equal(const A, B: TField): Boolean;
class operator NotEqual(const A, B: TField): Boolean; inline;
property FieldType: TFieldType read FFieldType;
property Name: string read FName;
property Size: Integer read GetSize;
@@ -54,13 +59,22 @@ type
FFields: TArray<TField>;
constructor Create(const AFields: TArray<TField>);
function GetSize: Integer;
public
class function FromRecord<T>: TLayout; static;
class function FromRecord<T>: TLayout; overload; static;
class function FromRecord(ATypeInfo: PtypeInfo): TLayout; overload; static;
class operator Equal(const A, B: TLayout): Boolean;
class operator NotEqual(const A, B: TLayout): Boolean; inline;
class function Construct(const Def: TArray<TFieldDef>): TLayout; static;
procedure Copy(Src, Dst: Pointer);
function IndexOf(const Name: String): Integer;
property Fields: TArray<TField> read FFields;
property Size: Integer read GetSize;
end;
const
@@ -110,12 +124,7 @@ constructor TDataRecord.Create(const ALayout: TLayout);
begin
FLayout := ALayout;
var bufSize := 0;
if Length(FLayout.Fields) > 0 then
with FLayout.Fields[High(FLayout.Fields)] do
bufSize := Offset + AlignedSize;
SetLength(FBuffer, bufSize);
SetLength(FBuffer, FLayout.Size);
for var i := 0 to High(FLayout.Fields) do
FLayout.Fields[i].InitField(FBuffer);
end;
@@ -269,48 +278,7 @@ end;
procedure TDataRecord.TField.FromType(const [ref] Buffer: TBytes; const Src);
begin
Assert(FOffset + Size <= Length(Buffer));
var Dst := @Buffer[FOffset];
case FFieldType of
dfFloat:
begin
Assert(FTypeInfo.Kind = tkFloat);
case GetTypeData(FTypeInfo).FloatType of
ftSingle: PSingle(Dst)^ := PSingle(@Src)^;
ftDouble: PDouble(Dst)^ := PDouble(@Src)^;
else
Assert(false);
end;
end;
dfInteger:
begin
case FTypeInfo.Kind of
tkInteger: PInteger(Dst)^ := PInteger(@Src)^;
tkInt64: PInt64(Dst)^ := PInt64(@Src)^;
else
Assert(false);
end;
end;
dfString:
begin
Assert(FTypeInfo.Kind in [tkString, tkLString, tkUString, tkWString]);
PString(Dst)^ := PString(@Src)^;
end;
dfTimestamp:
begin
Assert(FTypeInfo.Kind = tkFloat);
Assert(FTypeInfo.Name = PTypeInfo(System.TypeInfo(TDateTime)).Name);
PDateTime(Dst)^ := PDateTime(@Src)^;
end;
dfRecord:
begin
Assert(FTypeInfo = System.TypeInfo(TDataRecord));
Assert(FTypeInfo.Name = PTypeInfo(System.TypeInfo(TDataRecord)).Name);
TDataRecord(Dst^) := TDataRecord(Src);
end;
else
Assert(false);
end;
Copy(@Src, @Buffer[FOffset]);
end;
function TDataRecord.TField.GetSize: Integer;
@@ -390,6 +358,60 @@ begin
end;
end;
procedure TDataRecord.TField.Copy(Src, Dst: Pointer);
begin
case FFieldType of
dfFloat:
begin
Assert(FTypeInfo.Kind = tkFloat);
case GetTypeData(FTypeInfo).FloatType of
ftSingle: PSingle(Dst)^ := PSingle(Src)^;
ftDouble: PDouble(Dst)^ := PDouble(Src)^;
else
Assert(false);
end;
end;
dfInteger:
begin
case FTypeInfo.Kind of
tkInteger: PInteger(Dst)^ := PInteger(Src)^;
tkInt64: PInt64(Dst)^ := PInt64(Src)^;
else
Assert(false);
end;
end;
dfString:
begin
Assert(FTypeInfo.Kind in [tkString, tkLString, tkUString, tkWString]);
PString(Dst)^ := PString(Src)^;
end;
dfTimestamp:
begin
Assert(FTypeInfo.Kind = tkFloat);
Assert(FTypeInfo.Name = PTypeInfo(System.TypeInfo(TDateTime)).Name);
PDateTime(Dst)^ := PDateTime(Src)^;
end;
dfRecord:
begin
Assert(FTypeInfo = System.TypeInfo(TDataRecord));
Assert(FTypeInfo.Name = PTypeInfo(System.TypeInfo(TDataRecord)).Name);
TDataRecord(Dst^) := TDataRecord(Src^);
end;
else
Assert(false);
end;
end;
class operator TDataRecord.TField.Equal(const A, B: TField): Boolean;
begin
Result := (A.FFieldType = B.FFieldType) and (A.FTypeInfo = B.FTypeInfo) and (A.FOffset = B.FOffset) and (A.FName = B.FName);
end;
class operator TDataRecord.TField.NotEqual(const A, B: TField): Boolean;
begin
Result := not (A = B);
end;
constructor TDataRecord.TLayout.Create(const AFields: TArray<TField>);
begin
FFields := AFields;
@@ -419,12 +441,25 @@ begin
Result.Create(Fields);
end;
procedure TDataRecord.TLayout.Copy(Src, Dst: Pointer);
begin
for var i := 0 to High(FFields) do
begin
var ofs := FFields[i].Offset;
var S: PByte := Src;
inc(S, ofs);
var D: PByte := Dst;
inc(D, ofs);
FFields[i].Copy(S, D);
end;
end;
{ TLayout }
class function TDataRecord.TLayout.FromRecord<T>: TLayout;
class function TDataRecord.TLayout.FromRecord(ATypeInfo: PtypeInfo): TLayout;
begin
var ctx := TRttiContext.Create;
var rttiType := ctx.GetType(TypeInfo(T));
var rttiType := ctx.GetType(ATypeInfo);
var rttiFields := rttiType.GetFields;
var fields: TArray<TField>;
@@ -467,6 +502,21 @@ begin
Result.Create(fields);
end;
{ TLayout }
class function TDataRecord.TLayout.FromRecord<T>: TLayout;
begin
Result := FromRecord(TypeInfo(T));
end;
function TDataRecord.TLayout.GetSize: Integer;
begin
Result := 0;
if Length(FFields) > 0 then
with FFields[High(FFields)] do
Result := Offset + Size;
end;
function TDataRecord.TLayout.IndexOf(const Name: String): Integer;
begin
for var i := 0 to High(FFields) do
@@ -475,4 +525,20 @@ begin
exit(-1);
end;
class operator TDataRecord.TLayout.Equal(const A, B: TLayout): Boolean;
begin
if Length(A.FFields) <> Length(B.FFields) then
exit(false);
for var i := 0 to High(A.FFields) do
if A.FFields[i] <> B.FFields[i] then
exit(false);
exit(true);
end;
class operator TDataRecord.TLayout.NotEqual(const A, B: TLayout): Boolean;
begin
Result := not (A = B);
end;
end.