Reputation: 2552
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
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
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