From e0c63306ddc35e0f0e54cebe5b952fcbf4c0f46a Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Wed, 5 Oct 2016 23:16:39 -0500 Subject: [PATCH 1/4] Ensure SubArray constructor inlines --- base/subarray.jl | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/base/subarray.jl b/base/subarray.jl index 0aede224b8337..85ed8083bc2d1 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) + @_inline_meta SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, dims) end function SubArray{P, I, N}(::LinearSlow, parent::P, indexes::I, dims::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}) + @_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) @@ -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))) @@ -253,10 +257,11 @@ end # 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, 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 +283,10 @@ 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) From 627393a496eafadbd5c8ede070b7276c6d6bdeea Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Wed, 5 Oct 2016 23:30:29 -0500 Subject: [PATCH 2/4] Don't bother calculating the size of the SubArray during creation All it needs is the dimensionality of the indexing result. --- base/multidimensional.jl | 10 ++++++++++ base/subarray.jl | 15 ++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) 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 85ed8083bc2d1..15b85cf942a11 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -18,15 +18,16 @@ immutable SubArray{T,N,P,I,L} <: AbstractArray{T,N} 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(parent::AbstractArray, indexes::Tuple, dims::Tuple) = SubArray(parent, indexes) # for compatibility +function SubArray(parent::AbstractArray, indexes::Tuple) @_inline_meta - SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, dims) + 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) @@ -96,7 +97,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 @@ -107,7 +108,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))) @@ -115,7 +116,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]] From f66bc82adec98fc21a1bd2b3fb48749222c0f5f7 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Wed, 5 Oct 2016 23:31:12 -0500 Subject: [PATCH 3/4] Deprecate three-argument `SubArray` constructor --- base/deprecated.jl | 3 +++ base/subarray.jl | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) 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/subarray.jl b/base/subarray.jl index 15b85cf942a11..c06df35d2fa45 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -18,7 +18,6 @@ immutable SubArray{T,N,P,I,L} <: AbstractArray{T,N} end end # Compute the linear indexability of the indices, and combine it with the linear indexing of the parent -SubArray(parent::AbstractArray, indexes::Tuple, dims::Tuple) = SubArray(parent, indexes) # for compatibility function SubArray(parent::AbstractArray, indexes::Tuple) @_inline_meta SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, index_dimsum(indexes...)) From 410cd4928253fd6045be49f227fbb6cdb2655b5b Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Mon, 2 Jan 2017 23:44:14 -0600 Subject: [PATCH 4/4] Wrap long lines --- base/subarray.jl | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/base/subarray.jl b/base/subarray.jl index c06df35d2fa45..1a6b8d5c2e3bb 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -256,9 +256,12 @@ 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) = (@_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 +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 @@ -283,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) = (@_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...)) +_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)