Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
911
julia-0.6.2/share/julia/base/range.jl
Normal file
911
julia-0.6.2/share/julia/base/range.jl
Normal file
@@ -0,0 +1,911 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
colon(a::Real, b::Real) = colon(promote(a,b)...)
|
||||
|
||||
colon(start::T, stop::T) where {T<:Real} = UnitRange{T}(start, stop)
|
||||
|
||||
range(a::Real, len::Integer) = UnitRange{typeof(a)}(a, oftype(a, a+len-1))
|
||||
|
||||
colon(start::T, stop::T) where {T} = colon(start, oftype(stop-start, 1), stop)
|
||||
|
||||
range(a, len::Integer) = range(a, oftype(a-a, 1), len)
|
||||
|
||||
# first promote start and stop, leaving step alone
|
||||
colon(start::A, step, stop::C) where {A<:Real,C<:Real} =
|
||||
colon(convert(promote_type(A,C),start), step, convert(promote_type(A,C),stop))
|
||||
colon(start::T, step::Real, stop::T) where {T<:Real} = colon(promote(start, step, stop)...)
|
||||
|
||||
"""
|
||||
colon(start, [step], stop)
|
||||
|
||||
Called by `:` syntax for constructing ranges.
|
||||
|
||||
```jldoctest
|
||||
julia> colon(1, 2, 5)
|
||||
1:2:5
|
||||
```
|
||||
"""
|
||||
colon(start::T, step::T, stop::T) where {T<:AbstractFloat} =
|
||||
_colon(TypeOrder(T), TypeArithmetic(T), start, step, stop)
|
||||
colon(start::T, step::T, stop::T) where {T<:Real} =
|
||||
_colon(TypeOrder(T), TypeArithmetic(T), start, step, stop)
|
||||
_colon(::HasOrder, ::Any, start::T, step, stop::T) where {T} = StepRange(start, step, stop)
|
||||
# for T<:Union{Float16,Float32,Float64} see twiceprecision.jl
|
||||
_colon(::HasOrder, ::ArithmeticRounds, start::T, step, stop::T) where {T} =
|
||||
StepRangeLen(start, step, floor(Int, (stop-start)/step)+1)
|
||||
_colon(::Any, ::Any, start::T, step, stop::T) where {T} =
|
||||
StepRangeLen(start, step, floor(Int, (stop-start)/step)+1)
|
||||
|
||||
"""
|
||||
:(start, [step], stop)
|
||||
|
||||
Range operator. `a:b` constructs a range from `a` to `b` with a step size of 1, and `a:s:b`
|
||||
is similar but uses a step size of `s`. These syntaxes call the function `colon`. The colon
|
||||
is also used in indexing to select whole dimensions.
|
||||
"""
|
||||
colon(start::T, step, stop::T) where {T} = _colon(start, step, stop)
|
||||
colon(start::T, step, stop::T) where {T<:Real} = _colon(start, step, stop)
|
||||
# without the second method above, the first method above is ambiguous with
|
||||
# colon{A<:Real,C<:Real}(start::A, step, stop::C)
|
||||
function _colon(start::T, step, stop::T) where T
|
||||
T′ = typeof(start+step)
|
||||
StepRange(convert(T′,start), step, convert(T′,stop))
|
||||
end
|
||||
|
||||
"""
|
||||
range(start, [step], length)
|
||||
|
||||
Construct a range by length, given a starting value and optional step (defaults to 1).
|
||||
"""
|
||||
range(a::T, step, len::Integer) where {T} = _range(TypeOrder(T), TypeArithmetic(T), a, step, len)
|
||||
_range(::HasOrder, ::ArithmeticOverflows, a::T, step::S, len::Integer) where {T,S} =
|
||||
StepRange{T,S}(a, step, convert(T, a+step*(len-1)))
|
||||
_range(::Any, ::Any, a::T, step::S, len::Integer) where {T,S} =
|
||||
StepRangeLen{typeof(a+0*step),T,S}(a, step, len)
|
||||
|
||||
# AbstractFloat specializations
|
||||
colon(a::T, b::T) where {T<:AbstractFloat} = colon(a, T(1), b)
|
||||
range(a::AbstractFloat, len::Integer) = range(a, oftype(a, 1), len)
|
||||
|
||||
colon(a::T, b::AbstractFloat, c::T) where {T<:Real} = colon(promote(a,b,c)...)
|
||||
colon(a::T, b::AbstractFloat, c::T) where {T<:AbstractFloat} = colon(promote(a,b,c)...)
|
||||
colon(a::T, b::Real, c::T) where {T<:AbstractFloat} = colon(promote(a,b,c)...)
|
||||
|
||||
range(a::AbstractFloat, st::AbstractFloat, len::Integer) = range(promote(a, st)..., len)
|
||||
range(a::Real, st::AbstractFloat, len::Integer) = range(float(a), st, len)
|
||||
range(a::AbstractFloat, st::Real, len::Integer) = range(a, float(st), len)
|
||||
|
||||
## 1-dimensional ranges ##
|
||||
|
||||
abstract type Range{T} <: AbstractArray{T,1} end
|
||||
|
||||
## ordinal ranges
|
||||
|
||||
abstract type OrdinalRange{T,S} <: Range{T} end
|
||||
abstract type AbstractUnitRange{T} <: OrdinalRange{T,Int} end
|
||||
|
||||
struct StepRange{T,S} <: OrdinalRange{T,S}
|
||||
start::T
|
||||
step::S
|
||||
stop::T
|
||||
|
||||
function StepRange{T,S}(start::T, step::S, stop::T) where {T,S}
|
||||
new(start, step, steprange_last(start,step,stop))
|
||||
end
|
||||
end
|
||||
|
||||
# to make StepRange constructor inlineable, so optimizer can see `step` value
|
||||
function steprange_last(start::T, step, stop) where T
|
||||
if isa(start,AbstractFloat) || 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 = steprange_last_empty(start, step, stop)
|
||||
else
|
||||
diff = stop - start
|
||||
if T<:Signed && (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
|
||||
else
|
||||
remain = steprem(start,stop,step)
|
||||
end
|
||||
last = stop - remain
|
||||
end
|
||||
end
|
||||
last
|
||||
end
|
||||
|
||||
function steprange_last_empty(start::Integer, step, stop)
|
||||
# empty range has a special representation where stop = start-1
|
||||
# this is needed to avoid the wrap-around that can happen computing
|
||||
# start - step, which leads to a range that looks very large instead
|
||||
# of empty.
|
||||
if step > zero(step)
|
||||
last = start - oneunit(stop-start)
|
||||
else
|
||||
last = start + oneunit(stop-start)
|
||||
end
|
||||
last
|
||||
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}
|
||||
start::T
|
||||
stop::T
|
||||
UnitRange{T}(start, stop) where {T<:Real} = new(start, unitrange_last(start,stop))
|
||||
end
|
||||
UnitRange(start::T, stop::T) where {T<:Real} = UnitRange{T}(start, stop)
|
||||
|
||||
unitrange_last(::Bool, stop::Bool) = stop
|
||||
unitrange_last(start::T, stop::T) where {T<:Integer} =
|
||||
ifelse(stop >= start, stop, convert(T,start-oneunit(stop-start)))
|
||||
unitrange_last(start::T, stop::T) where {T} =
|
||||
ifelse(stop >= start, convert(T,start+floor(stop-start)),
|
||||
convert(T,start-oneunit(stop-start)))
|
||||
|
||||
if isdefined(Main, :Base)
|
||||
getindex(t::Tuple, r::AbstractUnitRange{<:Real}) =
|
||||
(o = first(r) - 1; ntuple(n -> t[o + n], length(r)))
|
||||
end
|
||||
|
||||
"""
|
||||
Base.OneTo(n)
|
||||
|
||||
Define an `AbstractUnitRange` that behaves like `1:n`, with the added
|
||||
distinction that the lower limit is guaranteed (by the type system) to
|
||||
be 1.
|
||||
"""
|
||||
struct OneTo{T<:Integer} <: AbstractUnitRange{T}
|
||||
stop::T
|
||||
OneTo{T}(stop) where {T<:Integer} = new(max(zero(T), stop))
|
||||
end
|
||||
OneTo(stop::T) where {T<:Integer} = OneTo{T}(stop)
|
||||
|
||||
## Step ranges parametrized by length
|
||||
|
||||
"""
|
||||
StepRangeLen{T,R,S}(ref::R, step::S, len, [offset=1])
|
||||
|
||||
A range `r` where `r[i]` produces values of type `T`, parametrized by
|
||||
a `ref`erence value, a `step`, and the `len`gth. By default `ref` is
|
||||
the starting value `r[1]`, but alternatively you can supply it as the
|
||||
value of `r[offset]` for some other index `1 <= offset <= len`. In
|
||||
conjunction with `TwicePrecision` this can be used to implement ranges
|
||||
that are free of roundoff error.
|
||||
"""
|
||||
struct StepRangeLen{T,R,S} <: Range{T}
|
||||
ref::R # reference value (might be smallest-magnitude value in the range)
|
||||
step::S # step value
|
||||
len::Int # length of the range
|
||||
offset::Int # the index of ref
|
||||
|
||||
function StepRangeLen{T,R,S}(ref::R, step::S, len::Integer, offset::Integer = 1) where {T,R,S}
|
||||
len >= 0 || throw(ArgumentError("length cannot be negative, got $len"))
|
||||
1 <= offset <= max(1,len) || throw(ArgumentError("StepRangeLen: offset must be in [1,$len], got $offset"))
|
||||
new(ref, step, len, offset)
|
||||
end
|
||||
end
|
||||
|
||||
StepRangeLen(ref::R, step::S, len::Integer, offset::Integer = 1) where {R,S} =
|
||||
StepRangeLen{typeof(ref+0*step),R,S}(ref, step, len, offset)
|
||||
|
||||
## linspace and logspace
|
||||
|
||||
struct LinSpace{T} <: Range{T}
|
||||
start::T
|
||||
stop::T
|
||||
len::Int
|
||||
lendiv::Int
|
||||
|
||||
function LinSpace{T}(start,stop,len) where T
|
||||
len >= 0 || throw(ArgumentError("linspace($start, $stop, $len): negative length"))
|
||||
if len == 1
|
||||
start == stop || throw(ArgumentError("linspace($start, $stop, $len): endpoints differ"))
|
||||
return new(start, stop, 1, 1)
|
||||
end
|
||||
new(start,stop,len,max(len-1,1))
|
||||
end
|
||||
end
|
||||
|
||||
function LinSpace(start, stop, len::Integer)
|
||||
T = typeof((stop-start)/len)
|
||||
LinSpace{T}(start, stop, len)
|
||||
end
|
||||
|
||||
"""
|
||||
linspace(start, stop, n=50)
|
||||
|
||||
Construct a range of `n` linearly spaced elements from `start` to `stop`.
|
||||
|
||||
```jldoctest
|
||||
julia> linspace(1.3,2.9,9)
|
||||
1.3:0.2:2.9
|
||||
```
|
||||
"""
|
||||
linspace(start, stop, len::Real=50) = linspace(promote_noncircular(start, stop)..., Int(len))
|
||||
linspace(start::T, stop::T, len::Real=50) where {T} = linspace(start, stop, Int(len))
|
||||
|
||||
linspace(start::Real, stop::Real, len::Integer) = linspace(promote(start, stop)..., len)
|
||||
linspace(start::T, stop::T, len::Integer) where {T<:Integer} = linspace(Float64, start, stop, len, 1)
|
||||
# for Float16, Float32, and Float64 see twiceprecision.jl
|
||||
linspace(start::T, stop::T, len::Integer) where {T<:Real} = LinSpace{T}(start, stop, len)
|
||||
linspace(start::T, stop::T, len::Integer) where {T} = LinSpace{T}(start, stop, len)
|
||||
|
||||
function show(io::IO, r::LinSpace)
|
||||
print(io, "linspace(")
|
||||
show(io, first(r))
|
||||
print(io, ',')
|
||||
show(io, last(r))
|
||||
print(io, ',')
|
||||
show(io, length(r))
|
||||
print(io, ')')
|
||||
end
|
||||
|
||||
"""
|
||||
`print_range(io, r)` prints out a nice looking range r in terms of its elements
|
||||
as if it were `collect(r)`, dependent on the size of the
|
||||
terminal, and taking into account whether compact numbers should be shown.
|
||||
It figures out the width in characters of each element, and if they
|
||||
end up too wide, it shows the first and last elements separated by a
|
||||
horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`.
|
||||
|
||||
`print_range(io, r, pre, sep, post, hdots)` uses optional
|
||||
parameters `pre` and `post` characters for each printed row,
|
||||
`sep` separator string between printed elements,
|
||||
`hdots` string for the horizontal ellipsis.
|
||||
"""
|
||||
function print_range(io::IO, r::Range,
|
||||
pre::AbstractString = " ",
|
||||
sep::AbstractString = ",",
|
||||
post::AbstractString = "",
|
||||
hdots::AbstractString = ",\u2026,") # horiz ellipsis
|
||||
# This function borrows from print_matrix() in show.jl
|
||||
# and should be called by show and display
|
||||
limit = get(io, :limit, false)
|
||||
sz = displaysize(io)
|
||||
if !haskey(io, :compact)
|
||||
io = IOContext(io, :compact => true)
|
||||
end
|
||||
screenheight, screenwidth = sz[1] - 4, sz[2]
|
||||
screenwidth -= length(pre) + length(post)
|
||||
postsp = ""
|
||||
sepsize = length(sep)
|
||||
m = 1 # treat the range as a one-row matrix
|
||||
n = length(r)
|
||||
# Figure out spacing alignments for r, but only need to examine the
|
||||
# left and right edge columns, as many as could conceivably fit on the
|
||||
# screen, with the middle columns summarized by horz, vert, or diag ellipsis
|
||||
maxpossiblecols = div(screenwidth, 1+sepsize) # assume each element is at least 1 char + 1 separator
|
||||
colsr = n <= maxpossiblecols ? (1:n) : [1:div(maxpossiblecols,2)+1; (n-div(maxpossiblecols,2)):n]
|
||||
rowmatrix = reshape(r[colsr], 1, length(colsr)) # treat the range as a one-row matrix for print_matrix_row
|
||||
A = alignment(io, rowmatrix, 1:m, 1:length(rowmatrix), screenwidth, screenwidth, sepsize) # how much space range takes
|
||||
if n <= length(A) # cols fit screen, so print out all elements
|
||||
print(io, pre) # put in pre chars
|
||||
print_matrix_row(io,rowmatrix,A,1,1:n,sep) # the entire range
|
||||
print(io, post) # add the post characters
|
||||
else # cols don't fit so put horiz ellipsis in the middle
|
||||
# how many chars left after dividing width of screen in half
|
||||
# and accounting for the horiz ellipsis
|
||||
c = div(screenwidth-length(hdots)+1,2)+1 # chars remaining for each side of rowmatrix
|
||||
alignR = reverse(alignment(io, rowmatrix, 1:m, length(rowmatrix):-1:1, c, c, sepsize)) # which cols of rowmatrix to put on the right
|
||||
c = screenwidth - sum(map(sum,alignR)) - (length(alignR)-1)*sepsize - length(hdots)
|
||||
alignL = alignment(io, rowmatrix, 1:m, 1:length(rowmatrix), c, c, sepsize) # which cols of rowmatrix to put on the left
|
||||
print(io, pre) # put in pre chars
|
||||
print_matrix_row(io, rowmatrix,alignL,1,1:length(alignL),sep) # left part of range
|
||||
print(io, hdots) # horizontal ellipsis
|
||||
print_matrix_row(io, rowmatrix,alignR,1,length(rowmatrix)-length(alignR)+1:length(rowmatrix),sep) # right part of range
|
||||
print(io, post) # post chars
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
logspace(start::Real, stop::Real, n::Integer=50)
|
||||
|
||||
Construct a vector of `n` logarithmically spaced numbers from `10^start` to `10^stop`.
|
||||
|
||||
```jldoctest
|
||||
julia> logspace(1.,10.,5)
|
||||
5-element Array{Float64,1}:
|
||||
10.0
|
||||
1778.28
|
||||
3.16228e5
|
||||
5.62341e7
|
||||
1.0e10
|
||||
```
|
||||
"""
|
||||
logspace(start::Real, stop::Real, n::Integer=50) = 10.^linspace(start, stop, n)
|
||||
|
||||
## interface implementations
|
||||
|
||||
size(r::Range) = (length(r),)
|
||||
|
||||
isempty(r::StepRange) =
|
||||
(r.start != r.stop) & ((r.step > zero(r.step)) != (r.stop > r.start))
|
||||
isempty(r::AbstractUnitRange) = first(r) > last(r)
|
||||
isempty(r::StepRangeLen) = length(r) == 0
|
||||
isempty(r::LinSpace) = length(r) == 0
|
||||
|
||||
"""
|
||||
step(r)
|
||||
|
||||
Get the step size of a `Range` object.
|
||||
```jldoctest
|
||||
julia> step(1:10)
|
||||
1
|
||||
|
||||
julia> step(1:2:10)
|
||||
2
|
||||
|
||||
julia> step(2.5:0.3:10.9)
|
||||
0.3
|
||||
|
||||
julia> step(linspace(2.5,10.9,85))
|
||||
0.1
|
||||
```
|
||||
"""
|
||||
step(r::StepRange) = r.step
|
||||
step(r::AbstractUnitRange) = 1
|
||||
step(r::StepRangeLen) = r.step
|
||||
step(r::LinSpace) = (last(r)-first(r))/r.lendiv
|
||||
|
||||
unsafe_length(r::Range) = length(r) # generic fallback
|
||||
|
||||
function unsafe_length(r::StepRange)
|
||||
n = Integer(div(r.stop+r.step - r.start, r.step))
|
||||
isempty(r) ? zero(n) : n
|
||||
end
|
||||
length(r::StepRange) = unsafe_length(r)
|
||||
unsafe_length(r::AbstractUnitRange) = Integer(last(r) - first(r) + 1)
|
||||
unsafe_length(r::OneTo) = r.stop
|
||||
length(r::AbstractUnitRange) = unsafe_length(r)
|
||||
length(r::OneTo) = unsafe_length(r)
|
||||
length(r::StepRangeLen) = r.len
|
||||
length(r::LinSpace) = r.len
|
||||
|
||||
function length{T<:Union{Int,UInt,Int64,UInt64}}(r::StepRange{T})
|
||||
isempty(r) && return zero(T)
|
||||
if r.step > 1
|
||||
return checked_add(convert(T, div(unsigned(r.stop - r.start), r.step)), one(T))
|
||||
elseif r.step < -1
|
||||
return checked_add(convert(T, div(unsigned(r.start - r.stop), -r.step)), one(T))
|
||||
else
|
||||
checked_add(div(checked_sub(r.stop, r.start), r.step), one(T))
|
||||
end
|
||||
end
|
||||
|
||||
function length{T<:Union{Int,Int64}}(r::AbstractUnitRange{T})
|
||||
@_inline_meta
|
||||
checked_add(checked_sub(last(r), first(r)), one(T))
|
||||
end
|
||||
length{T<:Union{Int,Int64}}(r::OneTo{T}) = T(r.stop)
|
||||
|
||||
length{T<:Union{UInt,UInt64}}(r::AbstractUnitRange{T}) =
|
||||
r.stop < r.start ? zero(T) : checked_add(last(r) - first(r), one(T))
|
||||
|
||||
# some special cases to favor default Int type
|
||||
let smallint = (Int === Int64 ?
|
||||
Union{Int8,UInt8,Int16,UInt16,Int32,UInt32} :
|
||||
Union{Int8,UInt8,Int16,UInt16})
|
||||
global length
|
||||
|
||||
function length(r::StepRange{<:smallint})
|
||||
isempty(r) && return Int(0)
|
||||
div(Int(r.stop)+Int(r.step) - Int(r.start), Int(r.step))
|
||||
end
|
||||
|
||||
length(r::AbstractUnitRange{<:smallint}) = Int(last(r)) - Int(first(r)) + 1
|
||||
length(r::OneTo{<:smallint}) = Int(r.stop)
|
||||
end
|
||||
|
||||
first(r::OrdinalRange{T}) where {T} = convert(T, r.start)
|
||||
first(r::OneTo{T}) where {T} = oneunit(T)
|
||||
first(r::StepRangeLen) = unsafe_getindex(r, 1)
|
||||
first(r::LinSpace) = r.start
|
||||
|
||||
last(r::OrdinalRange{T}) where {T} = convert(T, r.stop)
|
||||
last(r::StepRangeLen) = unsafe_getindex(r, length(r))
|
||||
last(r::LinSpace) = r.stop
|
||||
|
||||
minimum(r::AbstractUnitRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : first(r)
|
||||
maximum(r::AbstractUnitRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : last(r)
|
||||
minimum(r::Range) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : min(first(r), last(r))
|
||||
maximum(r::Range) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : max(first(r), last(r))
|
||||
|
||||
# Ranges are immutable
|
||||
copy(r::Range) = r
|
||||
|
||||
|
||||
## iteration
|
||||
|
||||
start(r::LinSpace) = 1
|
||||
done(r::LinSpace, i::Int) = length(r) < i
|
||||
function next(r::LinSpace, i::Int)
|
||||
@_inline_meta
|
||||
unsafe_getindex(r, i), i+1
|
||||
end
|
||||
|
||||
start(r::StepRange) = oftype(r.start + r.step, r.start)
|
||||
next(r::StepRange{T}, i) where {T} = (convert(T,i), i+r.step)
|
||||
done(r::StepRange, i) = isempty(r) | (i < min(r.start, r.stop)) | (i > max(r.start, r.stop))
|
||||
done(r::StepRange, i::Integer) =
|
||||
isempty(r) | (i == oftype(i, r.stop) + r.step)
|
||||
|
||||
# see also twiceprecision.jl
|
||||
start(r::StepRangeLen) = (unsafe_getindex(r, 1), 1)
|
||||
next(r::StepRangeLen{T}, s) where {T} = s[1], (T(s[1]+r.step), s[2]+1)
|
||||
done(r::StepRangeLen, s) = s[2] > length(r)
|
||||
|
||||
start(r::UnitRange{T}) where {T} = oftype(r.start + oneunit(T), r.start)
|
||||
next(r::AbstractUnitRange{T}, i) where {T} = (convert(T, i), i + oneunit(T))
|
||||
done(r::AbstractUnitRange{T}, i) where {T} = i == oftype(i, r.stop) + oneunit(T)
|
||||
|
||||
start(r::OneTo{T}) where {T} = oneunit(T)
|
||||
|
||||
# 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 start
|
||||
global next
|
||||
start(r::StepRange{<:smallint}) = convert(Int, r.start)
|
||||
next(r::StepRange{T}, i) where {T<:smallint} = (i % T, i + r.step)
|
||||
start(r::UnitRange{<:smallint}) = convert(Int, r.start)
|
||||
next(r::AbstractUnitRange{T}, i) where {T<:smallint} = (i % T, i + 1)
|
||||
start(r::OneTo{<:smallint}) = 1
|
||||
end
|
||||
|
||||
## indexing
|
||||
|
||||
function getindex(v::UnitRange{T}, i::Integer) where T
|
||||
@_inline_meta
|
||||
ret = convert(T, first(v) + i - 1)
|
||||
@boundscheck ((i > 0) & (ret <= v.stop) & (ret >= v.start)) || throw_boundserror(v, i)
|
||||
ret
|
||||
end
|
||||
|
||||
function getindex(v::OneTo{T}, i::Integer) where T
|
||||
@_inline_meta
|
||||
@boundscheck ((i > 0) & (i <= v.stop)) || throw_boundserror(v, i)
|
||||
convert(T, i)
|
||||
end
|
||||
|
||||
function getindex(v::Range{T}, i::Integer) where T
|
||||
@_inline_meta
|
||||
ret = convert(T, first(v) + (i - 1)*step(v))
|
||||
ok = ifelse(step(v) > zero(step(v)),
|
||||
(ret <= v.stop) & (ret >= v.start),
|
||||
(ret <= v.start) & (ret >= v.stop))
|
||||
@boundscheck ((i > 0) & ok) || throw_boundserror(v, i)
|
||||
ret
|
||||
end
|
||||
|
||||
function getindex(r::Union{StepRangeLen,LinSpace}, i::Integer)
|
||||
@_inline_meta
|
||||
@boundscheck checkbounds(r, i)
|
||||
unsafe_getindex(r, i)
|
||||
end
|
||||
|
||||
# This is separate to make it useful even when running with --check-bounds=yes
|
||||
function unsafe_getindex(r::StepRangeLen{T}, i::Integer) where T
|
||||
u = i - r.offset
|
||||
T(r.ref + u*r.step)
|
||||
end
|
||||
|
||||
function unsafe_getindex(r::LinSpace, i::Integer)
|
||||
lerpi.(i-1, r.lendiv, r.start, r.stop)
|
||||
end
|
||||
|
||||
function lerpi{T}(j::Integer, d::Integer, a::T, b::T)
|
||||
@_inline_meta
|
||||
t = j/d
|
||||
T((1-t)*a + t*b)
|
||||
end
|
||||
|
||||
getindex(r::Range, ::Colon) = copy(r)
|
||||
|
||||
function getindex(r::AbstractUnitRange, s::AbstractUnitRange{<:Integer})
|
||||
@_inline_meta
|
||||
@boundscheck checkbounds(r, s)
|
||||
f = first(r)
|
||||
st = oftype(f, f + first(s)-1)
|
||||
range(st, length(s))
|
||||
end
|
||||
|
||||
function getindex(r::OneTo{T}, s::OneTo) where T
|
||||
@_inline_meta
|
||||
@boundscheck checkbounds(r, s)
|
||||
OneTo(T(s.stop))
|
||||
end
|
||||
|
||||
function getindex(r::AbstractUnitRange, s::StepRange{<:Integer})
|
||||
@_inline_meta
|
||||
@boundscheck checkbounds(r, s)
|
||||
st = oftype(first(r), first(r) + s.start-1)
|
||||
range(st, step(s), length(s))
|
||||
end
|
||||
|
||||
function getindex(r::StepRange, s::Range{<:Integer})
|
||||
@_inline_meta
|
||||
@boundscheck checkbounds(r, s)
|
||||
st = oftype(r.start, r.start + (first(s)-1)*step(r))
|
||||
range(st, step(r)*step(s), length(s))
|
||||
end
|
||||
|
||||
function getindex(r::StepRangeLen, s::OrdinalRange{<:Integer})
|
||||
@_inline_meta
|
||||
@boundscheck checkbounds(r, s)
|
||||
vfirst = unsafe_getindex(r, first(s))
|
||||
return StepRangeLen(vfirst, r.step*step(s), length(s))
|
||||
end
|
||||
|
||||
function getindex(r::LinSpace, s::OrdinalRange{<:Integer})
|
||||
@_inline_meta
|
||||
@boundscheck checkbounds(r, s)
|
||||
vfirst = unsafe_getindex(r, first(s))
|
||||
vlast = unsafe_getindex(r, last(s))
|
||||
return LinSpace(vfirst, vlast, length(s))
|
||||
end
|
||||
|
||||
show(io::IO, r::Range) = print(io, repr(first(r)), ':', repr(step(r)), ':', repr(last(r)))
|
||||
show(io::IO, r::UnitRange) = print(io, repr(first(r)), ':', repr(last(r)))
|
||||
show(io::IO, r::OneTo) = print(io, "Base.OneTo(", r.stop, ")")
|
||||
|
||||
==(r::T, s::T) where {T<:Range} =
|
||||
(first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s))
|
||||
==(r::OrdinalRange, s::OrdinalRange) =
|
||||
(first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s))
|
||||
==(r::T, s::T) where {T<:Union{StepRangeLen,LinSpace}} =
|
||||
(first(r) == first(s)) & (length(r) == length(s)) & (last(r) == last(s))
|
||||
==(r::Union{StepRange{T},StepRangeLen{T,T}}, s::Union{StepRange{T},StepRangeLen{T,T}}) where {T} =
|
||||
(first(r) == first(s)) & (last(r) == last(s)) & (step(r) == step(s))
|
||||
|
||||
function ==(r::Range, s::Range)
|
||||
lr = length(r)
|
||||
if lr != length(s)
|
||||
return false
|
||||
end
|
||||
u, v = start(r), start(s)
|
||||
while !done(r, u)
|
||||
x, u = next(r, u)
|
||||
y, v = next(s, v)
|
||||
if x != y
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
intersect(r::OneTo, s::OneTo) = OneTo(min(r.stop,s.stop))
|
||||
|
||||
intersect(r::AbstractUnitRange{<:Integer}, s::AbstractUnitRange{<:Integer}) = max(first(r),first(s)):min(last(r),last(s))
|
||||
|
||||
intersect(i::Integer, r::AbstractUnitRange{<:Integer}) =
|
||||
i < first(r) ? (first(r):i) :
|
||||
i > last(r) ? (i:last(r)) : (i:i)
|
||||
|
||||
intersect(r::AbstractUnitRange{<:Integer}, i::Integer) = intersect(i, r)
|
||||
|
||||
function intersect(r::AbstractUnitRange{<:Integer}, s::StepRange{<:Integer})
|
||||
if isempty(s)
|
||||
range(first(r), 0)
|
||||
elseif step(s) == 0
|
||||
intersect(first(s), r)
|
||||
elseif step(s) < 0
|
||||
intersect(r, reverse(s))
|
||||
else
|
||||
sta = first(s)
|
||||
ste = step(s)
|
||||
sto = last(s)
|
||||
lo = first(r)
|
||||
hi = last(r)
|
||||
i0 = max(sta, lo + mod(sta - lo, ste))
|
||||
i1 = min(sto, hi - mod(hi - sta, ste))
|
||||
i0:ste:i1
|
||||
end
|
||||
end
|
||||
|
||||
function intersect(r::StepRange{<:Integer}, s::AbstractUnitRange{<:Integer})
|
||||
if step(r) < 0
|
||||
reverse(intersect(s, reverse(r)))
|
||||
else
|
||||
intersect(s, r)
|
||||
end
|
||||
end
|
||||
|
||||
function intersect(r::StepRange, s::StepRange)
|
||||
if isempty(r) || isempty(s)
|
||||
return range(first(r), step(r), 0)
|
||||
elseif step(s) < 0
|
||||
return intersect(r, reverse(s))
|
||||
elseif step(r) < 0
|
||||
return reverse(intersect(reverse(r), s))
|
||||
end
|
||||
|
||||
start1 = first(r)
|
||||
step1 = step(r)
|
||||
stop1 = last(r)
|
||||
start2 = first(s)
|
||||
step2 = step(s)
|
||||
stop2 = last(s)
|
||||
a = lcm(step1, step2)
|
||||
|
||||
# if a == 0
|
||||
# # One or both ranges have step 0.
|
||||
# if step1 == 0 && step2 == 0
|
||||
# return start1 == start2 ? r : Range(start1, 0, 0)
|
||||
# elseif step1 == 0
|
||||
# return start2 <= start1 <= stop2 && rem(start1 - start2, step2) == 0 ? r : Range(start1, 0, 0)
|
||||
# else
|
||||
# return start1 <= start2 <= stop1 && rem(start2 - start1, step1) == 0 ? (start2:step1:start2) : Range(start1, step1, 0)
|
||||
# end
|
||||
# end
|
||||
|
||||
g, x, y = gcdx(step1, step2)
|
||||
|
||||
if rem(start1 - start2, g) != 0
|
||||
# Unaligned, no overlap possible.
|
||||
return range(start1, a, 0)
|
||||
end
|
||||
|
||||
z = div(start1 - start2, g)
|
||||
b = start1 - x * z * step1
|
||||
# Possible points of the intersection of r and s are
|
||||
# ..., b-2a, b-a, b, b+a, b+2a, ...
|
||||
# Determine where in the sequence to start and stop.
|
||||
m = max(start1 + mod(b - start1, a), start2 + mod(b - start2, a))
|
||||
n = min(stop1 - mod(stop1 - b, a), stop2 - mod(stop2 - b, a))
|
||||
m:a:n
|
||||
end
|
||||
|
||||
function intersect(r1::Range, r2::Range, r3::Range, r::Range...)
|
||||
i = intersect(intersect(r1, r2), r3)
|
||||
for t in r
|
||||
i = intersect(i, t)
|
||||
end
|
||||
i
|
||||
end
|
||||
|
||||
# findin (the index of intersection)
|
||||
function _findin(r::Range{<:Integer}, span::AbstractUnitRange{<:Integer})
|
||||
local ifirst
|
||||
local ilast
|
||||
fspan = first(span)
|
||||
lspan = last(span)
|
||||
fr = first(r)
|
||||
lr = last(r)
|
||||
sr = step(r)
|
||||
if sr > 0
|
||||
ifirst = fr >= fspan ? 1 : ceil(Integer,(fspan-fr)/sr)+1
|
||||
ilast = lr <= lspan ? length(r) : length(r) - ceil(Integer,(lr-lspan)/sr)
|
||||
elseif sr < 0
|
||||
ifirst = fr <= lspan ? 1 : ceil(Integer,(lspan-fr)/sr)+1
|
||||
ilast = lr >= fspan ? length(r) : length(r) - ceil(Integer,(lr-fspan)/sr)
|
||||
else
|
||||
ifirst = fr >= fspan ? 1 : length(r)+1
|
||||
ilast = fr <= lspan ? length(r) : 0
|
||||
end
|
||||
ifirst, ilast
|
||||
end
|
||||
|
||||
function findin(r::AbstractUnitRange{<:Integer}, span::AbstractUnitRange{<:Integer})
|
||||
ifirst, ilast = _findin(r, span)
|
||||
ifirst:ilast
|
||||
end
|
||||
|
||||
function findin(r::Range{<:Integer}, span::AbstractUnitRange{<:Integer})
|
||||
ifirst, ilast = _findin(r, span)
|
||||
ifirst:1:ilast
|
||||
end
|
||||
|
||||
## linear operations on ranges ##
|
||||
|
||||
-(r::OrdinalRange) = range(-first(r), -step(r), length(r))
|
||||
-(r::StepRangeLen) = StepRangeLen(-r.ref, -r.step, length(r), r.offset)
|
||||
-(r::LinSpace) = LinSpace(-r.start, -r.stop, length(r))
|
||||
|
||||
+(x::Real, r::AbstractUnitRange) = range(x + first(r), length(r))
|
||||
# For #18336 we need to prevent promotion of the step type:
|
||||
+(x::Number, r::AbstractUnitRange) = range(x + first(r), step(r), length(r))
|
||||
+(x::Number, r::Range) = (x+first(r)):step(r):(x+last(r))
|
||||
function +(x::Number, r::StepRangeLen)
|
||||
newref = x + r.ref
|
||||
StepRangeLen{eltype(newref),typeof(newref),typeof(r.step)}(newref, r.step, length(r), r.offset)
|
||||
end
|
||||
function +(x::Number, r::LinSpace)
|
||||
LinSpace(x + r.start, x + r.stop, r.len)
|
||||
end
|
||||
+(r::Range, x::Number) = x + r # assumes addition is commutative
|
||||
|
||||
-(x::Number, r::Range) = (x-first(r)):-step(r):(x-last(r))
|
||||
-(x::Number, r::StepRangeLen) = +(x, -r)
|
||||
function -(x::Number, r::LinSpace)
|
||||
LinSpace(x - r.start, x - r.stop, r.len)
|
||||
end
|
||||
|
||||
-(r::Range, x::Number) = +(-x, r)
|
||||
|
||||
*(x::Number, r::Range) = range(x*first(r), x*step(r), length(r))
|
||||
*(x::Number, r::StepRangeLen) = StepRangeLen(x*r.ref, x*r.step, length(r), r.offset)
|
||||
*(x::Number, r::LinSpace) = LinSpace(x * r.start, x * r.stop, r.len)
|
||||
# separate in case of noncommutative multiplication
|
||||
*(r::Range, x::Number) = range(first(r)*x, step(r)*x, length(r))
|
||||
*(r::StepRangeLen, x::Number) = StepRangeLen(r.ref*x, r.step*x, length(r), r.offset)
|
||||
*(r::LinSpace, x::Number) = LinSpace(r.start * x, r.stop * x, r.len)
|
||||
|
||||
/(r::Range, x::Number) = range(first(r)/x, step(r)/x, length(r))
|
||||
/(r::StepRangeLen, x::Number) = StepRangeLen(r.ref/x, r.step/x, length(r), r.offset)
|
||||
/(r::LinSpace, x::Number) = LinSpace(r.start / x, r.stop / x, r.len)
|
||||
|
||||
/(x::Number, r::Range) = [ x/y for y=r ]
|
||||
|
||||
promote_rule(::Type{UnitRange{T1}},::Type{UnitRange{T2}}) where {T1,T2} =
|
||||
UnitRange{promote_type(T1,T2)}
|
||||
convert(::Type{UnitRange{T}}, r::UnitRange{T}) where {T<:Real} = r
|
||||
convert(::Type{UnitRange{T}}, r::UnitRange) where {T<:Real} = UnitRange{T}(r.start, r.stop)
|
||||
|
||||
promote_rule(::Type{OneTo{T1}},::Type{OneTo{T2}}) where {T1,T2} =
|
||||
OneTo{promote_type(T1,T2)}
|
||||
convert(::Type{OneTo{T}}, r::OneTo{T}) where {T<:Real} = r
|
||||
convert(::Type{OneTo{T}}, r::OneTo) where {T<:Real} = OneTo{T}(r.stop)
|
||||
|
||||
promote_rule(::Type{UnitRange{T1}}, ::Type{UR}) where {T1,UR<:AbstractUnitRange} =
|
||||
UnitRange{promote_type(T1,eltype(UR))}
|
||||
convert(::Type{UnitRange{T}}, r::AbstractUnitRange) where {T<:Real} = UnitRange{T}(first(r), last(r))
|
||||
convert(::Type{UnitRange}, r::AbstractUnitRange) = UnitRange(first(r), last(r))
|
||||
|
||||
promote_rule(::Type{StepRange{T1a,T1b}},::Type{StepRange{T2a,T2b}}) where {T1a,T1b,T2a,T2b} =
|
||||
StepRange{promote_type(T1a,T2a),promote_type(T1b,T2b)}
|
||||
convert(::Type{StepRange{T1,T2}}, r::StepRange{T1,T2}) where {T1,T2} = r
|
||||
|
||||
promote_rule(::Type{StepRange{T1a,T1b}},::Type{UR}) where {T1a,T1b,UR<:AbstractUnitRange} =
|
||||
StepRange{promote_type(T1a,eltype(UR)),promote_type(T1b,eltype(UR))}
|
||||
convert(::Type{StepRange{T1,T2}}, r::Range) where {T1,T2} =
|
||||
StepRange{T1,T2}(convert(T1, first(r)), convert(T2, step(r)), convert(T1, last(r)))
|
||||
convert(::Type{StepRange}, r::AbstractUnitRange{T}) where {T} =
|
||||
StepRange{T,T}(first(r), step(r), last(r))
|
||||
|
||||
promote_rule(::Type{StepRangeLen{T1,R1,S1}},::Type{StepRangeLen{T2,R2,S2}}) where {T1,T2,R1,R2,S1,S2} =
|
||||
StepRangeLen{promote_type(T1,T2), promote_type(R1,R2), promote_type(S1,S2)}
|
||||
convert(::Type{StepRangeLen{T,R,S}}, r::StepRangeLen{T,R,S}) where {T,R,S} = r
|
||||
convert(::Type{StepRangeLen{T,R,S}}, r::StepRangeLen) where {T,R,S} =
|
||||
StepRangeLen{T,R,S}(convert(R, r.ref), convert(S, r.step), length(r), r.offset)
|
||||
convert(::Type{StepRangeLen{T}}, r::StepRangeLen) where {T} =
|
||||
StepRangeLen(convert(T, r.ref), convert(T, r.step), length(r), r.offset)
|
||||
|
||||
promote_rule(::Type{StepRangeLen{T,R,S}}, ::Type{OR}) where {T,R,S,OR<:Range} =
|
||||
StepRangeLen{promote_type(T,eltype(OR)),promote_type(R,eltype(OR)),promote_type(S,eltype(OR))}
|
||||
convert(::Type{StepRangeLen{T,R,S}}, r::Range) where {T,R,S} =
|
||||
StepRangeLen{T,R,S}(R(first(r)), S(step(r)), length(r))
|
||||
convert(::Type{StepRangeLen{T}}, r::Range) where {T} =
|
||||
StepRangeLen(T(first(r)), T(step(r)), length(r))
|
||||
convert(::Type{StepRangeLen}, r::Range) = convert(StepRangeLen{eltype(r)}, r)
|
||||
|
||||
promote_rule(::Type{LinSpace{T1}},::Type{LinSpace{T2}}) where {T1,T2} =
|
||||
LinSpace{promote_type(T1,T2)}
|
||||
convert(::Type{LinSpace{T}}, r::LinSpace{T}) where {T} = r
|
||||
convert(::Type{LinSpace{T}}, r::Range) where {T} =
|
||||
LinSpace{T}(first(r), last(r), length(r))
|
||||
convert(::Type{LinSpace}, r::Range{T}) where {T} =
|
||||
convert(LinSpace{T}, r)
|
||||
|
||||
promote_rule(::Type{LinSpace{T}}, ::Type{OR}) where {T,OR<:OrdinalRange} =
|
||||
LinSpace{promote_type(T,eltype(OR))}
|
||||
|
||||
promote_rule(::Type{LinSpace{L}}, ::Type{StepRangeLen{T,R,S}}) where {L,T,R,S} =
|
||||
StepRangeLen{promote_type(L,T),promote_type(L,R),promote_type(L,S)}
|
||||
|
||||
# +/- of ranges is defined in operators.jl (to be able to use @eval etc.)
|
||||
|
||||
## concatenation ##
|
||||
|
||||
function vcat(rs::Range{T}...) where T
|
||||
n::Int = 0
|
||||
for ra in rs
|
||||
n += length(ra)
|
||||
end
|
||||
a = Vector{T}(n)
|
||||
i = 1
|
||||
for ra in rs, x in ra
|
||||
@inbounds a[i] = x
|
||||
i += 1
|
||||
end
|
||||
return a
|
||||
end
|
||||
|
||||
convert(::Type{Array{T,1}}, r::Range{T}) where {T} = vcat(r)
|
||||
collect(r::Range) = vcat(r)
|
||||
|
||||
reverse(r::OrdinalRange) = colon(last(r), -step(r), first(r))
|
||||
reverse(r::StepRangeLen) = StepRangeLen(r.ref, -r.step, length(r), length(r)-r.offset+1)
|
||||
reverse(r::LinSpace) = LinSpace(r.stop, r.start, length(r))
|
||||
|
||||
## sorting ##
|
||||
|
||||
issorted(r::AbstractUnitRange) = true
|
||||
issorted(r::Range) = length(r) <= 1 || step(r) >= zero(step(r))
|
||||
|
||||
sort(r::AbstractUnitRange) = r
|
||||
sort!(r::AbstractUnitRange) = r
|
||||
|
||||
sort(r::Range) = issorted(r) ? r : reverse(r)
|
||||
|
||||
sortperm(r::AbstractUnitRange) = 1:length(r)
|
||||
sortperm(r::Range) = issorted(r) ? (1:1:length(r)) : (length(r):-1:1)
|
||||
|
||||
function sum(r::Range{<:Real})
|
||||
l = length(r)
|
||||
# note that a little care is required to avoid overflow in l*(l-1)/2
|
||||
return l * first(r) + (iseven(l) ? (step(r) * (l-1)) * (l>>1)
|
||||
: (step(r) * l) * ((l-1)>>1))
|
||||
end
|
||||
|
||||
function mean(r::Range{<:Real})
|
||||
isempty(r) && throw(ArgumentError("mean of an empty range is undefined"))
|
||||
(first(r) + last(r)) / 2
|
||||
end
|
||||
|
||||
median(r::Range{<:Real}) = mean(r)
|
||||
|
||||
function in(x, r::Range)
|
||||
n = step(r) == 0 ? 1 : round(Integer,(x-first(r))/step(r))+1
|
||||
n >= 1 && n <= length(r) && r[n] == x
|
||||
end
|
||||
|
||||
in(x::Integer, r::AbstractUnitRange{<:Integer}) = (first(r) <= x) & (x <= last(r))
|
||||
in(x, r::Range{T}) where {T<:Integer} =
|
||||
isinteger(x) && !isempty(r) && x >= minimum(r) && x <= maximum(r) &&
|
||||
(mod(convert(T,x),step(r))-mod(first(r),step(r)) == 0)
|
||||
in(x::Char, r::Range{Char}) =
|
||||
!isempty(r) && x >= minimum(r) && x <= maximum(r) &&
|
||||
(mod(Int(x) - Int(first(r)), step(r)) == 0)
|
||||
|
||||
# Addition/subtraction of ranges
|
||||
|
||||
function _define_range_op(f::ANY)
|
||||
@eval begin
|
||||
function $f(r1::OrdinalRange, r2::OrdinalRange)
|
||||
r1l = length(r1)
|
||||
(r1l == length(r2) ||
|
||||
throw(DimensionMismatch("argument dimensions must match")))
|
||||
range($f(first(r1),first(r2)), $f(step(r1),step(r2)), r1l)
|
||||
end
|
||||
|
||||
function $f(r1::LinSpace{T}, r2::LinSpace{T}) where T
|
||||
len = r1.len
|
||||
(len == r2.len ||
|
||||
throw(DimensionMismatch("argument dimensions must match")))
|
||||
linspace(convert(T, $f(first(r1), first(r2))),
|
||||
convert(T, $f(last(r1), last(r2))), len)
|
||||
end
|
||||
|
||||
$f(r1::Union{StepRangeLen, OrdinalRange, LinSpace},
|
||||
r2::Union{StepRangeLen, OrdinalRange, LinSpace}) =
|
||||
$f(promote_noncircular(r1, r2)...)
|
||||
end
|
||||
end
|
||||
_define_range_op(:+)
|
||||
_define_range_op(:-)
|
||||
|
||||
function +(r1::StepRangeLen{T,S}, r2::StepRangeLen{T,S}) where {T,S}
|
||||
len = length(r1)
|
||||
(len == length(r2) ||
|
||||
throw(DimensionMismatch("argument dimensions must match")))
|
||||
StepRangeLen(first(r1)+first(r2), step(r1)+step(r2), len)
|
||||
end
|
||||
|
||||
-(r1::StepRangeLen, r2::StepRangeLen) = +(r1, -r2)
|
||||
Reference in New Issue
Block a user