diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 9792108e155dc..0624fffd2a42c 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -128,14 +128,13 @@ macro _noinline_meta() end ## Bounds checking ## -_checkbounds(sz::Int, i::Int) = 1 <= i <= sz -_checkbounds(sz::Int, i::Real) = (@_inline_meta; _checkbounds(sz, to_index(i))) -_checkbounds(sz::Int, I::AbstractVector{Bool}) = length(I) == sz -_checkbounds(sz::Int, I::AbstractArray{Bool}) = length(I) == sz # setindex! allows this -_checkbounds(sz::Int, r::Range{Int}) = (@_inline_meta; isempty(r) || (minimum(r) >= 1 && maximum(r) <= sz)) -_checkbounds{T<:Real}(sz::Int, r::Range{T}) = (@_inline_meta; _checkbounds(sz, to_index(r))) -_checkbounds(sz::Int, ::Colon) = true -function _checkbounds{T <: Real}(sz::Int, I::AbstractArray{T}) +_checkbounds(sz, i::Integer) = 1 <= i <= sz +_checkbounds(sz, i::Real) = 1 <= to_index(i) <= sz +_checkbounds(sz, I::AbstractVector{Bool}) = length(I) == sz +_checkbounds(sz, r::Range{Int}) = (@_inline_meta; isempty(r) || (minimum(r) >= 1 && maximum(r) <= sz)) +_checkbounds{T<:Real}(sz, r::Range{T}) = (@_inline_meta; _checkbounds(sz, to_index(r))) +_checkbounds(sz, ::Colon) = true +function _checkbounds{T <: Real}(sz, I::AbstractArray{T}) @_inline_meta b = true for i in I diff --git a/base/array.jl b/base/array.jl index 6e2a463c343d5..c7fbb35f46150 100644 --- a/base/array.jl +++ b/base/array.jl @@ -293,111 +293,47 @@ done(a::Array,i) = (i > length(a)) ## Indexing: getindex ## -getindex(a::Array) = arrayref(a,1) - -getindex(A::Array, i0::Real) = arrayref(A,to_index(i0)) -getindex(A::Array, i0::Real, i1::Real) = arrayref(A,to_index(i0),to_index(i1)) -getindex(A::Array, i0::Real, i1::Real, i2::Real) = - arrayref(A,to_index(i0),to_index(i1),to_index(i2)) -getindex(A::Array, i0::Real, i1::Real, i2::Real, i3::Real) = - arrayref(A,to_index(i0),to_index(i1),to_index(i2),to_index(i3)) -getindex(A::Array, i0::Real, i1::Real, i2::Real, i3::Real, i4::Real) = - arrayref(A,to_index(i0),to_index(i1),to_index(i2),to_index(i3),to_index(i4)) -getindex(A::Array, i0::Real, i1::Real, i2::Real, i3::Real, i4::Real, i5::Real) = - arrayref(A,to_index(i0),to_index(i1),to_index(i2),to_index(i3),to_index(i4),to_index(i5)) - -getindex(A::Array, i0::Real, i1::Real, i2::Real, i3::Real, i4::Real, i5::Real, I::Real...) = - arrayref(A,to_index(i0),to_index(i1),to_index(i2),to_index(i3),to_index(i4),to_index(i5),to_index(I)...) - -# Fast copy using copy! for UnitRange -function getindex(A::Array, I::UnitRange{Int}) +getindex(A::Array, i1::Int) = arrayref(A, i1) +unsafe_getindex(A::Array, i1::Int) = @inbounds return arrayref(A, i1) + +# Faster contiguous indexing using copy! for UnitRange and Colon +getindex(A::Array, I::UnitRange{Int}) = (checkbounds(A, I); unsafe_getindex(A, I)) +function unsafe_getindex(A::Array, I::UnitRange{Int}) lI = length(I) X = similar(A, lI) if lI > 0 - copy!(X, 1, A, first(I), lI) + unsafe_copy!(X, 1, A, first(I), lI) end return X end - -function getindex{T<:Real}(A::Array, I::AbstractVector{T}) - return [ A[i] for i in to_index(I) ] -end -function getindex{T<:Real}(A::Range, I::AbstractVector{T}) - return [ A[i] for i in to_index(I) ] -end -function getindex(A::Range, I::AbstractVector{Bool}) - checkbounds(A, I) - return [ A[i] for i in to_index(I) ] -end - -function getindex(A::Array, ::Colon) - return [ a for a in A ] -end - -# logical indexing -# (when the indexing is provided as an Array{Bool} or a BitArray we can be -# sure about the behaviour and use unsafe_getindex; in the general case -# we can't and must use getindex, otherwise silent corruption can happen) - -@generated function getindex_bool_1d(A::Array, I::AbstractArray{Bool}) - idxop = I <: Union(Array{Bool}, BitArray) ? :unsafe_getindex : :getindex - quote - checkbounds(A, I) - n = sum(I) - out = similar(A, n) - c = 1 - for i = 1:length(I) - if $idxop(I, i) - @inbounds out[c] = A[i] - c += 1 - end - end - out +getindex(A::Array, c::Colon) = unsafe_getindex(A, c) +function unsafe_getindex(A::Array, ::Colon) + lI = length(A) + X = similar(A, lI) + if lI > 0 + unsafe_copy!(X, 1, A, 1, lI) end + return X end -getindex(A::Vector, I::AbstractVector{Bool}) = getindex_bool_1d(A, I) -getindex(A::Vector, I::AbstractArray{Bool}) = getindex_bool_1d(A, I) -getindex(A::Array, I::AbstractVector{Bool}) = getindex_bool_1d(A, I) -getindex(A::Array, I::AbstractArray{Bool}) = getindex_bool_1d(A, I) - +# This is redundant with the abstract fallbacks, but needed for bootstrap +function getindex{T<:Real}(A::Array, I::Range{T}) + return [ A[to_index(i)] for i in I ] +end ## Indexing: setindex! ## -setindex!{T}(A::Array{T}, x) = arrayset(A, convert(T,x), 1) - setindex!{T}(A::Array{T}, x, i0::Real) = arrayset(A, convert(T,x), to_index(i0)) -setindex!{T}(A::Array{T}, x, i0::Real, i1::Real) = - arrayset(A, convert(T,x), to_index(i0), to_index(i1)) -setindex!{T}(A::Array{T}, x, i0::Real, i1::Real, i2::Real) = - arrayset(A, convert(T,x), to_index(i0), to_index(i1), to_index(i2)) -setindex!{T}(A::Array{T}, x, i0::Real, i1::Real, i2::Real, i3::Real) = - arrayset(A, convert(T,x), to_index(i0), to_index(i1), to_index(i2), to_index(i3)) -setindex!{T}(A::Array{T}, x, i0::Real, i1::Real, i2::Real, i3::Real, i4::Real) = - arrayset(A, convert(T,x), to_index(i0), to_index(i1), to_index(i2), to_index(i3), to_index(i4)) -setindex!{T}(A::Array{T}, x, i0::Real, i1::Real, i2::Real, i3::Real, i4::Real, i5::Real) = - arrayset(A, convert(T,x), to_index(i0), to_index(i1), to_index(i2), to_index(i3), to_index(i4), to_index(i5)) -setindex!{T}(A::Array{T}, x, i0::Real, i1::Real, i2::Real, i3::Real, i4::Real, i5::Real, I::Real...) = - arrayset(A, convert(T,x), to_index(i0), to_index(i1), to_index(i2), to_index(i3), to_index(i4), to_index(i5), to_index(I)...) - -function setindex!{T<:Real}(A::Array, x, I::AbstractVector{T}) + +# These are redundant with the abstract fallbacks but needed for bootstrap +function setindex!(A::Array, x, I::AbstractVector{Int}) + is(A, I) && (I = copy(I)) for i in I A[i] = x end return A end - -function setindex!{T}(A::Array{T}, X::Array{T}, I::UnitRange{Int}) - if length(X) != length(I) - throw_setindex_mismatch(X, (I,)) - end - copy!(A, first(I), X, 1, length(I)) - return A -end - -function setindex!{T<:Real}(A::Array, X::AbstractArray, I::AbstractVector{T}) - if length(X) != length(I) - throw_setindex_mismatch(X, (I,)) - end +function setindex!(A::Array, X::AbstractArray, I::AbstractVector{Int}) + setindex_shape_check(X, length(I)) count = 1 if is(X,A) X = copy(X) @@ -412,49 +348,26 @@ function setindex!{T<:Real}(A::Array, X::AbstractArray, I::AbstractVector{T}) return A end -setindex!(A::Array, x, I::Colon) = setindex!(A, x, 1:length(A)) - -# logical indexing -# (when the indexing is provided as an Array{Bool} or a BitArray we can be -# sure about the behaviour and use unsafe_getindex; in the general case -# we can't and must use getindex, otherwise silent corruption can happen) - -@generated function assign_bool_scalar_1d!(A::Array, x, I::AbstractArray{Bool}) - idxop = I <: Union(Array{Bool}, BitArray) ? :unsafe_getindex : :getindex - quote - checkbounds(A, I) - for i = 1:length(I) - if $idxop(I, i) - @inbounds A[i] = x - end - end - A +# Faster contiguous setindex! with copy! +setindex!{T}(A::Array{T}, X::Array{T}, I::UnitRange{Int}) = (checkbounds(A, I); unsafe_setindex!(A, X, I)) +function unsafe_setindex!{T}(A::Array{T}, X::Array{T}, I::UnitRange{Int}) + lI = length(I) + setindex_shape_check(X, lI) + if lI > 0 + unsafe_copy!(A, first(I), X, 1, lI) end + return A end - -@generated function assign_bool_vector_1d!(A::Array, X::AbstractArray, I::AbstractArray{Bool}) - idxop = I <: Union(Array{Bool}, BitArray) ? :unsafe_getindex : :getindex - quote - checkbounds(A, I) - c = 1 - for i = 1:length(I) - if $idxop(I, i) - x = X[c] - @inbounds A[i] = x - c += 1 - end - end - if length(X) != c-1 - throw(DimensionMismatch("assigned $(length(X)) elements to length $(c-1) destination")) - end - A +setindex!{T}(A::Array{T}, X::Array{T}, c::Colon) = unsafe_setindex!(A, X, c) +function unsafe_setindex!{T}(A::Array{T}, X::Array{T}, ::Colon) + lI = length(A) + setindex_shape_check(X, lI) + if lI > 0 + unsafe_copy!(A, 1, X, 1, lI) end + return A end -setindex!(A::Array, X::AbstractArray, I::AbstractVector{Bool}) = assign_bool_vector_1d!(A, X, I) -setindex!(A::Array, X::AbstractArray, I::AbstractArray{Bool}) = assign_bool_vector_1d!(A, X, I) -setindex!(A::Array, x, I::AbstractVector{Bool}) = assign_bool_scalar_1d!(A, x, I) -setindex!(A::Array, x, I::AbstractArray{Bool}) = assign_bool_scalar_1d!(A, x, I) # efficiently grow an array diff --git a/base/bitarray.jl b/base/bitarray.jl index 961bb998f5c12..231a78e26ea9f 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -348,60 +348,8 @@ bitpack{T,N}(A::AbstractArray{T,N}) = convert(BitArray{N}, A) return r end -@inline function getindex(B::BitArray, i::Int) - 1 <= i <= length(B) || throw(BoundsError(B, i)) - return unsafe_bitgetindex(B.chunks, i) -end - -getindex(B::BitArray, i::Real) = getindex(B, to_index(i)) - -getindex(B::BitArray) = getindex(B, 1) - -# 0d bitarray -getindex(B::BitArray{0}) = unsafe_bitgetindex(B.chunks, 1) - -function getindex{T<:Real}(B::BitArray, I::AbstractVector{T}) - X = BitArray(length(I)) - lB = length(B) - Xc = X.chunks - Bc = B.chunks - ind = 1 - for i in I - # faster X[ind] = B[i] - j = to_index(i) - 1 <= j <= lB || throw(BoundsError(B, j)) - unsafe_bitsetindex!(Xc, unsafe_bitgetindex(Bc, j), ind) - ind += 1 - end - return X -end - -# logical indexing -# (when the indexing is provided as an Array{Bool} or a BitArray we can be -# sure about the behaviour and use unsafe_getindex; in the general case -# we can't and must use getindex, otherwise silent corruption can happen) -# (multiple signatures for disambiguation) -for IT in [AbstractVector{Bool}, AbstractArray{Bool}] - @eval @generated function getindex(B::BitArray, I::$IT) - idxop = I <: Union(Array{Bool}, BitArray) ? :unsafe_getindex : :getindex - quote - checkbounds(B, I) - n = sum(I) - X = BitArray(n) - Xc = X.chunks - Bc = B.chunks - ind = 1 - for i = 1:length(I) - if $idxop(I, i) - # faster X[ind] = B[i] - unsafe_bitsetindex!(Xc, unsafe_bitgetindex(Bc, i), ind) - ind += 1 - end - end - return X - end - end -end +@inline getindex(B::BitArray, i::Int) = (checkbounds(B, i); unsafe_getindex(B, i)) +@inline unsafe_getindex(B::BitArray, i::Int) = unsafe_bitgetindex(B.chunks, i) ## Indexing: setindex! ## @@ -417,11 +365,9 @@ end end end -setindex!(B::BitArray, x) = setindex!(B, convert(Bool,x), 1) - -function setindex!(B::BitArray, x::Bool, i::Int) - 1 <= i <= length(B) || throw(BoundsError(B, i)) - unsafe_bitsetindex!(B.chunks, x, i) +setindex!(B::BitArray, x, i::Int) = (checkbounds(B, i); unsafe_setindex!(B, x, i)) +@inline function unsafe_setindex!(B::BitArray, x, i::Int) + unsafe_bitsetindex!(B.chunks, convert(Bool, x), i) return B end @@ -430,12 +376,13 @@ end # sure about the behaviour and use unsafe_getindex; in the general case # we can't and must use getindex, otherwise silent corruption can happen) -function setindex!(B::BitArray, x, I::BitArray) - checkbounds(B, I) +# When indexing with a BitArray, we can operate whole chunks at a time for a ~100x gain +setindex!(B::BitArray, x, I::BitArray) = (checkbounds(B, I); unsafe_setindex!(B, x, I)) +function unsafe_setindex!(B::BitArray, x, I::BitArray) y = convert(Bool, x) Bc = B.chunks Ic = I.chunks - @assert length(Bc) == length(Ic) + length(Bc) == length(Ic) || throw_boundserror(B, I) @inbounds if y for i = 1:length(Bc) Bc[i] |= Ic[i] @@ -448,26 +395,15 @@ function setindex!(B::BitArray, x, I::BitArray) return B end -@generated function setindex!(B::BitArray, x, I::AbstractArray{Bool}) - idxop = I <: Array{Bool} ? :unsafe_getindex : :getindex - quote - checkbounds(B, I) - y = convert(Bool, x) - Bc = B.chunks - for i = 1:length(I) - # faster I[i] && B[i] = y - $idxop(I, i) && unsafe_bitsetindex!(Bc, y, i) - end - return B - end -end - -function setindex!(B::BitArray, X::AbstractArray, I::BitArray) - checkbounds(B, I) +# Assigning an array of bools is more complicated, but we can still do some +# work on chunks by combining X and I 64 bits at a time to improve perf by ~40% +setindex!(B::BitArray, X::AbstractArray, I::BitArray) = (checkbounds(B, I); unsafe_setindex!(B, X, I)) +function unsafe_setindex!(B::BitArray, X::AbstractArray, I::BitArray) Bc = B.chunks Ic = I.chunks - @assert length(Bc) == length(Ic) + length(Bc) == length(Ic) || throw_boundserror(B, I) lc = length(Bc) + lx = length(X) last_chunk_len = Base._mod64(length(B)-1)+1 c = 1 @@ -477,7 +413,8 @@ function setindex!(B::BitArray, X::AbstractArray, I::BitArray) u = UInt64(1) for j = 1:(i < lc ? 64 : last_chunk_len) if Imsk & u != 0 - x = convert(Bool, X[c]) + lx < c && throw_setindex_mismatch(X, c) + x = convert(Bool, unsafe_getindex(X, c)) if x C |= u else @@ -490,31 +427,11 @@ function setindex!(B::BitArray, X::AbstractArray, I::BitArray) @inbounds Bc[i] = C end if length(X) != c-1 - throw(DimensionMismatch("assigned $(length(X)) elements to length $(c-1) destination")) + throw_setindex_mismatch(X, c-1) end return B end -@generated function setindex!(B::BitArray, X::AbstractArray, I::AbstractArray{Bool}) - idxop = I <: Array{Bool} ? :unsafe_getindex : :getindex - quote - checkbounds(B, I) - Bc = B.chunks - c = 1 - for i = 1:length(I) - if $idxop(I, i) - # faster B[i] = X[c] - unsafe_bitsetindex!(Bc, convert(Bool, X[c]), i) - c += 1 - end - end - if length(X) != c-1 - throw(DimensionMismatch("assigned $(length(X)) elements to length $(c-1) destination")) - end - return B - end -end - ## Dequeue functionality ## function push!(B::BitVector, item) diff --git a/base/deprecated.jl b/base/deprecated.jl index 3552ee9fc1ea0..d926e93d1f46a 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -489,3 +489,12 @@ function chol(A::AbstractMatrix, uplo::Symbol) "use chol(a::AbstractMatrix, uplo::Union(Val{:L},Val{:U})) instead"), :chol) chol(A, Val{uplo}) end + +_ensure_vector(A::AbstractArray) = vec(A) +_ensure_vector(A) = A +_ensure_vectors() = () +_ensure_vectors(A, As...) = (_ensure_vector(A), _ensure_vectors(As...)...) +function _unsafe_setindex!(l::LinearIndexing, A::AbstractArray, x, J::Union(Real,AbstractArray,Colon)...) + depwarn("multidimensional indexed assignment with multidimensional arrays is deprecated, use vec to convert indices to vectors", :_unsafe_setindex!) + _unsafe_setindex!(l, A, x, _ensure_vectors(J...)...) +end diff --git a/base/linalg/diagonal.jl b/base/linalg/diagonal.jl index e8e88b94a96f2..131865ba31690 100644 --- a/base/linalg/diagonal.jl +++ b/base/linalg/diagonal.jl @@ -34,14 +34,8 @@ end fill!(D::Diagonal, x) = (fill!(D.diag, x); D) full(D::Diagonal) = diagm(D.diag) -getindex(D::Diagonal, i::Integer, j::Integer) = i == j ? D.diag[i] : zero(eltype(D.diag)) - -function getindex(D::Diagonal, i::Integer) - n = length(D.diag) - id = div(i-1, n) - id + id * n == i-1 && return D.diag[id+1] - zero(eltype(D.diag)) -end +getindex(D::Diagonal, i::Int, j::Int) = i == j ? D.diag[i] : zero(eltype(D.diag)) +unsafe_getindex(D::Diagonal, i::Int, j::Int) = i == j ? unsafe_getindex(D.diag, i) : zero(eltype(D.diag)) ishermitian{T<:Real}(D::Diagonal{T}) = true ishermitian(D::Diagonal) = all(D.diag .== real(D.diag)) diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index 133ace895bba1..2fa2772356735 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -23,9 +23,10 @@ typealias HermOrSym{T,S} Union(Hermitian{T,S}, Symmetric{T,S}) typealias RealHermSymComplexHerm{T<:Real,S} Union(Hermitian{T,S}, Symmetric{T,S}, Hermitian{Complex{T},S}) size(A::HermOrSym, args...) = size(A.data, args...) -getindex(A::HermOrSym, i::Integer) = ((q, r) = divrem(i - 1, size(A, 1)); A[r + 1, q + 1]) getindex(A::Symmetric, i::Integer, j::Integer) = (A.uplo == 'U') == (i < j) ? getindex(A.data, i, j) : getindex(A.data, j, i) getindex(A::Hermitian, i::Integer, j::Integer) = (A.uplo == 'U') == (i < j) ? getindex(A.data, i, j) : conj(getindex(A.data, j, i)) +unsafe_getindex(A::Symmetric, i::Integer, j::Integer) = (A.uplo == 'U') == (i < j) ? unsafe_getindex(A.data, i, j) : unsafe_getindex(A.data, j, i) +unsafe_getindex(A::Hermitian, i::Integer, j::Integer) = (A.uplo == 'U') == (i < j) ? unsafe_getindex(A.data, i, j) : conj(unsafe_getindex(A.data, j, i)) full(A::Symmetric) = copytri!(copy(A.data), A.uplo) full(A::Hermitian) = copytri!(copy(A.data), A.uplo, true) convert{T,S<:AbstractMatrix}(::Type{Symmetric{T,S}},A::Symmetric{T,S}) = A diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index ea984dd5717cc..d6dee55628f6b 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -107,7 +107,6 @@ function full!{T,S}(A::UnitUpperTriangular{T,S}) B end -getindex(A::AbstractTriangular, i::Integer) = ((m, n) = divrem(i - 1, size(A, 1)); A[n + 1, m + 1]) getindex{T,S}(A::UnitLowerTriangular{T,S}, i::Integer, j::Integer) = i == j ? one(T) : (i > j ? A.data[i,j] : zero(A.data[i,j])) getindex{T,S}(A::LowerTriangular{T,S}, i::Integer, j::Integer) = i >= j ? A.data[i,j] : zero(A.data[i,j]) getindex{T,S}(A::UnitUpperTriangular{T,S}, i::Integer, j::Integer) = i == j ? one(T) : (i < j ? A.data[i,j] : zero(A.data[i,j])) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index d1afc368d740a..87096095155b7 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -414,34 +414,6 @@ end end end - -### subarray.jl - -# This is the code-generation block for SubArray's staged setindex! function: -# _setindex!(V::SubArray, x, J::Union(Real,AbstractVector,Colon)...) -function gen_setindex_body(N::Int) - quote - Base.Cartesian.@nexprs $N d->(J_d = J[d]) - Base.Cartesian.@ncall $N checkbounds V J - Base.Cartesian.@nexprs $N d->(I_d = Base.to_index(J_d)) - idxlens = @ncall $N index_lengths V I - if !isa(x, AbstractArray) - Base.Cartesian.@nloops $N i d->(1:idxlens[d]) d->(@inbounds j_d = Base.unsafe_getindex(I_d, i_d)) begin - @inbounds (Base.Cartesian.@nref $N V j) = x - end - else - X = x - setindex_shape_check(X, idxlens...) - k = 1 - Base.Cartesian.@nloops $N i d->(1:idxlens[d]) d->(@inbounds j_d = Base.unsafe_getindex(I_d, i_d)) begin - @inbounds (Base.Cartesian.@nref $N V j) = X[k] - k += 1 - end - end - V - end -end - ## SubArray index merging # A view created like V = A[2:3:8, 5:2:17] can later be indexed as V[2:7], # creating a new 1d view. @@ -637,70 +609,19 @@ end ## getindex -@inline unsafe_getindex(v::BitArray, ind::Int) = Base.unsafe_bitgetindex(v.chunks, ind) - -# general scalar indexing with two or more indices -# (uses linear indexing, which is defined in bitarray.jl) -# (code is duplicated for safe and unsafe versions for performance reasons) - -@generated function unsafe_getindex(B::BitArray, I_0::Int, I::Int...) - N = length(I) - quote - stride = 1 - index = I_0 - @nexprs $N d->begin - stride *= size(B,d) - index += (I[d] - 1) * stride - end - return unsafe_getindex(B, index) - end -end - -@generated function getindex(B::BitArray, I_0::Int, I::Int...) - N = length(I) - quote - stride = 1 - index = I_0 - @nexprs $N d->(I_d = I[d]) - @nexprs $N d->begin - l = size(B,d) - stride *= l - 1 <= I_{d-1} <= l || throw(BoundsError()) - index += (I_d - 1) * stride - end - return B[index] - end -end - # contiguous multidimensional indexing: if the first dimension is a range, # we can get some performance from using copy_chunks! - -function unsafe_getindex(B::BitArray, I0::UnitRange{Int}) - X = BitArray(length(I0)) - copy_chunks!(X.chunks, 1, B.chunks, first(I0), length(I0)) +@inline function _unsafe_getindex!(X::BitArray, ::LinearFast, B::BitArray, I0::Union(UnitRange{Int}, Colon)) + copy_chunks!(X.chunks, 1, B.chunks, first(I0), index_lengths(B, I0)[1]) return X end -function getindex(B::BitArray, I0::UnitRange{Int}) - checkbounds(B, I0) - return unsafe_getindex(B, I0) -end - -function getindex(B::BitArray, ::Colon) - X = BitArray(0) - X.chunks = copy(B.chunks) - X.len = length(B) - return X -end - -getindex{T<:Real}(B::BitArray, I0::UnitRange{T}) = getindex(B, to_index(I0)) - -@generated function unsafe_getindex(B::BitArray, I0::Union(Colon,UnitRange{Int}), I::Union(Int,UnitRange{Int},Colon)...) +# Optimization where the inner dimension is contiguous improves perf dramatically +@generated function _unsafe_getindex!(X::BitArray, ::LinearFast, B::BitArray, I0::Union(Colon,UnitRange{Int}), I::Union(Int,UnitRange{Int},Colon)...) N = length(I) - Isplat = Expr[:(I[$d]) for d = 1:N] quote + $(Expr(:meta, :inline)) @nexprs $N d->(I_d = I[d]) - X = BitArray(index_shape(B, I0, $(Isplat...))) f0 = first(I0) l0 = size(X, 1) @@ -717,92 +638,40 @@ getindex{T<:Real}(B::BitArray, I0::UnitRange{T}) = getindex(B, to_index(I0)) end storeind = 1 + Xc, Bc = X.chunks, B.chunks @nloops($N, i, d->I_d, d->nothing, # PRE d->(ind += stride_lst_d - gap_lst_d), # POST begin # BODY - copy_chunks!(X.chunks, storeind, B.chunks, ind, l0) + copy_chunks!(Xc, storeind, Bc, ind, l0) storeind += l0 end) return X end end -# general multidimensional non-scalar indexing - -@generated function unsafe_getindex(B::BitArray, I::Union(Int,AbstractVector{Int},Colon)...) +# in the general multidimensional non-scalar case, can we do about 10% better +# in most cases by manually hoisting the bitarray chunks access out of the loop +# (This should really be handled by the compiler or with an immutable BitArray) +@generated function _unsafe_getindex!(X::BitArray, ::LinearFast, B::BitArray, I::Union(Int,AbstractVector{Int},Colon)...) N = length(I) - Isplat = Expr[:(I[$d]) for d = 1:N] quote - @nexprs $N d->(I_d = I[d]) - shape = @ncall $N index_shape B I - X = BitArray(shape) - Xc = X.chunks - + $(Expr(:meta, :inline)) stride_1 = 1 - @nexprs $N d->(stride_{d+1} = stride_d * size(B, d)) - @nexprs 1 d->(offset_{$N} = 1) - ind = 1 - @nloops($N, i, X, d->(@inbounds j_d = unsafe_getindex(I[d], i_d); - offset_{d-1} = offset_d + (j_d-1)*stride_d), # PRE - begin - unsafe_bitsetindex!(Xc, B[offset_0], ind) - ind += 1 - end) + @nexprs $N d->(stride_{d+1} = stride_d*size(B, d)) + $(symbol(:offset_, N)) = 1 + ind = 0 + Xc, Bc = X.chunks, B.chunks + @nloops $N i X d->(offset_{d-1} = offset_d + (unsafe_getindex(I[d], i_d)-1)*stride_d) begin + ind += 1 + unsafe_bitsetindex!(Xc, unsafe_bitgetindex(Bc, offset_0), ind) + end return X end end -# general version with Real (or logical) indexing which dispatches on the appropriate method - -@generated function getindex(B::BitArray, I::Union(Real,AbstractVector,Colon)...) - N = length(I) - Isplat = Expr[:(I[$d]) for d = 1:N] - Jsplat = Expr[:(to_index(I[$d])) for d = 1:N] - quote - checkbounds(B, $(Isplat...)) - return unsafe_getindex(B, $(Jsplat...)) - end -end - ## setindex! -# general scalar indexing with two or more indices -# (uses linear indexing, which - in the safe version - performs the final -# bounds check and is defined in bitarray.jl) -# (code is duplicated for safe and unsafe versions for performance reasons) - -@generated function unsafe_setindex!(B::BitArray, x::Bool, I_0::Int, I::Int...) - N = length(I) - quote - stride = 1 - index = I_0 - @nexprs $N d->begin - stride *= size(B,d) - index += (I[d] - 1) * stride - end - unsafe_setindex!(B, x, index) - return B - end -end - -@generated function setindex!(B::BitArray, x::Bool, I_0::Int, I::Int...) - N = length(I) - quote - stride = 1 - index = I_0 - @nexprs $N d->(I_d = I[d]) - @nexprs $N d->begin - l = size(B,d) - stride *= l - 1 <= I_{d-1} <= l || throw(BoundsError()) - index += (I_d - 1) * stride - end - B[index] = x - return B - end -end - # contiguous multidimensional indexing: if the first dimension is a range, # we can get some performance from using copy_chunks! @@ -882,75 +751,6 @@ end end end - -# general multidimensional non-scalar indexing - -@generated function unsafe_setindex!(B::BitArray, X::AbstractArray, I::Union(Int,AbstractArray{Int},Colon)...) - N = length(I) - quote - refind = 1 - @nexprs $N d->(I_d = I[d]) - idxlens = @ncall $N index_lengths B I - @nloops $N i d->(1:idxlens[d]) d->(J_d = I_d[i_d]) @inbounds begin - @ncall $N unsafe_setindex! B convert(Bool,X[refind]) J - refind += 1 - end - return B - end -end - -@generated function unsafe_setindex!(B::BitArray, x::Bool, I::Union(Int,AbstractArray{Int},Colon)...) - N = length(I) - quote - @nexprs $N d->(I_d = I[d]) - idxlens = @ncall $N index_lengths B I - @nloops $N i d->(1:idxlens[d]) d->(J_d = I_d[i_d]) begin - @ncall $N unsafe_setindex! B x J - end - return B - end -end - -# general versions with Real (or logical) indexing which dispatch on the appropriate method - -# this one is for disambiguation only -function setindex!(B::BitArray, x, i::Real) - checkbounds(B, i) - return unsafe_setindex!(B, convert(Bool,x), to_index(i)) -end - -@generated function setindex!(B::BitArray, x, I::Union(Real,AbstractArray,Colon)...) - N = length(I) - quote - checkbounds(B, I...) - #return unsafe_setindex!(B, convert(Bool,x), to_index(I...)...) # segfaults! (???) - @nexprs $N d->(J_d = to_index(I[d])) - return @ncall $N unsafe_setindex! B convert(Bool,x) J - end -end - - -# this one is for disambiguation only -function setindex!(B::BitArray, X::AbstractArray, i::Real) - checkbounds(B, i) - j = to_index(i) - setindex_shape_check(X, index_lengths(A, j)[1]) - return unsafe_setindex!(B, X, j) -end - -@generated function setindex!(B::BitArray, X::AbstractArray, I::Union(Real,AbstractArray,Colon)...) - N = length(I) - quote - checkbounds(B, I...) - @nexprs $N d->(J_d = to_index(I[d])) - idxlens = @ncall $N index_lengths B J - setindex_shape_check(X, idxlens...) - return @ncall $N unsafe_setindex! B X J - end -end - - - ## findn @generated function findn{N}(B::BitArray{N}) diff --git a/base/number.jl b/base/number.jl index 1c0029ce60419..fcd6a02d5f5d0 100644 --- a/base/number.jl +++ b/base/number.jl @@ -15,6 +15,7 @@ getindex(x::Number) = x getindex(x::Number, i::Integer) = i == 1 ? x : throw(BoundsError()) getindex(x::Number, I::Integer...) = all([i == 1 for i in I]) ? x : throw(BoundsError()) getindex(x::Number, I::Real...) = getindex(x, to_index(I)...) +unsafe_getindex(x::Real, i::Real) = x first(x::Number) = x last(x::Number) = x diff --git a/base/range.jl b/base/range.jl index d3503d94fd547..7e58a677eb3d1 100644 --- a/base/range.jl +++ b/base/range.jl @@ -347,57 +347,44 @@ done(r::UnitRange, i) = i==oftype(i,r.stop)+1 ## indexing -getindex(r::Range, i::Real) = getindex(r, to_index(i)) +getindex(r::Range, i::Integer) = (checkbounds(r, i); unsafe_getindex(r, i)) +unsafe_getindex{T}(v::Range{T}, i::Integer) = convert(T, first(v) + (i-1)*step(v)) -function getindex{T}(r::Range{T}, i::Integer) - 1 <= i <= length(r) || throw(BoundsError()) - convert(T, first(r) + (i-1)*step(r)) -end -function getindex{T}(r::FloatRange{T}, i::Integer) - 1 <= i <= length(r) || throw(BoundsError()) - convert(T, (r.start + (i-1)*r.step)/r.divisor) -end -function getindex{T}(r::LinSpace{T}, i::Integer) - 1 <= i <= length(r) || throw(BoundsError()) - convert(T, ((r.len-i)*r.start + (i-1)*r.stop)/r.divisor) -end +getindex{T}(r::FloatRange{T}, i::Integer) = (checkbounds(r, i); unsafe_getindex(r, i)) +unsafe_getindex{T}(r::FloatRange{T}, i::Integer) = convert(T, (r.start + (i-1)*r.step)/r.divisor) + +getindex{T}(r::LinSpace{T}, i::Integer) = (checkbounds(r, i); unsafe_getindex(r, i)) +unsafe_getindex{T}(r::LinSpace{T}, i::Integer) = convert(T, ((r.len-i)*r.start + (i-1)*r.stop)/r.divisor) getindex(r::Range, ::Colon) = copy(r) unsafe_getindex(r::Range, ::Colon) = copy(r) -function check_indexingrange(s, r) - sl = length(s) - rl = length(r) - sl == 0 || 1 <= first(s) <= rl && - 1 <= last(s) <= rl || throw(BoundsError()) - sl -end - -function getindex(r::UnitRange, s::UnitRange{Int}) - sl = check_indexingrange(s, r) +getindex(r::UnitRange, s::UnitRange{Int}) = (checkbounds(r, s); unsafe_getindex(r, s)) +function unsafe_getindex(r::UnitRange, s::UnitRange{Int}) st = oftype(r.start, r.start + s.start-1) - range(st, sl) + range(st, length(s)) end -function getindex(r::UnitRange, s::StepRange{Int}) - sl = check_indexingrange(s, r) +getindex(r::UnitRange, s::StepRange{Int}) = (checkbounds(r, s); unsafe_getindex(r, s)) +function unsafe_getindex(r::UnitRange, s::StepRange{Int}) st = oftype(r.start, r.start + s.start-1) - range(st, step(s), sl) + range(st, step(s), length(s)) end -function getindex(r::StepRange, s::Range{Int}) - sl = check_indexingrange(s, r) +getindex(r::StepRange, s::Range{Int}) = (checkbounds(r, s); unsafe_getindex(r, s)) +function unsafe_getindex(r::StepRange, s::Range{Int}) st = oftype(r.start, r.start + (first(s)-1)*step(r)) - range(st, step(r)*step(s), sl) + range(st, step(r)*step(s), length(s)) end -function getindex(r::FloatRange, s::OrdinalRange) - sl = check_indexingrange(s, r) - FloatRange(r.start + (first(s)-1)*r.step, step(s)*r.step, sl, r.divisor) +getindex(r::FloatRange, s::OrdinalRange) = (checkbounds(r, s); unsafe_getindex(r, s)) +function unsafe_getindex(r::FloatRange, s::OrdinalRange) + FloatRange(r.start + (first(s)-1)*r.step, step(s)*r.step, length(s), r.divisor) end -function getindex{T}(r::LinSpace{T}, s::OrdinalRange) - sl::T = check_indexingrange(s, r) +getindex(r::LinSpace, s::OrdinalRange) = (checkbounds(r, s); unsafe_getindex(r, s)) +function unsafe_getindex{T}(r::LinSpace{T}, s::OrdinalRange) + sl::T = length(s) ifirst = first(s) ilast = last(s) vfirst::T = ((r.len - ifirst) * r.start + (ifirst - 1) * r.stop) / r.divisor diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index 5382777a85e3b..c2e1a1aead03e 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -2,7 +2,8 @@ module CHOLMOD -import Base: (*), convert, copy, eltype, getindex, show, size +import Base: (*), convert, copy, eltype, getindex, show, size, + linearindexing, LinearFast, LinearSlow import Base.LinAlg: (\), A_mul_Bc, A_mul_Bt, Ac_ldiv_B, Ac_mul_B, At_ldiv_B, At_mul_B, cholfact, cholfact!, det, diag, ishermitian, isposdef, @@ -935,19 +936,14 @@ function size(F::Factor, i::Integer) return 1 end +linearindexing(::Dense) = LinearFast() function getindex(A::Dense, i::Integer) s = unsafe_load(A.p) 0 < i <= s.nrow*s.ncol || throw(BoundsError()) unsafe_load(s.x, i) end -function getindex(A::Dense, i::Integer, j::Integer) - s = unsafe_load(A.p) - 0 < i <= s.nrow || throw(BoundsError()) - 0 < j <= s.ncol || throw(BoundsError()) - unsafe_load(s.x, i + (j - 1)*s.d) -end -getindex(A::Sparse, i::Integer) = getindex(A, ind2sub(size(A),i)...) +linearindexing(::Sparse) = LinearSlow() function getindex{T}(A::Sparse{T}, i0::Integer, i1::Integer) s = unsafe_load(A.p) !(1 <= i0 <= s.nrow && 1 <= i1 <= s.ncol) && throw(BoundsError()) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index feb9430f18bd6..a15c12bebc2cf 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -146,7 +146,6 @@ copy(S::SparseMatrixCSC) = SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), copy(S.nzval)) similar(S::SparseMatrixCSC, Tv::Type=eltype(S)) = SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), Array(Tv, length(S.nzval))) -similar{Tv,Ti,TvNew}(S::SparseMatrixCSC{Tv,Ti}, ::Type{TvNew}, ::Type{Ti}) = similar(S, TvNew) similar{Tv,Ti,TvNew,TiNew}(S::SparseMatrixCSC{Tv,Ti}, ::Type{TvNew}, ::Type{TiNew}) = SparseMatrixCSC(S.m, S.n, convert(Array{TiNew},S.colptr), convert(Array{TiNew}, S.rowval), Array(TvNew, length(S.nzval))) similar{Tv}(S::SparseMatrixCSC, ::Type{Tv}, d::NTuple{Integer}) = spzeros(Tv, d...) @@ -1225,7 +1224,6 @@ function rangesearch(haystack::Range, needle) (rem==0 && 1<=i+1<=length(haystack)) ? i+1 : 0 end -getindex(A::SparseMatrixCSC, i::Integer) = isempty(A) ? throw(BoundsError()) : getindex(A, ind2sub(size(A),i)) getindex(A::SparseMatrixCSC, I::Tuple{Integer,Integer}) = getindex(A, I[1], I[2]) function getindex{T}(A::SparseMatrixCSC{T}, i0::Integer, i1::Integer) @@ -1687,8 +1685,6 @@ end ## setindex! -setindex!(A::SparseMatrixCSC, v, i::Integer) = setindex!(A, v, ind2sub(size(A),i)...) - function setindex!{T,Ti}(A::SparseMatrixCSC{T,Ti}, v, i0::Integer, i1::Integer) i0 = convert(Ti, i0) i1 = convert(Ti, i1) diff --git a/base/subarray2.jl b/base/subarray2.jl index a8266da72f0f4..59532baeacc85 100644 --- a/base/subarray2.jl +++ b/base/subarray2.jl @@ -1,109 +1,49 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license ## Scalar indexing -# Low dimensions: avoid splatting -newsym = (:i_1, :i_2, :i_3, :i_4) -vars = Array(Expr, 0) -varsInt = Array(Expr, 0) -varsOther = Array(Expr, 0) -vars_toindex = Array(Expr, 0) -for i = 1:4 - sym = newsym[i] - push!(vars, Expr(:quote, sym)) - push!(varsInt, :($sym::Int)) - push!(varsOther, :($sym::Union(Real, AbstractVector))) - push!(vars_toindex, :(to_index($sym))) - ex = i == 1 ? quote - getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, $sym::Real) = getindex(V, to_index($sym)) - setindex!{T,N,P,IV}(V::SubArray{T,N,P,IV}, v, $sym::Real) = setindex!(V, v, to_index($sym)) - getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, $sym::AbstractVector{Bool}) = getindex(V, to_index($sym)) - setindex!{T,N,P,IV}(V::SubArray{T,N,P,IV}, v, $sym::AbstractVector{Bool}) = setindex!(V, v, to_index($sym)) - end : quote - getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, $(varsOther...)) = getindex(V, $(vars_toindex...)) - setindex!{T,N,P,IV}(V::SubArray{T,N,P,IV}, v, $(varsOther...)) = setindex!(V, v, $(vars_toindex...)) - end - @eval begin - @generated function getindex{T,N,P,IV,LD}(V::SubArray{T,N,P,IV,LD}, $(varsInt...)) - if $i == 1 && length(IV.parameters) == LD # linear indexing - meta = Expr(:meta, :inline) - if iscontiguous(V) - return :($meta; V.parent[V.first_index + i_1 - 1]) - end - return :($meta; V.parent[V.first_index + V.stride1*(i_1-1)]) - end - exhead, ex = index_generate(ndims(P), IV, :V, [$(vars...)]) - quote - $exhead - $ex - end +@inline getindex(V::SubArray, I::Int...) = (checkbounds(V, I...); unsafe_getindex(V, I...)) +@generated function unsafe_getindex{T,N,P,IV,LD}(V::SubArray{T,N,P,IV,LD}, I::Int...) + ni = length(I) + if ni == 1 && length(IV.parameters) == LD # linear indexing + meta = Expr(:meta, :inline) + if iscontiguous(V) + return :($meta; V.parent[V.first_index + I[1] - 1]) end - @generated function setindex!{T,N,P,IV,LD}(V::SubArray{T,N,P,IV,LD}, v, $(varsInt...)) - if $i == 1 && length(IV.parameters) == LD # linear indexing - meta = Expr(:meta, :inline) - if iscontiguous(V) - return :($meta; V.parent[V.first_index + i_1 - 1] = v) - end - return :($meta; V.parent[V.first_index + V.stride1*(i_1-1)] = v) - end - exhead, ex = index_generate(ndims(P), IV, :V, [$(vars...)]) - quote - $exhead - $ex = v - end - end - $ex + return :($meta; V.parent[V.first_index + V.stride1*(I[1]-1)]) end -end -# V[] notation (extracts the first element) -@generated function getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}) - Isyms = ones(Int, N) - exhead, ex = index_generate(ndims(P), IV, :V, Isyms) + Isyms = [:(I[$d]) for d = 1:ni] + exhead, idxs = index_generate(ndims(P), IV, :V, Isyms) quote $exhead - $ex + unsafe_getindex(V.parent, $(idxs...)) end end -# Splatting variants -@generated function getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, I::Int...) - Isyms = [:(I[$d]) for d = 1:length(I)] - exhead, ex = index_generate(ndims(P), IV, :V, Isyms) - quote - $exhead - $ex +@inline setindex!(V::SubArray, v, I::Int...) = (checkbounds(V, I...); unsafe_setindex!(V, v, I...)) +@generated function unsafe_setindex!{T,N,P,IV,LD}(V::SubArray{T,N,P,IV,LD}, v, I::Int...) + ni = length(I) + if ni == 1 && length(IV.parameters) == LD # linear indexing + meta = Expr(:meta, :inline) + if iscontiguous(V) + return :($meta; V.parent[V.first_index + I[1] - 1] = v) + end + return :($meta; V.parent[V.first_index + V.stride1*(I[1]-1)] = v) end -end -@generated function setindex!{T,N,P,IV}(V::SubArray{T,N,P,IV}, v, I::Int...) - Isyms = [:(I[$d]) for d = 1:length(I)] - exhead, ex = index_generate(ndims(P), IV, :V, Isyms) + Isyms = [:(I[$d]) for d = 1:ni] + exhead, idxs = index_generate(ndims(P), IV, :V, Isyms) quote $exhead - $ex = v + unsafe_setindex!(V.parent, v, $(idxs...)) end end # Indexing with non-scalars. For now, this returns a copy, but changing that # is just a matter of deleting the explicit call to copy. getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, I::ViewIndex...) = copy(sub(V, I...)) -getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, I::AbstractArray{Bool,N}) = copy(sub(V, find(I))) # this could be much better optimized -getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, I::Union(Real, AbstractVector, Colon)...) = getindex(V, to_index(I)...) +getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, I::Union(Real, AbstractArray, Colon)...) = getindex(V, to_index(I)...) +unsafe_getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, I::ViewIndex...) = copy(sub_unsafe(V, I)) +unsafe_getindex{T,N,P,IV}(V::SubArray{T,N,P,IV}, I::Union(Real, AbstractArray, Colon)...) = unsafe_getindex(V, to_index(I)...) -function setindex!{T,P,IV}(V::SubArray{T,1,P,IV}, v, I::AbstractArray{Bool,1}) - length(I) == length(V) || throw(DimensionMismatch("logical vector must match array length")) - setindex!(V, v, to_index(I)) -end -function setindex!{T,N,P,IV}(V::SubArray{T,N,P,IV}, v, I::AbstractArray{Bool,1}) - length(I) == length(V) || throw(DimensionMismatch("logical vector must match array length")) - setindex!(V, v, to_index(I)) -end -function setindex!{T,N,P,IV}(V::SubArray{T,N,P,IV}, v, I::AbstractArray{Bool,N}) - size(I) == size(V) || throw(DimensionMismatch("size of Boolean mask must match array size")) - _setindex!(V, v, find(I)) # this could be better optimized -end -setindex!{T,N,P,IV}(V::SubArray{T,N,P,IV}, v, I::Union(Real,AbstractVector,Colon)...) = setindex!(V, v, to_index(I)...) -setindex!{T,N,P,IV}(V::SubArray{T,N,P,IV}, x, J::Union(Int,AbstractVector,Colon)...) = _setindex!(V, x, J...) -@generated function _setindex!(V::SubArray, x, J::Union(Real,AbstractVector,Colon)...) - gen_setindex_body(length(J)) -end +# Nonscalar setindex! falls back to the AbstractArray versions # NP is parent dimensionality, Itypes is the tuple typeof(V.indexes) # NP may not be equal to length(Itypes), because a view of a 2d matrix A @@ -153,26 +93,13 @@ function index_generate(NP, Itypes, Vsym, Isyms) indexexprs[i] = :($Vsym.indexes[$i]) else j += 1 - indexexprs[i] = :(unsafe_getindex($Vsym.indexes[$i], $(Isyms[j]))) # TODO: make Range bounds-checking respect @inbounds + indexexprs[i] = :(unsafe_getindex($Vsym.indexes[$i], $(Isyms[j]))) end end - # Append any extra indexes. Must be trailing 1s or it will cause a BoundsError. - if L < NP && j < length(Isyms) - # This view was created as V = A[5:13], so appending them would generate interpretive confusion. - # Instead, use double-indexing, i.e., A[indexes1...][indexes2...], where indexes2 contains the leftovers. - return exhead, :($Vsym.parent[$(indexexprs...)][$(Isyms[j+1:end]...)]) - end - for k = j+1:length(Isyms) - push!(indexexprs, Isyms[k]) - end + # Note that we drop any extra indices. We're trusting that the indices are + # already checked to be in-bounds, so any extra indices must be 1 (and no-op) if exhead == :nothing exhead = Expr(:meta, :inline) end - exhead, :($Vsym.parent[$(indexexprs...)]) + exhead, indexexprs end - -unsafe_getindex(v::Real, ind::Int) = v -unsafe_getindex(v::Range, ind::Int) = first(v) + (ind-1)*step(v) -@inline unsafe_getindex(v::Array, ind::Int) = (@inbounds x = v[ind]; x) -unsafe_getindex(v::AbstractArray, ind::Int) = v[ind] -unsafe_getindex(v::Colon, ind::Int) = ind diff --git a/test/sparsedir/sparse.jl b/test/sparsedir/sparse.jl index aa0fab1cd4ca0..1475ad14ee6df 100644 --- a/test/sparsedir/sparse.jl +++ b/test/sparsedir/sparse.jl @@ -746,6 +746,7 @@ end @test sparse([]') == reshape(sparse([]), 1, 0) @test full(sparse([])) == zeros(0, 1) @test_throws BoundsError sparse([])[1] +@test_throws BoundsError sparse([])[1] = 1 x = speye(100) @test_throws BoundsError x[-10:10]