the problem now is calling (a..., )
inside a function would give warntype when a is a Vector
(NOT a Tuple
). It happens inside map()
(see base\tuple.jl
line 186).
using a SizedVector
instead of a Vector
, and using StaticArrays.Tuple()
instead of Core.tuple()
would avoid warntype:
using StaticArrays
function mymap2(f, t::Base.All16{T, N} ) where {T, N}
N_ = 16 + N
A = SizedVector{N_, T}(undef)
for i=1:N_
A[i] = f(t[i])
end
# (A..., ) # warntype
Tuple(A) # NO warntype
end
julia> const nt1000 = (1:1000..., );
julia> @code_warntype mymap2(x -> x + 1, nt1000); # NO warntype
okay, now I’m thinking ways of avoiding whatever vector: to use recursion of recursions like:
mymap3(f, t::Tuple{}) = () # same as map()
mymap3(f, t::Tuple{Any,}) = (f(t[1]),) # same as map()
mymap3(f, t::Tuple{Any, Any}) = (f(t[1]), f(t[2])) # same as map()
mymap3(f, t::Tuple{Any, Any, Any}) = (f(t[1]), f(t[2]), f(t[3])) # same as map()
mymap3(f, t::Tuple) = (Base.@_inline_meta; (f(t[1] ), mymap3(f,Base.tail(t) )... ) )
argheadtail(x1, x2, x3, x4,
x5, x6, x7, x8,
x9, x10, x11, x12,
x13, x14, x15,
rest...) = ((x1, x2, x3, x4,
x5, x6, x7, x8,
x9, x10, x11, x12,
x13, x14, x15),
rest)
headtail(x::Tuple) = argheadtail(x...)
mymap3(f, t::Base.All16) = (Base.@_inline_meta;
(head, tail) = headtail(t);
(mymap3(f, head)..., mymap3(f, tail)... ) )
julia> map(x->x+1,nt1000)===mymap2(x->x+1,nt1000)===mymap3(x->x+1,nt1000)
true
julia> @code_warntype mymap3(x -> x + 1, nt1000); # NO warntype
finally, mymap3()
avoids any warntype.
now, check the performance:
julia> @btime map(x -> x + 1, $nt1000); # Vector & Core.tuple()
25.667 μs (494 allocations: 39.34 KiB)
julia> @btime mymap2(x -> x + 1, $nt1000); # SizedVector & Tuple()
1.413 μs (1 allocation: 7.94 KiB)
julia> @btime mymap3(x -> x + 1, $nt1000); # recursion of recursions
2.118 ms (50195 allocations: 2.59 MiB)
mymap2()
has no warntype and is much faster!
however, even mymap3()
also avoids warntype, somehow it’s much slower!!!