Skip to content

Commit 7c517f4

Browse files
committed
Fix unaliascopy for SubArray with indices of Array{<:CartesianIndex}
1 parent 89671ae commit 7c517f4

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

base/subarray.jl

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,32 @@ unaliascopy(A::SubArray) = typeof(A)(unaliascopy(A.parent), map(unaliascopy, A.i
107107
# When the parent is an Array we can trim the size down a bit. In the future this
108108
# could possibly be extended to any mutable array.
109109
function unaliascopy(V::SubArray{T,N,A,I,LD}) where {T,N,A<:Array,I<:Tuple{Vararg{Union{Real,AbstractRange,Array}}},LD}
110-
dest = Array{T}(undef, index_lengths(V.indices...))
111-
copyto!(dest, V)
110+
dest = Array{T}(undef, _trimmed_shape(V.indices...))
111+
copyto!(dest, view(V, _trimmed_vind(V.indices...)...))
112112
SubArray{T,N,A,I,LD}(dest, map(_trimmedindex, V.indices), 0, Int(LD))
113113
end
114+
# We can avoid the repeation from `AbstractArray{CartesianIndex{0}}`
115+
@inline _trimmed_vind(A, rest...) = (_trimmed_vind1(A)..., _trimmed_vind(rest...)...)
116+
_trimmed_vind() = ()
117+
_trimmed_vind1(i::AbstractArray{<:AbstractCartesianIndex{0}}) = map(firstindex, axes(i))
118+
_trimmed_vind1(i) = axes(i)
119+
# Get the proper trimmed shape
120+
@inline _trimmed_shape(A, rest...) = (_trimmed_shape1(A)..., _trimmed_shape(rest...)...)
121+
_trimmed_shape() = ()
122+
_trimmed_shape1(::Real) = (1,)
123+
_trimmed_shape1(i::AbstractArray{<:Integer}) = (length(i),)
124+
_trimmed_shape1(i::AbstractArray{<:AbstractCartesianIndex{0}}) = ()
125+
_trimmed_shape1(i::AbstractArray{<:AbstractCartesianIndex{N}}) where {N} = (length(i), ntuple(Returns(1), Val(N - 1))...)
114126
# Transform indices to be "dense"
115127
_trimmedindex(i::Real) = oftype(i, 1)
116-
_trimmedindex(i::AbstractUnitRange) = oftype(i, oneto(length(i)))
117-
_trimmedindex(i::AbstractArray) = oftype(i, reshape(eachindex(IndexLinear(), i), axes(i)))
118-
128+
_trimmedindex(i::AbstractUnitRange{<:Integer}) = oftype(i, oneto(length(i)))
129+
_trimmedindex(i::AbstractArray{<:Integer}) = oftype(i, reshape(eachindex(IndexLinear(), i), axes(i)))
130+
_trimmedindex(i::AbstractArray{<:AbstractCartesianIndex{0}}) = oftype(i, copy(i))
131+
function _trimmedindex(i::AbstractArray{<:AbstractCartesianIndex{N}}) where {N}
132+
padding = ntuple(Returns(1), Val(N - 1))
133+
ax1 = eachindex(IndexLinear(), i)
134+
return oftype(i, reshape(CartesianIndices((ax1, padding...)), axes(i)))
135+
end
119136
## SubArray creation
120137
# We always assume that the dimensionality of the parent matches the number of
121138
# indices that end up getting passed to it, so we store the parent as a

test/subarray.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,8 +663,15 @@ end
663663
@testset "unaliascopy trimming; Issue #26263" begin
664664
A = rand(5,5,5,5)
665665
V = view(A, 2:5, :, 2:5, 1:2:5)
666-
@test @inferred(Base.unaliascopy(V)) == V == A[2:5, :, 2:5, 1:2:5]
666+
@test @inferred(Base.unaliascopy(V))::typeof(V) == V == A[2:5, :, 2:5, 1:2:5]
667667
@test @inferred(sum(Base.unaliascopy(V))) sum(V) sum(A[2:5, :, 2:5, 1:2:5])
668+
i1 = collect(CartesianIndices((2:5)))
669+
i2 = [CartesianIndex(), CartesianIndex()]
670+
i3 = collect(CartesianIndices((2:5, 1:2:5)))
671+
V = view(A, i1, 1:5, i2, i3)
672+
@test @inferred(Base.unaliascopy(V))::typeof(V) == V == A[i1, 1:5, i2, i3]
673+
V = view(A, i1, 1:5, i3, i2)
674+
@test @inferred(Base.unaliascopy(V))::typeof(V) == V == A[i1, 1:5, i3, i2]
668675
end
669676

670677
@testset "issue #27632" begin

0 commit comments

Comments
 (0)