diff --git a/base/deprecated.jl b/base/deprecated.jl index 41020dcb5fc62..ba0a5b90ae2d7 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -831,6 +831,9 @@ function convert(::Type{UpperTriangular}, A::Bidiagonal) end end +# Deprecate three-arg SubArray since the constructor doesn't need the dims tuple +@deprecate SubArray(parent::AbstractArray, indexes::Tuple, dims::Tuple) SubArray(parent, indexes) + # Deprecate vectorized unary functions over sparse matrices in favor of compact broadcast syntax (#17265). for f in (:sin, :sinh, :sind, :asin, :asinh, :asind, :tan, :tanh, :tand, :atan, :atanh, :atand, diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 3a3b155d8947b..7cdd7a1556f59 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -215,6 +215,16 @@ end end index_ndims() = () +# combined dimensionality of all indices +# rather than returning N, it returns an NTuple{N,Bool} so the result is inferrable +@inline index_dimsum(i1, I...) = (index_dimsum(I...)...) +@inline index_dimsum(::Colon, I...) = (true, index_dimsum(I...)...) +@inline index_dimsum(::AbstractArray{Bool}, I...) = (true, index_dimsum(I...)...) +@inline function index_dimsum{_,N}(::AbstractArray{_,N}, I...) + (ntuple(x->true, Val{N})..., index_dimsum(I...)...) +end +index_dimsum() = () + # Recursively compute the lengths of a list of indices, without dropping scalars # These need to be inlined for more than 3 indexes # Trailing CartesianIndex{0}s and arrays thereof are strange when used as diff --git a/base/subarray.jl b/base/subarray.jl index 0aede224b8337..1a6b8d5c2e3bb 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -12,18 +12,22 @@ immutable SubArray{T,N,P,I,L} <: AbstractArray{T,N} offset1::Int # for linear indexing and pointer, only valid when L==true stride1::Int # used only for linear indexing function SubArray(parent, indexes, offset1, stride1) + @_inline_meta check_parent_index_match(parent, indexes) new(parent, indexes, offset1, stride1) end end # Compute the linear indexability of the indices, and combine it with the linear indexing of the parent -function SubArray(parent::AbstractArray, indexes::Tuple, dims::Tuple) - SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, dims) +function SubArray(parent::AbstractArray, indexes::Tuple) + @_inline_meta + SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, index_dimsum(indexes...)) end -function SubArray{P, I, N}(::LinearSlow, parent::P, indexes::I, dims::NTuple{N}) +function SubArray{P, I, N}(::LinearSlow, parent::P, indexes::I, ::NTuple{N}) + @_inline_meta SubArray{eltype(P), N, P, I, false}(parent, indexes, 0, 0) end -function SubArray{P, I, N}(::LinearFast, parent::P, indexes::I, dims::NTuple{N}) +function SubArray{P, I, N}(::LinearFast, parent::P, indexes::I, ::NTuple{N}) + @_inline_meta # Compute the stride and offset stride1 = compute_stride1(parent, indexes) SubArray{eltype(P), N, P, I, true}(parent, indexes, compute_offset1(parent, stride1, indexes), stride1) @@ -92,7 +96,7 @@ view(A::AbstractArray, I::Union{ViewIndex, AbstractCartesianIndex}...) = view(A, function unsafe_view(A::AbstractArray, I::ViewIndex...) @_inline_meta J = to_indexes(I...) - SubArray(A, J, map(unsafe_length, index_shape(A, J...))) + SubArray(A, J) end # When we take the view of a view, it's often possible to "reindex" the parent # view's indices such that we can "pop" the parent view and keep just one layer @@ -103,7 +107,7 @@ end unsafe_view(V::SubArray, I::ViewIndex...) = (@_inline_meta; _maybe_reindex(V, to_indexes(I...))) _maybe_reindex(V, I) = (@_inline_meta; _maybe_reindex(V, I, I)) _maybe_reindex{C<:AbstractCartesianIndex}(V, I, ::Tuple{AbstractArray{C}, Vararg{Any}}) = - (@_inline_meta; SubArray(V, I, map(unsafe_length, index_shape(V, I...)))) + (@_inline_meta; SubArray(V, I)) # But allow arrays of CartesianIndex{1}; they behave just like arrays of Ints _maybe_reindex{C<:AbstractCartesianIndex{1}}(V, I, A::Tuple{AbstractArray{C}, Vararg{Any}}) = (@_inline_meta; _maybe_reindex(V, I, tail(A))) @@ -111,7 +115,7 @@ _maybe_reindex(V, I, A::Tuple{Any, Vararg{Any}}) = (@_inline_meta; _maybe_reinde function _maybe_reindex(V, I, ::Tuple{}) @_inline_meta idxs = reindex(V, V.indexes, to_indexes(I...)) - SubArray(V.parent, idxs, map(unsafe_length, (index_shape(V.parent, idxs...)))) + SubArray(V.parent, idxs) end ## Re-indexing is the heart of a view, transforming A[i, j][x, y] to A[i[x], j[y]] @@ -222,7 +226,7 @@ substrides(s, parent, dim, I::Tuple{Any, Vararg{Any}}) = throw(ArgumentError("st stride(V::SubArray, d::Integer) = d <= ndims(V) ? strides(V)[d] : strides(V)[end] * size(V)[end] compute_stride1{N}(parent::AbstractArray, I::NTuple{N}) = - compute_stride1(1, fill_to_length(indices(parent), OneTo(1), Val{N}), I) + (@_inline_meta; compute_stride1(1, fill_to_length(indices(parent), OneTo(1), Val{N}), I)) compute_stride1(s, inds, I::Tuple{}) = s compute_stride1(s, inds, I::Tuple{Real, Vararg{Any}}) = (@_inline_meta; compute_stride1(s*unsafe_length(inds[1]), tail(inds), tail(I))) @@ -252,11 +256,15 @@ end # If the result is one-dimensional and it's a Colon, then linear # indexing uses the indices along the given dimension. Otherwise # linear indexing always starts with 1. -compute_offset1(parent, stride1::Integer, I::Tuple) = (@_inline_meta; compute_offset1(parent, stride1, find_extended_dims(I)..., I)) -compute_offset1(parent, stride1::Integer, dims::Tuple{Int}, inds::Tuple{Colon}, I::Tuple) = compute_linindex(parent, I) - stride1*first(indices(parent, dims[1])) # index-preserving case -compute_offset1(parent, stride1::Integer, dims, inds, I::Tuple) = compute_linindex(parent, I) - stride1 # linear indexing starts with 1 +compute_offset1(parent, stride1::Integer, I::Tuple) = + (@_inline_meta; compute_offset1(parent, stride1, find_extended_dims(I)..., I)) +compute_offset1(parent, stride1::Integer, dims::Tuple{Int}, inds::Tuple{Colon}, I::Tuple) = + (@_inline_meta; compute_linindex(parent, I) - stride1*first(indices(parent, dims[1]))) # index-preserving case +compute_offset1(parent, stride1::Integer, dims, inds, I::Tuple) = + (@_inline_meta; compute_linindex(parent, I) - stride1) # linear indexing starts with 1 function compute_linindex{N}(parent, I::NTuple{N}) + @_inline_meta IP = fill_to_length(indices(parent), OneTo(1), Val{N}) compute_linindex(1, 1, IP, I) end @@ -278,10 +286,13 @@ end compute_linindex(f, s, IP::Tuple, I::Tuple{}) = f find_extended_dims(I) = (@_inline_meta; _find_extended_dims((), (), 1, I...)) -_find_extended_dims(dims, inds, dim) = dims, inds -_find_extended_dims(dims, inds, dim, ::Real, I...) = _find_extended_dims(dims, inds, dim+1, I...) -_find_extended_dims(dims, inds, dim, i1::AbstractCartesianIndex, I...) = _find_extended_dims(dims, inds, dim, i1.I..., I...) -_find_extended_dims(dims, inds, dim, i1, I...) = _find_extended_dims((dims..., dim), (inds..., i1), dim+1, I...) +_find_extended_dims(dims, inds, dim) = (@_inline_meta; return (dims, inds)) +_find_extended_dims(dims, inds, dim, ::Real, I...) = + (@_inline_meta; _find_extended_dims(dims, inds, dim+1, I...)) +_find_extended_dims(dims, inds, dim, i1::AbstractCartesianIndex, I...) = + (@_inline_meta; _find_extended_dims(dims, inds, dim, i1.I..., I...)) +_find_extended_dims(dims, inds, dim, i1, I...) = + (@_inline_meta; _find_extended_dims((dims..., dim), (inds..., i1), dim+1, I...)) unsafe_convert{T,N,P,I<:Tuple{Vararg{RangeIndex}}}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) = unsafe_convert(Ptr{T}, V.parent) + (first_index(V)-1)*sizeof(T)