Here is a slightly convoluted solution, using a generated function which uses a macro which calls a function to construct the expression:
function valuedispatch_expr(
::Val{lower}, ::Val{upper}, fun, val,
) where {lower, upper}
if lower >= upper
return :( $fun(Val($upper)) )
end
midpoint = lower + div(upper - lower, 2)
expr_a = valuedispatch_expr(Val(lower), Val(midpoint), fun, val)
expr_b = valuedispatch_expr(Val(midpoint+1), Val(upper), fun, val)
quote
if $val <= $midpoint
$expr_a
else
$expr_b
end
end
end
macro valuedispatch(lower::Int, upper::Int, fun, val)
valuedispatch_expr(Val(lower), Val(upper), esc(fun), esc(val))
end
@generated function valuedispatch_gen(
::Val{lower}, ::Val{upper}, fun, val,
) where {lower, upper}
:( @valuedispatch($lower, $upper, fun, val) )
end
## Timings
N = rand(1:32, 10000)
@btime foreach(n -> myfunc(Val(n)), $N)
@btime foreach(n -> valuedispatch1to32(myfunc, n), $N)
@btime foreach(n -> valuedispatch(Val(1), Val(32), myfunc, n), $N)
@btime foreach(n -> valuedispatch_gen(Val(1), Val(32), myfunc, n), $N)
5.518 ms (10000 allocations: 156.25 KiB)
1.295 ms (0 allocations: 0 bytes)
1.844 ms (10000 allocations: 156.25 KiB)
1.282 ms (0 allocations: 0 bytes)