Skip to content

Commit

Permalink
Clean up steprange_last.
Browse files Browse the repository at this point in the history
  • Loading branch information
tkoolen committed May 29, 2018
1 parent e0dc6f8 commit d748060
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 15 deletions.
23 changes: 11 additions & 12 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,19 @@ function steprange_last(start::T, step, stop) where T
if (step > z) != (stop > start)
last = steprange_last_empty(start, step, stop)
else
diff = stop - start
if (diff > zero(diff)) != (stop > start)
# handle overflowed subtraction with unsigned rem
if diff > zero(diff)
remain = -convert(T, unsigned(-diff) % step)
else
remain = convert(T, unsigned(diff) % step)
end
# Compute absolute value of difference between `start` and `stop`
# (to simplify handling both signed and unsigned T and checking for signed overflow):
absdiff, absstep = stop > start ? (stop - start, step) : (start - stop, -step)

# Compute remainder as a nonnegative number:
if T <: Signed && absdiff < zero(absdiff)
# handle signed overflow with unsigned rem
remain = convert(T, unsigned(absdiff) % absstep)
else
remain = steprem(start,stop,step)
remain = absdiff % absstep
end
last = stop - remain
# Move `stop` closer to `start` if there is a remainder:
last = stop > start ? stop - remain : stop + remain
end
end
last
Expand All @@ -174,8 +175,6 @@ end
# For types where x+oneunit(x) may not be well-defined
steprange_last_empty(start, step, stop) = start - step

steprem(start,stop,step) = (stop-start) % step

StepRange(start::T, step::S, stop::T) where {T,S} = StepRange{T,S}(start, step, stop)

struct UnitRange{T<:Real} <: AbstractUnitRange{T}
Expand Down
27 changes: 24 additions & 3 deletions stdlib/Dates/src/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,30 @@ Base.length(r::StepRange{<:TimeType}) = isempty(r) ? Int64(0) : len(r.start, r.s
# Period ranges hook into Int64 overflow detection
Base.length(r::StepRange{<:Period}) = length(StepRange(value(r.start), value(r.step), value(r.stop)))

# Used to calculate the last valid date in the range given the start, stop, and step
# last = stop - steprem(start, stop, step)
Base.steprem(a::T, b::T, c) where {T<:TimeType} = b - (a + c * len(a, b, c))
# Overload Base.steprange_last because `rem` is not overloaded for `TimeType`s
function Base.steprange_last(start::T, step, stop) where T<:TimeType
if isa(step,AbstractFloat)
throw(ArgumentError("StepRange should not be used with floating point"))
end
z = zero(step)
step == z && throw(ArgumentError("step cannot be zero"))

if stop == start
last = stop
else
if (step > z) != (stop > start)
last = Base.steprange_last_empty(start, step, stop)
else
diff = stop - start
if (diff > zero(diff)) != (stop > start)
throw(OverflowError())
end
remain = stop - (start + step * len(start, stop, step))
last = stop - remain
end
end
last
end

import Base.in
function in(x::T, r::StepRange{T}) where T<:TimeType
Expand Down

0 comments on commit d748060

Please sign in to comment.