DeleteAndFreeRange<T: class> class method

Project: Array Utilities Unit

Unit: DelphiDabbler.Lib.ArrayUtils

Record: TArrayUtils

Applies to: ~>0.1

class procedure DeleteAndFreeRange<T: class>(var A: TArray<T>;
  AStartIndex, AEndIndex: Integer);
  overload; static;

class procedure DeleteAndFreeRange<T: class>(var A: TArray<T>;
  AStartIndex: Integer);
  overload; static;

Description

Deletes and frees a range of one or more elements of from an array of TObject descendant objects.

The length of the array is reduced by the number of elements deleted.

Parameters:

Notes

If you want to delete and free all the elements of an array with indices ≥ AStartIndex then there is no need to provide AEndIndex.

To delete and free a single element set both AStartIndex and AEndIndex to the same index. Alternatively use DeleteAndFree<T: class>.

Example

Both examples below use a custom TObjectEx class that records the number of objects currently instantiated. This is defined as follows:

type
  TObjectEx = class
  public
    var ID: Char;
    class var InstanceCount: Integer;
    constructor Create(AID: Char);
    destructor Destroy; override;
  end;

{ TObjectEx }

constructor TObjectEx.Create(AID: Char);
begin
  inherited Create;
  ID := AID;
  Inc(InstanceCount);
end;

destructor TObjectEx.Destroy;
begin
  Dec(InstanceCount);
  inherited;
end;

Example #1

This first example uses the overload of DeleteAndFreeRange<T: class> that takes both the start and end indices of a range as parameters.

procedure DeleteAndFreeRange_Eg1;
var
  A: TArray<TObjectEx>;
  Obj: TObjectEx;
  Constraint: TArrayUtils.TConstraint<TObjectEx>;
begin
  // Start with no objects
  Assert(TObjectEx.InstanceCount = 0, 'TObjectEx <> 0 instances');

  // Create array of 6 objects
  A := TArray<TObjectEx>.Create(
    TObjectEx.Create('A'), TObjectEx.Create('B'),
    TObjectEx.Create('C'), TObjectEx.Create('D'),
    TObjectEx.Create('E'), TObjectEx.Create('F')
  );
  Assert(Length(A) = 6, 'Array length <> 6');
  Assert(TObjectEx.InstanceCount = 6, 'TObjectEx <> 4 instances');
  Assert(A[2].ID = 'C', 'A[2] <> C');
  Assert(A[3].ID = 'D', 'A[3] <> D');
  Assert(A[4].ID = 'E', 'A[4] <> E');

  // Delete and free all objects in range [2..4]
  TArrayUtils.DeleteAndFreeRange<TObjectEx>(A, 2, 4);
  Assert(Length(A) = 3, 'Array length <> 3');
  Assert(TObjectEx.InstanceCount = 3, 'TObjectEx <> 3 instances');
  Constraint := function (const AElem: TObjectEx): Boolean
    begin
      Result := (AElem.ID = 'C') or (AElem.ID = 'D') or (AElem.ID = 'E');
    end;
  Assert(
    not TArrayUtils.Some<TObjectEx>(A, Constraint),
    'C, D, or E found in array'
  );

  // Tidy up remaining objects
  for Obj in A do
    Obj.Free;
  Assert(TObjectEx.InstanceCount = 0, 'TObjectEx <> 0 instances');
end;

Example #2

The second example uses the overload of DeleteAndFreeRange<T: class> that takes only start index of a range as a parameter.

procedure DeleteAndFreeRange_Eg2;
var
  A: TArray<TObjectEx>;
  Obj: TObjectEx;
  Constraint: TArrayUtils.TConstraint<TObjectEx>;
begin
  // Start with no objects
  Assert(TObjectEx.InstanceCount = 0, 'TObjectEx <> 0 instances');

  // Create array of 6 objects
  A := TArray<TObjectEx>.Create(
    TObjectEx.Create('A'), TObjectEx.Create('B'),
    TObjectEx.Create('C'), TObjectEx.Create('D'),
    TObjectEx.Create('E'), TObjectEx.Create('F')
  );
  Assert(Length(A) = 6, 'Array length <> 6');
  Assert(TObjectEx.InstanceCount = 6, 'TObjectEx <> 4 instances');
  Assert(A[2].ID = 'C', 'A[2] <> C');
  Assert(A[3].ID = 'D', 'A[3] <> D');
  Assert(A[4].ID = 'E', 'A[4] <> E');
  Assert(A[5].ID = 'F', 'A[4] <> F');

  // Delete and free all objects from index 2 to the end of the array
  TArrayUtils.DeleteAndFreeRange<TObjectEx>(A, 2);
  Assert(Length(A) = 2, 'Array length <> 2');
  Assert(TObjectEx.InstanceCount = 2, 'TObjectEx <> 2 instances');
  Constraint := function (const AElem: TObjectEx): Boolean
    begin
      Result := (AElem.ID = 'C') or (AElem.ID = 'D')
        or (AElem.ID = 'E') or (AElem.ID = 'F');
    end;
  Assert(
    not TArrayUtils.Some<TObjectEx>(A, Constraint),
    'C, D, E or F found in array'
  );

  // Tidy up remaining objects
  for Obj in A do
    Obj.Free;
  Assert(TObjectEx.InstanceCount = 0, 'TObjectEx <> 0 instances');
end;

See Also