It is a little difficult to get all the necessary values for this problem available at compile time. Now I have:
@generated updateindex(s::SVector{L,T},j::Type{Val{I}},v) where {L,T,I} =
Expr(:call, :(SVector{L,T}), (ifelse(i==I, :(s[$i]+v), :(s[$i])) for i=1:L)...)
or just set the coordinate:
@generated setindex(s::SVector{L,T},j::Type{Val{I}},v) where {L,T,I} =
Expr(:call, :(SVector{L,T}), (ifelse(i==I, :v, :(s[$i])) for i=1:L)...)
And it can be used as:
julia> Z = @SVector [1,1,1,1,1];
julia> updateindex(Z,Val{3},4)
5-element SVector{5,Int64}:
1
1
5
1
1
And compared as:
julia> using BenchmarkTools
julia> @btime updateindex($Z,Val{3},4);
2.032 ns (0 allocations: 0 bytes)
Minimum Code:
julia> @code_native updateindex(Z,Val{3},4)
.text
Filename: REPL[13]
pushq %rbp
movq %rsp, %rbp
Source line: 1
vmovups (%rsi), %xmm0
addq 16(%rsi), %rcx
movq 24(%rsi), %rax
movq 32(%rsi), %rdx
vmovups %xmm0, (%rdi)
movq %rcx, 16(%rdi)
movq %rax, 24(%rdi)
movq %rdx, 32(%rdi)
movq %rdi, %rax
popq %rbp
retq
nopl (%rax)
Does this solve the puzzle?
By the way, if there are ways to rewrite this in a more readable form, I will be glad to see in the comments (and update the answer accordingly).
UPDATE
Chris's comment correctly noted that a version with a non value type can be executed j:
@generated setindex(s::SVector{L,T},j,v) where {L,T} =
Expr(:call, :(SVector{L,T}), (:(ifelse($i==j, v, s[$i])) for i=1:L)...)
- ( , , , ):
julia> setindex(Z,4,3)
5-element SVector{5,Int64}:
1
1
1
3
1
julia> @code_native setindex(Z,4,3)
.text
Filename: REPL[15]
pushq %rbp
movq %rsp, %rbp
Source line: 1
cmpq $1, %rdx
movq (%rsi), %r8
cmoveq %rcx, %r8
cmpq $2, %rdx
movq 8(%rsi), %r9
cmoveq %rcx, %r9
cmpq $3, %rdx
movq 16(%rsi), %r10
cmoveq %rcx, %r10
cmpq $4, %rdx
movq 24(%rsi), %rax
cmoveq %rcx, %rax
cmpq $5, %rdx
cmovneq 32(%rsi), %rcx
movq %r8, (%rdi)
movq %r9, 8(%rdi)
movq %r10, 16(%rdi)
movq %rax, 24(%rdi)
movq %rcx, 32(%rdi)
movq %rdi, %rax
popq %rbp
retq
nopw %cs:(%rax,%rax)