This is a new site that's currently running on alpha code. There are going to be bugs. If you discover any, please report them on the site's issues page (GitHub account required). Thanks.
Warning: Many URLs are going to change. Refer to the README file to discover which library project's documentation has been completed.
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;
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:
Returns:
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:
When making deep copies that involve allocating memory, particular care must be taken to ensure that the memory is deallocated when no longer required.
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;
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;