diff --git a/base/abstractarray.jl b/base/abstractarray.jl index fec3620e2a2bbf..cef551de86049f 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -5,9 +5,15 @@ typealias AbstractVector{T} AbstractArray{T,1} typealias AbstractMatrix{T} AbstractArray{T,2} typealias AbstractVecOrMat{T} Union{AbstractVector{T}, AbstractMatrix{T}} -typealias RangeIndex Union{Int, Range{Int}, UnitRange{Int}, Colon} -typealias UnitRangeInteger{T<:Integer} UnitRange{T} -typealias Indices{N} NTuple{N,UnitRangeInteger} +typealias RangeIndex Union{Int, Range{Int}, AbstractUnitRange{Int}, Colon} +typealias Indices{N} NTuple{N,AbstractUnitRange} +typealias IndicesOne{N} NTuple{N,OneTo} +typealias DimOrInd Union{Integer, AbstractUnitRange} +typealias DimsOrInds{N} NTuple{N,DimOrInd} + +macro _inline_pure_meta() + Expr(:meta, :inline, :pure) +end ## Basic functions ## @@ -28,27 +34,19 @@ size{N}(x, d1::Integer, d2::Integer, dx::Vararg{Integer, N}) = (size(x, d1), siz Returns the valid range of indices for array `A` along dimension `d`. """ -function indices(A::AbstractArray, d) - @_inline_meta - 1:size(A,d) -end +indices{T,N}(A::AbstractArray{T,N}, d) = d <= N ? indices(A)[d] : OneTo(1) """ indices(A) Returns the tuple of valid indices for array `A`. """ -indices{T,N}(A::AbstractArray{T,N}) = _indices((), A) -_indices{T,N}(out::NTuple{N}, A::AbstractArray{T,N}) = out -function _indices(out, A::AbstractArray) - @_inline_meta - _indices((out..., indices(A, length(out)+1)), A) +function indices{T,N}(A::AbstractArray{T,N}) + @_inline_pure_meta + map(s->OneTo(s), size(A)) end -# This simpler implementation suffers from #16327 -# function indices{T,N}(A::AbstractArray{T,N}) -# @_inline_meta -# ntuple(d->indices(A, d), Val{N}) -# end + indices1(A) = (@_inline_meta; indices(A, 1)) + """ linearindices(A) @@ -144,15 +142,6 @@ linearindexing(A::AbstractArray, B::AbstractArray...) = linearindexing(linearind linearindexing(::LinearFast, ::LinearFast) = LinearFast() linearindexing(::LinearIndexing, ::LinearIndexing) = LinearSlow() -abstract IndicesBehavior -immutable IndicesStartAt1 <: IndicesBehavior end # indices 1:size(A,d) -immutable IndicesUnitRange <: IndicesBehavior end # arb UnitRange indices -immutable IndicesList <: IndicesBehavior end # indices like (:cat, :dog, :mouse) - -indicesbehavior(A::AbstractArray) = indicesbehavior(typeof(A)) -indicesbehavior{T<:AbstractArray}(::Type{T}) = IndicesStartAt1() -indicesbehavior(::Number) = IndicesStartAt1() - abstract IndicesPerformance immutable IndicesFast1D <: IndicesPerformance end # indices(A, d) is fast immutable IndicesSlow1D <: IndicesPerformance end # indices(A) is better than indices(A,d) @@ -160,29 +149,6 @@ immutable IndicesSlow1D <: IndicesPerformance end # indices(A) is better than i indicesperformance(A::AbstractArray) = indicesperformance(typeof(A)) indicesperformance{T<:AbstractArray}(::Type{T}) = IndicesFast1D() -""" - shape(A) - -Returns a tuple specifying the "shape" of array `A`. For arrays with -conventional indexing (indices start at 1), this is equivalent to -`size(A)`; otherwise it is equivalent to `indices(A)`. -""" -shape(a) = shape(indicesbehavior(a), a) -""" - shape(A, d) - -Specifies the "shape" of the array `A` along dimension `d`. For arrays -with conventional indexing (starting at 1), this is equivalent to -`size(A, d)`; for arrays with unconventional indexing (indexing may -start at something different from 1), it is equivalent to `indices(A, -d)`. -""" -shape(a, d) = shape(indicesbehavior(a), a, d) -shape(::IndicesStartAt1, a) = size(a) -shape(::IndicesStartAt1, a, d) = size(a, d) -shape(::IndicesBehavior, a) = indices(a) -shape(::IndicesBehavior, a, d) = indices(a, d) - ## Bounds checking ## @generated function trailingsize{T,N,n}(A::AbstractArray{T,N}, ::Type{Val{n}}) (isa(n, Int) && isa(N, Int)) || error("Must have concrete type") @@ -203,15 +169,15 @@ Return `true` if the given `index` is within the bounds of arrays can extend this method in order to provide a specialized bounds checking implementation. """ -checkindex(::Type{Bool}, inds::UnitRange, i) = throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))")) -checkindex(::Type{Bool}, inds::UnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds)) -checkindex(::Type{Bool}, inds::UnitRange, ::Colon) = true -function checkindex(::Type{Bool}, inds::UnitRange, r::Range) +checkindex(::Type{Bool}, inds::AbstractUnitRange, i) = throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))")) +checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds)) +checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true +function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::Range) @_propagate_inbounds_meta isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r))) end -checkindex{N}(::Type{Bool}, indx::UnitRange, I::AbstractArray{Bool,N}) = N == 1 && indx == indices1(I) -function checkindex(::Type{Bool}, inds::UnitRange, I::AbstractArray) +checkindex{N}(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool,N}) = N == 1 && indx == indices1(I) +function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray) @_inline_meta b = true for i in I @@ -312,7 +278,6 @@ checkbounds(A::AbstractArray) = checkbounds(A, 1) # 0-d case ## Constructors ## # default arguments to similar() -typealias SimIdx Union{Integer,UnitRangeInteger} """ similar(array, [element_type=eltype(array)], [dims=size(array)]) @@ -348,79 +313,54 @@ different element type it will create a regular `Array` instead: 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314 -See also `allocate_for`. """ similar{T}(a::AbstractArray{T}) = similar(a, T) -similar( a::AbstractArray, T::Type) = _similar(indicesbehavior(a), a, T) -similar{T}(a::AbstractArray{T}, dims::Tuple) = similar(a, T, dims) -similar{T}(a::AbstractArray{T}, dims::SimIdx...) = similar(a, T, dims) -similar( a::AbstractArray, T::Type, dims::SimIdx...) = similar(a, T, dims) -similar( a::AbstractArray, T::Type, dims::DimsInteger) = similar(a, T, convert(Dims, dims)) +similar( a::AbstractArray, T::Type) = similar(a, T, to_shape(indices(a))) +similar{T}(a::AbstractArray{T}, dims::Tuple) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims)) +similar( a::AbstractArray, T::Type, dims::DimOrInd...) = similar(a, T, to_shape(dims)) +similar( a::AbstractArray, T::Type, dims) = similar(a, T, to_shape(dims)) # similar creates an Array by default -similar( a::AbstractArray, T::Type, dims::Dims) = Array(T, dims) +similar( a::AbstractArray, T::Type, dims::Dims) = Array{T}(dims) -_similar(::IndicesStartAt1, a::AbstractArray, T::Type) = similar(a, T, size(a)) -_similar(::IndicesBehavior, a::AbstractArray, T::Type) = similar(a, T, indices(a)) +to_shape(::Tuple{}) = () +to_shape(dims::Dims) = dims +to_shape(dims::DimsOrInds) = map(to_shape, dims) +# each dimension +to_shape(i::Int) = i +to_shape(i::Integer) = Int(i) +to_shape(r::OneTo) = Int(last(r)) +to_shape(r::UnitRange) = convert(UnitRange{Int}, r) """ - allocate_for(storagetype, referencearray, [shape]) + similar(storagetype, indices) Create an uninitialized mutable array analogous to that specified by -`storagetype`, but with type and shape specified by the final two -arguments. The main purpose of this function is to support allocation -of arrays that may have unconventional indexing (starting at other -than 1), as determined by `referencearray` and the optional `shape` -information. +`storagetype`, but with `indices` specified by the last +argument. `storagetype` might be a type or a function. **Examples**: - allocate_for(Array{Int}, A) + similar(Array{Int}, indices(A)) creates an array that "acts like" an `Array{Int}` (and might indeed be backed by one), but which is indexed identically to `A`. If `A` has -conventional indexing, this will likely just call +conventional indexing, this will be identical to `Array{Int}(size(A))`, but if `A` has unconventional indexing then the indices of the result will match `A`. - allocate_for(BitArray, A, (shape(A, 2),)) + similar(BitArray, (indices(A, 2),)) would create a 1-dimensional logical array whose indices match those of the columns of `A`. -The main purpose of the `referencearray` argument is to select a -particular array type supporting unconventional indexing (as it is -possible that several different ones will be simultaneously in use). + similar(dims->zeros(Int, dims), indices(A)) -See also `similar`. +would create an array of `Int`, initialized to zero, matching the +indices of `A`. """ -allocate_for(f, a, shape::Union{SimIdx,Tuple{Vararg{SimIdx}}}) = f(shape) -allocate_for(f, a) = allocate_for(f, a, shape(a)) -# allocate_for when passed multiple arrays. Necessary for broadcast, etc. -function allocate_for(f, as::Tuple, shape::Union{SimIdx,Tuple{Vararg{SimIdx}}}) - @_inline_meta - a = promote_indices(as...) - allocate_for(f, a, shape) -end - -promote_indices(a) = a -function promote_indices(a, b, c...) - @_inline_meta - promote_indices(promote_indices(a, b), c...) -end -# overload this to return true for your type, e.g., -# promote_indices(a::OffsetArray, b::OffsetArray) = a -promote_indices(a::AbstractArray, b::AbstractArray) = _promote_indices(indicesbehavior(a), indicesbehavior(b), a, b) -_promote_indices(::IndicesStartAt1, ::IndicesStartAt1, a, b) = a -_promote_indices(::IndicesBehavior, ::IndicesBehavior, a, b) = throw(ArgumentError("types $(typeof(a)) and $(typeof(b)) do not have promote_indices defined")) -promote_indices(a::Number, b::AbstractArray) = b -promote_indices(a::AbstractArray, b::Number) = a - -# Strip off the index-changing container---this assumes that `parent` -# performs such an operation. TODO: since few things in Base need this, it -# would be great to find a way to eliminate this function. -normalize_indices(A) = normalize_indices(indicesbehavior(A), A) -normalize_indices(::IndicesStartAt1, A) = A -normalize_indices(::IndicesBehavior, A) = parent(A) +similar(f, shape::Tuple) = f(to_shape(shape)) +similar(f, dims::DimOrInd...) = similar(f, dims) ## from general iterable to any array @@ -629,6 +569,7 @@ next(A::AbstractArray,i) = (@_propagate_inbounds_meta; (idx, s) = next(i[1], i[2 done(A::AbstractArray,i) = (@_propagate_inbounds_meta; done(i[1], i[2])) # eachindex iterates over all indices. LinearSlow definitions are later. +eachindex(A::AbstractVector) = (@_inline_meta(); indices1(A)) eachindex(A::AbstractArray) = (@_inline_meta(); eachindex(linearindexing(A), A)) function eachindex(A::AbstractArray, B::AbstractArray) @@ -1255,38 +1196,27 @@ end # sub2ind and ind2sub # fallbacks function sub2ind(A::AbstractArray, I...) - @_inline_meta - sub2ind(indicesbehavior(A), A, I...) -end -function sub2ind(::IndicesStartAt1, A::AbstractArray, I...) - @_inline_meta - sub2ind(size(A), I...) -end -function sub2ind(::IndicesBehavior, A::AbstractArray, I...) @_inline_meta sub2ind(indices(A), I...) end function ind2sub(A::AbstractArray, ind) - @_inline_meta - ind2sub(indicesbehavior(A), A, ind) -end -function ind2sub(::IndicesStartAt1, A::AbstractArray, ind) - @_inline_meta - ind2sub(size(A), ind) -end -function ind2sub(::IndicesBehavior, A::AbstractArray, ind) @_inline_meta ind2sub(indices(A), ind) end +# 0-dimensional arrays and indexing with [] sub2ind(::Tuple{}) = 1 sub2ind(::DimsInteger) = 1 sub2ind(::Indices) = 1 sub2ind(::Tuple{}, I::Integer...) = (@_inline_meta; _sub2ind((), 1, 1, I...)) +# Generic cases sub2ind(dims::DimsInteger, I::Integer...) = (@_inline_meta; _sub2ind(dims, 1, 1, I...)) sub2ind(inds::Indices, I::Integer...) = (@_inline_meta; _sub2ind(inds, 1, 1, I...)) -# In 1d, there's a question of whether we're doing cartesian indexing or linear indexing. Support only the former. +# In 1d, there's a question of whether we're doing cartesian indexing +# or linear indexing. Support only the former. sub2ind(inds::Indices{1}, I::Integer...) = throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays")) +sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@_inline_meta; _sub2ind(inds, 1, 1, I...)) # only OneTo is safe +sub2ind(inds::Tuple{OneTo}, i::Integer) = i _sub2ind(::Any, L, ind) = ind function _sub2ind(::Tuple{}, L, ind, i::Integer, I::Integer...) @@ -1300,37 +1230,34 @@ function _sub2ind(inds, L, ind, i::Integer, I::Integer...) end nextL(L, l::Integer) = L*l -nextL(L, r::UnitRange) = L*unsafe_length(r) +nextL(L, r::AbstractUnitRange) = L*unsafe_length(r) offsetin(i, l::Integer) = i-1 -offsetin(i, r::UnitRange) = i-first(r) +offsetin(i, r::AbstractUnitRange) = i-first(r) unsafe_length(r::UnitRange) = r.stop-r.start+1 +unsafe_length(r::OneTo) = length(r) ind2sub(::Tuple{}, ind::Integer) = (@_inline_meta; ind == 1 ? () : throw(BoundsError())) -ind2sub(dims::DimsInteger, ind::Integer) = (@_inline_meta; _ind2sub((), dims, ind-1)) -ind2sub(inds::Indices, ind::Integer) = (@_inline_meta; _ind2sub((), inds, ind-1)) +ind2sub(dims::DimsInteger, ind::Integer) = (@_inline_meta; _ind2sub(dims, ind-1)) +ind2sub(inds::Indices, ind::Integer) = (@_inline_meta; _ind2sub(inds, ind-1)) ind2sub(inds::Indices{1}, ind::Integer) = throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays")) +ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,) -_ind2sub(::Tuple{}, ::Tuple{}, ind) = (ind+1,) -function _ind2sub(out, indslast::NTuple{1}, ind) +_ind2sub(::Tuple{}, ind) = (ind+1,) +function _ind2sub(indslast::NTuple{1}, ind) @_inline_meta - (out..., _lookup(ind, indslast[1])) + (_lookup(ind, indslast[1]),) end -function _ind2sub(out, inds, ind) +function _ind2sub(inds, ind) @_inline_meta r1 = inds[1] indnext, f, l = _div(ind, r1) - _ind2sub((out..., ind-l*indnext+f), tail(inds), indnext) + (ind-l*indnext+f, _ind2sub(tail(inds), indnext)...) end _lookup(ind, d::Integer) = ind+1 -_lookup(ind, r::UnitRange) = ind+first(r) +_lookup(ind, r::AbstractUnitRange) = ind+first(r) _div(ind, d::Integer) = div(ind, d), 1, d -_div(ind, r::UnitRange) = (d = unsafe_length(r); (div(ind, d), first(r), d)) - -smart_ind2sub(shape::NTuple{1}, ind) = (ind,) -smart_ind2sub(shape, ind) = ind2sub(shape, ind) -smart_sub2ind(shape::NTuple{1}, i) = (i,) -smart_sub2ind(shape, I...) = (@_inline_meta; sub2ind(shape, I...)) +_div(ind, r::AbstractUnitRange) = (d = unsafe_length(r); (div(ind, d), first(r), d)) # Vectorized forms function sub2ind{N,T<:Integer}(inds::Union{Dims{N},Indices{N}}, I::AbstractVector{T}...) @@ -1405,7 +1332,7 @@ function mapslices(f, A::AbstractArray, dims::AbstractVector) return map(f,A) end - dimsA = [shape(A)...] + dimsA = [indices(A)...] ndimsA = ndims(A) alldims = [1:ndimsA;] @@ -1430,7 +1357,7 @@ function mapslices(f, A::AbstractArray, dims::AbstractVector) if eltype(Rsize) == Int Rsize[dims] = [size(r1)..., ntuple(d->1, nextra)...] else - Rsize[dims] = [indices(r1)..., ntuple(d->1:1, nextra)...] + Rsize[dims] = [indices(r1)..., ntuple(d->OneTo(1), nextra)...] end R = similar(r1, tuple(Rsize...,)) diff --git a/base/arraymath.jl b/base/arraymath.jl index cb3cd4625e26e6..c89ac3c2d6a305 100644 --- a/base/arraymath.jl +++ b/base/arraymath.jl @@ -211,8 +211,8 @@ function flipdim{T}(A::Array{T}, d::Integer) end function rotl90(A::AbstractMatrix) - B = similar_transpose(A) - ind2 = indices(A,2) + ind1, ind2 = indices(A) + B = similar(A, (ind2,ind1)) n = first(ind2)+last(ind2) for i=indices(A,1), j=ind2 B[n-j,i] = A[i,j] @@ -220,8 +220,8 @@ function rotl90(A::AbstractMatrix) return B end function rotr90(A::AbstractMatrix) - B = similar_transpose(A) - ind1 = indices(A,1) + ind1, ind2 = indices(A) + B = similar(A, (ind2,ind1)) m = first(ind1)+last(ind1) for i=ind1, j=indices(A,2) B[j,m-i] = A[i,j] @@ -246,10 +246,6 @@ end rotr90(A::AbstractMatrix, k::Integer) = rotl90(A,-k) rot180(A::AbstractMatrix, k::Integer) = mod(k, 2) == 1 ? rot180(A) : copy(A) -similar_transpose(A::AbstractMatrix) = similar_transpose(indicesbehavior(A), A) -similar_transpose(::IndicesStartAt1, A::AbstractMatrix) = similar(A, (size(A,2), size(A,1))) -similar_transpose(::IndicesBehavior, A::AbstractMatrix) = similar(A, (indices(A,2), indices(A,1))) - ## Transpose ## transpose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(transpose, B, A) ctranspose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(ctranspose, B, A) @@ -315,11 +311,13 @@ function ccopy!(B, A) end function transpose(A::AbstractMatrix) - B = similar_transpose(A) + ind1, ind2 = indices(A) + B = similar(A, (ind2, ind1)) transpose!(B, A) end function ctranspose(A::AbstractMatrix) - B = similar_transpose(A) + ind1, ind2 = indices(A) + B = similar(A, (ind2, ind1)) ctranspose!(B, A) end ctranspose{T<:Real}(A::AbstractVecOrMat{T}) = transpose(A) diff --git a/base/bitarray.jl b/base/bitarray.jl index 946deb1b4fa3c2..e0754de7096660 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -47,6 +47,8 @@ end isassigned{N}(B::BitArray{N}, i::Int) = 1 <= i <= length(B) +linearindexing{A<:BitArray}(::Type{A}) = LinearFast() + ## aux functions ## const _msk64 = ~UInt64(0) diff --git a/base/broadcast.jl b/base/broadcast.jl index ab8fee3c97753d..e671e414c326f0 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -3,7 +3,7 @@ module Broadcast using Base.Cartesian -using Base: promote_op, promote_eltype, promote_eltype_op, @get!, _msk_end, unsafe_bitgetindex, shape, linearindices, allocate_for, tail, dimlength +using Base: promote_op, promote_eltype, promote_eltype_op, @get!, _msk_end, unsafe_bitgetindex, linearindices, to_shape, tail, dimlength, OneTo import Base: .+, .-, .*, ./, .\, .//, .==, .<, .!=, .<=, .รท, .%, .<<, .>>, .^ export broadcast, broadcast!, bitbroadcast export broadcast_getindex, broadcast_setindex! @@ -13,8 +13,8 @@ export broadcast_getindex, broadcast_setindex! ## Calculate the broadcast shape of the arguments, or error if incompatible # array inputs broadcast_shape() = () -broadcast_shape(A) = shape(A) -@inline broadcast_shape(A, B...) = broadcast_shape((), shape(A), map(shape, B)...) +broadcast_shape(A) = indices(A) +@inline broadcast_shape(A, B...) = broadcast_shape((), indices(A), map(indices, B)...) # shape inputs broadcast_shape(shape::Tuple) = shape @inline broadcast_shape(shape::Tuple, shape1::Tuple, shapes::Tuple...) = broadcast_shape(_bcs((), shape, shape1), shapes...) @@ -39,8 +39,10 @@ _bcsm(a::Number, b::Number) = a == b || b == 1 ## Check that all arguments are broadcast compatible with shape ## Check that all arguments are broadcast compatible with shape # comparing one input against a shape +check_broadcast_shape(::Tuple{}) = nothing +check_broadcast_shape(::Tuple{}, A::Union{AbstractArray,Number}) = check_broadcast_shape((), indices(A)) check_broadcast_shape(shp) = nothing -check_broadcast_shape(shp, A) = check_broadcast_shape(shp, shape(A)) +check_broadcast_shape(shp, A) = check_broadcast_shape(shp, indices(A)) check_broadcast_shape(::Tuple{}, ::Tuple{}) = nothing check_broadcast_shape(shp, ::Tuple{}) = nothing check_broadcast_shape(::Tuple{}, Ashp::Tuple) = throw(DimensionMismatch("cannot broadcast array to have fewer dimensions")) @@ -133,7 +135,7 @@ end end @inline function broadcast!{nargs}(f, B::AbstractArray, As::Vararg{Any,nargs}) - check_broadcast_shape(shape(B), As...) + check_broadcast_shape(indices(B), As...) sz = size(B) mapindex = map(x->newindexer(sz, x), As) _broadcast!(f, B, mapindex, As, Val{nargs}) @@ -179,7 +181,7 @@ function broadcast_t(f, ::Type{Any}, As...) shp = broadcast_shape(As...) iter = CartesianRange(shp) if isempty(iter) - return allocate_for(Array{Union{}}, As, shp) + return similar(Array{Union{}}, shp) end nargs = length(As) sz = size(iter) @@ -187,12 +189,12 @@ function broadcast_t(f, ::Type{Any}, As...) st = start(iter) I, st = next(iter, st) val = f([ As[i][newindex(I, indexmaps[i])] for i=1:nargs ]...) - B = allocate_for(Array{typeof(val)}, As, shp) + B = similar(Array{typeof(val)}, shp) B[I] = val return _broadcast!(f, B, indexmaps, As, Val{nargs}, iter, st, 1) end -@inline broadcast_t(f, T, As...) = broadcast!(f, allocate_for(Array{T}, As, broadcast_shape(As...)), As...) +@inline broadcast_t(f, T, As...) = broadcast!(f, similar(Array{T}, broadcast_shape(As...)), As...) @inline broadcast(f, As...) = broadcast_t(f, promote_eltype_op(f, As...), As...) @@ -215,15 +217,15 @@ function broadcast(f, As...) end =# -@inline bitbroadcast(f, As...) = broadcast!(f, allocate_for(BitArray, As, broadcast_shape(As...)), As...) +@inline bitbroadcast(f, As...) = broadcast!(f, similar(BitArray, broadcast_shape(As...)), As...) -broadcast_getindex(src::AbstractArray, I::AbstractArray...) = broadcast_getindex!(Array{eltype(src)}(broadcast_shape(I...)), src, I...) +broadcast_getindex(src::AbstractArray, I::AbstractArray...) = broadcast_getindex!(Array{eltype(src)}(to_shape(broadcast_shape(I...))), src, I...) @generated function broadcast_getindex!(dest::AbstractArray, src::AbstractArray, I::AbstractArray...) N = length(I) Isplat = Expr[:(I[$d]) for d = 1:N] quote @nexprs $N d->(I_d = I[d]) - check_broadcast_shape(size(dest), $(Isplat...)) # unnecessary if this function is never called directly + check_broadcast_shape(indices(dest), $(Isplat...)) # unnecessary if this function is never called directly checkbounds(src, $(Isplat...)) @nloops $N i dest d->(@nexprs $N k->(j_d_k = size(I_k, d) == 1 ? 1 : i_d)) begin @nexprs $N k->(@inbounds J_k = @nref $N I_k d->j_d_k) @@ -240,22 +242,22 @@ end @nexprs $N d->(I_d = I[d]) checkbounds(A, $(Isplat...)) shape = broadcast_shape($(Isplat...)) - @nextract $N shape d->(length(shape) < d ? 1 : shape[d]) + @nextract $N shape d->(length(shape) < d ? OneTo(1) : shape[d]) if !isa(x, AbstractArray) - @nloops $N i d->(1:shape_d) d->(@nexprs $N k->(j_d_k = size(I_k, d) == 1 ? 1 : i_d)) begin + xA = convert(eltype(A), x) + @nloops $N i d->shape_d d->(@nexprs $N k->(j_d_k = size(I_k, d) == 1 ? 1 : i_d)) begin @nexprs $N k->(@inbounds J_k = @nref $N I_k d->j_d_k) - @inbounds (@nref $N A J) = x + @inbounds (@nref $N A J) = xA end else X = x - # To call setindex_shape_check, we need to create fake 1-d indexes of the proper size - @nexprs $N d->(fakeI_d = 1:shape_d) - @ncall $N Base.setindex_shape_check X shape - k = 1 - @nloops $N i d->(1:shape_d) d->(@nexprs $N k->(j_d_k = size(I_k, d) == 1 ? 1 : i_d)) begin - @nexprs $N k->(@inbounds J_k = @nref $N I_k d->j_d_k) - @inbounds (@nref $N A J) = X[k] - k += 1 + @nexprs $N d->(shapelen_d = dimlength(shape_d)) + @ncall $N Base.setindex_shape_check X shapelen + Xstate = start(X) + @inbounds @nloops $N i d->shape_d d->(@nexprs $N k->(j_d_k = size(I_k, d) == 1 ? 1 : i_d)) begin + @nexprs $N k->(J_k = @nref $N I_k d->j_d_k) + x_el, Xstate = next(X, Xstate) + (@nref $N A J) = x_el end end A @@ -271,22 +273,22 @@ end eltype_plus(As::AbstractArray...) = promote_eltype_op(+, As...) -.+(As::AbstractArray...) = broadcast!(+, Array{eltype_plus(As...)}(broadcast_shape(As...)), As...) +.+(As::AbstractArray...) = broadcast!(+, Array{eltype_plus(As...)}(to_shape(broadcast_shape(As...))), As...) function .-(A::AbstractArray, B::AbstractArray) - broadcast!(-, Array{promote_op(-, eltype(A), eltype(B))}(broadcast_shape(A,B)), A, B) + broadcast!(-, Array{promote_op(-, eltype(A), eltype(B))}(to_shape(broadcast_shape(A,B))), A, B) end eltype_mul(As::AbstractArray...) = promote_eltype_op(*, As...) -.*(As::AbstractArray...) = broadcast!(*, Array{eltype_mul(As...)}(broadcast_shape(As...)), As...) +.*(As::AbstractArray...) = broadcast!(*, Array{eltype_mul(As...)}(to_shape(broadcast_shape(As...))), As...) function ./(A::AbstractArray, B::AbstractArray) - broadcast!(/, Array{promote_op(/, eltype(A), eltype(B))}(broadcast_shape(A, B)), A, B) + broadcast!(/, Array{promote_op(/, eltype(A), eltype(B))}(to_shape(broadcast_shape(A, B))), A, B) end function .\(A::AbstractArray, B::AbstractArray) - broadcast!(\, Array{promote_op(\, eltype(A), eltype(B))}(broadcast_shape(A, B)), A, B) + broadcast!(\, Array{promote_op(\, eltype(A), eltype(B))}(to_shape(broadcast_shape(A, B))), A, B) end typealias RatIntT{T<:Integer} Union{Type{Rational{T}},Type{T}} @@ -296,11 +298,11 @@ type_rdiv{T<:Integer,S<:Integer}(::RatIntT{T}, ::RatIntT{S}) = type_rdiv{T<:Integer,S<:Integer}(::CRatIntT{T}, ::CRatIntT{S}) = Complex{Rational{promote_type(T,S)}} function .//(A::AbstractArray, B::AbstractArray) - broadcast!(//, Array{type_rdiv(eltype(A), eltype(B))}(broadcast_shape(A, B)), A, B) + broadcast!(//, Array{type_rdiv(eltype(A), eltype(B))}(to_shape(broadcast_shape(A, B))), A, B) end function .^(A::AbstractArray, B::AbstractArray) - broadcast!(^, Array{promote_op(^, eltype(A), eltype(B))}(broadcast_shape(A, B)), A, B) + broadcast!(^, Array{promote_op(^, eltype(A), eltype(B))}(to_shape(broadcast_shape(A, B))), A, B) end # ## element-wise comparison operators returning BitArray ## @@ -363,10 +365,10 @@ for (f, scalarf) in ((:.==, :(==)), :((A,ind)->A), :((B,ind)->B[ind])), (:AbstractArray, :Any, :A, :((A,ind)->A[ind]), :((B,ind)->B))) - shape = :(shape($active)) + shape = :(indices($active)) @eval begin function ($f)(A::$sigA, B::$sigB) - P = allocate_for(BitArray, $active, $shape) + P = similar(BitArray, $shape) F = parent(P) l = length(F) l == 0 && return F diff --git a/base/deprecated.jl b/base/deprecated.jl index b22c1a3cc6523a..f1051985b1f303 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -766,6 +766,12 @@ function first(::Colon) 1 end +# Not exported, but may be useful just in case +function Broadcast.check_broadcast_shape(sz::Dims, As::Union{AbstractArray,Number}...) + depwarn("check_broadcast_shape(size(A), B...) should be replaced with check_broadcast_shape(indices(A), B...)", :check_broadcast_shape) + Broadcast.check_broadcast_shape(map(OneTo, sz), As...) +end + @deprecate slice view @deprecate sub view diff --git a/base/essentials.jl b/base/essentials.jl index bdc95b133b7f4f..6635d99670c0b5 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -171,7 +171,7 @@ start(v::SimpleVector) = 1 next(v::SimpleVector,i) = (v[i],i+1) done(v::SimpleVector,i) = (i > v.length) isempty(v::SimpleVector) = (v.length == 0) -indices(v::SimpleVector, d) = d == 1 ? (1:length(v)) : (1:1) +indices(v::SimpleVector, d) = d == 1 ? OneTo(length(v)) : OneTo(1) linearindices(v::SimpleVector) = indices(v, 1) function ==(v1::SimpleVector, v2::SimpleVector) diff --git a/base/exports.jl b/base/exports.jl index 000d2b4a96d2fd..e97f804792eb6d 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -28,6 +28,7 @@ export # Types AbstractChannel, AbstractMatrix, + AbstractUnitRange, AbstractVector, AbstractVecOrMat, Array, @@ -483,7 +484,6 @@ export zeta, # arrays - allocate_for, bitbroadcast, broadcast!, broadcast, @@ -583,7 +583,6 @@ export searchsortedlast, select!, select, - shape, shuffle, shuffle!, size, diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 838101efd83281..3c4e3b3bef9300 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -10,9 +10,6 @@ using Base: LinearFast, LinearSlow, AbstractCartesianIndex, fill_to_length, tail export CartesianIndex, CartesianRange -# Traits for linear indexing -linearindexing{A<:BitArray}(::Type{A}) = LinearFast() - # CartesianIndex immutable CartesianIndex{N} <: AbstractCartesianIndex{N} I::NTuple{N,Int} @@ -78,12 +75,12 @@ end CartesianRange{N}(index::CartesianIndex{N}) = CartesianRange(one(index), index) CartesianRange(::Tuple{}) = CartesianRange{CartesianIndex{0}}(CartesianIndex{0}(()),CartesianIndex{0}(())) CartesianRange{N}(sz::NTuple{N,Int}) = CartesianRange(CartesianIndex(sz)) -CartesianRange{N}(rngs::NTuple{N,Union{Int,UnitRange{Int}}}) = CartesianRange(CartesianIndex(map(r->first(r), rngs)), CartesianIndex(map(r->last(r), rngs))) +CartesianRange{N}(rngs::NTuple{N,Union{Integer,AbstractUnitRange}}) = CartesianRange(CartesianIndex(map(r->first(r), rngs)), CartesianIndex(map(r->last(r), rngs))) ndims(R::CartesianRange) = length(R.start) ndims{I<:CartesianIndex}(::Type{CartesianRange{I}}) = length(I) -eachindex(::LinearSlow, A::AbstractArray) = CartesianRange(size(A)) +eachindex(::LinearSlow, A::AbstractArray) = CartesianRange(indices(A)) @inline eachindex(::LinearSlow, A::AbstractArray, B::AbstractArray...) = CartesianRange(maxsize((), A, B...)) maxsize(sz) = sz @@ -178,18 +175,18 @@ index_lengths_dim(A, dim, ::Colon) = (trailingsize(A, dim),) # whose length is equal to the dimension we're to process next. This # allows us to dispatch, which is important for the type-stability of # the lines involving Colon as the final index. -index_shape(A::AbstractVector, I::Colon) = shape(A) +index_shape(A::AbstractVector, I::Colon) = indices(A) index_shape(A::AbstractArray, I::Colon) = (length(A),) @inline index_shape(A::AbstractArray, I...) = index_shape_dim(A, (true,), I...) @inline index_shape_dim(A, dim, ::Colon) = (trailingsize(A, length(dim)),) -@inline index_shape_dim{T,N}(A::AbstractArray{T,N}, dim::NTuple{N}, ::Colon) = (shape(A, N),) +@inline index_shape_dim{T,N}(A::AbstractArray{T,N}, dim::NTuple{N}, ::Colon) = (indices(A, N),) @inline index_shape_dim(A, dim, I::Real...) = () -@inline index_shape_dim(A, dim, ::Colon, i, I...) = (shape(A, length(dim)), index_shape_dim(A, (dim...,true), i, I...)...) +@inline index_shape_dim(A, dim, ::Colon, i, I...) = (indices(A, length(dim)), index_shape_dim(A, (dim...,true), i, I...)...) @inline index_shape_dim(A, dim, ::Real, I...) = (index_shape_dim(A, (dim...,true), I...)...) @inline index_shape_dim{N}(A, dim, ::CartesianIndex{N}, I...) = (index_shape_dim(A, (dim...,ntuple(d->true,Val{N})...), I...)...) -@inline index_shape_dim(A, dim, i::AbstractArray, I...) = (shape(i)..., index_shape_dim(A, (dim...,true), I...)...) +@inline index_shape_dim(A, dim, i::AbstractArray, I...) = (indices(i)..., index_shape_dim(A, (dim...,true), I...)...) @inline index_shape_dim(A, dim, i::AbstractArray{Bool}, I...) = (sum(i), index_shape_dim(A, (dim...,true), I...)...) -@inline index_shape_dim{N}(A, dim, i::AbstractArray{CartesianIndex{N}}, I...) = (shape(i)..., index_shape_dim(A, (dim...,ntuple(d->true,Val{N})...), I...)...) +@inline index_shape_dim{N}(A, dim, i::AbstractArray{CartesianIndex{N}}, I...) = (indices(i)..., index_shape_dim(A, (dim...,ntuple(d->true,Val{N})...), I...)...) @inline decolon(A::AbstractVector, ::Colon) = (indices(A,1),) @inline decolon(A::AbstractArray, ::Colon) = (1:length(A),) @@ -291,8 +288,6 @@ end end end -dimlength(r::Range) = length(r) -dimlength(i::Integer) = i @noinline throw_checksize_error(A, sz) = throw(DimensionMismatch("output array is the wrong size; expected $sz, got $(size(A))")) ## setindex! ## @@ -787,7 +782,7 @@ If `dim` is specified, returns unique regions of the array `itr` along `dim`. @generated function unique{T,N}(A::AbstractArray{T,N}, dim::Int) quote 1 <= dim <= $N || return copy(A) - hashes = allocate_for(inds->zeros(UInt, inds), A, shape(A, dim)) + hashes = similar(inds->zeros(UInt, inds), indices(A, dim)) # Compute hash for each row k = 0 @@ -796,7 +791,7 @@ If `dim` is specified, returns unique regions of the array `itr` along `dim`. end # Collect index of first row for each hash - uniquerow = allocate_for(Array{Int}, A, shape(A, dim)) + uniquerow = similar(Array{Int}, indices(A, dim)) firstrow = Dict{Prehashed,Int}() for k = indices(A, dim) uniquerow[k] = get!(firstrow, Prehashed(hashes[k]), k) @@ -804,7 +799,7 @@ If `dim` is specified, returns unique regions of the array `itr` along `dim`. uniquerows = collect(values(firstrow)) # Check for collisions - collided = allocate_for(falses, A, shape(A, dim)) + collided = similar(falses, indices(A, dim)) @inbounds begin @nloops $N i A d->(if d == dim k = i_d @@ -819,7 +814,7 @@ If `dim` is specified, returns unique regions of the array `itr` along `dim`. end if any(collided) - nowcollided = allocate_for(BitArray, A, shape(A, dim)) + nowcollided = similar(BitArray, indices(A, dim)) while any(collided) # Collect index of first row for each collided hash empty!(firstrow) diff --git a/base/number.jl b/base/number.jl index 3f8cbfc37c6105..d2d3270f1cfc45 100644 --- a/base/number.jl +++ b/base/number.jl @@ -7,7 +7,7 @@ isinteger(x::Integer) = true size(x::Number) = () size(x::Number,d) = convert(Int,d)<1 ? throw(BoundsError()) : 1 indices(x::Number) = () -indices(x::Number,d) = convert(Int,d)<1 ? throw(BoundsError()) : (1:1) +indices(x::Number,d) = convert(Int,d)<1 ? throw(BoundsError()) : OneTo(1) eltype{T<:Number}(::Type{T}) = T ndims(x::Number) = 0 ndims{T<:Number}(::Type{T}) = 0 diff --git a/base/operators.jl b/base/operators.jl index 6570a14e3e6127..ae9ccd639d525f 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -387,7 +387,7 @@ function promote_shape(a::AbstractArray, b::AbstractArray) throw(DimensionMismatch("dimensions must match")) end end - return shape(a) + return indices(a) end function throw_setindex_mismatch(X, I) @@ -403,7 +403,7 @@ end # for permutations that leave array elements in the same linear order. # those are the permutations that preserve the order of the non-singleton # dimensions. -function setindex_shape_check(X::AbstractArray, I...) +function setindex_shape_check(X::AbstractArray, I::Integer...) li = ndims(X) lj = length(I) i = j = 1 @@ -440,16 +440,16 @@ end setindex_shape_check(X::AbstractArray) = (length(X)==1 || throw_setindex_mismatch(X,())) -setindex_shape_check(X::AbstractArray, i) = +setindex_shape_check(X::AbstractArray, i::Integer) = (length(X)==i || throw_setindex_mismatch(X, (i,))) -setindex_shape_check{T}(X::AbstractArray{T,1}, i) = +setindex_shape_check{T}(X::AbstractArray{T,1}, i::Integer) = (length(X)==i || throw_setindex_mismatch(X, (i,))) -setindex_shape_check{T}(X::AbstractArray{T,1}, i, j) = +setindex_shape_check{T}(X::AbstractArray{T,1}, i::Integer, j::Integer) = (length(X)==i*j || throw_setindex_mismatch(X, (i,j))) -function setindex_shape_check{T}(X::AbstractArray{T,2}, i, j) +function setindex_shape_check{T}(X::AbstractArray{T,2}, i::Integer, j::Integer) if length(X) != i*j throw_setindex_mismatch(X, (i,j)) end diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index c5a461509d4949..dd64416fae86bf 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -2,8 +2,6 @@ module PermutedDimsArrays -using Base: IndicesStartAt1, IndicesBehavior, indicesbehavior - export permutedims # Some day we will want storage-order-aware iteration, so put perm in the parameters @@ -47,14 +45,10 @@ _genperm(out, I) = out @inline genperm(I, perm::AbstractVector{Int}) = genperm(I, (perm...,)) function Base.permutedims{T,N}(A::AbstractArray{T,N}, perm) - dest = similar_permute(A, perm) + dest = similar(A, genperm(indices(A), perm)) permutedims!(dest, A, perm) end -similar_permute(A::AbstractArray, perm) = similar_permute(indicesbehavior(A), A, perm) -similar_permute{T,N}(::IndicesStartAt1, A::AbstractArray{T,N}, perm) = similar(A, genperm(size(A), perm)) -similar_permute{T,N}(::IndicesBehavior, A::AbstractArray{T,N}, perm) = similar(A, genperm(indices(A), perm)) - function Base.permutedims!(dest, src::AbstractArray, perm) Base.checkdims_perm(dest, src, perm) P = PermutedDimsArray(dest, invperm(perm)) diff --git a/base/range.jl b/base/range.jl index 58ec756d1b0781..ae6ecc4cdb6754 100644 --- a/base/range.jl +++ b/base/range.jl @@ -10,6 +10,7 @@ abstract Range{T} <: AbstractArray{T,1} ## ordinal ranges abstract OrdinalRange{T,S} <: Range{T} +abstract AbstractUnitRange{T} <: OrdinalRange{T,Int} immutable StepRange{T,S} <: OrdinalRange{T,S} start::T @@ -64,7 +65,7 @@ steprem(start,stop,step) = (stop-start) % step StepRange{T,S}(start::T, step::S, stop::T) = StepRange{T,S}(start, step, stop) -immutable UnitRange{T<:Real} <: OrdinalRange{T,Int} +immutable UnitRange{T<:Real} <: AbstractUnitRange{T} start::T stop::T UnitRange(start, stop) = new(start, unitrange_last(start,stop)) @@ -78,6 +79,12 @@ unitrange_last{T}(start::T, stop::T) = ifelse(stop >= start, convert(T,start+floor(stop-start)), convert(T,start-one(stop-start))) +immutable OneTo{T<:Integer} <: AbstractUnitRange{T} + stop::T + OneTo(stop) = new(max(zero(T), stop)) +end +OneTo{T<:Integer}(stop::T) = OneTo{T}(stop) + colon(a::Real, b::Real) = colon(promote(a,b)...) colon{T<:Real}(start::T, stop::T) = UnitRange{T}(start, stop) @@ -310,12 +317,12 @@ size(r::Range) = (length(r),) isempty(r::StepRange) = (r.start != r.stop) & ((r.step > zero(r.step)) != (r.stop > r.start)) -isempty(r::UnitRange) = r.start > r.stop +isempty(r::AbstractUnitRange) = first(r) > last(r) isempty(r::FloatRange) = length(r) == 0 isempty(r::LinSpace) = length(r) == 0 step(r::StepRange) = r.step -step(r::UnitRange) = 1 +step(r::AbstractUnitRange) = 1 step(r::FloatRange) = r.step/r.divisor step{T}(r::LinSpace{T}) = ifelse(r.len <= 0, convert(T,NaN), (r.stop-r.start)/r.divisor) @@ -323,7 +330,8 @@ function length(r::StepRange) n = Integer(div(r.stop+r.step - r.start, r.step)) isempty(r) ? zero(n) : n end -length(r::UnitRange) = Integer(r.stop - r.start + 1) +length(r::AbstractUnitRange) = Integer(last(r) - first(r) + 1) +length(r::OneTo) = r.stop length(r::FloatRange) = Integer(r.len) length(r::LinSpace) = Integer(r.len + signbit(r.len - 1)) @@ -338,11 +346,12 @@ function length{T<:Union{Int,UInt,Int64,UInt64}}(r::StepRange{T}) end end -length{T<:Union{Int,Int64}}(r::UnitRange{T}) = - checked_add(checked_sub(r.stop, r.start), one(T)) +length{T<:Union{Int,Int64}}(r::AbstractUnitRange{T}) = + checked_add(checked_sub(last(r), first(r)), one(T)) +length{T<:Union{Int,Int64}}(r::OneTo{T}) = T(r.stop) -length{T<:Union{UInt,UInt64}}(r::UnitRange{T}) = - r.stop < r.start ? zero(T) : checked_add(r.stop - r.start, one(T)) +length{T<:Union{UInt,UInt64}}(r::AbstractUnitRange{T}) = + r.stop < r.start ? zero(T) : checked_add(last(r) - first(r), one(T)) # some special cases to favor default Int type let smallint = (Int === Int64 ? @@ -355,20 +364,21 @@ let smallint = (Int === Int64 ? div(Int(r.stop)+Int(r.step) - Int(r.start), Int(r.step)) end - length{T <: smallint}(r::UnitRange{T}) = Int(r.stop) - Int(r.start) + 1 + length{T <: smallint}(r::AbstractUnitRange{T}) = Int(last(r)) - Int(first(r)) + 1 + length{T <: smallint}(r::OneTo{T}) = Int(r.stop) end first{T}(r::OrdinalRange{T}) = convert(T, r.start) +first{T}(r::OneTo{T}) = one(T) first{T}(r::FloatRange{T}) = convert(T, r.start/r.divisor) first{T}(r::LinSpace{T}) = convert(T, (r.len-1)*r.start/r.divisor) -last{T}(r::StepRange{T}) = r.stop -last(r::UnitRange) = r.stop +last(r::OrdinalRange) = r.stop last{T}(r::FloatRange{T}) = convert(T, (r.start + (r.len-1)*r.step)/r.divisor) last{T}(r::LinSpace{T}) = convert(T, (r.len-1)*r.stop/r.divisor) -minimum(r::UnitRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : first(r) -maximum(r::UnitRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : last(r) +minimum(r::AbstractUnitRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : first(r) +maximum(r::AbstractUnitRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : last(r) minimum(r::Range) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : min(first(r), last(r)) maximum(r::Range) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : max(first(r), last(r)) @@ -398,9 +408,10 @@ done{T,S}(r::StepRange{T,S}, i::Integer) = isempty(r) | (i == oftype(i, r.stop) + r.step) start{T}(r::UnitRange{T}) = oftype(r.start + one(T), r.start) -next{T}(r::UnitRange{T}, i) = (convert(T, i), i + one(T)) -done{T}(r::UnitRange{T}, i) = i == oftype(i, r.stop) + one(T) +next{T}(r::AbstractUnitRange{T}, i) = (convert(T, i), i + one(T)) +done{T}(r::AbstractUnitRange{T}, i) = i == oftype(i, r.stop) + one(T) +start{T}(r::OneTo{T}) = one(T) # some special cases to favor default Int type to avoid overflow let smallint = (Int === Int64 ? @@ -411,7 +422,8 @@ let smallint = (Int === Int64 ? start{T<:smallint}(r::StepRange{T}) = convert(Int, r.start) next{T<:smallint}(r::StepRange{T}, i) = (i % T, i + r.step) start{T<:smallint}(r::UnitRange{T}) = convert(Int, r.start) - next{T<:smallint}(r::UnitRange{T}, i) = (i % T, i + 1) + next{T<:smallint}(r::AbstractUnitRange{T}, i) = (i % T, i + 1) + start{T<:smallint}(r::OneTo{T}) = 1 end ## indexing @@ -423,6 +435,12 @@ function getindex{T}(v::UnitRange{T}, i::Integer) ret end +function getindex{T}(v::OneTo{T}, i::Integer) + @_inline_meta + @boundscheck ((i > 0) & (i <= v.stop)) || throw_boundserror(v, i) + convert(T, i) +end + function getindex{T}(v::Range{T}, i::Integer) @_inline_meta ret = convert(T, first(v) + (i - 1)*step(v)) @@ -447,17 +465,23 @@ end getindex(r::Range, ::Colon) = copy(r) -function getindex{T<:Integer}(r::UnitRange, s::UnitRange{T}) +function getindex{T<:Integer}(r::UnitRange, s::AbstractUnitRange{T}) @_inline_meta @boundscheck checkbounds(r, s) - st = oftype(r.start, r.start + s.start-1) + st = oftype(r.start, r.start + first(s)-1) range(st, length(s)) end -function getindex{T<:Integer}(r::UnitRange, s::StepRange{T}) +function getindex{T}(r::OneTo{T}, s::OneTo) @_inline_meta @boundscheck checkbounds(r, s) - st = oftype(r.start, r.start + s.start-1) + OneTo(T(s.stop)) +end + +function getindex{T<:Integer}(r::AbstractUnitRange, s::StepRange{T}) + @_inline_meta + @boundscheck checkbounds(r, s) + st = oftype(first(r), first(r) + s.start-1) range(st, step(s), length(s)) end @@ -487,6 +511,7 @@ end show(io::IO, r::Range) = print(io, repr(first(r)), ':', repr(step(r)), ':', repr(last(r))) show(io::IO, r::UnitRange) = print(io, repr(first(r)), ':', repr(last(r))) +show(io::IO, r::OneTo) = print(io, "OneTo(", r.stop, ")") =={T<:Range}(r::T, s::T) = (first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)) ==(r::OrdinalRange, s::OrdinalRange) = (first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)) @@ -508,15 +533,17 @@ function ==(r::Range, s::Range) return true end -intersect{T1<:Integer, T2<:Integer}(r::UnitRange{T1}, s::UnitRange{T2}) = max(r.start,s.start):min(last(r),last(s)) +intersect(r::OneTo, s::OneTo) = OneTo(min(r.stop,s.stop)) -intersect{T<:Integer}(i::Integer, r::UnitRange{T}) = +intersect{T1<:Integer, T2<:Integer}(r::AbstractUnitRange{T1}, s::AbstractUnitRange{T2}) = max(first(r),first(s)):min(last(r),last(s)) + +intersect{T<:Integer}(i::Integer, r::AbstractUnitRange{T}) = i < first(r) ? (first(r):i) : i > last(r) ? (i:last(r)) : (i:i) intersect{T<:Integer}(r::UnitRange{T}, i::Integer) = intersect(i, r) -function intersect{T1<:Integer, T2<:Integer}(r::UnitRange{T1}, s::StepRange{T2}) +function intersect{T1<:Integer, T2<:Integer}(r::AbstractUnitRange{T1}, s::StepRange{T2}) if isempty(s) range(first(r), 0) elseif step(s) == 0 @@ -535,7 +562,7 @@ function intersect{T1<:Integer, T2<:Integer}(r::UnitRange{T1}, s::StepRange{T2}) end end -function intersect{T1<:Integer, T2<:Integer}(r::StepRange{T1}, s::UnitRange{T2}) +function intersect{T1<:Integer, T2<:Integer}(r::StepRange{T1}, s::AbstractUnitRange{T2}) if step(r) < 0 reverse(intersect(s, reverse(r))) else @@ -597,7 +624,7 @@ function intersect(r1::Range, r2::Range, r3::Range, r::Range...) end # findin (the index of intersection) -function _findin{T1<:Integer, T2<:Integer}(r::Range{T1}, span::UnitRange{T2}) +function _findin{T1<:Integer, T2<:Integer}(r::Range{T1}, span::AbstractUnitRange{T2}) local ifirst local ilast fspan = first(span) @@ -630,11 +657,11 @@ end ## linear operations on ranges ## --(r::OrdinalRange) = range(-r.start, -step(r), length(r)) +-(r::OrdinalRange) = range(-first(r), -step(r), length(r)) -(r::FloatRange) = FloatRange(-r.start, -r.step, r.len, r.divisor) -(r::LinSpace) = LinSpace(-r.start, -r.stop, r.len, r.divisor) -.+(x::Real, r::UnitRange) = range(x + r.start, length(r)) +.+(x::Real, r::AbstractUnitRange) = range(x + first(r), length(r)) .+(x::Real, r::Range) = (x+first(r)):step(r):(x+last(r)) #.+(x::Real, r::StepRange) = range(x + r.start, r.step, length(r)) .+(x::Real, r::FloatRange) = FloatRange(r.divisor*x + r.start, r.step, r.len, r.divisor) @@ -651,7 +678,7 @@ function .-(x::Real, r::LinSpace) x2 = x * r.divisor / (r.len - 1) LinSpace(x2 - r.start, x2 - r.stop, r.len, r.divisor) end -.-(r::UnitRange, x::Real) = range(r.start-x, length(r)) +.-(r::AbstractUnitRange, x::Real) = range(first(r)-x, length(r)) .-(r::StepRange , x::Real) = range(r.start-x, r.step, length(r)) .-(r::FloatRange, x::Real) = FloatRange(r.start - r.divisor*x, r.step, r.len, r.divisor) function .-(r::LinSpace, x::Real) @@ -659,14 +686,14 @@ function .-(r::LinSpace, x::Real) LinSpace(r.start - x2, r.stop - x2, r.len, r.divisor) end -.*(x::Real, r::OrdinalRange) = range(x*r.start, x*step(r), length(r)) +.*(x::Real, r::OrdinalRange) = range(x*first(r), x*step(r), length(r)) .*(x::Real, r::FloatRange) = FloatRange(x*r.start, x*r.step, r.len, r.divisor) .*(x::Real, r::LinSpace) = LinSpace(x * r.start, x * r.stop, r.len, r.divisor) .*(r::Range, x::Real) = x .* r .*(r::FloatRange, x::Real) = x .* r .*(r::LinSpace, x::Real) = x .* r -./(r::OrdinalRange, x::Real) = range(r.start/x, step(r)/x, length(r)) +./(r::OrdinalRange, x::Real) = range(first(r)/x, step(r)/x, length(r)) ./(r::FloatRange, x::Real) = FloatRange(r.start/x, r.step/x, r.len, r.divisor) ./(r::LinSpace, x::Real) = LinSpace(r.start / x, r.stop / x, r.len, r.divisor) @@ -675,15 +702,24 @@ promote_rule{T1,T2}(::Type{UnitRange{T1}},::Type{UnitRange{T2}}) = convert{T<:Real}(::Type{UnitRange{T}}, r::UnitRange{T}) = r convert{T<:Real}(::Type{UnitRange{T}}, r::UnitRange) = UnitRange{T}(r.start, r.stop) +promote_rule{T1,T2}(::Type{OneTo{T1}},::Type{OneTo{T2}}) = + OneTo{promote_type(T1,T2)} +convert{T<:Real}(::Type{OneTo{T}}, r::OneTo{T}) = r +convert{T<:Real}(::Type{OneTo{T}}, r::OneTo) = OneTo{T}(r.stop) + +promote_rule{T1,UR<:AbstractUnitRange}(::Type{UnitRange{T1}}, ::Type{UR}) = + UnitRange{promote_type(T1,eltype(UR))} +convert{T<:Real}(::Type{UnitRange{T}}, r::AbstractUnitRange) = UnitRange{T}(first(r), last(r)) + promote_rule{T1a,T1b,T2a,T2b}(::Type{StepRange{T1a,T1b}},::Type{StepRange{T2a,T2b}}) = StepRange{promote_type(T1a,T2a),promote_type(T1b,T2b)} convert{T1,T2}(::Type{StepRange{T1,T2}}, r::StepRange{T1,T2}) = r -promote_rule{T1a,T1b,T2}(::Type{StepRange{T1a,T1b}},::Type{UnitRange{T2}}) = - StepRange{promote_type(T1a,T2),promote_type(T1b,T2)} +promote_rule{T1a,T1b,UR<:AbstractUnitRange}(::Type{StepRange{T1a,T1b}},::Type{UR}) = + StepRange{promote_type(T1a,eltype(UR)),promote_type(T1b,eltype(UR))} convert{T1,T2}(::Type{StepRange{T1,T2}}, r::Range) = StepRange{T1,T2}(convert(T1, first(r)), convert(T2, step(r)), convert(T1, last(r))) -convert{T}(::Type{StepRange}, r::UnitRange{T}) = +convert{T}(::Type{StepRange}, r::AbstractUnitRange{T}) = StepRange{T,T}(first(r), step(r), last(r)) promote_rule{T1,T2}(::Type{FloatRange{T1}},::Type{FloatRange{T2}}) = @@ -765,15 +801,15 @@ reverse(r::LinSpace) = LinSpace(r.stop, r.start, r.len, r.divisor) ## sorting ## -issorted(r::UnitRange) = true +issorted(r::AbstractUnitRange) = true issorted(r::Range) = step(r) >= zero(step(r)) -sort(r::UnitRange) = r -sort!(r::UnitRange) = r +sort(r::AbstractUnitRange) = r +sort!(r::AbstractUnitRange) = r sort(r::Range) = issorted(r) ? r : reverse(r) -sortperm(r::UnitRange) = 1:length(r) +sortperm(r::AbstractUnitRange) = 1:length(r) sortperm(r::Range) = issorted(r) ? (1:1:length(r)) : (length(r):-1:1) function sum{T<:Real}(r::Range{T}) @@ -806,6 +842,6 @@ function in(x, r::Range) n >= 1 && n <= length(r) && r[n] == x end -in{T<:Integer}(x::Integer, r::UnitRange{T}) = (first(r) <= x) & (x <= last(r)) +in{T<:Integer}(x::Integer, r::AbstractUnitRange{T}) = (first(r) <= x) & (x <= last(r)) in{T<:Integer}(x, r::Range{T}) = isinteger(x) && !isempty(r) && x>=minimum(r) && x<=maximum(r) && (mod(convert(T,x),step(r))-mod(first(r),step(r)) == 0) in(x::Char, r::Range{Char}) = !isempty(r) && x >= minimum(r) && x <= maximum(r) && (mod(Int(x) - Int(first(r)), step(r)) == 0) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index a28a7fb2d47218..053a554eb821af 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -36,24 +36,20 @@ start(R::ReshapedArrayIterator) = start(R.iter) end length(R::ReshapedArrayIterator) = length(R.iter) -reshape(parent::AbstractArray, ref::AbstractArray) = reshape(indicesbehavior(ref), parent, ref) -reshape(::IndicesStartAt1, parent::AbstractArray, ref::AbstractArray) = reshape(parent, size(ref)) -reshape(::IndicesBehavior, parent::AbstractArray, ref::AbstractArray) = reshape(parent, indices(ref)) - -reshape(parent::AbstractArray, dims::Dims) = _reshape(parent, dims) -reshape(parent::AbstractArray, len::Integer) = reshape(parent, (Int(len),)) -reshape(parent::AbstractArray, dims::Int...) = reshape(parent, dims) +reshape(parent::AbstractArray, shp::Tuple) = _reshape(parent, to_shape(shp)) +reshape(parent::AbstractArray, dims::DimOrInd...) = reshape(parent, dims) reshape{T,N}(parent::AbstractArray{T,N}, ndims::Type{Val{N}}) = parent function reshape{T,AN,N}(parent::AbstractArray{T,AN}, ndims::Type{Val{N}}) - reshape(parent, rdims((), size(parent), Val{N})) + reshape(parent, rdims((), indices(parent), Val{N})) end -# Move elements from sz to out until out reaches the desired dimensionality N, -# either filling with 1 or collapsing the product of trailing dims into the last element -@pure rdims{N}(out::NTuple{N}, sz::Tuple{}, ::Type{Val{N}}) = out -@pure rdims{N}(out::NTuple{N}, sz::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) = (front(out)..., last(out) * prod(sz)) -@pure rdims{N}(out::Tuple, sz::Tuple{}, ::Type{Val{N}}) = rdims((out..., 1), (), Val{N}) -@pure rdims{N}(out::Tuple, sz::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) = rdims((out..., first(sz)), tail(sz), Val{N}) +# Move elements from inds to out until out reaches the desired +# dimensionality N, either filling with OneTo(1) or collapsing the +# product of trailing dims into the last element +@pure rdims{N}(out::NTuple{N}, inds::Tuple{}, ::Type{Val{N}}) = out +@pure rdims{N}(out::NTuple{N}, inds::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) = (front(out)..., length(last(out)) * prod(map(length, inds))) +@pure rdims{N}(out::Tuple, inds::Tuple{}, ::Type{Val{N}}) = rdims((out..., OneTo(1)), (), Val{N}) +@pure rdims{N}(out::Tuple, inds::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) = rdims((out..., first(inds)), tail(inds), Val{N}) function _reshape(parent::AbstractArray, dims::Dims) prod(dims) == length(parent) || throw(DimensionMismatch("parent has $(length(parent)) elements, which is incompatible with size $dims")) @@ -87,8 +83,6 @@ size_strides(out::Tuple) = out @inline size_strides(out, s, sz...) = size_strides((out..., out[end]*s), sz...) size(A::ReshapedArray) = A.dims -size(A::ReshapedArray, d) = d <= ndims(A) ? A.dims[d] : 1 -similar(A::ReshapedArray, eltype::Type) = similar(parent(A), eltype, size(A)) similar(A::ReshapedArray, eltype::Type, dims::Dims) = similar(parent(A), eltype, dims) linearindexing{R<:ReshapedArrayLF}(::Type{R}) = LinearFast() parent(A::ReshapedArray) = A.parent diff --git a/base/sort.jl b/base/sort.jl index 9b2bd7ea4e724f..99900be146ef42 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -2,7 +2,7 @@ module Sort -using Base: Order, copymutable, linearindices, allocate_for, shape, linearindexing, viewindexing, LinearFast +using Base: Order, copymutable, linearindices, linearindexing, viewindexing, LinearFast import Base.sort, @@ -447,7 +447,7 @@ function sortperm(v::AbstractVector; by=identity, rev::Bool=false, order::Ordering=Forward) - p = Base.allocate_for(Vector{Int}, v, shape(v, 1)) + p = similar(Vector{Int}, indices(v, 1)) for (i,ind) in zip(eachindex(p), indices(v, 1)) p[i] = ind end @@ -492,7 +492,7 @@ function sort(A::AbstractArray, dim::Integer; else Av = A[:] sort_chunks!(Av, size(A,1), alg, order) - reshape(Av, A) + reshape(Av, indices(A)) end end @@ -507,7 +507,7 @@ end function sortrows(A::AbstractMatrix; kws...) inds = indices(A,1) T = slicetypeof(A, inds, :) - rows = allocate_for(Vector{T}, A, shape(A, 1)) + rows = similar(Vector{T}, indices(A, 1)) for i in inds rows[i] = view(A, i, :) end @@ -518,7 +518,7 @@ end function sortcols(A::AbstractMatrix; kws...) inds = indices(A,2) T = slicetypeof(A, :, inds) - cols = allocate_for(Vector{T}, A, shape(A, 2)) + cols = similar(Vector{T}, indices(A, 2)) for i in inds cols[i] = view(A, :, i) end @@ -532,7 +532,7 @@ function slicetypeof{T,N}(A::AbstractArray{T,N}, i1, i2) SubArray{T,1,typeof(A),typeof(I),fast} end slice_dummy(::Colon) = Colon() -slice_dummy{T}(::UnitRange{T}) = one(T) +slice_dummy{T}(::AbstractUnitRange{T}) = one(T) ## fast clever sorting for floats ## diff --git a/base/sparse/sparse.jl b/base/sparse/sparse.jl index b09d036e6d8b19..7a7a5a82fc905c 100644 --- a/base/sparse/sparse.jl +++ b/base/sparse/sparse.jl @@ -2,7 +2,7 @@ module SparseArrays -using Base: ReshapedArray, setindex_shape_check +using Base: ReshapedArray, setindex_shape_check, to_shape using Base.Sort: Forward using Base.LinAlg: AbstractTriangular, PosDefException diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index a2f2391a2d6e58..9be5e09d739503 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -1413,8 +1413,8 @@ end function gen_broadcast_body_sparse(f::Function, is_first_sparse::Bool) F = Expr(:quote, f) quote - Base.Broadcast.check_broadcast_shape(size(B), A_1) - Base.Broadcast.check_broadcast_shape(size(B), A_2) + Base.Broadcast.check_broadcast_shape(indices(B), A_1) + Base.Broadcast.check_broadcast_shape(indices(B), A_2) colptrB = B.colptr; rowvalB = B.rowval; nzvalB = B.nzval colptr1 = A_1.colptr; rowval1 = A_1.rowval; nzval1 = A_1.nzval @@ -1577,8 +1577,8 @@ function gen_broadcast_body_zpreserving(f::Function, is_first_sparse::Bool) op2 = :(val1) end quote - Base.Broadcast.check_broadcast_shape(size(B), $A1) - Base.Broadcast.check_broadcast_shape(size(B), $A2) + Base.Broadcast.check_broadcast_shape(indices(B), $A1) + Base.Broadcast.check_broadcast_shape(indices(B), $A2) nnzB = isempty(B) ? 0 : nnz($A1) * div(B.n, ($A1).n) * div(B.m, ($A1).m) @@ -1647,16 +1647,16 @@ end broadcast{Tv1,Ti1,Tv2,Ti2}(f::Function, A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = - broadcast!(f, spzeros(promote_type(Tv1, Tv2), promote_type(Ti1, Ti2), broadcast_shape(A_1, A_2)...), A_1, A_2) + broadcast!(f, spzeros(promote_type(Tv1, Tv2), promote_type(Ti1, Ti2), to_shape(broadcast_shape(A_1, A_2))...), A_1, A_2) broadcast_zpreserving!(args...) = broadcast!(args...) broadcast_zpreserving(args...) = broadcast(args...) broadcast_zpreserving{Tv1,Ti1,Tv2,Ti2}(f::Function, A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = - broadcast_zpreserving!(f, spzeros(promote_type(Tv1, Tv2), promote_type(Ti1, Ti2), broadcast_shape(A_1, A_2)...), A_1, A_2) + broadcast_zpreserving!(f, spzeros(promote_type(Tv1, Tv2), promote_type(Ti1, Ti2), to_shape(broadcast_shape(A_1, A_2))...), A_1, A_2) broadcast_zpreserving{Tv,Ti}(f::Function, A_1::SparseMatrixCSC{Tv,Ti}, A_2::Union{Array,BitArray,Number}) = - broadcast_zpreserving!(f, spzeros(promote_eltype(A_1, A_2), Ti, broadcast_shape(A_1, A_2)...), A_1, A_2) + broadcast_zpreserving!(f, spzeros(promote_eltype(A_1, A_2), Ti, to_shape(broadcast_shape(A_1, A_2))...), A_1, A_2) broadcast_zpreserving{Tv,Ti}(f::Function, A_1::Union{Array,BitArray,Number}, A_2::SparseMatrixCSC{Tv,Ti}) = - broadcast_zpreserving!(f, spzeros(promote_eltype(A_1, A_2), Ti, broadcast_shape(A_1, A_2)...), A_1, A_2) + broadcast_zpreserving!(f, spzeros(promote_eltype(A_1, A_2), Ti, to_shape(broadcast_shape(A_1, A_2))...), A_1, A_2) ## Binary arithmetic and boolean operators @@ -1676,7 +1676,7 @@ for (op, pro) in ((+, :eltype_plus), throw(DimensionMismatch("")) end Tv = ($pro)(A_1, A_2) - B = spzeros(Tv, promote_type(Ti1, Ti2), broadcast_shape(A_1, A_2)...) + B = spzeros(Tv, promote_type(Ti1, Ti2), to_shape(broadcast_shape(A_1, A_2))...) $body B end @@ -1718,15 +1718,15 @@ end # macro (.^)(A::Array, B::SparseMatrixCSC) = (.^)(A, full(B)) .+{Tv1,Ti1,Tv2,Ti2}(A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = - broadcast!(+, spzeros(eltype_plus(A_1, A_2), promote_type(Ti1, Ti2), broadcast_shape(A_1, A_2)...), A_1, A_2) + broadcast!(+, spzeros(eltype_plus(A_1, A_2), promote_type(Ti1, Ti2), to_shape(broadcast_shape(A_1, A_2))...), A_1, A_2) function .-{Tva,Tia,Tvb,Tib}(A::SparseMatrixCSC{Tva,Tia}, B::SparseMatrixCSC{Tvb,Tib}) - broadcast!(-, spzeros(eltype_plus(A, B), promote_type(Tia, Tib), broadcast_shape(A, B)...), A, B) + broadcast!(-, spzeros(eltype_plus(A, B), promote_type(Tia, Tib), to_shape(broadcast_shape(A, B))...), A, B) end ## element-wise comparison operators returning SparseMatrixCSC ## -.<{Tv1,Ti1,Tv2,Ti2}(A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = broadcast!(<, spzeros( Bool, promote_type(Ti1, Ti2), broadcast_shape(A_1, A_2)...), A_1, A_2) -.!={Tv1,Ti1,Tv2,Ti2}(A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = broadcast!(!=, spzeros( Bool, promote_type(Ti1, Ti2), broadcast_shape(A_1, A_2)...), A_1, A_2) +.<{Tv1,Ti1,Tv2,Ti2}(A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = broadcast!(<, spzeros( Bool, promote_type(Ti1, Ti2), to_shape(broadcast_shape(A_1, A_2))...), A_1, A_2) +.!={Tv1,Ti1,Tv2,Ti2}(A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = broadcast!(!=, spzeros( Bool, promote_type(Ti1, Ti2), to_shape(broadcast_shape(A_1, A_2))...), A_1, A_2) ## full equality function ==(A1::SparseMatrixCSC, A2::SparseMatrixCSC) diff --git a/base/subarray.jl b/base/subarray.jl index adf7807b321ec6..e41e1faf3b6395 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -18,7 +18,7 @@ immutable SubArray{T,N,P,I,L} <: AbstractArray{T,N} 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, convert(Dims, dims)) + SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, map(dimlength, dims)) end function SubArray{P, I, N}(::LinearSlow, parent::P, indexes::I, dims::NTuple{N, Int}) SubArray{eltype(P), N, P, I, false}(parent, indexes, dims, 0, 0) @@ -47,6 +47,9 @@ viewindexing(I::Tuple{Vararg{Any}}) = LinearSlow() # Of course, all other array types are slow viewindexing(I::Tuple{AbstractArray, Vararg{Any}}) = LinearSlow() +dimlength(r::Range) = length(r) +dimlength(i::Integer) = Int(i) + # Simple utilities size(V::SubArray) = V.dims length(V::SubArray) = prod(V.dims) @@ -57,7 +60,7 @@ parent(V::SubArray) = V.parent parentindexes(V::SubArray) = V.indexes parent(a::AbstractArray) = a -parentindexes(a::AbstractArray) = ntuple(i->1:size(a,i), ndims(a)) +parentindexes(a::AbstractArray) = ntuple(i->OneTo(size(a,i)), ndims(a)) ## SubArray creation # Drops singleton dimensions (those indexed with a scalar) @@ -76,11 +79,17 @@ function view{N}(A::AbstractArray, I::Vararg{ViewIndex,N}) # TODO: DEPRECATE FOR @boundscheck checkbounds(A, I...) unsafe_view(reshape(A, Val{N}), I...) end + function unsafe_view{T,N}(A::AbstractArray{T,N}, I::Vararg{ViewIndex,N}) @_inline_meta J = to_indexes(I...) SubArray(A, J, map(dimlength, index_shape(A, J...))) end +function unsafe_view{T,N}(V::SubArray{T,N}, I::Vararg{ViewIndex,N}) + @_inline_meta + idxs = reindex(V, V.indexes, to_indexes(I...)) + SubArray(V.parent, idxs, map(dimlength, (index_shape(V.parent, idxs...)))) +end # Re-indexing is the heart of a view, transforming A[i, j][x, y] to A[i[x], j[y]] # @@ -166,12 +175,6 @@ function setindex!(V::FastContiguousSubArray, x, i::Real) V end -function unsafe_view{T,N}(V::SubArray{T,N}, I::Vararg{ViewIndex,N}) - @_inline_meta - idxs = reindex(V, V.indexes, to_indexes(I...)) - SubArray(V.parent, idxs, index_shape(V.parent, idxs...)) -end - linearindexing{T<:FastSubArray}(::Type{T}) = LinearFast() linearindexing{T<:SubArray}(::Type{T}) = LinearSlow() @@ -258,7 +261,9 @@ unsafe_convert{T,N,P,I<:Tuple{Vararg{RangeIndex}}}(::Type{Ptr{T}}, V::SubArray{T pointer(V::FastSubArray, i::Int) = pointer(V.parent, V.offset1 + V.stride1*i) pointer(V::FastContiguousSubArray, i::Int) = pointer(V.parent, V.offset1 + i) -pointer(V::SubArray, i::Int) = pointer(V, smart_ind2sub(shape(V), i)) +pointer(V::SubArray, i::Int) = _pointer(V, i) +_pointer{T}(V::SubArray{T,1}, i::Int) = pointer(V, (i,)) +_pointer(V::SubArray, i::Int) = pointer(V, ind2sub(indices(V), i)) function pointer{T,N,P<:Array,I<:Tuple{Vararg{RangeIndex}}}(V::SubArray{T,N,P,I}, is::Tuple{Vararg{Int}}) index = first_index(V) @@ -273,34 +278,21 @@ end # they are taken from the range/vector # Since bounds-checking is performance-critical and uses # indices, it's worth optimizing these implementations thoroughly -indices(S::SubArray, d::Integer) = 1 <= d <= ndims(S) ? indices(S)[d] : (d > ndims(S) ? (1:1) : error("dimension $d out of range")) -indices(S::SubArray) = (@_inline_meta; _indices(indicesbehavior(parent(S)), S)) -_indices(::IndicesStartAt1, S::SubArray) = (@_inline_meta; map(s->1:s, size(S))) -_indices(::IndicesBehavior, S::SubArray) = (@_inline_meta; _indices((), 1, S, S.indexes...)) -_indices(out::Tuple, dim, S::SubArray) = out -_indices(out::Tuple, dim, S::SubArray, i1, I...) = (@_inline_meta; _indices((out..., 1:length(i1)), dim+1, S, I...)) -_indices(out::Tuple, dim, S::SubArray, ::Real, I...) = (@_inline_meta; _indices(out, dim+1, S, I...)) -_indices(out::Tuple, dim, S::SubArray, ::Colon, I...) = (@_inline_meta; _indices((out..., indices(parent(S), dim)), dim+1, S, I...)) -indices1{T}(S::SubArray{T,0}) = 1:1 -indices1(S::SubArray) = (@_inline_meta; _indices1(indicesbehavior(parent(S)), S)) -_indices1(::IndicesStartAt1, S::SubArray) = 1:S.dims[1] -_indices1(::IndicesBehavior, S::SubArray) = (@_inline_meta; _indices1(S, 1, S.indexes...)) -_indices1(S::SubArray, dim, i1, I...) = (@_inline_meta; 1:length(i1)) +indices(S::SubArray, d::Integer) = 1 <= d <= ndims(S) ? indices(S)[d] : (d > ndims(S) ? OneTo(1) : error("dimension $d out of range")) +indices(S::SubArray) = (@_inline_meta; _indices_sub(S, 1, S.indexes...)) +_indices_sub(S::SubArray, dim::Int) = () +_indices_sub(S::SubArray, dim::Int, ::Real, I...) = (@_inline_meta; _indices_sub(S, dim+1, I...)) +_indices_sub(S::SubArray, dim::Int, ::Colon, I...) = (@_inline_meta; (indices(parent(S), dim), _indices_sub(S, dim+1, I...)...)) +_indices_sub(S::SubArray, dim::Int, i1::AbstractArray, I...) = (@_inline_meta; (indices(i1)..., _indices_sub(S, dim+1, I...)...)) +indices1{T}(S::SubArray{T,0}) = OneTo(1) +indices1(S::SubArray) = (@_inline_meta; _indices1(S, 1, S.indexes...)) _indices1(S::SubArray, dim, i1::Real, I...) = (@_inline_meta; _indices1(S, dim+1, I...)) _indices1(S::SubArray, dim, i1::Colon, I...) = (@_inline_meta; indices(parent(S), dim)) +_indices1(S::SubArray, dim, i1::AbstractArray, I...) = (@_inline_meta; indices1(i1)) # Moreover, incides(S) is fast but indices(S, d) is slower indicesperformance{T<:SubArray}(::Type{T}) = IndicesSlow1D() -indicesbehavior(S::SubArray) = _indicesbehavior(indicesbehavior(parent(S)), S) -_indicesbehavior(::IndicesStartAt1, S::SubArray) = IndicesStartAt1() -_indicesbehavior(::IndicesBehavior, S::SubArray) = (@_inline_meta; _indicesbehavior(keepcolon((), S.indexes...), S)) -keepcolon(out) = out -keepcolon(out, ::Colon, I...) = (@_inline_meta; (Colon(),)) -keepcolon(out, i1, I...) = (@_inline_meta; keepcolon(out, I...)) -_indicesbehavior(::Tuple{}, S::SubArray) = IndicesStartAt1() -_indicesbehavior(::Tuple{Colon}, S::SubArray) = indicesbehavior(parent(S)) - ## Compatability # deprecate? function parentdims(s::SubArray) diff --git a/doc/manual/interfaces.rst b/doc/manual/interfaces.rst index 5ede56eb24f8c3..b0f0886da6c224 100644 --- a/doc/manual/interfaces.rst +++ b/doc/manual/interfaces.rst @@ -166,9 +166,8 @@ Methods to implement :func:`similar(A, dims::NTuple{Int}) ` ``similar(A, eltype(A), dims)`` Return a mutable array with the same element type and size `dims` :func:`similar(A, ::Type{S}, dims::NTuple{Int}) ` ``Array{S}(dims)`` Return a mutable array with the specified element type and size **Non-traditional indices** **Default definition** **Brief description** -:func:`Base.indicesbehavior(::Type) ` ``Base.IndicesStartAt1()`` Trait with values ``IndicesStartAt1()``, ``IndicesUnitRange()``, ``IndicesList()`` -:func:`indices(A, d) ` ``1:size(A, d)`` Return the range of valid indices along dimension ``d`` -:func:`Base.similar(A, ::Type{S}, inds::NTuple{Ind}) ` ``similar(A, S, map(Base.dimlength, inds))`` Return a mutable array with the specified indices ``inds`` (see below for discussion of ``Ind``) +:func:`indices(A, d) ` ``OneTo(size(A, d))`` Return the ``AbstractUnitRange`` of valid indices along dimension ``d`` +:func:`Base.similar(A, ::Type{S}, inds::NTuple{Ind}) ` ``similar(A, S, map(Base.dimlength, inds))`` Return a mutable array with the specified indices ``inds`` (see below) ===================================================================== ============================================ ======================================================================================= If a type is defined as a subtype of ``AbstractArray``, it inherits a very large set of rich behaviors including iteration and multidimensional indexing built on top of single-element access. See the :ref:`arrays manual page ` and :ref:`standard library section ` for more supported methods. @@ -290,9 +289,9 @@ In addition to all the iterable and indexable methods from above, these types ca If you are defining an array type that allows non-traditional indexing (indices that start at something other than 1), you should specialize -``indices`` and ``indicesbehavior``. You should also specialize -``similar`` so that the ``dims`` argument (ordinarily a ``Dims`` -size-tuple) can be a mixture of ``Integer`` and ``UnitRange`` objects; -the ``Integer`` entries imply that the indexing starts from 1, whereas -the dimensions encoded with ``UnitRange`` may have arbitrary starting -index. +``indices``. You should also specialize ``similar`` so that the +``dims`` argument (ordinarily a ``Dims`` size-tuple) can accept +``AbstractUnitRange`` objects, perhaps range-types ``Ind`` of your own +design. For example, if indexing always starts with 0 for your +arrays, you likely want to define a ``ZeroTo`` range type. Otherwise, +you can use standard ``UnitRange``. diff --git a/test/broadcast.jl b/test/broadcast.jl index 0b43510974ae7e..c17610c5914fad 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -3,7 +3,7 @@ module TestBroadcastInternals using Base.Broadcast: broadcast_shape, check_broadcast_shape, newindex, _bcs, _bcsm -using Base.Test +using Base: Test, OneTo @test @inferred(_bcs((), (3,5), (3,5))) == (3,5) @test @inferred(_bcs((), (3,1), (3,5))) == (3,5) @@ -18,21 +18,21 @@ using Base.Test @test_throws DimensionMismatch _bcs((), (-1:1, 2:6), (-1:1, 2:5)) @test_throws DimensionMismatch _bcs((), (-1:1, 2:5), (2, 2:5)) -@test @inferred(broadcast_shape(zeros(3,4), zeros(3,4))) == (3,4) -@test @inferred(broadcast_shape(zeros(3,4), zeros(3))) == (3,4) -@test @inferred(broadcast_shape(zeros(3), zeros(3,4))) == (3,4) -@test @inferred(broadcast_shape(zeros(3), zeros(1,4), zeros(1))) == (3,4) - -check_broadcast_shape((3,5), zeros(3,5)) -check_broadcast_shape((3,5), zeros(3,1)) -check_broadcast_shape((3,5), zeros(3)) -check_broadcast_shape((3,5), zeros(3,5), zeros(3)) -check_broadcast_shape((3,5), zeros(3,5), 1) -check_broadcast_shape((3,5), 5, 2) -@test_throws DimensionMismatch check_broadcast_shape((3,5), zeros(2,5)) -@test_throws DimensionMismatch check_broadcast_shape((3,5), zeros(3,4)) -@test_throws DimensionMismatch check_broadcast_shape((3,5), zeros(3,4,2)) -@test_throws DimensionMismatch check_broadcast_shape((3,5), zeros(3,5), zeros(2)) +@test @inferred(broadcast_shape(zeros(3,4), zeros(3,4))) == (OneTo(3),OneTo(4)) +@test @inferred(broadcast_shape(zeros(3,4), zeros(3))) == (OneTo(3),OneTo(4)) +@test @inferred(broadcast_shape(zeros(3), zeros(3,4))) == (OneTo(3),OneTo(4)) +@test @inferred(broadcast_shape(zeros(3), zeros(1,4), zeros(1))) == (OneTo(3),OneTo(4)) + +check_broadcast_shape((OneTo(3),OneTo(5)), zeros(3,5)) +check_broadcast_shape((OneTo(3),OneTo(5)), zeros(3,1)) +check_broadcast_shape((OneTo(3),OneTo(5)), zeros(3)) +check_broadcast_shape((OneTo(3),OneTo(5)), zeros(3,5), zeros(3)) +check_broadcast_shape((OneTo(3),OneTo(5)), zeros(3,5), 1) +check_broadcast_shape((OneTo(3),OneTo(5)), 5, 2) +@test_throws DimensionMismatch check_broadcast_shape((OneTo(3),OneTo(5)), zeros(2,5)) +@test_throws DimensionMismatch check_broadcast_shape((OneTo(3),OneTo(5)), zeros(3,4)) +@test_throws DimensionMismatch check_broadcast_shape((OneTo(3),OneTo(5)), zeros(3,4,2)) +@test_throws DimensionMismatch check_broadcast_shape((OneTo(3),OneTo(5)), zeros(3,5), zeros(2)) check_broadcast_shape((-1:1, 6:9), (-1:1, 6:9)) check_broadcast_shape((-1:1, 6:9), (-1:1, 1)) @@ -40,7 +40,6 @@ check_broadcast_shape((-1:1, 6:9), (1, 6:9)) @test_throws DimensionMismatch check_broadcast_shape((-1:1, 6:9), (-1, 6:9)) @test_throws DimensionMismatch check_broadcast_shape((-1:1, 6:9), (-1:1, 6)) check_broadcast_shape((-1:1, 6:9), 1) -check_broadcast_shape((-1:1, 6:9), zeros(1,1)) ci(x) = CartesianIndex(x) @test @inferred(newindex(ci((2,2)), (true, true))) == ci((2,2)) diff --git a/test/choosetests.jl b/test/choosetests.jl index 9818d9acbeb12c..9484d0e394f7c8 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -17,7 +17,7 @@ function choosetests(choices = []) testnames = [ "linalg", "subarray", "core", "inference", "keywordargs", "numbers", "printf", "char", "string", "triplequote", "unicode", - "dates", "dict", "hashing", "iobuffer", "staged", + "dates", "dict", "hashing", "iobuffer", "staged", "offsetarray", "arrayops", "tuple", "reduce", "reducedim", "random", "abstractarray", "intfuncs", "simdloop", "vecelement", "blas", "sparse", "bitarray", "copy", "math", "fastmath", "functional", @@ -33,7 +33,7 @@ function choosetests(choices = []) "markdown", "base64", "serialize", "misc", "threads", "enums", "cmdlineargs", "i18n", "workspace", "libdl", "int", "checked", "intset", "floatfuncs", "compile", "parallel", "inline", - "boundscheck", "error", "ambiguous", "offsetarray", "cartesian" + "boundscheck", "error", "ambiguous", "cartesian" ] if Base.USE_GPL_LIBS diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 790edde60d3506..4a91bf6a29f269 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -7,7 +7,7 @@ module OAs -using Base: SimIdx, Indices, LinearSlow, LinearFast +using Base: DimOrInd, DimsOrInds, Indices, LinearSlow, LinearFast export OffsetArray @@ -24,14 +24,11 @@ OffsetArray{T,N}(A::AbstractArray{T,N}, offsets::Vararg{Int,N}) = OffsetArray(A, (::Type{OffsetArray{T}}){T,N}(inds::Indices{N}) = OffsetArray{T,N}(inds) Base.linearindexing{T<:OffsetArray}(::Type{T}) = Base.linearindexing(parenttype(T)) -Base.indicesbehavior{T<:OffsetArray}(::Type{T}) = Base.IndicesUnitRange() parenttype{T,N,AA}(::Type{OffsetArray{T,N,AA}}) = AA parenttype(A::OffsetArray) = parenttype(typeof(A)) Base.parent(A::OffsetArray) = A.parent Base.size(A::OffsetArray) = size(parent(A)) -Base.eachindex(::LinearSlow, A::OffsetArray) = CartesianRange(indices(A)) -Base.eachindex(::LinearFast, A::OffsetVector) = indices(A, 1) Base.summary(A::OffsetArray) = string(typeof(A))*" with indices "*string(indices(A)) # Implementations of indices and indices1. Since bounds-checking is @@ -48,16 +45,14 @@ Base.indices1{T}(A::OffsetArray{T,0}) = 1:1 function Base.similar(A::OffsetArray, T::Type, dims::Dims) B = similar(parent(A), T, dims) end -function Base.similar(A::AbstractArray, T::Type, inds::Tuple{Vararg{SimIdx}}) +function Base.similar(A::AbstractArray, T::Type, inds::Tuple{UnitRange,Vararg{UnitRange}}) B = similar(A, T, map(Base.dimlength, inds)) OffsetArray(B, map(indsoffset, inds)) end -Base.allocate_for(f, A::OffsetArray, shape::SimIdx) = OffsetArray(f(Base.dimlength(shape)), (indsoffset(shape),)) -Base.allocate_for(f, A::OffsetArray, shape::Tuple{Vararg{SimIdx}}) = OffsetArray(f(map(Base.dimlength, shape)), map(indsoffset, shape)) -Base.promote_indices(a::OffsetArray, b::OffsetArray) = a +Base.similar(f::Union{Function,Type}, shape::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(f(map(Base.dimlength, shape)), map(indsoffset, shape)) -Base.reshape(A::AbstractArray, inds::Indices) = OffsetArray(reshape(A, map(Base.dimlength, inds)), map(indsoffset, inds)) +Base.reshape(A::AbstractArray, inds::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(reshape(A, map(Base.dimlength, inds)), map(indsoffset, inds)) @inline function Base.getindex{T,N}(A::OffsetArray{T,N}, I::Vararg{Int,N}) @boundscheck checkbounds(A, I...) @@ -102,6 +97,7 @@ end using OAs +let # Basics A0 = [1 3; 2 4] A = OffsetArray(A0, (-1,2)) # LinearFast @@ -136,26 +132,30 @@ S = OffsetArray(view(A0, 1:2, 1:2), (-1,2)) # LinearSlow @test eachindex(A) == 1:4 @test eachindex(S) == CartesianRange((0:1,3:4)) -# slice +# view S = view(A, :, 3) @test S == OffsetArray([1,2], (A.offsets[1],)) @test S[0] == 1 @test S[1] == 2 @test_throws BoundsError S[2] +@test indices(S) === (0:1,) S = view(A, 0, :) @test S == OffsetArray([1,3], (A.offsets[2],)) @test S[3] == 1 @test S[4] == 3 @test_throws BoundsError S[1] +@test indices(S) === (3:4,) S = view(A, 0:0, 4) @test S == [3] @test S[1] == 3 @test_throws BoundsError S[0] +@test indices(S) === (Base.OneTo(1),) S = view(A, 1, 3:4) @test S == [2,4] @test S[1] == 2 @test S[2] == 4 @test_throws BoundsError S[3] +@test indices(S) === (Base.OneTo(2),) S = view(A, :, :) @test S == A @test S[0,3] == S[1] == 1 @@ -163,6 +163,7 @@ S = view(A, :, :) @test S[0,4] == S[3] == 3 @test S[1,4] == S[4] == 4 @test_throws BoundsError S[1,1] +@test indices(S) === (0:1, 3:4) # iteration for (a,d) in zip(A, A0) @@ -204,29 +205,33 @@ cmp_showf(Base.print_matrix, io, OffsetArray(rand(10^3,10^3), (10,-9))) # neithe B = similar(A, Float32) @test isa(B, OffsetArray{Float32,2}) @test size(B) == size(A) -@test indices(B) == indices(A) +@test indices(B) === indices(A) B = similar(A, (3,4)) @test isa(B, Array{Int,2}) @test size(B) == (3,4) -@test indices(B) == (1:3, 1:4) -B = similar(A, (-3:3,4)) +@test indices(B) === (Base.OneTo(3), Base.OneTo(4)) +B = similar(A, (-3:3,1:4)) @test isa(B, OffsetArray{Int,2}) -@test indices(B) == (-3:3, 1:4) -B = similar(parent(A), (-3:3,4)) +@test indices(B) === (-3:3, 1:4) +B = similar(parent(A), (-3:3,1:4)) @test isa(B, OffsetArray{Int,2}) -@test indices(B) == (-3:3, 1:4) +@test indices(B) === (-3:3, 1:4) # Indexing with OffsetArray indices i1 = OffsetArray([2,1], (-5,)) i1 = OffsetArray([2,1], -5) b = A0[i1, 1] -@test indices(b) == (-4:-3,) +@test indices(b) === (-4:-3,) @test b[-4] == 2 @test b[-3] == 1 b = A0[1,i1] -@test indices(b) == (-4:-3,) +@test indices(b) === (-4:-3,) @test b[-4] == 3 @test b[-3] == 1 +v = view(A0, i1, 1) +@test indices(v) === (-4:-3,) +v = view(A0, 1:1, i1) +@test indices(v) === (Base.OneTo(1), -4:-3) # logical indexing @test A[A .> 2] == [3,4] @@ -357,3 +362,4 @@ v = OffsetArray(rand(8), (-2,)) @test 2*A == OffsetArray(2*parent(A), A.offsets) @test A+A == OffsetArray(parent(A)+parent(A), A.offsets) @test A.*A == OffsetArray(parent(A).*parent(A), A.offsets) +end diff --git a/test/ranges.jl b/test/ranges.jl index bbe8a4ad931f4a..16672be5a8bfa0 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -736,3 +736,33 @@ let r = 1:3, a = [1,2,3] @test convert(Array{Int,1}, r) == a @test convert(Array{Float64,1}, r) == a end + +# OneTo +r = Base.OneTo(-5) +@test isempty(r) +@test length(r) == 0 +@test size(r) == (0,) +r = Base.OneTo(3) +@test !isempty(r) +@test length(r) == 3 +@test size(r) == (3,) +@test step(r) == 1 +@test first(r) == 1 +@test last(r) == 3 +@test minimum(r) == 1 +@test maximum(r) == 3 +@test r[2] == 2 +@test_throws BoundsError r[4] +@test_throws BoundsError r[0] +@test r+1 === 2:4 +@test 2*r === 2:2:6 +k = 0 +for i in r + @test i == (k+=1) +end +@test intersect(r, Base.OneTo(2)) == Base.OneTo(2) +@test intersect(r, 0:5) == 1:3 +io = IOBuffer() +show(io, r) +str = takebuf_string(io) +@test str == "OneTo(3)" diff --git a/test/subarray.jl b/test/subarray.jl index 771e0c963f1e0a..5181bf4f6671b6 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -1,10 +1,6 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license using Base.Test -# import Base: ViewIndex, dimsizeexpr, rangetype, merge_indexes, first_index, stride1expr, tailsize -using Base.Cartesian - -print_underestimates = false ######## Utilities ########### @@ -336,6 +332,7 @@ sA = view(A, 2:2, 1:5, :) @test parentindexes(sA) == (2:2, 1:5, :) @test Base.parentdims(sA) == [1:3;] @test size(sA) == (1, 5, 8) +@test indices(sA) === (Base.OneTo(1), Base.OneTo(5), Base.OneTo(8)) @test sA[1, 2, 1:8][:] == [5:15:120;] sA[2:5:end] = -1 @test all(sA[2:5:end] .== -1) @@ -355,6 +352,7 @@ test_bounds(sA) sA = view(A, 1:3, 3:3, 2:5) @test Base.parentdims(sA) == [1:3;] @test size(sA) == (3,1,4) +@test indices(sA) === (Base.OneTo(3), Base.OneTo(1), Base.OneTo(4)) @test sA == A[1:3,3:3,2:5] @test sA[:] == A[1:3,3,2:5][:] test_bounds(sA) @@ -367,6 +365,12 @@ sA = view(A, 1:2:3, 1:3:5, 1:2:8) # Test with mixed types @test sA[:, Int16[1,2], big(2)] == [31 40; 33 42] test_bounds(sA) +sA = view(A, 1:1, 1:5, [1 3; 4 2]) +@test ndims(sA) == 4 +@test indices(sA) === (Base.OneTo(1), Base.OneTo(5), Base.OneTo(2), Base.OneTo(2)) +sA = view(A, 1:2, 3, [1 3; 4 2]) +@test ndims(sA) == 3 +@test indices(sA) === (Base.OneTo(2), Base.OneTo(2), Base.OneTo(2)) # sub logical indexing #4763 A = view([1:10;], 5:8) @@ -384,6 +388,7 @@ sA = view(A, 2, :, 1:8) @test parentindexes(sA) == (2, :, 1:8) @test Base.parentdims(sA) == [2:3;] @test size(sA) == (5, 8) +@test indices(sA) === (Base.OneTo(5), Base.OneTo(8)) @test strides(sA) == (3,15) @test sA[2, 1:8][:] == [5:15:120;] @test sA[:,1] == [2:3:14;] @@ -395,11 +400,13 @@ test_bounds(sA) sA = view(A, 1:3, 1:5, 5) @test Base.parentdims(sA) == [1:2;] @test size(sA) == (3,5) +@test indices(sA) === (Base.OneTo(3),Base.OneTo(5)) @test strides(sA) == (1,3) test_bounds(sA) sA = view(A, 1:2:3, 3, 1:2:8) @test Base.parentdims(sA) == [1,3] @test size(sA) == (2,4) +@test indices(sA) === (Base.OneTo(2), Base.OneTo(4)) @test strides(sA) == (2,30) @test sA[:] == A[sA.indexes...][:] test_bounds(sA)