From e6165fdc30642f508929fda74b33d51074c12607 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 16 Feb 2017 06:57:56 -0600 Subject: [PATCH] Rename LinearIndexing->IndexMethod, LinearSlow->IndexLinear, etc. --- base/abstractarray.jl | 137 ++++++++++++++++++--------------- base/abstractarraymath.jl | 2 +- base/bitarray.jl | 2 +- base/deprecated.jl | 5 ++ base/exports.jl | 5 +- base/linalg/conjarray.jl | 4 +- base/linalg/linalg.jl | 4 +- base/linalg/rowvector.jl | 4 +- base/multidimensional.jl | 32 ++++---- base/multinverses.jl | 2 +- base/reduce.jl | 8 +- base/reshapedarray.jl | 10 +-- base/sharedarray.jl | 2 +- base/sort.jl | 4 +- base/sparse/cholmod.jl | 6 +- base/sparse/sparsematrix.jl | 2 +- base/subarray.jl | 20 ++--- doc/src/devdocs/boundscheck.md | 4 +- doc/src/devdocs/subarrays.md | 4 +- doc/src/manual/arrays.md | 4 +- doc/src/manual/interfaces.md | 23 +++--- doc/src/stdlib/arrays.md | 2 +- test/TestHelpers.jl | 8 +- test/abstractarray.jl | 14 ++-- test/arrayops.jl | 22 +++--- test/offsetarray.jl | 4 +- test/perf/array/indexing.jl | 12 +-- test/subarray.jl | 6 +- 28 files changed, 186 insertions(+), 166 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index effa15fc17268..50af380337667 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -245,36 +245,49 @@ end ## Traits for array types ## -abstract type LinearIndexing end -struct LinearFast <: LinearIndexing end -struct LinearSlow <: LinearIndexing end +abstract type IndexMethod end +struct IndexLinear <: IndexMethod end +struct IndexCartesian <: IndexMethod end """ - Base.linearindexing(A) + IndexMethod(A) + IndexMethod(typeof(A)) -`linearindexing` defines how an AbstractArray most efficiently accesses its elements. If -`Base.linearindexing(A)` returns `Base.LinearFast()`, this means that linear indexing with -only one index is an efficient operation. If it instead returns `Base.LinearSlow()` (by -default), this means that the array intrinsically accesses its elements with indices -specified for every dimension. Since converting a linear index to multiple indexing -subscripts is typically very expensive, this provides a traits-based mechanism to enable -efficient generic code for all array types. +`IndexMethod` specifies the "native indexing style" for AbstractArray +`A`. When you define a new AbstractArray type, you can choose to +implement either linear indexing or cartesian indexing. If you decide +to implement linear indexing, then you must set this trait for your +array type: -An abstract array subtype `MyArray` that wishes to opt into fast linear indexing behaviors -should define `linearindexing` in the type-domain: + Base.IndexMethod(::Type{<:MyArray}) = IndexLinear() - Base.linearindexing(::Type{<:MyArray}) = Base.LinearFast() +The default is `IndexCartesian()`. + +Julia's internal indexing machinery will automatically (and invisibly) +convert all indexing operations into the preferred style using +`sub2ind` or `ind2sub`. This allows users to access elements of your +array using any indexing style, even when explicit methods have not +been provided. + +If you define both styles of indexing for your AbstractArray, this +trait can be used to select the most performant indexing style. Some +methods check this trait on their inputs, and dispatch to different +algorithms depending on the most efficient access pattern. In +particular, `eachindex` creates an iterator whose type depends on the +setting of this trait. + +See also: [`eachindex`](@ref). """ -linearindexing(A::AbstractArray) = linearindexing(typeof(A)) -linearindexing(::Type{Union{}}) = LinearFast() -linearindexing(::Type{<:AbstractArray}) = LinearSlow() -linearindexing(::Type{<:Array}) = LinearFast() -linearindexing(::Type{<:Range}) = LinearFast() +IndexMethod(A::AbstractArray) = IndexMethod(typeof(A)) +IndexMethod(::Type{Union{}}) = IndexLinear() +IndexMethod(::Type{<:AbstractArray}) = IndexCartesian() +IndexMethod(::Type{<:Array}) = IndexLinear() +IndexMethod(::Type{<:Range}) = IndexLinear() -linearindexing(A::AbstractArray, B::AbstractArray) = linearindexing(linearindexing(A), linearindexing(B)) -linearindexing(A::AbstractArray, B::AbstractArray...) = linearindexing(linearindexing(A), linearindexing(B...)) -linearindexing(::LinearFast, ::LinearFast) = LinearFast() -linearindexing(::LinearIndexing, ::LinearIndexing) = LinearSlow() +IndexMethod(A::AbstractArray, B::AbstractArray) = IndexMethod(IndexMethod(A), IndexMethod(B)) +IndexMethod(A::AbstractArray, B::AbstractArray...) = IndexMethod(IndexMethod(A), IndexMethod(B...)) +IndexMethod(::IndexLinear, ::IndexLinear) = IndexLinear() +IndexMethod(::IndexMethod, ::IndexMethod) = IndexCartesian() ## Bounds checking ## @@ -617,9 +630,9 @@ end ## since a single index variable can be used. copy!(dest::AbstractArray, src::AbstractArray) = - copy!(linearindexing(dest), dest, linearindexing(src), src) + copy!(IndexMethod(dest), dest, IndexMethod(src), src) -function copy!(::LinearIndexing, dest::AbstractArray, ::LinearIndexing, src::AbstractArray) +function copy!(::IndexMethod, dest::AbstractArray, ::IndexMethod, src::AbstractArray) destinds, srcinds = linearindices(dest), linearindices(src) isempty(srcinds) || (first(srcinds) ∈ destinds && last(srcinds) ∈ destinds) || throw(BoundsError(dest, srcinds)) @inbounds for i in srcinds @@ -628,7 +641,7 @@ function copy!(::LinearIndexing, dest::AbstractArray, ::LinearIndexing, src::Abs return dest end -function copy!(::LinearIndexing, dest::AbstractArray, ::LinearSlow, src::AbstractArray) +function copy!(::IndexMethod, dest::AbstractArray, ::IndexCartesian, src::AbstractArray) destinds, srcinds = linearindices(dest), linearindices(src) isempty(srcinds) || (first(srcinds) ∈ destinds && last(srcinds) ∈ destinds) || throw(BoundsError(dest, srcinds)) i = 0 @@ -720,16 +733,16 @@ copymutable(itr) = collect(itr) zero{T}(x::AbstractArray{T}) = fill!(similar(x), zero(T)) ## iteration support for arrays by iterating over `eachindex` in the array ## -# Allows fast iteration by default for both LinearFast and LinearSlow arrays +# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays -# While the definitions for LinearFast are all simple enough to inline on their -# own, LinearSlow's CartesianRange is more complicated and requires explicit +# While the definitions for IndexLinear are all simple enough to inline on their +# own, IndexCartesian's CartesianRange is more complicated and requires explicit # inlining. start(A::AbstractArray) = (@_inline_meta; itr = eachindex(A); (itr, start(itr))) next(A::AbstractArray,i) = (@_propagate_inbounds_meta; (idx, s) = next(i[1], i[2]); (A[idx], (i[1], s))) done(A::AbstractArray,i) = (@_propagate_inbounds_meta; done(i[1], i[2])) -# eachindex iterates over all indices. LinearSlow definitions are later. +# eachindex iterates over all indices. IndexCartesian definitions are later. eachindex(A::AbstractVector) = (@_inline_meta(); indices1(A)) """ @@ -776,18 +789,18 @@ otherwise). If the arrays have different sizes and/or dimensionalities, `eachindex` returns an iterable that spans the largest range along each dimension. """ -eachindex(A::AbstractArray) = (@_inline_meta(); eachindex(linearindexing(A), A)) +eachindex(A::AbstractArray) = (@_inline_meta(); eachindex(IndexMethod(A), A)) function eachindex(A::AbstractArray, B::AbstractArray) @_inline_meta - eachindex(linearindexing(A,B), A, B) + eachindex(IndexMethod(A,B), A, B) end function eachindex(A::AbstractArray, B::AbstractArray...) @_inline_meta - eachindex(linearindexing(A,B...), A, B...) + eachindex(IndexMethod(A,B...), A, B...) end -eachindex(::LinearFast, A::AbstractArray) = linearindices(A) -function eachindex(::LinearFast, A::AbstractArray, B::AbstractArray...) +eachindex(::IndexLinear, A::AbstractArray) = linearindices(A) +function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...) @_inline_meta 1:_maxlength(A, B...) end @@ -838,15 +851,15 @@ pointer{T}(x::AbstractArray{T}, i::Integer) = (@_inline_meta; unsafe_convert(Ptr # That dispatches to an (inlined) internal _getindex function, where the goal is # to transform the indices such that we can call the only getindex method that # we require the type A{T,N} <: AbstractArray{T,N} to define; either: -# getindex(::A, ::Int) # if linearindexing(A) == LinearFast() OR -# getindex{T,N}(::A{T,N}, ::Vararg{Int, N}) # if LinearSlow() +# getindex(::A, ::Int) # if IndexMethod(A) == IndexLinear() OR +# getindex{T,N}(::A{T,N}, ::Vararg{Int, N}) # if IndexCartesian() # If the subtype hasn't defined the required method, it falls back to the # _getindex function again where an error is thrown to prevent stack overflows. function getindex(A::AbstractArray, I...) @_propagate_inbounds_meta - error_if_canonical_indexing(linearindexing(A), A, I...) - _getindex(linearindexing(A), A, to_indices(A, I)...) + error_if_canonical_indexing(IndexMethod(A), A, I...) + _getindex(IndexMethod(A), A, to_indices(A, I)...) end function unsafe_getindex(A::AbstractArray, I...) @_inline_meta @@ -854,17 +867,17 @@ function unsafe_getindex(A::AbstractArray, I...) r end -error_if_canonical_indexing(::LinearFast, A::AbstractArray, ::Int) = error("indexing not defined for ", typeof(A)) -error_if_canonical_indexing{T,N}(::LinearSlow, A::AbstractArray{T,N}, ::Vararg{Int, N}) = error("indexing not defined for ", typeof(A)) -error_if_canonical_indexing(::LinearIndexing, ::AbstractArray, ::Any...) = nothing +error_if_canonical_indexing(::IndexLinear, A::AbstractArray, ::Int) = error("indexing not defined for ", typeof(A)) +error_if_canonical_indexing{T,N}(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int, N}) = error("indexing not defined for ", typeof(A)) +error_if_canonical_indexing(::IndexMethod, ::AbstractArray, ::Any...) = nothing ## Internal definitions -_getindex(::LinearIndexing, A::AbstractArray, I...) = error("indexing $(typeof(A)) with types $(typeof(I)) is not supported") +_getindex(::IndexMethod, A::AbstractArray, I...) = error("indexing $(typeof(A)) with types $(typeof(I)) is not supported") -## LinearFast Scalar indexing: canonical method is one Int -_getindex(::LinearFast, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i)) -_getindex(::LinearFast, A::AbstractArray) = (@_propagate_inbounds_meta; getindex(A, _to_linear_index(A))) -function _getindex(::LinearFast, A::AbstractArray, I::Int...) +## IndexLinear Scalar indexing: canonical method is one Int +_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i)) +_getindex(::IndexLinear, A::AbstractArray) = (@_propagate_inbounds_meta; getindex(A, _to_linear_index(A))) +function _getindex(::IndexLinear, A::AbstractArray, I::Int...) @_inline_meta @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking @inbounds r = getindex(A, _to_linear_index(A, I...)) @@ -876,15 +889,15 @@ _to_linear_index{T,N}(A::AbstractArray{T,N}, I::Vararg{Int,N}) = (@_inline_meta; _to_linear_index(A::AbstractArray) = 1 # TODO: DEPRECATE FOR #14770 _to_linear_index(A::AbstractArray, I::Int...) = (@_inline_meta; sub2ind(A, I...)) # TODO: DEPRECATE FOR #14770 -## LinearSlow Scalar indexing: Canonical method is full dimensionality of Ints -_getindex(::LinearSlow, A::AbstractArray) = (@_propagate_inbounds_meta; getindex(A, _to_subscript_indices(A)...)) -function _getindex(::LinearSlow, A::AbstractArray, I::Int...) +## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints +_getindex(::IndexCartesian, A::AbstractArray) = (@_propagate_inbounds_meta; getindex(A, _to_subscript_indices(A)...)) +function _getindex(::IndexCartesian, A::AbstractArray, I::Int...) @_inline_meta @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking @inbounds r = getindex(A, _to_subscript_indices(A, I...)...) r end -_getindex{T,N}(::LinearSlow, A::AbstractArray{T,N}, I::Vararg{Int, N}) = (@_propagate_inbounds_meta; getindex(A, I...)) +_getindex{T,N}(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) = (@_propagate_inbounds_meta; getindex(A, I...)) _to_subscript_indices(A::AbstractArray, i::Int) = (@_inline_meta; _unsafe_ind2sub(A, i)) _to_subscript_indices{T,N}(A::AbstractArray{T,N}) = (@_inline_meta; fill_to_length((), 1, Val{N})) # TODO: DEPRECATE FOR #14770 _to_subscript_indices{T}(A::AbstractArray{T,0}) = () # TODO: REMOVE FOR #14770 @@ -920,8 +933,8 @@ _unsafe_ind2sub(sz, i) = (@_inline_meta; ind2sub(sz, i)) # function that allows dispatch on array storage function setindex!(A::AbstractArray, v, I...) @_propagate_inbounds_meta - error_if_canonical_indexing(linearindexing(A), A, I...) - _setindex!(linearindexing(A), A, v, to_indices(A, I)...) + error_if_canonical_indexing(IndexMethod(A), A, I...) + _setindex!(IndexMethod(A), A, v, to_indices(A, I)...) end function unsafe_setindex!(A::AbstractArray, v, I...) @_inline_meta @@ -929,22 +942,22 @@ function unsafe_setindex!(A::AbstractArray, v, I...) r end ## Internal defitions -_setindex!(::LinearIndexing, A::AbstractArray, v, I...) = error("indexing $(typeof(A)) with types $(typeof(I)) is not supported") +_setindex!(::IndexMethod, A::AbstractArray, v, I...) = error("indexing $(typeof(A)) with types $(typeof(I)) is not supported") -## LinearFast Scalar indexing -_setindex!(::LinearFast, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i)) -_setindex!(::LinearFast, A::AbstractArray, v) = (@_propagate_inbounds_meta; setindex!(A, v, _to_linear_index(A))) -function _setindex!(::LinearFast, A::AbstractArray, v, I::Int...) +## IndexLinear Scalar indexing +_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i)) +_setindex!(::IndexLinear, A::AbstractArray, v) = (@_propagate_inbounds_meta; setindex!(A, v, _to_linear_index(A))) +function _setindex!(::IndexLinear, A::AbstractArray, v, I::Int...) @_inline_meta @boundscheck checkbounds(A, I...) @inbounds r = setindex!(A, v, _to_linear_index(A, I...)) r end -# LinearSlow Scalar indexing -_setindex!{T,N}(::LinearSlow, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) = (@_propagate_inbounds_meta; setindex!(A, v, I...)) -_setindex!(::LinearSlow, A::AbstractArray, v) = (@_propagate_inbounds_meta; setindex!(A, v, _to_subscript_indices(A)...)) -function _setindex!(::LinearSlow, A::AbstractArray, v, I::Int...) +# IndexCartesian Scalar indexing +_setindex!{T,N}(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) = (@_propagate_inbounds_meta; setindex!(A, v, I...)) +_setindex!(::IndexCartesian, A::AbstractArray, v) = (@_propagate_inbounds_meta; setindex!(A, v, _to_subscript_indices(A)...)) +function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Int...) @_inline_meta @boundscheck checkbounds(A, I...) @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 8c34f7aa36c77..80ee687ea43a5 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -229,7 +229,7 @@ function cumsum_kbn{T<:AbstractFloat}(v::AbstractVector{T}) end # Uses K-B-N summation -# TODO: Needs a separate LinearSlow method, this is only fast for LinearIndexing +# TODO: Needs a separate IndexCartesian method, this is only fast for IndexMethod """ cumsum_kbn(A, [dim::Integer=1]) diff --git a/base/bitarray.jl b/base/bitarray.jl index 72bcc8a46778c..90d5e3f020998 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -69,7 +69,7 @@ end isassigned(B::BitArray, i::Int) = 1 <= i <= length(B) -linearindexing(::Type{<:BitArray}) = LinearFast() +IndexMethod(::Type{<:BitArray}) = IndexLinear() ## aux functions ## diff --git a/base/deprecated.jl b/base/deprecated.jl index 43fdf4db93f7e..7807577446670 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1272,6 +1272,11 @@ for f in (:airyai, :airyaiprime, :airybi, :airybiprime, :airyaix, :airyaiprimex, end end +@deprecate_binding LinearIndexing IndexMethod +@deprecate_binding LinearFast IndexLinear +@deprecate_binding LinearSlow IndexCartesian +@deprecate linearindexing IndexMethod + # END 0.6 deprecations # BEGIN 1.0 deprecations diff --git a/base/exports.jl b/base/exports.jl index 3479a2324d444..c2e5fa0226127 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -66,9 +66,11 @@ export ExponentialBackOff, Factorization, FileMonitor, - StepRangeLen, Hermitian, UniformScaling, + IndexCartesian, + IndexLinear, + IndexMethod, InsertionSort, IntSet, IOBuffer, @@ -109,6 +111,7 @@ export SharedMatrix, SharedVector, StepRange, + StepRangeLen, StridedArray, StridedMatrix, StridedVecOrMat, diff --git a/base/linalg/conjarray.jl b/base/linalg/conjarray.jl index 3679d5607c49a..1f55e5e5987a1 100644 --- a/base/linalg/conjarray.jl +++ b/base/linalg/conjarray.jl @@ -42,8 +42,8 @@ ConjMatrix{T, M <: AbstractMatrix} = ConjArray{T, 2, M} @inline parent_type{T,N,A}(::Type{ConjArray{T,N,A}}) = A @inline size(a::ConjArray) = size(a.parent) -linearindexing{CA <: ConjArray}(::CA) = linearindexing(parent_type(CA)) -linearindexing{CA <: ConjArray}(::Type{CA}) = linearindexing(parent_type(CA)) +IndexMethod{CA <: ConjArray}(::CA) = IndexMethod(parent_type(CA)) +IndexMethod{CA <: ConjArray}(::Type{CA}) = IndexMethod(parent_type(CA)) @propagate_inbounds getindex{T,N}(a::ConjArray{T,N}, i::Int) = conj(getindex(a.parent, i)) @propagate_inbounds getindex{T,N}(a::ConjArray{T,N}, i::Vararg{Int,N}) = conj(getindex(a.parent, i...)) diff --git a/base/linalg/linalg.jl b/base/linalg/linalg.jl index 51ec2ebb76a8c..666c0380c893b 100644 --- a/base/linalg/linalg.jl +++ b/base/linalg/linalg.jl @@ -7,10 +7,10 @@ import Base: A_mul_Bt, At_ldiv_Bt, A_rdiv_Bc, At_ldiv_B, Ac_mul_Bc, A_mul_Bc, Ac Ac_ldiv_B, Ac_ldiv_Bc, At_mul_Bt, A_rdiv_Bt, At_mul_B import Base: USE_BLAS64, abs, big, broadcast, ceil, conj, convert, copy, copy!, ctranspose, eltype, eye, findmax, findmin, fill!, floor, full, getindex, - hcat, imag, indices, inv, isapprox, kron, length, linearindexing, map, + hcat, imag, indices, inv, isapprox, kron, length, IndexMethod, map, ndims, oneunit, parent, power_by_squaring, print_matrix, promote_rule, real, round, setindex!, show, similar, size, transpose, trunc, typed_hcat -using Base: promote_op, _length, iszero, @pure, @propagate_inbounds, LinearFast, +using Base: promote_op, _length, iszero, @pure, @propagate_inbounds, IndexLinear, reduce, hvcat_fill, typed_vcat, promote_typeof # We use `_length` because of non-1 indices; releases after julia 0.5 # can go back to `length`. `_length(A)` is equivalent to `length(linearindices(A))`. diff --git a/base/linalg/rowvector.jl b/base/linalg/rowvector.jl index 9af083d1f038a..3dd3be1f88689 100644 --- a/base/linalg/rowvector.jl +++ b/base/linalg/rowvector.jl @@ -110,8 +110,8 @@ julia> conj(v) @inline size(rowvec::RowVector, d) = ifelse(d==2, length(rowvec.vec), 1) @inline indices(rowvec::RowVector) = (Base.OneTo(1), indices(rowvec.vec)[1]) @inline indices(rowvec::RowVector, d) = ifelse(d == 2, indices(rowvec.vec)[1], Base.OneTo(1)) -linearindexing(::RowVector) = LinearFast() -linearindexing(::Type{<:RowVector}) = LinearFast() +IndexMethod(::RowVector) = IndexLinear() +IndexMethod(::Type{<:RowVector}) = IndexLinear() @propagate_inbounds getindex(rowvec::RowVector, i) = transpose(rowvec.vec[i]) @propagate_inbounds setindex!(rowvec::RowVector, v, i) = setindex!(rowvec.vec, transpose(v), i) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 07eb83a273b0e..c1017349ad4dd 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -3,12 +3,12 @@ ### Multidimensional iterators module IteratorsMD import Base: eltype, length, size, start, done, next, last, in, getindex, - setindex!, linearindexing, min, max, zero, one, isless, eachindex, + setindex!, IndexMethod, min, max, zero, one, isless, eachindex, ndims, iteratorsize, convert importall ..Base.Operators import Base: simd_outer_range, simd_inner_length, simd_index - using Base: LinearFast, LinearSlow, AbstractCartesianIndex, fill_to_length, tail + using Base: IndexLinear, IndexCartesian, AbstractCartesianIndex, fill_to_length, tail export CartesianIndex, CartesianRange @@ -100,9 +100,9 @@ module IteratorsMD ndims(R::CartesianRange) = length(R.start) ndims{I<:CartesianIndex}(::Type{CartesianRange{I}}) = length(I) - eachindex(::LinearSlow, A::AbstractArray) = CartesianRange(indices(A)) + eachindex(::IndexCartesian, A::AbstractArray) = CartesianRange(indices(A)) - @inline eachindex(::LinearSlow, A::AbstractArray, B::AbstractArray...) = + @inline eachindex(::IndexCartesian, A::AbstractArray, B::AbstractArray...) = CartesianRange(maxsize((), A, B...)) maxsize(sz) = sz @inline maxsize(sz, A, B...) = maxsize(maxt(sz, size(A)), B...) @@ -363,9 +363,9 @@ end end # As an optimization, we allow trailing Array{Bool} and BitArray to be linear over trailing dimensions @inline to_indices{N}(A, inds, I::Tuple{Union{Array{Bool,N}, BitArray{N}}}) = - (_maybe_linear_logical_index(linearindexing(A), A, I[1]),) -_maybe_linear_logical_index(::LinearIndexing, A, i) = to_index(A, i) -_maybe_linear_logical_index(::LinearFast, A, i) = LogicalIndex{Int}(i) + (_maybe_linear_logical_index(IndexMethod(A), A, I[1]),) +_maybe_linear_logical_index(::IndexMethod, A, i) = to_index(A, i) +_maybe_linear_logical_index(::IndexLinear, A, i) = LogicalIndex{Int}(i) # Colons get converted to slices by `uncolon` @inline to_indices(A, inds, I::Tuple{Colon, Vararg{Any}}) = @@ -389,7 +389,7 @@ getindex(t::Tuple, i::CartesianIndex{1}) = getindex(t, i.I[1]) # These are not defined on directly on getindex to avoid # ambiguities for AbstractArray subtypes. See the note in abstractarray.jl -@generated function _getindex(l::LinearIndexing, A::AbstractArray, I::Union{Real, AbstractArray}...) +@generated function _getindex(l::IndexMethod, A::AbstractArray, I::Union{Real, AbstractArray}...) N = length(I) quote @_inline_meta @@ -397,14 +397,14 @@ getindex(t::Tuple, i::CartesianIndex{1}) = getindex(t, i.I[1]) _unsafe_getindex(l, _maybe_reshape(l, A, I...), I...) end end -# But we can speed up LinearSlow arrays by reshaping them to the appropriate dimensionality: -_maybe_reshape(::LinearFast, A::AbstractArray, I...) = A -_maybe_reshape(::LinearSlow, A::AbstractVector, I...) = A -@inline _maybe_reshape(::LinearSlow, A::AbstractArray, I...) = __maybe_reshape(A, index_ndims(I...)) +# But we can speed up IndexCartesian arrays by reshaping them to the appropriate dimensionality: +_maybe_reshape(::IndexLinear, A::AbstractArray, I...) = A +_maybe_reshape(::IndexCartesian, A::AbstractVector, I...) = A +@inline _maybe_reshape(::IndexCartesian, A::AbstractArray, I...) = __maybe_reshape(A, index_ndims(I...)) @inline __maybe_reshape{T,N}(A::AbstractArray{T,N}, ::NTuple{N,Any}) = A @inline __maybe_reshape{N}(A::AbstractArray, ::NTuple{N,Any}) = reshape(A, Val{N}) -@generated function _unsafe_getindex(::LinearIndexing, A::AbstractArray, I::Union{Real, AbstractArray}...) +@generated function _unsafe_getindex(::IndexMethod, A::AbstractArray, I::Union{Real, AbstractArray}...) N = length(I) quote # This is specifically not inlined to prevent exessive allocations in type unstable code @@ -435,7 +435,7 @@ end @noinline throw_checksize_error(A, sz) = throw(DimensionMismatch("output array is the wrong size; expected $sz, got $(size(A))")) ## setindex! ## -@generated function _setindex!(l::LinearIndexing, A::AbstractArray, x, I::Union{Real, AbstractArray}...) +@generated function _setindex!(l::IndexMethod, A::AbstractArray, x, I::Union{Real, AbstractArray}...) N = length(I) quote @_inline_meta @@ -447,7 +447,7 @@ end _iterable(v::AbstractArray) = v _iterable(v) = Iterators.repeated(v) -@generated function _unsafe_setindex!(::LinearIndexing, A::AbstractArray, x, I::Union{Real,AbstractArray}...) +@generated function _unsafe_setindex!(::IndexMethod, A::AbstractArray, x, I::Union{Real,AbstractArray}...) N = length(I) quote X = _iterable(x) @@ -749,7 +749,7 @@ end function copy!{T,N}(dest::AbstractArray{T,N}, src::AbstractArray{T,N}) @boundscheck checkbounds(dest, indices(src)...) - for I in eachindex(linearindexing(src,dest), src) + for I in eachindex(IndexMethod(src,dest), src) @inbounds dest[I] = src[I] end dest diff --git a/base/multinverses.jl b/base/multinverses.jl index 765d5a55f0804..39109d16bcac8 100644 --- a/base/multinverses.jl +++ b/base/multinverses.jl @@ -3,7 +3,7 @@ module MultiplicativeInverses import Base: div, divrem, rem, unsigned -using Base: LinearFast, LinearSlow, tail +using Base: IndexLinear, IndexCartesian, tail export multiplicativeinverse unsigned(::Type{Int8}) = UInt8 diff --git a/base/reduce.jl b/base/reduce.jl index eafd39bb173de..9f1973ca481d2 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -246,9 +246,9 @@ mr_empty_iter(f, op::typeof(&), itr, ::EltypeUnknown) = true mr_empty_iter(f, op::typeof(|), itr, ::EltypeUnknown) = false mr_empty_iter(f, op, itr, ::EltypeUnknown) = _empty_reduce_error() -_mapreduce(f, op, A::AbstractArray) = _mapreduce(f, op, linearindexing(A), A) +_mapreduce(f, op, A::AbstractArray) = _mapreduce(f, op, IndexMethod(A), A) -function _mapreduce{T}(f, op, ::LinearFast, A::AbstractArray{T}) +function _mapreduce{T}(f, op, ::IndexLinear, A::AbstractArray{T}) inds = linearindices(A) n = length(inds) @inbounds begin @@ -272,9 +272,9 @@ function _mapreduce{T}(f, op, ::LinearFast, A::AbstractArray{T}) end end -_mapreduce(f, op, ::LinearSlow, A::AbstractArray) = mapfoldl(f, op, A) +_mapreduce(f, op, ::IndexCartesian, A::AbstractArray) = mapfoldl(f, op, A) -mapreduce(f, op, A::AbstractArray) = _mapreduce(f, op, linearindexing(A), A) +mapreduce(f, op, A::AbstractArray) = _mapreduce(f, op, IndexMethod(A), A) mapreduce(f, op, a::Number) = f(a) """ diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 94e3d3f924613..7963841d55eb8 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -9,7 +9,7 @@ struct ReshapedArray{T,N,P<:AbstractArray,MI<:Tuple{Vararg{SignedMultiplicativeI end ReshapedArray{T,N}(parent::AbstractArray{T}, dims::NTuple{N,Int}, mi) = ReshapedArray{T,N,typeof(parent),typeof(mi)}(parent, dims, mi) -# LinearFast ReshapedArray +# IndexLinear ReshapedArray ReshapedArrayLF{T,N,P<:AbstractArray} = ReshapedArray{T,N,P,Tuple{}} # Fast iteration on ReshapedArrays: use the parent iterator @@ -139,14 +139,14 @@ end function _reshape(parent::AbstractArray, dims::Dims) n = _length(parent) prod(dims) == n || throw(DimensionMismatch("parent has $n elements, which is incompatible with size $dims")) - __reshape((parent, linearindexing(parent)), dims) + __reshape((parent, IndexMethod(parent)), dims) end # Reshaping a ReshapedArray _reshape(v::ReshapedArray{<:Any,1}, dims::Dims{1}) = _reshape(v.parent, dims) _reshape(R::ReshapedArray, dims::Dims) = _reshape(R.parent, dims) -function __reshape(p::Tuple{AbstractArray,LinearSlow}, dims::Dims) +function __reshape(p::Tuple{AbstractArray,IndexCartesian}, dims::Dims) parent = p[1] strds = front(size_strides(parent)) strds1 = map(s->max(1,s), strds) # for resizing empty arrays @@ -154,7 +154,7 @@ function __reshape(p::Tuple{AbstractArray,LinearSlow}, dims::Dims) ReshapedArray(parent, dims, reverse(mi)) end -function __reshape(p::Tuple{AbstractArray,LinearFast}, dims::Dims) +function __reshape(p::Tuple{AbstractArray,IndexLinear}, dims::Dims) parent = p[1] ReshapedArray(parent, dims, ()) end @@ -165,7 +165,7 @@ size_strides(out::Tuple) = out size(A::ReshapedArray) = A.dims similar(A::ReshapedArray, eltype::Type, dims::Dims) = similar(parent(A), eltype, dims) -linearindexing(::Type{<:ReshapedArrayLF}) = LinearFast() +IndexMethod(::Type{<:ReshapedArrayLF}) = IndexLinear() parent(A::ReshapedArray) = A.parent parentindexes(A::ReshapedArray) = map(s->1:s, size(parent(A))) reinterpret{T}(::Type{T}, A::ReshapedArray, dims::Dims) = reinterpret(T, parent(A), dims) diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 134445c898f41..c0e2adf235b5b 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -256,7 +256,7 @@ SharedMatrix{T} = SharedArray{T,2} length(S::SharedArray) = prod(S.dims) size(S::SharedArray) = S.dims ndims(S::SharedArray) = length(S.dims) -linearindexing(::Type{<:SharedArray}) = LinearFast() +IndexMethod(::Type{<:SharedArray}) = IndexLinear() function reshape{T,N}(a::SharedArray{T}, dims::NTuple{N,Int}) if length(a) != prod(dims) diff --git a/base/sort.jl b/base/sort.jl index 424fd92012a98..3dcb830a32398 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -2,7 +2,7 @@ module Sort -using Base: Order, Checked, copymutable, linearindices, linearindexing, viewindexing, LinearFast, _length +using Base: Order, Checked, copymutable, linearindices, IndexMethod, viewindexing, IndexLinear, _length import Base.sort, @@ -774,7 +774,7 @@ end function slicetypeof{T}(A::AbstractArray{T}, i1, i2) I = map(slice_dummy, to_indices(A, (i1, i2))) - fast = isa(linearindexing(viewindexing(I), linearindexing(A)), LinearFast) + fast = isa(IndexMethod(viewindexing(I), IndexMethod(A)), IndexLinear) SubArray{T,1,typeof(A),typeof(I),fast} end slice_dummy(S::Slice) = S diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index 094c50174feee..db4bff81860be 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -3,7 +3,7 @@ module CHOLMOD import Base: (*), convert, copy, eltype, get, getindex, show, size, - linearindexing, LinearFast, LinearSlow, ctranspose + IndexMethod, IndexLinear, IndexCartesian, ctranspose 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, @@ -1225,7 +1225,7 @@ function size(F::Factor, i::Integer) end size(F::Factor) = (size(F, 1), size(F, 2)) -linearindexing(::Dense) = LinearFast() +IndexMethod(::Dense) = IndexLinear() size(FC::FactorComponent, i::Integer) = size(FC.F, i) size(FC::FactorComponent) = size(FC.F) @@ -1246,7 +1246,7 @@ function getindex(A::Dense, i::Integer) unsafe_load(s.x, i) end -linearindexing(::Sparse) = LinearSlow() +IndexMethod(::Sparse) = IndexCartesian() function getindex{T}(A::Sparse{T}, i0::Integer, i1::Integer) s = unsafe_load(get(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 13b8c4144d301..954d1f1c23a3a 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -1522,7 +1522,7 @@ function _mapreducezeros(f, op, T::Type, nzeros::Int, v0) v end -function Base._mapreduce{T}(f, op, ::Base.LinearSlow, A::SparseMatrixCSC{T}) +function Base._mapreduce{T}(f, op, ::Base.IndexCartesian, A::SparseMatrixCSC{T}) z = nnz(A) n = length(A) if z == 0 diff --git a/base/subarray.jl b/base/subarray.jl index ba083b330b521..fee0271f147ab 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -19,13 +19,13 @@ end # Compute the linear indexability of the indices, and combine it with the linear indexing of the parent function SubArray(parent::AbstractArray, indexes::Tuple) @_inline_meta - SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, ensure_indexable(indexes), index_dimsum(indexes...)) + SubArray(IndexMethod(viewindexing(indexes), IndexMethod(parent)), parent, ensure_indexable(indexes), index_dimsum(indexes...)) end -function SubArray(::LinearSlow, parent::P, indexes::I, ::NTuple{N,Any}) where {P,I,N} +function SubArray(::IndexCartesian, parent::P, indexes::I, ::NTuple{N,Any}) where {P,I,N} @_inline_meta SubArray{eltype(P), N, P, I, false}(parent, indexes, 0, 0) end -function SubArray(::LinearFast, parent::P, indexes::I, ::NTuple{N,Any}) where {P,I,N} +function SubArray(::IndexLinear, parent::P, indexes::I, ::NTuple{N,Any}) where {P,I,N} @_inline_meta # Compute the stride and offset stride1 = compute_stride1(parent, indexes) @@ -38,19 +38,19 @@ check_parent_index_match{N}(parent, ::NTuple{N, Bool}) = throw(ArgumentError("number of indices ($N) must match the parent dimensionality ($(ndims(parent)))")) # This computes the linear indexing compatability for a given tuple of indices -viewindexing() = LinearFast() +viewindexing() = IndexLinear() # Leading scalar indexes simply increase the stride viewindexing(I::Tuple{ScalarIndex, Vararg{Any}}) = (@_inline_meta; viewindexing(tail(I))) # Slices may begin a section which may be followed by any number of Slices viewindexing(I::Tuple{Slice, Slice, Vararg{Any}}) = (@_inline_meta; viewindexing(tail(I))) # A UnitRange can follow Slices, but only if all other indices are scalar -viewindexing(I::Tuple{Slice, UnitRange, Vararg{ScalarIndex}}) = LinearFast() +viewindexing(I::Tuple{Slice, UnitRange, Vararg{ScalarIndex}}) = IndexLinear() # In general, ranges are only fast if all other indices are scalar -viewindexing(I::Tuple{Union{Range, Slice}, Vararg{ScalarIndex}}) = LinearFast() +viewindexing(I::Tuple{Union{Range, Slice}, Vararg{ScalarIndex}}) = IndexLinear() # All other index combinations are slow -viewindexing(I::Tuple{Vararg{Any}}) = LinearSlow() +viewindexing(I::Tuple{Vararg{Any}}) = IndexCartesian() # Of course, all other array types are slow -viewindexing(I::Tuple{AbstractArray, Vararg{Any}}) = LinearSlow() +viewindexing(I::Tuple{AbstractArray, Vararg{Any}}) = IndexCartesian() # Simple utilities size(V::SubArray) = (@_inline_meta; map(n->Int(unsafe_length(n)), indices(V))) @@ -221,8 +221,8 @@ function setindex!(V::FastContiguousSubArray, x, i::Int) V end -linearindexing(::Type{<:FastSubArray}) = LinearFast() -linearindexing(::Type{<:SubArray}) = LinearSlow() +IndexMethod(::Type{<:FastSubArray}) = IndexLinear() +IndexMethod(::Type{<:SubArray}) = IndexCartesian() # Strides are the distance between adjacent elements in a given dimension, # so they are well-defined even for non-linear memory layouts diff --git a/doc/src/devdocs/boundscheck.md b/doc/src/devdocs/boundscheck.md index 178bedc4e5a59..b921cbe59fcfa 100644 --- a/doc/src/devdocs/boundscheck.md +++ b/doc/src/devdocs/boundscheck.md @@ -42,8 +42,8 @@ code further up the stack. There may be certain scenarios where for code-organization reasons you want more than one layer between the `@inbounds` and `@boundscheck` declarations. For instance, the default `getindex` -methods have the chain `getindex(A::AbstractArray, i::Real)` calls `getindex(linearindexing(A), A, i)` -calls `_getindex(::LinearFast, A, i)`. +methods have the chain `getindex(A::AbstractArray, i::Real)` calls `getindex(IndexMethod(A), A, i)` +calls `_getindex(::IndexLinear, A, i)`. To override the "one layer of inlining" rule, a function may be marked with `@propagate_inbounds` to propagate an inbounds context (or out of bounds context) through one additional layer of inlining. diff --git a/doc/src/devdocs/subarrays.md b/doc/src/devdocs/subarrays.md index fafe9869e03ca..8055e72865b38 100644 --- a/doc/src/devdocs/subarrays.md +++ b/doc/src/devdocs/subarrays.md @@ -139,10 +139,10 @@ a given set of indices supports fast linear indexing with the internal `Base.vie ```julia julia> Base.viewindexing(S1.indexes) -Base.LinearSlow() +IndexCartesian() julia> Base.viewindexing(S2.indexes) -Base.LinearFast() +IndexLinear() ``` This is computed during construction of the `SubArray` and stored in the `L` type parameter as diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index 1cf8d4eb4d160..5edb6235c118d 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -513,11 +513,11 @@ iterate over any array type. If you write a custom `AbstractArray` type, you can specify that it has fast linear indexing using ```julia -Base.linearindexing{T<:MyArray}(::Type{T}) = LinearFast() +Base.IndexMethod{T<:MyArray}(::Type{T}) = IndexLinear() ``` This setting will cause `eachindex` iteration over a `MyArray` to use integers. If you don't -specify this trait, the default value `LinearSlow()` is used. +specify this trait, the default value `IndexCartesian()` is used. ### Vectorized Operators and Functions diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 04d4f550a5c66..b57a7831c654b 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -194,12 +194,12 @@ ourselves, we can officially define it as a subtype of an `AbstractArray`. | Methods to implement |   | Brief description | |:----------------------------------------------- |:---------------------------------------- |:------------------------------------------------------------------------------------- | | `size(A)` |   | Returns a tuple containing the dimensions of `A` | -| `getindex(A, i::Int)` |   | (if `LinearFast`) Linear scalar indexing | -| `getindex(A, I::Vararg{Int, N})` |   | (if `LinearSlow`, where `N = ndims(A)`) N-dimensional scalar indexing | -| `setindex!(A, v, i::Int)` |   | (if `LinearFast`) Scalar indexed assignment | -| `setindex!(A, v, I::Vararg{Int, N})` |   | (if `LinearSlow`, where `N = ndims(A)`) N-dimensional scalar indexed assignment | +| `getindex(A, i::Int)` |   | (if `IndexLinear`) Linear scalar indexing | +| `getindex(A, I::Vararg{Int, N})` |   | (if `IndexCartesian`, where `N = ndims(A)`) N-dimensional scalar indexing | +| `setindex!(A, v, i::Int)` |   | (if `IndexLinear`) Scalar indexed assignment | +| `setindex!(A, v, I::Vararg{Int, N})` |   | (if `IndexCartesian`, where `N = ndims(A)`) N-dimensional scalar indexed assignment | | **Optional methods** | **Default definition** | **Brief description** | -| `Base.linearindexing(::Type)` | `Base.LinearSlow()` | Returns either `Base.LinearFast()` or `Base.LinearSlow()`. See the description below. | +| `IndexMethod(::Type)` | `IndexCartesian()` | Returns either `IndexLinear()` or `IndexCartesian()`. See the description below. | | `getindex(A, I...)` | defined in terms of scalar `getindex()` | [Multidimensional and nonscalar indexing](@ref man-array-indexing) | | `setindex!(A, I...)` | defined in terms of scalar `setindex!()` | [Multidimensional and nonscalar indexed assignment](@ref man-array-indexing) | | `start()`/`next()`/`done()` | defined in terms of scalar `getindex()` | Iteration | @@ -217,19 +217,19 @@ If a type is defined as a subtype of `AbstractArray`, it inherits a very large s including iteration and multidimensional indexing built on top of single-element access. See the [arrays manual page](@ref man-multi-dim-arrays) and [standard library section](@ref lib-arrays) for more supported methods. -A key part in defining an `AbstractArray` subtype is [`Base.linearindexing()`](@ref). Since indexing is +A key part in defining an `AbstractArray` subtype is [`IndexMethod`](@ref). Since indexing is such an important part of an array and often occurs in hot loops, it's important to make both indexing and indexed assignment as efficient as possible. Array data structures are typically defined in one of two ways: either it most efficiently accesses its elements using just one index (linear indexing) or it intrinsically accesses the elements with indices specified for every dimension. - These two modalities are identified by Julia as `Base.LinearFast()` and `Base.LinearSlow()`. + These two modalities are identified by Julia as `IndexLinear()` and `IndexCartesian()`. Converting a linear index to multiple indexing subscripts is typically very expensive, so this provides a traits-based mechanism to enable efficient generic code for all array types. -This distinction determines which scalar indexing methods the type must define. `LinearFast()` +This distinction determines which scalar indexing methods the type must define. `IndexLinear()` arrays are simple: just define `getindex(A::ArrayType, i::Int)`. When the array is subsequently indexed with a multidimensional set of indices, the fallback `getindex(A::AbstractArray, I...)()` -efficiently converts the indices into one linear index and then calls the above method. `LinearSlow()` +efficiently converts the indices into one linear index and then calls the above method. `IndexCartesian()` arrays, on the other hand, require methods to be defined for each supported dimensionality with `ndims(A)``Int` indices. For example, the builtin `SparseMatrixCSC` type only supports two dimensions, so it just defines `getindex(A::SparseMatrixCSC, i::Int, j::Int)()`. The same holds for `setindex!()`. @@ -244,7 +244,7 @@ julia> struct SquaresVector <: AbstractArray{Int, 1} julia> Base.size(S::SquaresVector) = (S.count,) -julia> Base.linearindexing{T<:SquaresVector}(::Type{T}) = Base.LinearFast() +julia> Base.IndexMethod{T<:SquaresVector}(::Type{T}) = IndexLinear() julia> Base.getindex(S::SquaresVector, i::Int) = i*i ``` @@ -301,7 +301,7 @@ julia> Base.getindex{T,N}(A::SparseArray{T,N}, I::Vararg{Int,N}) = get(A.data, I julia> Base.setindex!{T,N}(A::SparseArray{T,N}, v, I::Vararg{Int,N}) = (A.data[I] = v) ``` -Notice that this is a `LinearSlow` array, so we must manually define [`getindex()`](@ref) and [`setindex!()`](@ref) +Notice that this is a `IndexCartesian` array, so we must manually define [`getindex()`](@ref) and [`setindex!()`](@ref) at the dimensionality of the array. Unlike the `SquaresVector`, we are able to define [`setindex!()`](@ref), and so we can mutate the array: @@ -370,4 +370,3 @@ If you are defining an array type that allows non-traditional indexing (indices something other than 1), you should specialize `indices`. You should also specialize [`similar`](@ref) so that the `dims` argument (ordinarily a `Dims` size-tuple) can accept `AbstractUnitRange` objects, perhaps range-types `Ind` of your own design. For more information, see [Arrays with custom indices](@ref). - diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index 1043845c2651e..4c80cce6f130e 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -10,7 +10,7 @@ Base.indices(::AbstractArray, ::Any) Base.length(::AbstractArray) Base.eachindex Base.linearindices -Base.linearindexing +Base.IndexMethod Base.countnz Base.conj! Base.stride diff --git a/test/TestHelpers.jl b/test/TestHelpers.jl index 5be66c81f78ed..3c366cfc3ef7e 100644 --- a/test/TestHelpers.jl +++ b/test/TestHelpers.jl @@ -53,7 +53,7 @@ end module OAs -using Base: Indices, LinearSlow, LinearFast, tail +using Base: Indices, IndexCartesian, IndexLinear, tail export OffsetArray @@ -69,7 +69,7 @@ OffsetArray{T,N}(A::AbstractArray{T,N}, offsets::Vararg{Int,N}) = OffsetArray(A, (::Type{OffsetArray{T,N}}){T,N}(inds::Indices{N}) = OffsetArray{T,N,Array{T,N}}(Array{T,N}(map(length, inds)), map(indsoffset, inds)) (::Type{OffsetArray{T}}){T,N}(inds::Indices{N}) = OffsetArray{T,N}(inds) -Base.linearindexing{T<:OffsetArray}(::Type{T}) = Base.linearindexing(parenttype(T)) +Base.IndexMethod{T<:OffsetArray}(::Type{T}) = Base.IndexMethod(parenttype(T)) parenttype{T,N,AA}(::Type{OffsetArray{T,N,AA}}) = AA parenttype(A::OffsetArray) = parenttype(typeof(A)) @@ -78,8 +78,8 @@ Base.parent(A::OffsetArray) = A.parent errmsg(A) = error("size not supported for arrays with indices $(indices(A)); see http://docs.julialang.org/en/latest/devdocs/offset-arrays/") Base.size(A::OffsetArray) = errmsg(A) Base.size(A::OffsetArray, d) = errmsg(A) -Base.eachindex(::LinearSlow, A::OffsetArray) = CartesianRange(indices(A)) -Base.eachindex(::LinearFast, A::OffsetVector) = indices(A, 1) +Base.eachindex(::IndexCartesian, A::OffsetArray) = CartesianRange(indices(A)) +Base.eachindex(::IndexLinear, A::OffsetVector) = indices(A, 1) # Implementations of indices and indices1. Since bounds-checking is # performance-critical and relies on indices, these are usually worth diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 5bd1f95cef8bf..49b05fb8044e7 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -191,8 +191,8 @@ Base.convert{T,N,_}(::Type{T24Linear{T }}, X::AbstractArray{_,N}) = convert(T24 Base.convert{T,N }(::Type{T24Linear{T,N}}, X::AbstractArray ) = T24Linear{T,N,size(X)}(X...) Base.size{T,N,dims}(::T24Linear{T,N,dims}) = dims -import Base: LinearFast -Base.linearindexing{A<:T24Linear}(::Type{A}) = LinearFast() +import Base: IndexLinear +Base.IndexMethod{A<:T24Linear}(::Type{A}) = IndexLinear() Base.getindex(A::T24Linear, i::Int) = getfield(A, i) Base.setindex!{T}(A::T24Linear{T}, v, i::Int) = setfield!(A, i, convert(T, v)) @@ -217,8 +217,8 @@ end Base.size(A::TSlow) = A.dims Base.similar{T}(A::TSlow, ::Type{T}, dims::Dims) = TSlow(T, dims) -import Base: LinearSlow -Base.linearindexing{A<:TSlow}(::Type{A}) = LinearSlow() +import Base: IndexCartesian +Base.IndexMethod{A<:TSlow}(::Type{A}) = IndexCartesian() # Until #11242 is merged, we need to define each dimension independently Base.getindex{T}(A::TSlow{T,0}) = get(A.data, (), zero(T)) Base.getindex{T}(A::TSlow{T,1}, i1::Int) = get(A.data, (i1,), zero(T)) @@ -451,10 +451,10 @@ function test_in_bounds(::Type{TestAbstractArray}) end mutable struct UnimplementedFastArray{T, N} <: AbstractArray{T, N} end -Base.linearindexing(::UnimplementedFastArray) = Base.LinearFast() +Base.IndexMethod(::UnimplementedFastArray) = Base.IndexLinear() mutable struct UnimplementedSlowArray{T, N} <: AbstractArray{T, N} end -Base.linearindexing(::UnimplementedSlowArray) = Base.LinearSlow() +Base.IndexMethod(::UnimplementedSlowArray) = Base.IndexCartesian() mutable struct UnimplementedArray{T, N} <: AbstractArray{T, N} end @@ -593,7 +593,7 @@ end mutable struct TSlowNIndexes{T,N} <: AbstractArray{T,N} data::Array{T,N} end -Base.linearindexing{A<:TSlowNIndexes}(::Type{A}) = Base.LinearSlow() +Base.IndexMethod{A<:TSlowNIndexes}(::Type{A}) = Base.IndexCartesian() Base.size(A::TSlowNIndexes) = size(A.data) Base.getindex(A::TSlowNIndexes, index::Int...) = error("Must use $(ndims(A)) indexes") Base.getindex{T}(A::TSlowNIndexes{T,2}, i::Int, j::Int) = A.data[i,j] diff --git a/test/arrayops.jl b/test/arrayops.jl index a35b1527dcc68..1ac82b6188beb 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -189,7 +189,7 @@ end @test convert(Vector{Float64}, b) == b end -@testset "operations with LinearFast ReshapedArray" begin +@testset "operations with IndexLinear ReshapedArray" begin b = collect(1:12) a = Base.ReshapedArray(b, (4,3), ()) @test a[3,2] == 7 @@ -1333,11 +1333,11 @@ end @testset "linear indexing" begin a = [1:5;] - @test isa(Base.linearindexing(a), Base.LinearFast) + @test isa(Base.IndexMethod(a), Base.IndexLinear) b = view(a, :) - @test isa(Base.linearindexing(b), Base.LinearFast) - @test isa(Base.linearindexing(trues(2)), Base.LinearFast) - @test isa(Base.linearindexing(BitArray{2}), Base.LinearFast) + @test isa(Base.IndexMethod(b), Base.IndexLinear) + @test isa(Base.IndexMethod(trues(2)), Base.IndexLinear) + @test isa(Base.IndexMethod(BitArray{2}), Base.IndexLinear) aa = fill(99, 10) aa[1:2:9] = a shp = [5] @@ -1347,7 +1347,7 @@ end @test mdsum2(A) == 15 AA = reshape(aa, tuple(2, shp...)) B = view(AA, 1:1, ntuple(i->Colon(), i)...) - @test isa(Base.linearindexing(B), Base.IteratorsMD.LinearSlow) + @test isa(Base.IndexMethod(B), Base.IteratorsMD.IndexCartesian) @test mdsum(B) == 15 @test mdsum2(B) == 15 unshift!(shp, 1) @@ -1528,8 +1528,8 @@ R = CartesianRange((0,3)) R = CartesianRange((3,0)) @test done(R, start(R)) == true -@test @inferred(eachindex(Base.LinearSlow(),zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2))) == CartesianRange((3,2,2)) -@test @inferred(eachindex(Base.LinearFast(),zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2))) == 1:8 +@test @inferred(eachindex(Base.IndexCartesian(),zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2))) == CartesianRange((3,2,2)) +@test @inferred(eachindex(Base.IndexLinear(),zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2))) == 1:8 @test @inferred(eachindex(zeros(3),view(zeros(3,3),1:2,1:2),zeros(2,2,2),zeros(2,2))) == CartesianRange((3,2,2)) @test @inferred(eachindex(zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2))) == 1:8 @@ -1659,14 +1659,14 @@ B = 1.5:5.5 end ### -### LinearSlow workout +### IndexCartesian workout ### struct LinSlowMatrix{T} <: DenseArray{T,2} data::Matrix{T} end # This is the default, but just to be sure -Base.linearindexing{A<:LinSlowMatrix}(::Type{A}) = Base.LinearSlow() +Base.IndexMethod{A<:LinSlowMatrix}(::Type{A}) = Base.IndexCartesian() Base.size(A::LinSlowMatrix) = size(A.data) @@ -1755,7 +1755,7 @@ struct SquaresVector <: AbstractArray{Int, 1} count::Int end Base.size(S::SquaresVector) = (S.count,) -Base.linearindexing(::Type{SquaresVector}) = Base.LinearFast() +Base.IndexMethod(::Type{SquaresVector}) = Base.IndexLinear() Base.getindex(S::SquaresVector, i::Int) = i*i foo_squares = SquaresVector(5) @test convert(Array{Int}, foo_squares) == [1,4,9,16,25] diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 909ffe6de63b0..3d9e1355b9b27 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -15,8 +15,8 @@ h = OffsetArray([-1,1,-2,2,0], (-3,)) @test_throws ErrorException size(v, 1) A0 = [1 3; 2 4] -A = OffsetArray(A0, (-1,2)) # LinearFast -S = OffsetArray(view(A0, 1:2, 1:2), (-1,2)) # LinearSlow +A = OffsetArray(A0, (-1,2)) # IndexLinear +S = OffsetArray(view(A0, 1:2, 1:2), (-1,2)) # IndexCartesian @test indices(A) == indices(S) == (0:1, 3:4) @test_throws ErrorException size(A) @test_throws ErrorException size(A, 1) diff --git a/test/perf/array/indexing.jl b/test/perf/array/indexing.jl index 0f6af0e181919..f7a48a67c82a7 100644 --- a/test/perf/array/indexing.jl +++ b/test/perf/array/indexing.jl @@ -106,10 +106,10 @@ end abstract type MyArray{T,N} <: AbstractArray{T,N} end -struct ArrayLS{T,N} <: MyArray{T,N} # LinearSlow +struct ArrayLS{T,N} <: MyArray{T,N} # IndexCartesian data::Array{T,N} end -struct ArrayLSLS{T,N} <: MyArray{T,N} # LinearSlow with LinearSlow similar +struct ArrayLSLS{T,N} <: MyArray{T,N} # IndexCartesian with IndexCartesian similar data::Array{T,N} end Base.similar{T}(A::ArrayLSLS, ::Type{T}, dims::Tuple{Vararg{Int}}) = ArrayLSLS(similar(A.data, T, dims)) @@ -117,7 +117,7 @@ Base.similar{T}(A::ArrayLSLS, ::Type{T}, dims::Tuple{Vararg{Int}}) = ArrayLSLS(s @inline Base.unsafe_setindex!(A::ArrayLSLS, v, I::Int...) = Base.unsafe_setindex!(A.data, v, I...) Base.first(A::ArrayLSLS) = first(A.data) -struct ArrayLF{T,N} <: MyArray{T,N} # LinearFast +struct ArrayLF{T,N} <: MyArray{T,N} # IndexLinear data::Array{T,N} end struct ArrayStrides{T,N} <: MyArray{T,N} @@ -145,10 +145,10 @@ Base.size(A::MyArray) = size(A.data) @inline Base.unsafe_getindex{T}(A::ArrayStrides{T,2}, i::Real, j::Real) = unsafe_getindex(A.data, 1+A.strides[1]*(i-1)+A.strides[2]*(j-1)) @inline Base.unsafe_getindex(A::ArrayStrides1, i::Real, j::Real) = unsafe_getindex(A.data, i + A.stride1*(j-1)) -# Using the qualified Base.LinearFast() in the linearindexing definition +# Using the qualified Base.IndexLinear() in the IndexMethod definition # requires looking up the symbol in the module on each call. -import Base: LinearFast -Base.linearindexing{T<:ArrayLF}(::Type{T}) = LinearFast() +import Base: IndexLinear +Base.IndexMethod{T<:ArrayLF}(::Type{T}) = IndexLinear() if !applicable(unsafe_getindex, [1 2], 1:1, 2) @inline Base.unsafe_getindex(A::Array, I...) = @inbounds return A[I...] diff --git a/test/subarray.jl b/test/subarray.jl index 0ff38ff999298..f0a061b07ff3f 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -545,13 +545,13 @@ let size=(x,y)-> error("should not happen"), Base=nothing end # issue #18034 -# ensure that it is possible to create an isbits, LinearFast view of an immutable Array +# ensure that it is possible to create an isbits, IndexLinear view of an immutable Array let struct ImmutableTestArray{T, N} <: Base.DenseArray{T, N} end Base.size(::Union{ImmutableTestArray, Type{ImmutableTestArray}}) = (0, 0) - Base.linearindexing(::Union{ImmutableTestArray, Type{ImmutableTestArray}}) = Base.LinearFast() + Base.IndexMethod(::Union{ImmutableTestArray, Type{ImmutableTestArray}}) = Base.IndexLinear() a = ImmutableTestArray{Float64, 2}() - @test Base.linearindexing(view(a, :, :)) == Base.LinearFast() + @test Base.IndexMethod(view(a, :, :)) == Base.IndexLinear() @test isbits(view(a, :, :)) end