unit Unit1;
interface
uses system.Generics.Collections, system.Typinfo, system.sysutils;
type
TDynamicArrayFormatter<T> = class
strict private
FData: TArray<T>;
FDimensions: TArray<cardinal>;
FIndices: TArray<cardinal>;
FType: PTypeInfo;
strict protected
procedure AddValue(aBuilder: TStringBuilder);
function CalcLinearIndex: Integer;
function GetText: string;
procedure ProcessDimension(aDimension: Cardinal; aBuilder: TStringBuilder);
public
constructor Create(const aDimensions: array of cardinal; const aDataArray:
TArray<T>);
class function Execute(const aDimensions: array of cardinal; const aDataArray:
TArray<T>): string;
end;
implementation
constructor TDynamicArrayFormatter<T>.Create(const aDimensions: array of
cardinal; const aDataArray: TArray<T>);
begin
inherited Create;
SetLength(FDimensions, Length(aDimensions));
Move(aDimensions[0], FDimensions[0], Length(FDimensions) * Sizeof(Cardinal));
FData := aDataArray;
FType:= TypeInfo(T);
SetLength(FIndices, Length(FDimensions));
end;
procedure TDynamicArrayFormatter<T>.AddValue(aBuilder: TStringBuilder);
var
LValue: T;
N: Integer;
S: string;
begin
N:= CalcLinearIndex;
LValue := FData[N];
case FType.Kind of
tkInteger: S:= Pinteger(@LValue)^.ToString;
tkUnicodeString: S:= PPChar(@LValue)^;
else
S:= 'unknown type of T';
end;
aBuilder.Append(S);
end;
function TDynamicArrayFormatter<T>.CalcLinearIndex: Integer;
var
I, N: Integer;
begin
Result := 0;
N:= 1;
for I := High(FDimensions) downto Low(FDimensions) do begin
Inc(Result, N * Pred(FIndices[I]));
N := N * FDimensions[I];
end;
end;
class function TDynamicArrayFormatter<T>.Execute(const aDimensions: array of
cardinal; const aDataArray: TArray<T>): string;
var
LInstance: TDynamicArrayFormatter<T>;
begin
LInstance := TDynamicArrayFormatter<T>.create(aDimensions, aDataArray);
try
Result := LInstance.GetText;
finally
LInstance.Free;
end;
end;
function TDynamicArrayFormatter<T>.GetText: string;
var
LBuilder: TStringBuilder;
begin
LBuilder := TStringBuilder.Create;
try
ProcessDimension(1, LBuilder);
Result := LBuilder.ToString;
finally
LBuilder.Free;
end;
end;
procedure TDynamicArrayFormatter<T>.ProcessDimension(aDimension: Cardinal;
aBuilder: TStringBuilder);
var
I: Cardinal;
LAddValues: Boolean;
begin
aBuilder.Append('{');
LAddValues := integer(aDimension) = Length(FDimensions);
for I := 1 to FDimensions[Pred(aDimension)] do begin
FIndices[aDimension-1] := I;
if LAddValues then begin
if I > 1 then
aBuilder.Append(',');
AddValue(aBuilder);
end
else
ProcessDimension(Succ(aDimension), aBuilder);
end;
aBuilder.Append('}');
end;
end.
Usage like
var
S: string;
begin
S:= TDynamicArrayFormatter<string>.execute([1,2,2], ['one','two','three','four']);
WriteLn(S);
end;