From 173fc8f25c8267e26fabe42a22e5d2ff7ab97348 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 18 May 2018 23:39:02 +0300 Subject: [PATCH 1/5] Make step of unit range return the unit in the element type --- base/range.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/range.jl b/base/range.jl index cbb3da7f7843d..754f2cf31da9b 100644 --- a/base/range.jl +++ b/base/range.jl @@ -117,7 +117,7 @@ convert(::Type{T}, r::AbstractRange) where {T<:AbstractRange} = r isa T ? r : T( ## ordinal ranges abstract type OrdinalRange{T,S} <: AbstractRange{T} end -abstract type AbstractUnitRange{T} <: OrdinalRange{T,Int} end +abstract type AbstractUnitRange{T} <: OrdinalRange{T,T} end struct StepRange{T,S} <: OrdinalRange{T,S} start::T @@ -374,7 +374,7 @@ julia> step(range(2.5, stop=10.9, length=85)) ``` """ step(r::StepRange) = r.step -step(r::AbstractUnitRange) = 1 +step(r::AbstractUnitRange{T}) where{T} = oneunit(T) step(r::StepRangeLen{T}) where {T} = T(r.step) step(r::LinRange) = (last(r)-first(r))/r.lendiv From 13c92aeed44178bd655bf6631b576439d785a612 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 18 May 2018 23:39:50 +0300 Subject: [PATCH 2/5] Simplify iteration over ordinal range --- base/range.jl | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/base/range.jl b/base/range.jl index 754f2cf31da9b..520312c6da980 100644 --- a/base/range.jl +++ b/base/range.jl @@ -456,34 +456,22 @@ function iterate(r::LinRange, i::Int=1) unsafe_getindex(r, i), i+1 end -function iterate(r::StepRange{T}, i=oftype(r.start + r.step, r.start)) where {T} - if i isa Integer - (isempty(r) | (i == oftype(i, r.stop) + r.step)) && return nothing - else - (isempty(r) | (i < min(r.start, r.stop)) | (i > max(r.start, r.stop))) && return nothing - end - (convert(T,i), i+r.step) -end - iterate(r::StepRangeLen{T}, i=1) where {T} = i > length(r) ? nothing : (unsafe_getindex(r, i), i+1) -iterate(r::AbstractUnitRange) = isless(last(r), first(r)) ? nothing : (first(r), first(r)) +iterate(r::OrdinalRange) = isempty(r) ? nothing : (first(r), first(r)) -function iterate(r::AbstractUnitRange{T}, i) where {T} +function iterate(r::OrdinalRange{T}, i) where {T} + @_inline_meta i == last(r) && return nothing - next = convert(T, i + oneunit(T)) + next = convert(T, i + step(r)) (next, next) end -# some special cases to favor default Int type to avoid overflow -let smallint = (Int === Int64 ? - Union{Int8,UInt8,Int16,UInt16,Int32,UInt32} : - Union{Int8,UInt8,Int16,UInt16}) - global iterate - function iterate(r::StepRange{T}, i=convert(Int, r.start)) where {T<:smallint} - (isempty(r) | (i == oftype(i, r.stop) + r.step)) && return nothing - (i % T, i + r.step) - end +# In the case of floats we might not land exactly on the boundary due to rounding errors +function iterate(r::StepRange{T}, i) where {T<:AbstractFloat} + next = convert(T, i + step(r)) + ((next < min(r.start, r.stop)) | (next > max(r.start, r.stop))) && return nothing + (next, next) end ## indexing From 69ae13a1e364668e05cee879f68b1a307938c18e Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Sat, 19 May 2018 00:18:19 +0300 Subject: [PATCH 3/5] Test whether we can iterate over the full inclusive step range of the largest bits integer type --- test/ranges.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/ranges.jl b/test/ranges.jl index 23b45ba068034..57238e0f8846a 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -438,6 +438,13 @@ end end @test s == 256 + s = 0 + for i = typemin(UInt):1:typemax(UInt) + i == 10 && break + s += 1 + end + @test s == 10 + # loops past typemax(Int) n = 0 s = Int128(0) From d4b5fdc913644dfaffad3c7e24c2bc2eb1d492f8 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Sun, 20 May 2018 20:14:55 +0300 Subject: [PATCH 4/5] StepRange can safely assume we will land on the boundary of the range; specialization for floats makes no sense, since a StepRange will throw when being constructed with it. --- base/range.jl | 7 ------- 1 file changed, 7 deletions(-) diff --git a/base/range.jl b/base/range.jl index 520312c6da980..5d854f18cc8f9 100644 --- a/base/range.jl +++ b/base/range.jl @@ -467,13 +467,6 @@ function iterate(r::OrdinalRange{T}, i) where {T} (next, next) end -# In the case of floats we might not land exactly on the boundary due to rounding errors -function iterate(r::StepRange{T}, i) where {T<:AbstractFloat} - next = convert(T, i + step(r)) - ((next < min(r.start, r.stop)) | (next > max(r.start, r.stop))) && return nothing - (next, next) -end - ## indexing function getindex(v::UnitRange{T}, i::Integer) where T From 87f630bf2cbafc7385af87a257272effac30e5a1 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Sun, 20 May 2018 23:39:56 +0300 Subject: [PATCH 5/5] Combine iteration method of LinRange and StepRangeLen --- base/range.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/base/range.jl b/base/range.jl index 5d854f18cc8f9..cf45e158940e4 100644 --- a/base/range.jl +++ b/base/range.jl @@ -450,14 +450,12 @@ copy(r::AbstractRange) = r ## iteration -function iterate(r::LinRange, i::Int=1) +function iterate(r::Union{LinRange,StepRangeLen}, i::Int=1) @_inline_meta length(r) < i && return nothing - unsafe_getindex(r, i), i+1 + unsafe_getindex(r, i), i + 1 end -iterate(r::StepRangeLen{T}, i=1) where {T} = i > length(r) ? nothing : (unsafe_getindex(r, i), i+1) - iterate(r::OrdinalRange) = isempty(r) ? nothing : (first(r), first(r)) function iterate(r::OrdinalRange{T}, i) where {T}