General function for increasing an array of pointers

I am working on code that has a data structure like this:

type TData1 = record IntField: Integer; StrField: string; end; TData2 = record DateField: TDateTime; StrField: string; end; var AData1 = array of ^TData1; AData2 = array of ^TData2; 

Sometimes I need to add an element to one of these arrays, for example:

 L := Length(AData1); SetLength(AData1, L + 1); New(AData1[L]); 

How can I write a procedure that does this work to increase the size of the array and allocate memory for a new element that works for any pointer? And this should be done without changing the definitions of records (TData1, TData2) and arrays (AData1, AData2), so it will not break the existing code.

Ps: I don’t have a big background with pointers and such programming, I would of course use objects and dynamic linked lists, but in this case it’s obsolete code, and I can’t change it, at least for Now.

+4
source share
1 answer

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. 
+2
source

All Articles