Hi there,
I would like to make a function that returns a view on an an 2-dimensional array. The view would change based on if the array has more rows and columns. MWE:
using BenchmarkTools
data1 = randn(100, 2)
data2 = randn(2, 100)
function grab(data, index::Integer, byrow::Bool)
return byrow ? view(data, index, :) : view(data, :, index)
end
grab(data1, 10, true) #2-element view(::Matrix{Float64}, 10, :) with eltype Float64
grab(data2, 10, false) #2-element view(::Matrix{Float64}, :, 10) with eltype Float64
@btime grab($data1, $10, $true) #7.900 ns (1 allocation: 48 bytes)
@btime grab($data2, $10, $false) #8.000 ns (1 allocation: 48 bytes)
@code_warntype grab(data1, 10, true) #Body::Union{SubArray{Float64, 1, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}, SubArray{Float64, 1, Matrix{Float64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true}}
Now for some reason, I cannot make this function without allocations. Is there any clever trick to make the allocation go away? If I just define the row and column function separately, there is no allocation:
function grabcols(data, index::Integer)
return view(data, index, :)
end
function grabrows(data, index::Integer)
return view(data, :, index)
end
grabcols(data1, 10)
grabrows(data2, 10)
@btime grabcols($data1, $10) #2.300 ns (0 allocations: 0 bytes)
@btime grabrows($data2, $10) #2.300 ns (0 allocations: 0 bytes)
However, I am not able to make this allocation free by including the Boolean (and neither with defining a separate ByRow/ByCol struct and dispatching it). Is there any better way?
function grab2(data, index::Integer, byrow::Bool)
return byrow ? grabcols(data, index) : grabrows(data, index)
end
grab2(data1, 10, true)
grab2(data2, 10, false)
@btime grab2($data1, $10, $true) #7.800 ns (1 allocation: 48 bytes)
@btime grab2($data2, $10, $false) #8.000 ns (1 allocation: 48 bytes)