Update:
This is not a complete answer. Using TDynArray , as mentioned by David, may solve your problem.
Using RTTI, I made another solution for you. This is a general solution, and you can easily add additional features / capabilities. It will save your type declarations. An example of adding / removing entries is included.
Record TDynPtArray processes any dynamic array of pointers to records. It is initialized by calling Init :
DPA.Init(TypeInfo(TData1), AData1); Data1 := DPA.Add; // Adds a record with default values and // returns a pointer to the record DPA.Remove; // Finalizes/deallocates the last record and // shrinks the dynamic array
-
uses Windows,System.SysUtils,System.TypInfo; Type TPtArray = array of Pointer; PPtArray = ^TPtArray; TDynPtArray = record private FDynArray: PPtArray; FTypeInfo: PTypeInfo; FTypeData: PTypeData; public constructor Init( T: Pointer; var dynArray); function Add : Pointer; procedure Remove; procedure Clear; end; constructor TDynPtArray.Init(T: Pointer; var dynArray); begin FTypeInfo := T; if (FTypeInfo^.Kind <> tkRecord) then raise Exception.CreateFmt('%s is not a record',[FTypeInfo^.Name]); FTypeData := GetTypeData( FTypeInfo); FDynArray := @dynArray; end; function TDynPtArray.Add: Pointer; var L: integer; begin L := Length(FDynArray^); SetLength(FDynArray^,L+1); GetMem( FDynArray^[L], FTypeData^.elSize); ZeroMemory( FDynArray^[L], FTypeData^.elSize); Result := FDynArray^[L]; end; procedure RecordClear(var Dest; TypeInfo: pointer); asm {$ifdef CPUX64} .NOFRAME {$endif} jmp System.@FinalizeRecord end; procedure TDynPtArray.Remove; var L: integer; begin L := Length(FDynArray^); if (L = 0) then exit; RecordClear( FDynArray^[L-1]^,FTypeInfo); // Finalize record FreeMem( FDynArray^[L-1], FTypeData^.elSize); SetLength(FDynArray^,L-1); end; procedure TDynPtArray.Clear; begin while (Length(FDynArray^) <> 0) do Self.Remove; end;
And a little test:
type PData1 = ^TData1; TData1 = record IntField: Integer; StrField: string; end; TData1Arr = array of PData1; var AData1: TData1Arr; Data1: PData1; DPA: TDynPtArray; begin DPA.Init(TypeInfo(TData1), AData1); Data1:= DPA.Add; Data1^.StrField := '111'; WriteLn(Data1^.IntField); WriteLn(Data1^.StrField); DPA.Clear; ReadLn; end.
source share