Skip to content

Commit 191256e

Browse files
authored
Assume size is non-negative for increased efficiency (#50530)
I noticed [here](#50467 (comment)) that `lastindex(x::Base.OneTo)` is not simply `x.stop`. This PR performs that optimization and many more by assuming `size` always returns positive numbers. ``` julia> @code_native lastindex(Base.OneTo(5)) # master .section __TEXT,__text,regular,pure_instructions .build_version macos, 13, 0 .globl _julia_lastindex_81 ; -- Begin function julia_lastindex_81 .p2align 2 _julia_lastindex_81: ; @julia_lastindex_81 ; ┌ @ abstractarray.jl:423 within `lastindex` ; %bb.0: ; %top ; │┌ @ abstractarray.jl:386 within `eachindex` ; ││┌ @ abstractarray.jl:134 within `axes1` ; │││┌ @ range.jl:708 within `axes` ; ││││┌ @ range.jl:471 within `oneto` ; │││││┌ @ range.jl:469 within `OneTo` @ range.jl:454 ; ││││││┌ @ promotion.jl:532 within `max` ; │││││││┌ @ int.jl:83 within `<` ldr x8, [x0] ; │││││││└ ; │││││││┌ @ essentials.jl:642 within `ifelse` cmp x8, #0 csel x0, x8, xzr, gt ; │└└└└└└└ ret ; └ ; -- End function .subsections_via_symbols julia> @code_native lastindex(Base.OneTo(5)) # pr .section __TEXT,__text,regular,pure_instructions .build_version macos, 13, 0 .globl _julia_lastindex_13253 ; -- Begin function julia_lastindex_13253 .p2align 2 _julia_lastindex_13253: ; @julia_lastindex_13253 ; ┌ @ abstractarray.jl:423 within `lastindex` ; %bb.0: ; %top ldr x0, [x0] ret ; └ ; -- End function .subsections_via_symbols ``` Also removed `axes(r::AbstractRange) = (oneto(length(r)),)` (added in #40382, @vtjnash) as redundant with the general `axes` method. The obvious downside here is that if someone defines an object with negative size, its axes will include Base.OneTo with negative stop. I think that is acceptable, but if not, we can gate this optimization to a set of known types (all AbstractArray types defined in Base should have non-negative size)
2 parents 99e2604 + cae9576 commit 191256e

File tree

3 files changed

+5
-4
lines changed

3 files changed

+5
-4
lines changed

base/abstractarray.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ julia> axes(A)
9595
"""
9696
function axes(A)
9797
@inline
98-
map(oneto, size(A))
98+
map(unchecked_oneto, size(A))
9999
end
100100

101101
"""

base/range.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ distinction that the lower limit is guaranteed (by the type system) to
447447
be 1.
448448
"""
449449
struct OneTo{T<:Integer} <: AbstractUnitRange{T}
450-
stop::T
450+
stop::T # invariant: stop >= zero(stop)
451451
function OneTo{T}(stop) where {T<:Integer}
452452
throwbool(r) = (@noinline; throw(ArgumentError("invalid index: $r of type Bool")))
453453
T === Bool && throwbool(stop)
@@ -463,6 +463,8 @@ struct OneTo{T<:Integer} <: AbstractUnitRange{T}
463463
T === Bool && throwbool(r)
464464
return new(max(zero(T), last(r)))
465465
end
466+
467+
global unchecked_oneto(stop::Integer) = new{typeof(stop)}(stop)
466468
end
467469
OneTo(stop::T) where {T<:Integer} = OneTo{T}(stop)
468470
OneTo(r::AbstractRange{T}) where {T<:Integer} = OneTo{T}(r)
@@ -703,8 +705,6 @@ step(r::LinRange) = (last(r)-first(r))/r.lendiv
703705
step_hp(r::StepRangeLen) = r.step
704706
step_hp(r::AbstractRange) = step(r)
705707

706-
axes(r::AbstractRange) = (oneto(length(r)),)
707-
708708
# Needed to ensure `has_offset_axes` can constant-fold.
709709
has_offset_axes(::StepRange) = false
710710

test/testhelpers/InfiniteArrays.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@ Base.length(r::OneToInf) = Infinity()
4848
Base.last(r::OneToInf) = Infinity()
4949
Base.unitrange(r::OneToInf) = r
5050
Base.oneto(::Infinity) = OneToInf()
51+
Base.unchecked_oneto(::Infinity) = OneToInf()
5152

5253
end

0 commit comments

Comments
 (0)