Generic indicator factory
This commit is contained in:
+117
-51
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user