diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 94bf3170feb38..df0dc88efe347 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -387,6 +387,7 @@ function eachindex(A::AbstractArray, B::AbstractArray...) @inline eachindex(IndexStyle(A,B...), A, B...) end +eachindex(::IndexLinear, A::Union{Array, Memory}) = unchecked_oneto(length(A)) eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A))) eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A)) function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...) @@ -1237,15 +1238,15 @@ oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x) iterate_starting_state(A) = iterate_starting_state(A, IndexStyle(A)) iterate_starting_state(A, ::IndexLinear) = firstindex(A) iterate_starting_state(A, ::IndexStyle) = (eachindex(A),) -iterate(A::AbstractArray, state = iterate_starting_state(A)) = _iterate(A, state) -function _iterate(A::AbstractArray, state::Tuple) +@inline iterate(A::AbstractArray, state = iterate_starting_state(A)) = _iterate(A, state) +@inline function _iterate(A::AbstractArray, state::Tuple) y = iterate(state...) y === nothing && return nothing A[y[1]], (state[1], tail(y)...) end -function _iterate(A::AbstractArray, state::Integer) +@inline function _iterate(A::AbstractArray, state::Integer) checkbounds(Bool, A, state) || return nothing - @inbounds(A[state]), state + one(state) + A[state], state + one(state) end isempty(a::AbstractArray) = (length(a) == 0) diff --git a/base/array.jl b/base/array.jl index 61a3c39ca2bb7..cacef7c4acd5d 100644 --- a/base/array.jl +++ b/base/array.jl @@ -902,10 +902,6 @@ function grow_to!(dest, itr, st) return dest end -## Iteration ## - -iterate(A::Array, i=1) = (@inline; _iterate_array(A, i)) - ## Indexing: getindex ## """ diff --git a/base/genericmemory.jl b/base/genericmemory.jl index d25d213a3546e..b180462115f41 100644 --- a/base/genericmemory.jl +++ b/base/genericmemory.jl @@ -223,15 +223,6 @@ Memory{T}(x::AbstractArray{S,1}) where {T,S} = copyto_axcheck!(Memory{T}(undef, ## copying iterators to containers -## Iteration ## - -function _iterate_array(A::Union{Memory, Array}, i::Int) - @inline - checkbounds(Bool, A, i) ? (A[i], i + 1) : nothing -end - -iterate(A::Memory, i=1) = (@inline; _iterate_array(A, i)) - ## Indexing: getindex ## # Faster contiguous indexing using copyto! for AbstractUnitRange and Colon diff --git a/base/range.jl b/base/range.jl index 9d2b9fd736b22..3e1cd77eb914b 100644 --- a/base/range.jl +++ b/base/range.jl @@ -687,7 +687,7 @@ end ## interface implementations length(r::AbstractRange) = error("length implementation missing") # catch mistakes -size(r::AbstractRange) = (length(r),) +size(r::AbstractRange) = (@inline; (length(r),)) isempty(r::StepRange) = # steprange_last(r.start, r.step, r.stop) == r.stop @@ -802,6 +802,7 @@ let bigints = Union{Int, UInt, Int64, UInt64, Int128, UInt128}, # slightly more accurate length and checked_length in extreme cases # (near typemax) for types with known `unsigned` functions function length(r::OrdinalRange{T}) where T<:bigints + @inline s = step(r) diff = last(r) - first(r) isempty(r) && return zero(diff) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 6619a2b25574e..a436a5494fa79 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -797,7 +797,7 @@ size(s::CodeUnits) = (length(s),) elsize(s::Type{<:CodeUnits{T}}) where {T} = sizeof(T) @propagate_inbounds getindex(s::CodeUnits, i::Int) = codeunit(s.s, i) IndexStyle(::Type{<:CodeUnits}) = IndexLinear() -@inline iterate(s::CodeUnits, i=1) = checkbounds(Bool, s, i) ? (@inbounds s[i], i + 1) : nothing +checkbounds(::Type{Bool}, s::CodeUnits, i::Integer) = checkbounds(Bool, s.s, i) write(io::IO, s::CodeUnits) = write(io, s.s) diff --git a/base/subarray.jl b/base/subarray.jl index eacaddc068f1f..3a0be7d82b981 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -522,6 +522,16 @@ function _indices_sub(i1::AbstractArray, I...) (axes(i1)..., _indices_sub(I...)...) end +axes1(::SubArray{<:Any,0}) = OneTo(1) +axes1(S::SubArray) = (@inline; _axes1_sub(S.indices...)) +_axes1_sub() = () +_axes1_sub(::Real, I...) = (@inline; _axes1_sub(I...)) +_axes1_sub(::AbstractArray{<:Any,0}, I...) = _axes1_sub(I...) +function _axes1_sub(i1::AbstractArray, I...) + @inline + axes1(i1) +end + has_offset_axes(S::SubArray) = has_offset_axes(S.indices...) function replace_in_print_matrix(S::SubArray{<:Any,2,<:AbstractMatrix}, i::Integer, j::Integer, s::AbstractString) diff --git a/test/boundscheck_exec.jl b/test/boundscheck_exec.jl index e3d5e77c05384..2822176929f4a 100644 --- a/test/boundscheck_exec.jl +++ b/test/boundscheck_exec.jl @@ -353,4 +353,20 @@ if bc_opt == bc_default @test (@allocated no_alias_prove(5)) == 0 end +@testset "automatic boundscheck elision for iteration on some important types" begin + if bc_opt != bc_on + @test !contains(sprint(code_llvm, iterate, (Memory{UInt8}, Int)), "unreachable") + + @test !contains(sprint(code_llvm, iterate, (Vector{UInt8}, Int)), "unreachable") + @test !contains(sprint(code_llvm, iterate, (Matrix{UInt8}, Int)), "unreachable") + @test !contains(sprint(code_llvm, iterate, (Array{UInt8,3}, Int)), "unreachable") + + @test !contains(sprint(code_llvm, iterate, (SubArray{Float64, 1, Vector{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}}, true}, Int)), "unreachable") + @test !contains(sprint(code_llvm, iterate, (SubArray{Float64, 2, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}}, true}, Int)), "unreachable") + @test !contains(sprint(code_llvm, iterate, (SubArray{Float64, 2, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, UnitRange{Int64}}, true}, Int)), "unreachable") + + @test !contains(sprint(code_llvm, iterate, (Base.CodeUnits{UInt8,String}, Int)), "unreachable") + end +end + end