unit Myc.DataRecord.Impl; interface uses System.SysUtils, System.Rtti, System.TypInfo, System.Generics.Collections, System.Generics.Defaults, Myc.DataRecord; type // The builder implementation class, now in the global scope. TDataRecordBuilder = class(TInterfacedObject, TDataRecord.TBuilder.IBuilder) private FStagedValues: TList>; public constructor Create; destructor Destroy; override; // IBuilder implementation procedure AddField(const Name: String; const Value: TValue); overload; procedure SetupRecord(out Layout: TArray; out Buffer: TBytes); end; type TField = class(TInterfacedObject, TDataRecord.IField) private FBuffer: TBytes; FFieldLayout: TDataRecord.TFieldLayout; protected function GetRawRef: Pointer; inline; public constructor Create(ABuffer: TBytes; const AField: TDataRecord.TFieldLayout); procedure GetRaw(Dst: Pointer); virtual; procedure SetRaw(Src: Pointer); virtual; property FieldLayout: TDataRecord.TFieldLayout read FFieldLayout; end; type TGenericField = class(TField, TDataRecord.IField) public function GetValue: T; procedure SetValue(const Value: T); end; type TIntegerField = class(TGenericField) public procedure GetRaw(Dst: Pointer); override; procedure SetRaw(Src: Pointer); override; end; type TSingleField = class(TGenericField) public procedure GetRaw(Dst: Pointer); override; procedure SetRaw(Src: Pointer); override; end; type TDoubleField = class(TGenericField) public procedure GetRaw(Dst: Pointer); override; procedure SetRaw(Src: Pointer); override; end; type TInt64Field = class(TGenericField) public procedure GetRaw(Dst: Pointer); override; procedure SetRaw(Src: Pointer); override; end; type TStringField = class(TGenericField) public procedure GetRaw(Dst: Pointer); override; procedure SetRaw(Src: Pointer); override; end; type TFieldLayoutComparer = class(TComparer) strict private class var FDefaultComparer: IComparer; class constructor CreateClass; public function Compare(const Left, Right: TDataRecord.TFieldLayout): Integer; override; class property DefaultComparer: IComparer read FDefaultComparer; end; implementation { TDataRecordBuilder } constructor TDataRecordBuilder.Create; begin inherited; FStagedValues := TList>.Create; end; destructor TDataRecordBuilder.Destroy; begin FStagedValues.Free; inherited; end; procedure TDataRecordBuilder.AddField(const Name: String; const Value: TValue); begin FStagedValues.Add(TPair.Create(Name, Value)); end; procedure TDataRecordBuilder.SetupRecord(out Layout: TArray; out Buffer: TBytes); var layoutList: TList; pair: TPair; field: TDataRecord.TFieldLayout; begin layoutList := TList.Create; try layoutList.Capacity := FStagedValues.Count; var ofs: NativeUInt := 0; for pair in FStagedValues do begin field.Name := pair.Key; field.Size := pair.Value.DataSize; ofs := (ofs + 15) and not 15; field.Offset := ofs; inc(ofs, field.Size); field.TypeInfo := pair.Value.TypeInfo; layoutList.Add(field); end; SetLength(Buffer, ofs); for var i := 0 to layoutList.Count - 1 do begin var P: PByte := @Buffer[layoutList[i].Offset]; FStagedValues[i].Value.ExtractRawData(P); end; layoutList.Sort(TFieldLayoutComparer.DefaultComparer); Layout := layoutList.ToArray; finally layoutList.Free; end; FStagedValues.Clear; end; { TField and descendants... } constructor TField.Create(ABuffer: TBytes; const AField: TDataRecord.TFieldLayout); begin inherited Create; FBuffer := ABuffer; FFieldLayout := AField; end; procedure TField.GetRaw(Dst: Pointer); var Val: TValue; begin TValue.MakeWithoutCopy(GetRawRef, FFieldLayout.TypeInfo, val, true); val.ExtractRawData(Dst); end; function TField.GetRawRef: Pointer; begin Result := @FBuffer[FFieldLayout.Offset]; end; procedure TField.SetRaw(Src: Pointer); var Val: TValue; begin TValue.MakeWithoutCopy(Src, FFieldLayout.TypeInfo, val, true); val.ExtractRawData(GetRawRef); end; { TGenericField } function TGenericField.GetValue: T; type PT = ^T; begin Result := PT(@FBuffer[FFieldLayout.Offset])^; end; procedure TGenericField.SetValue(const Value: T); type PT = ^T; begin PT(@FBuffer[FFieldLayout.Offset])^ := Value; end; procedure TIntegerField.GetRaw(Dst: Pointer); begin PInteger(Dst)^ := PInteger(GetRawRef)^; end; procedure TIntegerField.SetRaw(Src: Pointer); begin PInteger(GetRawRef)^ := PInteger(Src)^; end; procedure TSingleField.GetRaw(Dst: Pointer); begin PSingle(Dst)^ := PSingle(GetRawRef)^; end; procedure TSingleField.SetRaw(Src: Pointer); begin PSingle(GetRawRef)^ := PSingle(Src)^; end; procedure TDoubleField.GetRaw(Dst: Pointer); begin PDouble(Dst)^ := PDouble(GetRawRef)^; end; procedure TDoubleField.SetRaw(Src: Pointer); begin PDouble(GetRawRef)^ := PDouble(Src)^; end; procedure TInt64Field.GetRaw(Dst: Pointer); begin PInt64(Dst)^ := PInt64(GetRawRef)^; end; procedure TInt64Field.SetRaw(Src: Pointer); begin PInt64(GetRawRef)^ := PInt64(Src)^; end; procedure TStringField.GetRaw(Dst: Pointer); begin PString(Dst)^ := PString(GetRawRef)^; end; procedure TStringField.SetRaw(Src: Pointer); begin PString(GetRawRef)^ := PString(Src)^; end; { TFieldLayoutComparer } class constructor TFieldLayoutComparer.CreateClass; begin FDefaultComparer := TFieldLayoutComparer.Create; end; function TFieldLayoutComparer.Compare(const Left, Right: TDataRecord.TFieldLayout): Integer; begin Result := TComparer.Default.Compare(Left.Name, Right.Name); end; end.