Skip to content

Commit 2bd4cf8

Browse files
jishnubN5N3
andauthored
Avoid allocations in views of views (#53231)
Currently, views-of-views construct their re-indexed indices by slicing into the parent indices. This PR changes this to use views of the parent indices instead. This makes the operation faster and non-allocating if the `parentindices` for the original view are `Vector`s. ```julia julia> a = rand(200, 200); julia> av = view(a, collect.(axes(a))...); julia> @Btime view($av, axes($av)...); 312.393 ns (4 allocations: 3.25 KiB) # master 7.354 ns (0 allocations: 0 bytes) # PR ``` Indexing into the resulting view seems equally fast in simple cases: ```julia julia> av2 = view(av, axes(av)...); julia> @Btime sum($av2); 66.883 μs (0 allocations: 0 bytes) # master 66.888 μs (0 allocations: 0 bytes) # PR julia> av2 = view(av, collect.(axes(av))...); julia> @Btime sum($av2); 66.886 μs (0 allocations: 0 bytes) # master 66.891 μs (0 allocations: 0 bytes) # PR ``` --------- Co-authored-by: N5N3 <[email protected]>
1 parent a6ce761 commit 2bd4cf8

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

base/subarray.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -290,18 +290,18 @@ reindex(idxs::Tuple{Slice, Vararg{Any}}, subidxs::Tuple{Any, Vararg{Any}}) =
290290

291291
# Re-index into parent vectors with one subindex
292292
reindex(idxs::Tuple{AbstractVector, Vararg{Any}}, subidxs::Tuple{Any, Vararg{Any}}) =
293-
(@_propagate_inbounds_meta; (idxs[1][subidxs[1]], reindex(tail(idxs), tail(subidxs))...))
293+
(@_propagate_inbounds_meta; (maybeview(idxs[1], subidxs[1]), reindex(tail(idxs), tail(subidxs))...))
294294

295295
# Parent matrices are re-indexed with two sub-indices
296296
reindex(idxs::Tuple{AbstractMatrix, Vararg{Any}}, subidxs::Tuple{Any, Any, Vararg{Any}}) =
297-
(@_propagate_inbounds_meta; (idxs[1][subidxs[1], subidxs[2]], reindex(tail(idxs), tail(tail(subidxs)))...))
297+
(@_propagate_inbounds_meta; (maybeview(idxs[1], subidxs[1], subidxs[2]), reindex(tail(idxs), tail(tail(subidxs)))...))
298298

299299
# In general, we index N-dimensional parent arrays with N indices
300300
@generated function reindex(idxs::Tuple{AbstractArray{T,N}, Vararg{Any}}, subidxs::Tuple{Vararg{Any}}) where {T,N}
301301
if length(subidxs.parameters) >= N
302302
subs = [:(subidxs[$d]) for d in 1:N]
303303
tail = [:(subidxs[$d]) for d in N+1:length(subidxs.parameters)]
304-
:(@_propagate_inbounds_meta; (idxs[1][$(subs...)], reindex(tail(idxs), ($(tail...),))...))
304+
:(@_propagate_inbounds_meta; (maybeview(idxs[1], $(subs...)), reindex(tail(idxs), ($(tail...),))...))
305305
else
306306
:(throw(ArgumentError("cannot re-index SubArray with fewer indices than dimensions\nThis should not occur; please submit a bug report.")))
307307
end

test/subarray.jl

+25
Original file line numberDiff line numberDiff line change
@@ -999,3 +999,28 @@ end
999999
catch err
10001000
err isa ErrorException && startswith(err.msg, "syntax:")
10011001
end
1002+
1003+
1004+
@testset "avoid allocating in reindex" begin
1005+
a = reshape(1:16, 4, 4)
1006+
inds = ([2,3], [3,4])
1007+
av = view(a, inds...)
1008+
av2 = view(av, 1, 1)
1009+
@test parentindices(av2) === (2,3)
1010+
av2 = view(av, 2:2, 2:2)
1011+
@test parentindices(av2) === (view(inds[1], 2:2), view(inds[2], 2:2))
1012+
1013+
inds = (reshape([eachindex(a);], size(a)),)
1014+
av = view(a, inds...)
1015+
av2 = view(av, 1, 1)
1016+
@test parentindices(av2) === (1,)
1017+
av2 = view(av, 2:2, 2:2)
1018+
@test parentindices(av2) === (view(inds[1], 2:2, 2:2),)
1019+
1020+
inds = (reshape([eachindex(a);], size(a)..., 1),)
1021+
av = view(a, inds...)
1022+
av2 = view(av, 1, 1, 1)
1023+
@test parentindices(av2) === (1,)
1024+
av2 = view(av, 2:2, 2:2, 1:1)
1025+
@test parentindices(av2) === (view(inds[1], 2:2, 2:2, 1:1),)
1026+
end

0 commit comments

Comments
 (0)