-1

I have the following object with an array of a record type:

type
  TTimeMark = record
   // many fields here
  end;

  TTimeMarks = array of TTimeMark;

  TUserProfile = class(TObject)
    TimeLine: TTimeMarks;
    ....
  end;

In this list TUserProfile.TimeLine will be inserted items at run time. I don't know a method of inserting items other than increasing the lenghth of the array with one and then moving all the items a place down until I reach the desired possition. But in this array, the items are records with many fields, so, if I do TimeLine[I]:= TimeLine[I-1], all the data in the memory will be copied from one place to another (am I right ?), and this will take some time. Do you think should I use an array of pointers of that record, instead ? Or is there other fast method to do this ?

Marus Gradinaru
  • 2,824
  • 1
  • 26
  • 55
  • 2
    You can use generic `TList` (just beware of some issues in this particular release). Or reallocate your array memory by more items (not just by 1). – Victoria Aug 05 '18 at 18:45
  • 1
    Or use dynamically allocated records, ie. `PTimeMark = ^TTimeMark;` and `ARRAY OF PTimeMark;`, thereby only moving pointers (4 bytes) whenever you need to "push" the array in a direction. With proper code, you can even use `MOVE` to move them all in one go, since pointers aren't compiler-lifetime-handled, like f.ex. `STRING` or dynamic arrays are. Requires a bit more housekeeping, but when encapsulated in proper properties, it can be just as easy to work with from the outside. – HeartWare Aug 05 '18 at 19:33
  • It depends. On the detail that you can see and we cannot. What does your profiling tell you? Or can't you be bothered to do that? – David Heffernan Aug 05 '18 at 20:14
  • @HEARTWARE But it might be slower to use pointers to non contiguous memory depending on access patterns. – David Heffernan Aug 05 '18 at 20:15
  • Is there a way to shift a section of array items, with a `MOVE` instruction, to make room for inserted item ? – Marus Gradinaru Aug 05 '18 at 20:43
  • I gues this is it: https://stackoverflow.com/questions/3730709/move-to-insert-delete-items-from-a-dynamic-array-of-string – Marus Gradinaru Aug 05 '18 at 21:30
  • Or you use `TList` and rely on the RTL to do the work. – David Heffernan Aug 06 '18 at 07:03

1 Answers1

0

This is how I've done.. I used an array of pointers and I make some procedures to easy add, delete and move items:

TPointerArray = array of Pointer;

procedure PArrayInsert(var AArray: TPointerArray; Position: Integer; Count: Integer = 1);
var L, CTail: Integer;
begin
 L:= Length(AArray);
 if (Count = 0) or (Position > L) then Exit;
 SetLength(AArray, L + Count);
 CTail:= L - Position;
 if CTail > 0 then
  Move(AArray[Position], AArray[Position+Count], CTail * SizeOf(Pointer));
end;

procedure PArrayDelete(var AArray: TPointerArray; Position: Integer; Count: Integer = 1);
var L, CTail: Integer;
begin
 L:= Length(AArray);
 if (L = 0) or (Count = 0) or (Position >= L) or ((Position+Count) > L) then Exit;
 CTail:= L - (Position + Count);
 if CTail > 0 then
  Move(AArray[Position+Count], AArray[Position], CTail * SizeOf(Pointer));
 SetLength(AArray, L - Count);
end;

function PArrayMove(var AArray: TPointerArray; FromIndex, ToIndex: Integer; Count: Integer = 1): Boolean;
var L, Size, CT: Integer;
    Buff: Pointer;
begin
 Result:= False;
 L:= High(AArray);
 if (FromIndex > L) or (ToIndex > L+1) or
  ((ToIndex >= FromIndex) and (ToIndex <= (FromIndex+Count)))  then Exit;
 Size:= Count * SizeOf(Pointer);
 GetMem(Buff, Size);
 Move(AArray[FromIndex], Buff^, Size);
 if FromIndex > ToIndex then begin
  CT:= FromIndex - ToIndex;
  Move(AArray[ToIndex], AArray[FromIndex+Count-CT], CT * SizeOf(Pointer));
  Move(Buff^, AArray[ToIndex], Size);
 end
 else begin
  CT:= ToIndex - FromIndex - Count;
  Move(AArray[FromIndex+Count], AArray[FromIndex], CT * SizeOf(Pointer));
  Move(Buff^, AArray[FromIndex+CT], Size);
 end;
 FreeMem(Buff);
 Result:= True;
end;
Marus Gradinaru
  • 2,824
  • 1
  • 26
  • 55