In some cases you can use an MVector, perform your operations, and convert to SVector. If the array doesn’t escape, everything is stack allocated and fast:
function test3(::Val{K},x::Int) where K
y = MVector{K,Int}(undef)
y[1] = K
for i in 2:K
y[i] = y[i-1] + 1
end
return SVector(y)
end
Comparing to the code using Setfield:
1.7.2> @btime test2(Val(4),1)
3.200 ns (0 allocations: 0 bytes);
1.7.2> @btime test3(Val(4),1);
2.300 ns (0 allocations: 0 bytes)
The difference grows larger for bigger arrays:
1.7.2> @btime test2(Val(8),1);
11.011 ns (0 allocations: 0 bytes)
1.7.2> @btime test3(Val(8),1);
2.600 ns (0 allocations: 0 bytes)
1.7.2> @btime test2(Val(16),1);
37.538 ns (0 allocations: 0 bytes)
1.7.2> @btime test3(Val(16),1);
3.100 ns (0 allocations: 0 bytes)
1.7.2> @btime test2(Val(32),1);
110.645 ns (0 allocations: 0 bytes)
1.7.2> @btime test3(Val(32),1);
21.486 ns (0 allocations: 0 bytes)
1.7.2> @btime test2(Val(64),1);
1.300 μs (0 allocations: 0 bytes)
1.7.2> @btime test3(Val(64),1);
38.547 ns (0 allocations: 0 bytes)