Assume my NamedTuple contains only floating point values T and SVector{N, T} entries, e.g.,
using StaticArrays
nt = ( a = rand(), b = SA[1.0, 2.0 ,3.0] )
Taking such a NamedTuple and interpreting it as an SVector is straightforward
v = reinterpret(SVector{4, Float64}, nt)
I can write a @generated function that does the reverse, but it is awful (see below) and I just wondered whether is a more straightforward way to achieve this?
@generated function _svec2nt(v::SVector, x::NamedTuple)
SYMS = fieldnames(x)
TT = fieldtypes(x)
_len(::Type{T}) where {T <: Number} = 1
_len(::Type{SVector{N, T}}) where {N, T <: Number} = N
i0 = Int[]
idx = 1
for T in TT
push!(i0, idx)
idx += _len(T)
end
push!(i0, idx)
# indexing into v::SVector
inds = []
for i = 1:length(TT)
rg = i0[i]:i0[i+1]-1
if length(rg) == 1
push!(inds, "$(first(rg))")
else
rg = SVector(rg...)
push!(inds, "SA$rg")
end
end
code = "(; "
for (sym, ind) in zip(SYMS, inds)
code *= "$sym = v[$ind], "
end
code *= ")"
return quote
$(Meta.parse(code))
end
end
julia> nt = ( a = rand(), b = SA[1.0, 2.0 ,3.0] )
(a = 0.4808058471551182, b = [1.0, 2.0, 3.0])
julia> v = reinterpret(SVector{4, Float64}, nt)
4-element SVector{4, Float64} with indices SOneTo(4):
0.4808058471551182
1.0
2.0
3.0
julia> reinterpret(typeof(nt), Tuple(v))
(a = 0.4808058471551182, b = [1.0, 2.0, 3.0])
For some reason, one has to use Tuple(v) instead of v.
reinterpret(T::DataType, A::AbstractArray) tries to lazily reinterpret an array as an array of a different element type, rather than an instance of said type.
If we try to index it though, at some point it tries to convert the reinterpreted axes 1:1 to the type of the parent SVector’s axes SOneTo{4}, which is only compatible with 1:4. Not really sure why that convert happens, maybe fordoes not allow automatic offset indices.
It’s all isbits reinterpretation, it’s just designed to do so across elements of an input AbstractArray. If the axes glitch wasn’t there, indexing the only element of the reinterpreted array would’ve returned the desired NamedTuple. Of course, reinterpreting the same bits as a Tuple is just easier.