maf-soft
maf-soft

Reputation: 2552

Convert array to array of const in Delphi

I am looking for a simple and ideally general (or using generics) way to convert an array to an array of const (=array of TVarRec). My specific case is that I have an array of Variant and want to pass it to the Format() function.

This is what I've found so far, but it looks hackish to me:

function MyFormat(const Fmt: string; const Args: TArray<Variant>): string;
var
  A: array of TVarRec;
  I: Integer;
begin
  SetLength(A, Length(Args));
  for I:= Low(Args) to High(Args) do begin
    A[I].VType:= vtVariant;
    A[I].VVariant:= @Args[I];
  end;
  Result:= Format(Fmt, A);
end;

It seems to work. Is it safe?

Could it be done shorter, better, faster, or can I use something ready instead? :)


Just some additional thoughts and fun facts:

System.Rtti.TValue recently became my friend. However, it seems it is missing a feature here. I am able to read my array using TValue.From(), but it seems there is no way to get it out as array of TVarRec. There is a wonderful TValueArrayToArrayOfConst, but it doesn't really help, because I had to construct an array of TValue first, which is different from an array stored in a single TValue... :(

At least TValue is able to output a single element as TVarRec, so I thought I could create a generic converter for all types of arrays. But...

Would you think this works?

for I:= Low(Args) to High(Args) do A[I]:= TValue.From(Args[I]).AsVarRec;

It compiles, but TValue's memory is released after use, and since TVarRec.VVariant is a pointer, it then points to some old location which is overridden on next cycle.

Upvotes: 2

Views: 2267

Answers (2)

JAS
JAS

Reputation: 101

A straight forward and short solution (in code). If your formatstring (fmt) and array of values (sa) are unknown.

setlength(sa,5);      // or more
result := format(fmt,[sa[0],sa[1],sa[2],sa[3],sa[4]];

Upvotes: 0

Arnaud Bouchez
Arnaud Bouchez

Reputation: 43043

Your function is safe and fast. It only allocates a small memory array A[], and passes all values by reference. I can't think on anything faster - without being premature optimization. I may only do some refactoring to reuse the TArray<variant> into TArray<TVarRec> conversion routine.

Using TValue.From().AsVarRec will definitively be slower, if your input is indeed a TArray<Variant>.

About TVarRec dandling references, you are right: those structures are just simple pointers on the stack, with no allocation, so all the referred variables should be available during the function call. So if you use a TArray<TVarRec> local conversion, you should ensure that the TArray<variant> is still allocated when calling the format() function.

Upvotes: 5

Related Questions