2021-02-27

Removing elements from an array of records containing string fields?

Check the example below... I have an array TSrvClientList.Items with record elements. These elements have string fields. When I remove an element, I need to move the following ones in that empty space left. I don't like to copy field by field... And I thought I'd use the Move function to do it faster, but I'm not sure if this is a proper way to do it. If the record contained only unmanaged types, I'm sure it's OK, I uesed many times. But with those strings, I don't know... Should I call a Finalize first ? Or do it differently ? My test code seems it works as it is, directly moving those strings, but I'd like to make sure it's not just a coincidence.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, SynCommons, System.SyncObjs,
  Vcl.StdCtrls;

type
  TSrvClientInfo = record
   ClientIP: String;
   ClientGUID: Cardinal;
   AESKey: THash256;
   TransCons: Integer;
  end;

  TSrvClientList = record
   private
    Valid: DWord;
   public
    Items: array of TSrvClientInfo;
    procedure Init;
    procedure Free;
    procedure AddClient(const IP: String; GUID: Cardinal; AESKey: THash256);
    procedure RemoveClient(const IP: String; GUID: Cardinal);
  end;

  TForm1 = class(TForm)
    BAddItem: TButton;
    BRemoveItem: TButton;
    procedure FormCreate(Sender: TObject);
    procedure BAddItemClick(Sender: TObject);
    procedure BRemoveItemClick(Sender: TObject);
  public
    Code: Byte;
    Clients: TSrvClientList;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//===== TSrvClientList =======================================================

procedure TSrvClientList.Init;
begin
 if Valid <> $12344321 then begin
  Valid:= $12344321;
  SetLength(Items, 0);
 end;
end;

procedure TSrvClientList.Free;
begin
 if Valid = $12344321 then begin
  SetLength(Items, 0);
  Valid:= 0;
 end;
end;

procedure TSrvClientList.AddClient(const IP: String; GUID: Cardinal; AESKey: THash256);
var I: Integer;
begin
 if Valid <> $12344321 then Exit;
 I:= Length(Items); SetLength(Items, I+1);
 Items[I].ClientIP:= IP;
 Items[I].ClientGUID:= GUID;
 Items[I].AESKey:= AESKey;
 Items[I].TransCons:= 0;
end;

procedure TSrvClientList.RemoveClient(const IP: String; GUID: Cardinal);
var I, R: Integer;
begin
 if Valid <> $12344321 then Exit;
 I:= 0; while (I < Length(Items)) and ((Items[I].ClientIP <> IP) or (Items[I].ClientGUID <> GUID)) do Inc(I);
 if (I > High(Items)) then Exit;
 R:= High(Items) - I;
 if R > 0 then Move(Items[I+1], Items[I], SizeOf(TSrvClientInfo) * R);
 SetLength(Items, Length(Items)-1);
end;

// ----------------------------------------------------

procedure TForm1.FormCreate(Sender: TObject);
begin
 Clients.Init;
 Code:= 1;
end;

procedure TForm1.BAddItemClick(Sender: TObject);
var IP: String;
    GUID: Cardinal;
    AESKey: THash256;
begin
 IP:= '192.168.0.3';
 GUID:= $12345678;
 FillChar(AESKey[0], 32, 0); AESKey[0]:= Code; Inc(Code);
 Clients.AddClient(IP, GUID, AESKey);
 Caption:= IntToStr(Length(Clients.Items));
end;

procedure TForm1.BRemoveItemClick(Sender: TObject);
var IP: String;
    GUID: Cardinal;
begin
 IP:= '192.168.0.3';
 GUID:= $12345678;
 Clients.RemoveClient(IP, GUID);
 Caption:= IntToStr(Length(Clients.Items));
end;

end.


from Recent Questions - Stack Overflow https://ift.tt/2ZWS1ZS
https://ift.tt/eA8V8J

No comments:

Post a Comment