Skip to content

Latest commit

 

History

History
150 lines (108 loc) · 3.68 KB

File metadata and controls

150 lines (108 loc) · 3.68 KB

Copy<T> class method

Project: Array Utilities Unit

Unit: DelphiDabbler.Lib.ArrayUtils

Record: TArrayUtils

Applies to: ~>0.1

type
  TCloner<T> = reference to function (const AElem: T): T;

class function Copy<T>(const A: array of T): TArray<T>;
  overload; static;

class function Copy<T>(const A: array of T;
  const ACloner: TCloner<T>): TArray<T>;
  overload; static;

Description

Returns a copy of a given array.

The two overloaded methods enable either a shallow copy or a deep copy to be returned.

Parameters:

  • A - The array to be copied.

  • ACloner - An optional callback function that must create and return a deep copy of a given element of A.

    Parameter:

    • AElem - The element to be cloned.

    Returns:

    • The cloned copy of AElem.

    If this parameter is omitted then a shallow copy of A is returned.

    When the parameter is provided then a deep copy of A is returned. Here, a deep copy is a copy whose properties do not share the same references (i.e. point to the same underlying values) as those of the source item. For simple types this is trivial. For reference types this means that ACloner must create fresh data objects with the same properties as the type being cloned.

Returns:

  • The required copy of the array.

Note

When making deep copies that involve allocating memory, particular care must be taken to ensure that the memory is deallocated when no longer required.

Examples

Example #1

Creating a shallow copy:

procedure Copy_Eg1;
var
  A, B: TArray<Integer>;
  C, D: TArray<TStrings>;
  O1, O2, O3: TStrings;
  Idx: Integer;
begin
  A := TArray<Integer>.Create(1, 2, 3);
  B := TArrayUtils.Copy<Integer>(A);
  Assert(TArrayUtils.Equal<Integer>(A, B));

  O1 := TStringList.Create;
  O2 := TStringList.Create;
  O3 := TStringList.Create;
  O1.Add('a');
  O2.Add('b'); O2.Add('c');
  O3.Add('d');

  C := TArray<TStrings>.Create(O1, O2, O3);
  D := TArrayUtils.Copy<TStrings>(C);

  for Idx := Low(C) to High(C) do
    // these array elements refer to the same object references
    Assert(Pointer(C[Idx]) = Pointer(D[Idx]));

  Assert(D[0].Text = C[0].Text);
  C[0].Add('x');    // also updates D[0];
  Assert(D[0].Text = C[0].Text);

  for Idx := Low(C) to High(C) do
    C[Idx].Free;    // also frees D[Idx]
end;

Example #2

Creating a deep copy:

procedure Copy_Eg2;
var
  C, D: TArray<TStrings>;
  O1, O2, O3: TStrings;
  Idx: Integer;
  Cloner: TArrayUtils.TCloner<TStrings>;
begin
  O1 := TStringList.Create;
  O2 := TStringList.Create;
  O3 := TStringList.Create;
  O1.Add('a');
  O2.Add('b'); O2.Add('c');
  O3.Add('d');

  Cloner := function(const AElem: TStrings): TStrings
    var
      S: string;
    begin
      Result := TStringList.Create;
      for S in AElem do
        Result.Add(S);
    end;

  C := TArray<TStrings>.Create(O1, O2, O3);
  D := TArrayUtils.Copy<TStrings>(C, Cloner);

  for Idx := Low(C) to High(C) do
    // these array elements refer to different object references
    Assert(Pointer(C[Idx]) <> Pointer(D[Idx]));

  Assert(D[0].Text = C[0].Text);
  C[0].Add('x');    // does not update D[0];
  Assert(D[0].Text <> C[0].Text);

  for Idx := Low(C) to High(C) do
    C[Idx].Free;
  for Idx := Low(D) to High(D) do
    D[Idx].Free;    // these are separate objects to those in C
end;

See Also