| Line | Exclusive | Inclusive | Code |
|---|---|---|---|
| 1 | # This file is a part of Julia. License is MIT: https://julialang.org/license | ||
| 2 | |||
| 3 | (:)(a::Real, b::Real) = (:)(promote(a, b)...) | ||
| 4 | |||
| 5 | (:)(start::T, stop::T) where {T<:Real} = UnitRange{T}(start, stop) | ||
| 6 | |||
| 7 | (:)(start::T, stop::T) where {T} = (:)(start, oftype(stop >= start ? stop - start : start - stop, 1), stop) | ||
| 8 | |||
| 9 | # promote start and stop, leaving step alone | ||
| 10 | (:)(start::A, step, stop::C) where {A<:Real, C<:Real} = | ||
| 11 | (:)(convert(promote_type(A, C), start), step, convert(promote_type(A, C), stop)) | ||
| 12 | |||
| 13 | # AbstractFloat specializations | ||
| 14 | (:)(a::T, b::T) where {T<:AbstractFloat} = (:)(a, T(1), b) | ||
| 15 | |||
| 16 | (:)(a::T, b::AbstractFloat, c::T) where {T<:Real} = (:)(promote(a, b, c)...) | ||
| 17 | (:)(a::T, b::AbstractFloat, c::T) where {T<:AbstractFloat} = (:)(promote(a, b, c)...) | ||
| 18 | (:)(a::T, b::Real, c::T) where {T<:AbstractFloat} = (:)(promote(a, b, c)...) | ||
| 19 | |||
| 20 | (:)(start::T, step::T, stop::T) where {T<:AbstractFloat} = | ||
| 21 | _colon(OrderStyle(T), ArithmeticStyle(T), start, step, stop) | ||
| 22 | (:)(start::T, step::T, stop::T) where {T<:Real} = | ||
| 23 | _colon(OrderStyle(T), ArithmeticStyle(T), start, step, stop) | ||
| 24 | _colon(::Ordered, ::Any, start::T, step, stop::T) where {T} = StepRange(start, step, stop) | ||
| 25 | # for T<:Union{Float16,Float32,Float64} see twiceprecision.jl | ||
| 26 | _colon(::Ordered, ::ArithmeticRounds, start::T, step, stop::T) where {T} = | ||
| 27 | StepRangeLen(start, step, convert(Integer, fld(stop - start, step)) + 1) | ||
| 28 | _colon(::Any, ::Any, start::T, step, stop::T) where {T} = | ||
| 29 | StepRangeLen(start, step, convert(Integer, fld(stop - start, step)) + 1) | ||
| 30 | |||
| 31 | """ | ||
| 32 | (:)(start, [step], stop) | ||
| 33 | |||
| 34 | Range operator. `a:b` constructs a range from `a` to `b` with a step size | ||
| 35 | equal to 1, which produces: | ||
| 36 | |||
| 37 | * a [`UnitRange`](@ref) when `a` and `b` are integers, or | ||
| 38 | * a [`StepRange`](@ref) when `a` and `b` are characters, or | ||
| 39 | * a [`StepRangeLen`](@ref) when `a` and/or `b` are floating-point. | ||
| 40 | |||
| 41 | `a:s:b` is similar but uses a step size of `s` (a [`StepRange`](@ref) or | ||
| 42 | [`StepRangeLen`](@ref)). See also [`range`](@ref) for more control. | ||
| 43 | |||
| 44 | The operator `:` is also used in indexing to select whole dimensions, e.g. in `A[:, 1]`. | ||
| 45 | |||
| 46 | `:` is also used to [`quote`](@ref) code, e.g. `:(x + y) isa Expr` and `:x isa Symbol`. | ||
| 47 | Since `:2 isa Int`, it does *not* create a range in indexing: `v[:2] == v[2] != v[begin:2]`. | ||
| 48 | """ | ||
| 49 | (:)(start::T, step, stop::T) where {T} = _colon(start, step, stop) | ||
| 50 | (:)(start::T, step, stop::T) where {T<:Real} = _colon(start, step, stop) | ||
| 51 | # without the second method above, the first method above is ambiguous with | ||
| 52 | # (:)(start::A, step, stop::C) where {A<:Real,C<:Real} | ||
| 53 | function _colon(start::T, step, stop::T) where T | ||
| 54 | T′ = typeof(start+zero(step)) | ||
| 55 | StepRange(convert(T′,start), step, convert(T′,stop)) | ||
| 56 | end | ||
| 57 | |||
| 58 | """ | ||
| 59 | range(start, stop, length) | ||
| 60 | range(start, stop; length, step) | ||
| 61 | range(start; length, stop, step) | ||
| 62 | range(;start, length, stop, step) | ||
| 63 | |||
| 64 | Construct a specialized array with evenly spaced elements and optimized storage (an [`AbstractRange`](@ref)) from the arguments. | ||
| 65 | Mathematically a range is uniquely determined by any three of `start`, `step`, `stop` and `length`. | ||
| 66 | Valid invocations of range are: | ||
| 67 | * Call `range` with any three of `start`, `step`, `stop`, `length`. | ||
| 68 | * Call `range` with two of `start`, `stop`, `length`. In this case `step` will be assumed | ||
| 69 | to be one. If both arguments are Integers, a [`UnitRange`](@ref) will be returned. | ||
| 70 | * Call `range` with one of `stop` or `length`. `start` and `step` will be assumed to be one. | ||
| 71 | |||
| 72 | See Extended Help for additional details on the returned type. | ||
| 73 | |||
| 74 | # Examples | ||
| 75 | ```jldoctest | ||
| 76 | julia> range(1, length=100) | ||
| 77 | 1:100 | ||
| 78 | |||
| 79 | julia> range(1, stop=100) | ||
| 80 | 1:100 | ||
| 81 | |||
| 82 | julia> range(1, step=5, length=100) | ||
| 83 | 1:5:496 | ||
| 84 | |||
| 85 | julia> range(1, step=5, stop=100) | ||
| 86 | 1:5:96 | ||
| 87 | |||
| 88 | julia> range(1, 10, length=101) | ||
| 89 | 1.0:0.09:10.0 | ||
| 90 | |||
| 91 | julia> range(1, 100, step=5) | ||
| 92 | 1:5:96 | ||
| 93 | |||
| 94 | julia> range(stop=10, length=5) | ||
| 95 | 6:10 | ||
| 96 | |||
| 97 | julia> range(stop=10, step=1, length=5) | ||
| 98 | 6:1:10 | ||
| 99 | |||
| 100 | julia> range(start=1, step=1, stop=10) | ||
| 101 | 1:1:10 | ||
| 102 | |||
| 103 | julia> range(; length = 10) | ||
| 104 | Base.OneTo(10) | ||
| 105 | |||
| 106 | julia> range(; stop = 6) | ||
| 107 | Base.OneTo(6) | ||
| 108 | |||
| 109 | julia> range(; stop = 6.5) | ||
| 110 | 1.0:1.0:6.0 | ||
| 111 | ``` | ||
| 112 | If `length` is not specified and `stop - start` is not an integer multiple of `step`, a range that ends before `stop` will be produced. | ||
| 113 | ```jldoctest | ||
| 114 | julia> range(1, 3.5, step=2) | ||
| 115 | 1.0:2.0:3.0 | ||
| 116 | ``` | ||
| 117 | |||
| 118 | Special care is taken to ensure intermediate values are computed rationally. | ||
| 119 | To avoid this induced overhead, see the [`LinRange`](@ref) constructor. | ||
| 120 | |||
| 121 | !!! compat "Julia 1.1" | ||
| 122 | `stop` as a positional argument requires at least Julia 1.1. | ||
| 123 | |||
| 124 | !!! compat "Julia 1.7" | ||
| 125 | The versions without keyword arguments and `start` as a keyword argument | ||
| 126 | require at least Julia 1.7. | ||
| 127 | |||
| 128 | !!! compat "Julia 1.8" | ||
| 129 | The versions with `stop` as a sole keyword argument, | ||
| 130 | or `length` as a sole keyword argument require at least Julia 1.8. | ||
| 131 | |||
| 132 | |||
| 133 | # Extended Help | ||
| 134 | |||
| 135 | `range` will produce a `Base.OneTo` when the arguments are Integers and | ||
| 136 | * Only `length` is provided | ||
| 137 | * Only `stop` is provided | ||
| 138 | |||
| 139 | `range` will produce a `UnitRange` when the arguments are Integers and | ||
| 140 | * Only `start` and `stop` are provided | ||
| 141 | * Only `length` and `stop` are provided | ||
| 142 | |||
| 143 | A `UnitRange` is not produced if `step` is provided even if specified as one. | ||
| 144 | """ | ||
| 145 | function range end | ||
| 146 | |||
| 147 | range(start; stop=nothing, length::Union{Integer,Nothing}=nothing, step=nothing) = | ||
| 148 | _range(start, step, stop, length) | ||
| 149 | range(start, stop; length::Union{Integer,Nothing}=nothing, step=nothing) = _range(start, step, stop, length) | ||
| 150 | range(start, stop, length::Integer) = _range(start, nothing, stop, length) | ||
| 151 | |||
| 152 | range(;start=nothing, stop=nothing, length::Union{Integer, Nothing}=nothing, step=nothing) = | ||
| 153 | _range(start, step, stop, length) | ||
| 154 | |||
| 155 | _range(start::Nothing, step::Nothing, stop::Nothing, len::Nothing) = range_error(start, step, stop, len) | ||
| 156 | _range(start::Nothing, step::Nothing, stop::Nothing, len::Any ) = range_length(len) | ||
| 157 | _range(start::Nothing, step::Nothing, stop::Any , len::Nothing) = range_stop(stop) | ||
| 158 | _range(start::Nothing, step::Nothing, stop::Any , len::Any ) = range_stop_length(stop, len) | ||
| 159 | _range(start::Nothing, step::Any , stop::Nothing, len::Nothing) = range_error(start, step, stop, len) | ||
| 160 | _range(start::Nothing, step::Any , stop::Nothing, len::Any ) = range_error(start, step, stop, len) | ||
| 161 | _range(start::Nothing, step::Any , stop::Any , len::Nothing) = range_error(start, step, stop, len) | ||
| 162 | _range(start::Nothing, step::Any , stop::Any , len::Any ) = range_step_stop_length(step, stop, len) | ||
| 163 | _range(start::Any , step::Nothing, stop::Nothing, len::Nothing) = range_error(start, step, stop, len) | ||
| 164 | _range(start::Any , step::Nothing, stop::Nothing, len::Any ) = range_start_length(start, len) | ||
| 165 | _range(start::Any , step::Nothing, stop::Any , len::Nothing) = range_start_stop(start, stop) | ||
| 166 | _range(start::Any , step::Nothing, stop::Any , len::Any ) = range_start_stop_length(start, stop, len) | ||
| 167 | _range(start::Any , step::Any , stop::Nothing, len::Nothing) = range_error(start, step, stop, len) | ||
| 168 | _range(start::Any , step::Any , stop::Nothing, len::Any ) = range_start_step_length(start, step, len) | ||
| 169 | _range(start::Any , step::Any , stop::Any , len::Nothing) = range_start_step_stop(start, step, stop) | ||
| 170 | _range(start::Any , step::Any , stop::Any , len::Any ) = range_error(start, step, stop, len) | ||
| 171 | |||
| 172 | # Length as the only argument | ||
| 173 | range_length(len::Integer) = OneTo(len) | ||
| 174 | |||
| 175 | # Stop as the only argument | ||
| 176 | range_stop(stop) = range_start_stop(oftype(stop, 1), stop) | ||
| 177 | range_stop(stop::Integer) = range_length(stop) | ||
| 178 | |||
| 179 | function range_step_stop_length(step, a, len::Integer) | ||
| 180 | start = a - step * (len - oneunit(len)) | ||
| 181 | if start isa Signed | ||
| 182 | # overflow in recomputing length from stop is okay | ||
| 183 | return StepRange{typeof(start),typeof(step)}(start, step, convert(typeof(start), a)) | ||
| 184 | end | ||
| 185 | return StepRangeLen{typeof(start),typeof(start),typeof(step)}(start, step, len) | ||
| 186 | end | ||
| 187 | |||
| 188 | # Stop and length as the only argument | ||
| 189 | function range_stop_length(a, len::Integer) | ||
| 190 | step = oftype(a - a, 1) # assert that step is representable | ||
| 191 | start = a - (len - oneunit(len)) | ||
| 192 | if start isa Signed | ||
| 193 | # overflow in recomputing length from stop is okay | ||
| 194 | return UnitRange(start, oftype(start, a)) | ||
| 195 | end | ||
| 196 | return StepRangeLen{typeof(start),typeof(start),typeof(step)}(start, step, len) | ||
| 197 | end | ||
| 198 | |||
| 199 | # Start and length as the only argument | ||
| 200 | function range_start_length(a, len::Integer) | ||
| 201 | step = oftype(a - a, 1) # assert that step is representable | ||
| 202 | stop = a + (len - oneunit(len)) | ||
| 203 | if stop isa Signed | ||
| 204 | # overflow in recomputing length from stop is okay | ||
| 205 | return UnitRange(oftype(stop, a), stop) | ||
| 206 | end | ||
| 207 | return StepRangeLen{typeof(stop),typeof(a),typeof(step)}(a, step, len) | ||
| 208 | end | ||
| 209 | |||
| 210 | range_start_stop(start, stop) = start:stop | ||
| 211 | |||
| 212 | function range_start_step_length(a, step, len::Integer) | ||
| 213 | stop = a + step * (len - oneunit(len)) | ||
| 214 | if stop isa Signed | ||
| 215 | # overflow in recomputing length from stop is okay | ||
| 216 | return StepRange{typeof(stop),typeof(step)}(convert(typeof(stop), a), step, stop) | ||
| 217 | end | ||
| 218 | return StepRangeLen{typeof(stop),typeof(a),typeof(step)}(a, step, len) | ||
| 219 | end | ||
| 220 | |||
| 221 | range_start_step_stop(start, step, stop) = start:step:stop | ||
| 222 | |||
| 223 | function range_error(start, step, stop, length) | ||
| 224 | hasstart = start !== nothing | ||
| 225 | hasstep = step !== nothing | ||
| 226 | hasstop = stop !== nothing | ||
| 227 | haslength = start !== nothing | ||
| 228 | |||
| 229 | hint = if hasstart && hasstep && hasstop && haslength | ||
| 230 | "Try specifying only three arguments" | ||
| 231 | elseif !hasstop && !haslength | ||
| 232 | "At least one of `length` or `stop` must be specified." | ||
| 233 | elseif !hasstep && !haslength | ||
| 234 | "At least one of `length` or `step` must be specified." | ||
| 235 | elseif !hasstart && !hasstop | ||
| 236 | "At least one of `start` or `stop` must be specified." | ||
| 237 | else | ||
| 238 | "Try specifying more arguments." | ||
| 239 | end | ||
| 240 | |||
| 241 | msg = """ | ||
| 242 | Cannot construct range from arguments: | ||
| 243 | start = $start | ||
| 244 | step = $step | ||
| 245 | stop = $stop | ||
| 246 | length = $length | ||
| 247 | $hint | ||
| 248 | """ | ||
| 249 | throw(ArgumentError(msg)) | ||
| 250 | end | ||
| 251 | |||
| 252 | ## 1-dimensional ranges ## | ||
| 253 | |||
| 254 | """ | ||
| 255 | AbstractRange{T} | ||
| 256 | |||
| 257 | Supertype for ranges with elements of type `T`. | ||
| 258 | [`UnitRange`](@ref) and other types are subtypes of this. | ||
| 259 | """ | ||
| 260 | abstract type AbstractRange{T} <: AbstractArray{T,1} end | ||
| 261 | |||
| 262 | RangeStepStyle(::Type{<:AbstractRange}) = RangeStepIrregular() | ||
| 263 | RangeStepStyle(::Type{<:AbstractRange{<:Integer}}) = RangeStepRegular() | ||
| 264 | |||
| 265 | convert(::Type{T}, r::AbstractRange) where {T<:AbstractRange} = r isa T ? r : T(r)::T | ||
| 266 | |||
| 267 | ## ordinal ranges | ||
| 268 | |||
| 269 | """ | ||
| 270 | OrdinalRange{T, S} <: AbstractRange{T} | ||
| 271 | |||
| 272 | Supertype for ordinal ranges with elements of type `T` with | ||
| 273 | spacing(s) of type `S`. The steps should be always-exact | ||
| 274 | multiples of [`oneunit`](@ref), and `T` should be a "discrete" | ||
| 275 | type, which cannot have values smaller than `oneunit`. For example, | ||
| 276 | `Integer` or `Date` types would qualify, whereas `Float64` would not (since this | ||
| 277 | type can represent values smaller than `oneunit(Float64)`. | ||
| 278 | [`UnitRange`](@ref), [`StepRange`](@ref), and other types are subtypes of this. | ||
| 279 | """ | ||
| 280 | abstract type OrdinalRange{T,S} <: AbstractRange{T} end | ||
| 281 | |||
| 282 | """ | ||
| 283 | AbstractUnitRange{T} <: OrdinalRange{T, T} | ||
| 284 | |||
| 285 | Supertype for ranges with a step size of [`oneunit(T)`](@ref) with elements of type `T`. | ||
| 286 | [`UnitRange`](@ref) and other types are subtypes of this. | ||
| 287 | """ | ||
| 288 | abstract type AbstractUnitRange{T} <: OrdinalRange{T,T} end | ||
| 289 | |||
| 290 | """ | ||
| 291 | StepRange{T, S} <: OrdinalRange{T, S} | ||
| 292 | |||
| 293 | Ranges with elements of type `T` with spacing of type `S`. The step | ||
| 294 | between each element is constant, and the range is defined in terms | ||
| 295 | of a `start` and `stop` of type `T` and a `step` of type `S`. Neither | ||
| 296 | `T` nor `S` should be floating point types. The syntax `a:b:c` with `b != 0` | ||
| 297 | and `a`, `b`, and `c` all integers creates a `StepRange`. | ||
| 298 | |||
| 299 | # Examples | ||
| 300 | ```jldoctest | ||
| 301 | julia> collect(StepRange(1, Int8(2), 10)) | ||
| 302 | 5-element Vector{Int64}: | ||
| 303 | 1 | ||
| 304 | 3 | ||
| 305 | 5 | ||
| 306 | 7 | ||
| 307 | 9 | ||
| 308 | |||
| 309 | julia> typeof(StepRange(1, Int8(2), 10)) | ||
| 310 | StepRange{Int64, Int8} | ||
| 311 | |||
| 312 | julia> typeof(1:3:6) | ||
| 313 | StepRange{Int64, Int64} | ||
| 314 | ``` | ||
| 315 | """ | ||
| 316 | struct StepRange{T,S} <: OrdinalRange{T,S} | ||
| 317 | start::T | ||
| 318 | step::S | ||
| 319 | stop::T | ||
| 320 | |||
| 321 | function StepRange{T,S}(start, step, stop) where {T,S} | ||
| 322 | start = convert(T, start) | ||
| 323 | step = convert(S, step) | ||
| 324 | stop = convert(T, stop) | ||
| 325 | return new(start, step, steprange_last(start, step, stop)) | ||
| 326 | end | ||
| 327 | end | ||
| 328 | |||
| 329 | # to make StepRange constructor inlineable, so optimizer can see `step` value | ||
| 330 | function steprange_last(start, step, stop)::typeof(stop) | ||
| 331 | if isa(start, AbstractFloat) || isa(step, AbstractFloat) | ||
| 332 | throw(ArgumentError("StepRange should not be used with floating point")) | ||
| 333 | end | ||
| 334 | if isa(start, Integer) && !isinteger(start + step) | ||
| 335 | throw(ArgumentError("StepRange{<:Integer} cannot have non-integer step")) | ||
| 336 | end | ||
| 337 | z = zero(step) | ||
| 338 | step == z && throw(ArgumentError("step cannot be zero")) | ||
| 339 | |||
| 340 | if stop == start | ||
| 341 | last = stop | ||
| 342 | else | ||
| 343 | if (step > z) != (stop > start) | ||
| 344 | last = steprange_last_empty(start, step, stop) | ||
| 345 | else | ||
| 346 | # Compute absolute value of difference between `start` and `stop` | ||
| 347 | # (to simplify handling both signed and unsigned T and checking for signed overflow): | ||
| 348 | absdiff, absstep = stop > start ? (stop - start, step) : (start - stop, -step) | ||
| 349 | |||
| 350 | # Compute remainder as a nonnegative number: | ||
| 351 | if absdiff isa Signed && absdiff < zero(absdiff) | ||
| 352 | # unlikely, but handle the signed overflow case with unsigned rem | ||
| 353 | overflow_case(absdiff, absstep) = (@noinline; convert(typeof(absdiff), unsigned(absdiff) % absstep)) | ||
| 354 | remain = overflow_case(absdiff, absstep) | ||
| 355 | else | ||
| 356 | remain = convert(typeof(absdiff), absdiff % absstep) | ||
| 357 | end | ||
| 358 | # Move `stop` closer to `start` if there is a remainder: | ||
| 359 | last = stop > start ? stop - remain : stop + remain | ||
| 360 | end | ||
| 361 | end | ||
| 362 | return last | ||
| 363 | end | ||
| 364 | |||
| 365 | function steprange_last_empty(start::Integer, step, stop)::typeof(stop) | ||
| 366 | # empty range has a special representation where stop = start-1, | ||
| 367 | # which simplifies arithmetic for Signed numbers | ||
| 368 | if step > zero(step) | ||
| 369 | last = start - oneunit(step) | ||
| 370 | else | ||
| 371 | last = start + oneunit(step) | ||
| 372 | end | ||
| 373 | return last | ||
| 374 | end | ||
| 375 | # For types where x+oneunit(x) may not be well-defined use the user-given value for stop | ||
| 376 | steprange_last_empty(start, step, stop) = stop | ||
| 377 | |||
| 378 | StepRange{T}(start, step::S, stop) where {T,S} = StepRange{T,S}(start, step, stop) | ||
| 379 | StepRange(start::T, step::S, stop::T) where {T,S} = StepRange{T,S}(start, step, stop) | ||
| 380 | |||
| 381 | """ | ||
| 382 | UnitRange{T<:Real} | ||
| 383 | |||
| 384 | A range parameterized by a `start` and `stop` of type `T`, filled | ||
| 385 | with elements spaced by `1` from `start` until `stop` is exceeded. | ||
| 386 | The syntax `a:b` with `a` and `b` both `Integer`s creates a `UnitRange`. | ||
| 387 | |||
| 388 | # Examples | ||
| 389 | ```jldoctest | ||
| 390 | julia> collect(UnitRange(2.3, 5.2)) | ||
| 391 | 3-element Vector{Float64}: | ||
| 392 | 2.3 | ||
| 393 | 3.3 | ||
| 394 | 4.3 | ||
| 395 | |||
| 396 | julia> typeof(1:10) | ||
| 397 | UnitRange{Int64} | ||
| 398 | ``` | ||
| 399 | """ | ||
| 400 | struct UnitRange{T<:Real} <: AbstractUnitRange{T} | ||
| 401 | start::T | ||
| 402 | stop::T | ||
| 403 | UnitRange{T}(start::T, stop::T) where {T<:Real} = new(start, unitrange_last(start, stop)) | ||
| 404 | end | ||
| 405 | UnitRange{T}(start, stop) where {T<:Real} = UnitRange{T}(convert(T, start), convert(T, stop)) | ||
| 406 | UnitRange(start::T, stop::T) where {T<:Real} = UnitRange{T}(start, stop) | ||
| 407 | function UnitRange(start, stop) | ||
| 408 | startstop_promoted = promote(start, stop) | ||
| 409 | not_sametype((start, stop), startstop_promoted) | ||
| 410 | UnitRange(startstop_promoted...) | ||
| 411 | end | ||
| 412 | |||
| 413 | # if stop and start are integral, we know that their difference is a multiple of 1 | ||
| 414 | unitrange_last(start::Integer, stop::Integer) = | ||
| 415 | stop >= start ? stop : convert(typeof(stop), start - oneunit(start - stop)) | ||
| 416 | # otherwise, use `floor` as a more efficient way to compute modulus with step=1 | ||
| 417 | unitrange_last(start, stop) = | ||
| 418 | stop >= start ? convert(typeof(stop), start + floor(stop - start)) : | ||
| 419 | convert(typeof(stop), start - oneunit(start - stop)) | ||
| 420 | |||
| 421 | unitrange(x::AbstractUnitRange) = UnitRange(x) # convenience conversion for promoting the range type | ||
| 422 | |||
| 423 | if isdefined(Main, :Base) | ||
| 424 | # Constant-fold-able indexing into tuples to functionally expose Base.tail and Base.front | ||
| 425 | function getindex(@nospecialize(t::Tuple), r::AbstractUnitRange) | ||
| 426 | @inline | ||
| 427 | require_one_based_indexing(r) | ||
| 428 | if length(r) <= 10 | ||
| 429 | return ntuple(i -> t[i + first(r) - 1], length(r)) | ||
| 430 | elseif first(r) == 1 | ||
| 431 | last(r) == length(t) && return t | ||
| 432 | last(r) == length(t)-1 && return front(t) | ||
| 433 | last(r) == length(t)-2 && return front(front(t)) | ||
| 434 | elseif last(r) == length(t) | ||
| 435 | first(r) == 2 && return tail(t) | ||
| 436 | first(r) == 3 && return tail(tail(t)) | ||
| 437 | end | ||
| 438 | return (eltype(t)[t[ri] for ri in r]...,) | ||
| 439 | end | ||
| 440 | end | ||
| 441 | |||
| 442 | """ | ||
| 443 | Base.OneTo(n) | ||
| 444 | |||
| 445 | Define an `AbstractUnitRange` that behaves like `1:n`, with the added | ||
| 446 | distinction that the lower limit is guaranteed (by the type system) to | ||
| 447 | be 1. | ||
| 448 | """ | ||
| 449 | struct OneTo{T<:Integer} <: AbstractUnitRange{T} | ||
| 450 | stop::T | ||
| 451 | function OneTo{T}(stop) where {T<:Integer} | ||
| 452 | throwbool(r) = (@noinline; throw(ArgumentError("invalid index: $r of type Bool"))) | ||
| 453 | T === Bool && throwbool(stop) | ||
| 454 | return new(max(zero(T), stop)) | ||
| 455 | end | ||
| 456 | |||
| 457 | function OneTo{T}(r::AbstractRange) where {T<:Integer} | ||
| 458 | throwstart(r) = (@noinline; throw(ArgumentError("first element must be 1, got $(first(r))"))) | ||
| 459 | throwstep(r) = (@noinline; throw(ArgumentError("step must be 1, got $(step(r))"))) | ||
| 460 | throwbool(r) = (@noinline; throw(ArgumentError("invalid index: $r of type Bool"))) | ||
| 461 | first(r) == 1 || throwstart(r) | ||
| 462 | step(r) == 1 || throwstep(r) | ||
| 463 | T === Bool && throwbool(r) | ||
| 464 | return new(max(zero(T), last(r))) | ||
| 465 | end | ||
| 466 | end | ||
| 467 | OneTo(stop::T) where {T<:Integer} = OneTo{T}(stop) | ||
| 468 | OneTo(r::AbstractRange{T}) where {T<:Integer} = OneTo{T}(r) | ||
| 469 | oneto(r) = OneTo(r) | ||
| 470 | |||
| 471 | ## Step ranges parameterized by length | ||
| 472 | |||
| 473 | """ | ||
| 474 | StepRangeLen( ref::R, step::S, len, [offset=1]) where { R,S} | ||
| 475 | StepRangeLen{T,R,S}( ref::R, step::S, len, [offset=1]) where {T,R,S} | ||
| 476 | StepRangeLen{T,R,S,L}(ref::R, step::S, len, [offset=1]) where {T,R,S,L} | ||
| 477 | |||
| 478 | A range `r` where `r[i]` produces values of type `T` (in the first | ||
| 479 | form, `T` is deduced automatically), parameterized by a `ref`erence | ||
| 480 | value, a `step`, and the `len`gth. By default `ref` is the starting | ||
| 481 | value `r[1]`, but alternatively you can supply it as the value of | ||
| 482 | `r[offset]` for some other index `1 <= offset <= len`. The syntax `a:b` | ||
| 483 | or `a:b:c`, where any of `a`, `b`, or `c` are floating-point numbers, creates a | ||
| 484 | `StepRangeLen`. | ||
| 485 | |||
| 486 | !!! compat "Julia 1.7" | ||
| 487 | The 4th type parameter `L` requires at least Julia 1.7. | ||
| 488 | """ | ||
| 489 | struct StepRangeLen{T,R,S,L<:Integer} <: AbstractRange{T} | ||
| 490 | ref::R # reference value (might be smallest-magnitude value in the range) | ||
| 491 | step::S # step value | ||
| 492 | len::L # length of the range | ||
| 493 | offset::L # the index of ref | ||
| 494 | |||
| 495 | function StepRangeLen{T,R,S,L}(ref::R, step::S, len::Integer, offset::Integer = 1) where {T,R,S,L} | ||
| 496 | if T <: Integer && !isinteger(ref + step) | ||
| 497 | throw(ArgumentError("StepRangeLen{<:Integer} cannot have non-integer step")) | ||
| 498 | end | ||
| 499 | len = convert(L, len) | ||
| 500 | len >= zero(len) || throw(ArgumentError("length cannot be negative, got $len")) | ||
| 501 | offset = convert(L, offset) | ||
| 502 | L1 = oneunit(typeof(len)) | ||
| 503 | L1 <= offset <= max(L1, len) || throw(ArgumentError("StepRangeLen: offset must be in [1,$len], got $offset")) | ||
| 504 | return new(ref, step, len, offset) | ||
| 505 | end | ||
| 506 | end | ||
| 507 | |||
| 508 | StepRangeLen{T,R,S}(ref::R, step::S, len::Integer, offset::Integer = 1) where {T,R,S} = | ||
| 509 | StepRangeLen{T,R,S,promote_type(Int,typeof(len))}(ref, step, len, offset) | ||
| 510 | StepRangeLen(ref::R, step::S, len::Integer, offset::Integer = 1) where {R,S} = | ||
| 511 | StepRangeLen{typeof(ref+zero(step)),R,S,promote_type(Int,typeof(len))}(ref, step, len, offset) | ||
| 512 | StepRangeLen{T}(ref::R, step::S, len::Integer, offset::Integer = 1) where {T,R,S} = | ||
| 513 | StepRangeLen{T,R,S,promote_type(Int,typeof(len))}(ref, step, len, offset) | ||
| 514 | |||
| 515 | ## range with computed step | ||
| 516 | |||
| 517 | """ | ||
| 518 | LinRange{T,L} | ||
| 519 | |||
| 520 | A range with `len` linearly spaced elements between its `start` and `stop`. | ||
| 521 | The size of the spacing is controlled by `len`, which must | ||
| 522 | be an `Integer`. | ||
| 523 | |||
| 524 | # Examples | ||
| 525 | ```jldoctest | ||
| 526 | julia> LinRange(1.5, 5.5, 9) | ||
| 527 | 9-element LinRange{Float64, Int64}: | ||
| 528 | 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5 | ||
| 529 | ``` | ||
| 530 | |||
| 531 | Compared to using [`range`](@ref), directly constructing a `LinRange` should | ||
| 532 | have less overhead but won't try to correct for floating point errors: | ||
| 533 | ```jldoctest | ||
| 534 | julia> collect(range(-0.1, 0.3, length=5)) | ||
| 535 | 5-element Vector{Float64}: | ||
| 536 | -0.1 | ||
| 537 | 0.0 | ||
| 538 | 0.1 | ||
| 539 | 0.2 | ||
| 540 | 0.3 | ||
| 541 | |||
| 542 | julia> collect(LinRange(-0.1, 0.3, 5)) | ||
| 543 | 5-element Vector{Float64}: | ||
| 544 | -0.1 | ||
| 545 | -1.3877787807814457e-17 | ||
| 546 | 0.09999999999999999 | ||
| 547 | 0.19999999999999998 | ||
| 548 | 0.3 | ||
| 549 | ``` | ||
| 550 | """ | ||
| 551 | struct LinRange{T,L<:Integer} <: AbstractRange{T} | ||
| 552 | start::T | ||
| 553 | stop::T | ||
| 554 | len::L | ||
| 555 | lendiv::L | ||
| 556 | |||
| 557 | function LinRange{T,L}(start::T, stop::T, len::L) where {T,L<:Integer} | ||
| 558 | len >= 0 || throw(ArgumentError("range($start, stop=$stop, length=$len): negative length")) | ||
| 559 | onelen = oneunit(typeof(len)) | ||
| 560 | if len == onelen | ||
| 561 | start == stop || throw(ArgumentError("range($start, stop=$stop, length=$len): endpoints differ")) | ||
| 562 | return new(start, stop, len, len) | ||
| 563 | end | ||
| 564 | lendiv = max(len - onelen, onelen) | ||
| 565 | if T <: Integer && !iszero(mod(stop-start, lendiv)) | ||
| 566 | throw(ArgumentError("LinRange{<:Integer} cannot have non-integer step")) | ||
| 567 | end | ||
| 568 | return new(start, stop, len, lendiv) | ||
| 569 | end | ||
| 570 | end | ||
| 571 | |||
| 572 | function LinRange{T,L}(start, stop, len::Integer) where {T,L} | ||
| 573 | LinRange{T,L}(convert(T, start), convert(T, stop), convert(L, len)) | ||
| 574 | end | ||
| 575 | |||
| 576 | function LinRange{T}(start, stop, len::Integer) where T | ||
| 577 | LinRange{T,promote_type(Int,typeof(len))}(start, stop, len) | ||
| 578 | end | ||
| 579 | |||
| 580 | function LinRange(start, stop, len::Integer) | ||
| 581 | T = typeof((zero(stop) - zero(start)) / oneunit(len)) | ||
| 582 | LinRange{T}(start, stop, len) | ||
| 583 | end | ||
| 584 | |||
| 585 | range_start_stop_length(start, stop, len::Integer) = | ||
| 586 | range_start_stop_length(promote(start, stop)..., len) | ||
| 587 | range_start_stop_length(start::T, stop::T, len::Integer) where {T} = LinRange(start, stop, len) | ||
| 588 | range_start_stop_length(start::T, stop::T, len::Integer) where {T<:Integer} = | ||
| 589 | _linspace(float(T), start, stop, len) | ||
| 590 | ## for Float16, Float32, and Float64 we hit twiceprecision.jl to lift to higher precision StepRangeLen | ||
| 591 | # for all other types we fall back to a plain old LinRange | ||
| 592 | _linspace(::Type{T}, start::Integer, stop::Integer, len::Integer) where T = LinRange{T}(start, stop, len) | ||
| 593 | |||
| 594 | function show(io::IO, r::LinRange{T}) where {T} | ||
| 595 | print(io, "LinRange{") | ||
| 596 | show(io, T) | ||
| 597 | print(io, "}(") | ||
| 598 | ioc = IOContext(io, :typeinfo=>T) | ||
| 599 | show(ioc, first(r)) | ||
| 600 | print(io, ", ") | ||
| 601 | show(ioc, last(r)) | ||
| 602 | print(io, ", ") | ||
| 603 | show(io, length(r)) | ||
| 604 | print(io, ')') | ||
| 605 | end | ||
| 606 | |||
| 607 | """ | ||
| 608 | `print_range(io, r)` prints out a nice looking range r in terms of its elements | ||
| 609 | as if it were `collect(r)`, dependent on the size of the | ||
| 610 | terminal, and taking into account whether compact numbers should be shown. | ||
| 611 | It figures out the width in characters of each element, and if they | ||
| 612 | end up too wide, it shows the first and last elements separated by a | ||
| 613 | horizontal ellipsis. Typical output will look like `1.0, 2.0, …, 5.0, 6.0`. | ||
| 614 | |||
| 615 | `print_range(io, r, pre, sep, post, hdots)` uses optional | ||
| 616 | parameters `pre` and `post` characters for each printed row, | ||
| 617 | `sep` separator string between printed elements, | ||
| 618 | `hdots` string for the horizontal ellipsis. | ||
| 619 | """ | ||
| 620 | function print_range(io::IO, r::AbstractRange, | ||
| 621 | pre::AbstractString = " ", | ||
| 622 | sep::AbstractString = ", ", | ||
| 623 | post::AbstractString = "", | ||
| 624 | hdots::AbstractString = ", \u2026, ") # horiz ellipsis | ||
| 625 | # This function borrows from print_matrix() in show.jl | ||
| 626 | # and should be called by show and display | ||
| 627 | sz = displaysize(io) | ||
| 628 | if !haskey(io, :compact) | ||
| 629 | io = IOContext(io, :compact => true) | ||
| 630 | end | ||
| 631 | screenheight, screenwidth = sz[1] - 4, sz[2] | ||
| 632 | screenwidth -= length(pre) + length(post) | ||
| 633 | postsp = "" | ||
| 634 | sepsize = length(sep) | ||
| 635 | m = 1 # treat the range as a one-row matrix | ||
| 636 | n = length(r) | ||
| 637 | # Figure out spacing alignments for r, but only need to examine the | ||
| 638 | # left and right edge columns, as many as could conceivably fit on the | ||
| 639 | # screen, with the middle columns summarized by horz, vert, or diag ellipsis | ||
| 640 | maxpossiblecols = div(screenwidth, 1+sepsize) # assume each element is at least 1 char + 1 separator | ||
| 641 | colsr = n <= maxpossiblecols ? (1:n) : [1:div(maxpossiblecols,2)+1; (n-div(maxpossiblecols,2)):n] | ||
| 642 | rowmatrix = reshape(r[colsr], 1, length(colsr)) # treat the range as a one-row matrix for print_matrix_row | ||
| 643 | nrow, idxlast = size(rowmatrix, 2), last(axes(rowmatrix, 2)) | ||
| 644 | A = alignment(io, rowmatrix, 1:m, 1:length(rowmatrix), screenwidth, screenwidth, sepsize, nrow) # how much space range takes | ||
| 645 | if n <= length(A) # cols fit screen, so print out all elements | ||
| 646 | print(io, pre) # put in pre chars | ||
| 647 | print_matrix_row(io,rowmatrix,A,1,1:n,sep,idxlast) # the entire range | ||
| 648 | print(io, post) # add the post characters | ||
| 649 | else # cols don't fit so put horiz ellipsis in the middle | ||
| 650 | # how many chars left after dividing width of screen in half | ||
| 651 | # and accounting for the horiz ellipsis | ||
| 652 | c = div(screenwidth-length(hdots)+1,2)+1 # chars remaining for each side of rowmatrix | ||
| 653 | alignR = reverse(alignment(io, rowmatrix, 1:m, length(rowmatrix):-1:1, c, c, sepsize, nrow)) # which cols of rowmatrix to put on the right | ||
| 654 | c = screenwidth - sum(map(sum,alignR)) - (length(alignR)-1)*sepsize - length(hdots) | ||
| 655 | alignL = alignment(io, rowmatrix, 1:m, 1:length(rowmatrix), c, c, sepsize, nrow) # which cols of rowmatrix to put on the left | ||
| 656 | print(io, pre) # put in pre chars | ||
| 657 | print_matrix_row(io, rowmatrix,alignL,1,1:length(alignL),sep,idxlast) # left part of range | ||
| 658 | print(io, hdots) # horizontal ellipsis | ||
| 659 | print_matrix_row(io, rowmatrix,alignR,1,length(rowmatrix)-length(alignR)+1:length(rowmatrix),sep,idxlast) # right part of range | ||
| 660 | print(io, post) # post chars | ||
| 661 | end | ||
| 662 | end | ||
| 663 | |||
| 664 | ## interface implementations | ||
| 665 | |||
| 666 | length(r::AbstractRange) = error("length implementation missing") # catch mistakes | ||
| 667 | size(r::AbstractRange) = (length(r),) | ||
| 668 | |||
| 669 | isempty(r::StepRange) = | ||
| 670 | # steprange_last(r.start, r.step, r.stop) == r.stop | ||
| 671 | (r.start != r.stop) & ((r.step > zero(r.step)) != (r.stop > r.start)) | ||
| 672 | isempty(r::AbstractUnitRange) = first(r) > last(r) | ||
| 673 | isempty(r::StepRangeLen) = length(r) == 0 | ||
| 674 | isempty(r::LinRange) = length(r) == 0 | ||
| 675 | |||
| 676 | """ | ||
| 677 | step(r) | ||
| 678 | |||
| 679 | Get the step size of an [`AbstractRange`](@ref) object. | ||
| 680 | |||
| 681 | # Examples | ||
| 682 | ```jldoctest | ||
| 683 | julia> step(1:10) | ||
| 684 | 1 | ||
| 685 | |||
| 686 | julia> step(1:2:10) | ||
| 687 | 2 | ||
| 688 | |||
| 689 | julia> step(2.5:0.3:10.9) | ||
| 690 | 0.3 | ||
| 691 | |||
| 692 | julia> step(range(2.5, stop=10.9, length=85)) | ||
| 693 | 0.1 | ||
| 694 | ``` | ||
| 695 | """ | ||
| 696 | step(r::StepRange) = r.step | ||
| 697 | step(r::AbstractUnitRange{T}) where {T} = oneunit(T) - zero(T) | ||
| 698 | step(r::StepRangeLen) = r.step | ||
| 699 | step(r::StepRangeLen{T}) where {T<:AbstractFloat} = T(r.step) | ||
| 700 | step(r::LinRange) = (last(r)-first(r))/r.lendiv | ||
| 701 | |||
| 702 | # high-precision step | ||
| 703 | step_hp(r::StepRangeLen) = r.step | ||
| 704 | step_hp(r::AbstractRange) = step(r) | ||
| 705 | |||
| 706 | axes(r::AbstractRange) = (oneto(length(r)),) | ||
| 707 | |||
| 708 | # Needed to ensure `has_offset_axes` can constant-fold. | ||
| 709 | has_offset_axes(::StepRange) = false | ||
| 710 | |||
| 711 | # n.b. checked_length for these is defined iff checked_add and checked_sub are | ||
| 712 | # defined between the relevant types | ||
| 713 | function checked_length(r::OrdinalRange{T}) where T | ||
| 714 | s = step(r) | ||
| 715 | start = first(r) | ||
| 716 | if isempty(r) | ||
| 717 | return Integer(div(start - start, oneunit(s))) | ||
| 718 | end | ||
| 719 | stop = last(r) | ||
| 720 | if isless(s, zero(s)) | ||
| 721 | diff = checked_sub(start, stop) | ||
| 722 | s = -s | ||
| 723 | else | ||
| 724 | diff = checked_sub(stop, start) | ||
| 725 | end | ||
| 726 | a = div(diff, s) | ||
| 727 | return Integer(checked_add(a, oneunit(a))) | ||
| 728 | end | ||
| 729 | |||
| 730 | function checked_length(r::AbstractUnitRange{T}) where T | ||
| 731 | # compiler optimization: remove dead cases from above | ||
| 732 | if isempty(r) | ||
| 733 | return Integer(first(r) - first(r)) | ||
| 734 | end | ||
| 735 | a = checked_sub(last(r), first(r)) | ||
| 736 | return Integer(checked_add(a, oneunit(a))) | ||
| 737 | end | ||
| 738 | |||
| 739 | function length(r::OrdinalRange{T}) where T | ||
| 740 | s = step(r) | ||
| 741 | start = first(r) | ||
| 742 | if isempty(r) | ||
| 743 | return Integer(div(start - start, oneunit(s))) | ||
| 744 | end | ||
| 745 | stop = last(r) | ||
| 746 | if isless(s, zero(s)) | ||
| 747 | diff = start - stop | ||
| 748 | s = -s | ||
| 749 | else | ||
| 750 | diff = stop - start | ||
| 751 | end | ||
| 752 | a = div(diff, s) | ||
| 753 | return Integer(a + oneunit(a)) | ||
| 754 | end | ||
| 755 | |||
| 756 | function length(r::AbstractUnitRange{T}) where T | ||
| 757 | @inline | ||
| 758 | start, stop = first(r), last(r) | ||
| 759 | a = oneunit(zero(stop) - zero(start)) | ||
| 760 | if a isa Signed || stop >= start | ||
| 761 | a += stop - start # Signed are allowed to go negative | ||
| 762 | else | ||
| 763 | a = zero(a) # Unsigned don't necessarily underflow | ||
| 764 | end | ||
| 765 | return Integer(a) | ||
| 766 | end | ||
| 767 | |||
| 768 | length(r::OneTo) = Integer(r.stop - zero(r.stop)) | ||
| 769 | length(r::StepRangeLen) = r.len | ||
| 770 | length(r::LinRange) = r.len | ||
| 771 | |||
| 772 | let bigints = Union{Int, UInt, Int64, UInt64, Int128, UInt128}, | ||
| 773 | smallints = (Int === Int64 ? | ||
| 774 | Union{Int8, UInt8, Int16, UInt16, Int32, UInt32} : | ||
| 775 | Union{Int8, UInt8, Int16, UInt16}), | ||
| 776 | bitints = Union{bigints, smallints} | ||
| 777 | global length, checked_length, firstindex | ||
| 778 | # compile optimization for which promote_type(T, Int) == T | ||
| 779 | length(r::OneTo{T}) where {T<:bigints} = r.stop | ||
| 780 | # slightly more accurate length and checked_length in extreme cases | ||
| 781 | # (near typemax) for types with known `unsigned` functions | ||
| 782 | function length(r::OrdinalRange{T}) where T<:bigints | ||
| 783 | s = step(r) | ||
| 784 | diff = last(r) - first(r) | ||
| 785 | isempty(r) && return zero(diff) | ||
| 786 | # if |s| > 1, diff might have overflowed, but unsigned(diff)÷s should | ||
| 787 | # therefore still be valid (if the result is representable at all) | ||
| 788 | # n.b. !(s isa T) | ||
| 789 | if s isa Unsigned || -1 <= s <= 1 || s == -s | ||
| 790 | a = div(diff, s) % typeof(diff) | ||
| 791 | elseif s < 0 | ||
| 792 | a = div(unsigned(-diff), -s) % typeof(diff) | ||
| 793 | else | ||
| 794 | a = div(unsigned(diff), s) % typeof(diff) | ||
| 795 | end | ||
| 796 | return a + oneunit(a) | ||
| 797 | end | ||
| 798 | function checked_length(r::OrdinalRange{T}) where T<:bigints | ||
| 799 | s = step(r) | ||
| 800 | stop, start = last(r), first(r) | ||
| 801 | ET = promote_type(typeof(stop), typeof(start)) | ||
| 802 | isempty(r) && return zero(ET) | ||
| 803 | # n.b. !(s isa T) | ||
| 804 | if s > 1 | ||
| 805 | diff = stop - start | ||
| 806 | a = convert(ET, div(unsigned(diff), s)) | ||
| 807 | elseif s < -1 | ||
| 808 | diff = start - stop | ||
| 809 | a = convert(ET, div(unsigned(diff), -s)) | ||
| 810 | elseif s > 0 | ||
| 811 | a = convert(ET, div(checked_sub(stop, start), s)) | ||
| 812 | else | ||
| 813 | a = convert(ET, div(checked_sub(start, stop), -s)) | ||
| 814 | end | ||
| 815 | return checked_add(a, oneunit(a)) | ||
| 816 | end | ||
| 817 | firstindex(r::StepRange{<:bigints,<:bitints}) = one(last(r)-first(r)) | ||
| 818 | |||
| 819 | # some special cases to favor default Int type | ||
| 820 | function length(r::OrdinalRange{<:smallints}) | ||
| 821 | s = step(r) | ||
| 822 | isempty(r) && return 0 | ||
| 823 | # n.b. !(step isa T) | ||
| 824 | return Int(div(Int(last(r)) - Int(first(r)), s)) + 1 | ||
| 825 | end | ||
| 826 | length(r::AbstractUnitRange{<:smallints}) = Int(last(r)) - Int(first(r)) + 1 | ||
| 827 | length(r::OneTo{<:smallints}) = Int(r.stop) | ||
| 828 | checked_length(r::OrdinalRange{<:smallints}) = length(r) | ||
| 829 | checked_length(r::AbstractUnitRange{<:smallints}) = length(r) | ||
| 830 | checked_length(r::OneTo{<:smallints}) = length(r) | ||
| 831 | firstindex(::StepRange{<:smallints,<:bitints}) = 1 | ||
| 832 | end | ||
| 833 | |||
| 834 | first(r::OrdinalRange{T}) where {T} = convert(T, r.start) | ||
| 835 | first(r::OneTo{T}) where {T} = oneunit(T) | ||
| 836 | first(r::StepRangeLen) = unsafe_getindex(r, 1) | ||
| 837 | first(r::LinRange) = r.start | ||
| 838 | |||
| 839 | last(r::OrdinalRange{T}) where {T} = convert(T, r.stop) # via steprange_last | ||
| 840 | last(r::StepRangeLen) = unsafe_getindex(r, length(r)) | ||
| 841 | last(r::LinRange) = r.stop | ||
| 842 | |||
| 843 | minimum(r::AbstractUnitRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : first(r) | ||
| 844 | maximum(r::AbstractUnitRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : last(r) | ||
| 845 | minimum(r::AbstractRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : min(first(r), last(r)) | ||
| 846 | maximum(r::AbstractRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : max(first(r), last(r)) | ||
| 847 | |||
| 848 | """ | ||
| 849 | argmin(r::AbstractRange) | ||
| 850 | |||
| 851 | Ranges can have multiple minimal elements. In that case | ||
| 852 | `argmin` will return a minimal index, but not necessarily the | ||
| 853 | first one. | ||
| 854 | """ | ||
| 855 | function argmin(r::AbstractRange) | ||
| 856 | if isempty(r) | ||
| 857 | throw(ArgumentError("range must be non-empty")) | ||
| 858 | elseif step(r) > 0 | ||
| 859 | firstindex(r) | ||
| 860 | else | ||
| 861 | lastindex(r) | ||
| 862 | end | ||
| 863 | end | ||
| 864 | |||
| 865 | """ | ||
| 866 | argmax(r::AbstractRange) | ||
| 867 | |||
| 868 | Ranges can have multiple maximal elements. In that case | ||
| 869 | `argmax` will return a maximal index, but not necessarily the | ||
| 870 | first one. | ||
| 871 | """ | ||
| 872 | function argmax(r::AbstractRange) | ||
| 873 | if isempty(r) | ||
| 874 | throw(ArgumentError("range must be non-empty")) | ||
| 875 | elseif step(r) > 0 | ||
| 876 | lastindex(r) | ||
| 877 | else | ||
| 878 | firstindex(r) | ||
| 879 | end | ||
| 880 | end | ||
| 881 | |||
| 882 | extrema(r::AbstractRange) = (minimum(r), maximum(r)) | ||
| 883 | |||
| 884 | # Ranges are immutable | ||
| 885 | copy(r::AbstractRange) = r | ||
| 886 | |||
| 887 | |||
| 888 | ## iteration | ||
| 889 | |||
| 890 | function iterate(r::Union{StepRangeLen,LinRange}, i::Integer=zero(length(r))) | ||
| 891 | @inline | ||
| 892 | i += oneunit(i) | ||
| 893 | length(r) < i && return nothing | ||
| 894 | unsafe_getindex(r, i), i | ||
| 895 | end | ||
| 896 | |||
| 897 | iterate(r::OrdinalRange) = isempty(r) ? nothing : (first(r), first(r)) | ||
| 898 | |||
| 899 | function iterate(r::OrdinalRange{T}, i) where {T} | ||
| 900 | @inline | ||
| 901 | 1 (2 %) |
1 (100 %)
samples spent calling
==
i == last(r) && return nothing
|
|
| 902 | next = convert(T, i + step(r)) | ||
| 903 | (next, next) | ||
| 904 | end | ||
| 905 | |||
| 906 | ## indexing | ||
| 907 | |||
| 908 | function isassigned(r::AbstractRange, i::Integer) | ||
| 909 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 910 | firstindex(r) <= i <= lastindex(r) | ||
| 911 | end | ||
| 912 | |||
| 913 | _in_unit_range(v::UnitRange, val, i::Integer) = i > 0 && val <= v.stop && val >= v.start | ||
| 914 | |||
| 915 | function getindex(v::UnitRange{T}, i::Integer) where T | ||
| 916 | @inline | ||
| 917 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 918 | val = convert(T, v.start + (i - oneunit(i))) | ||
| 919 | @boundscheck _in_unit_range(v, val, i) || throw_boundserror(v, i) | ||
| 920 | val | ||
| 921 | end | ||
| 922 | |||
| 923 | const OverflowSafe = Union{Bool,Int8,Int16,Int32,Int64,Int128, | ||
| 924 | UInt8,UInt16,UInt32,UInt64,UInt128} | ||
| 925 | |||
| 926 | function getindex(v::UnitRange{T}, i::Integer) where {T<:OverflowSafe} | ||
| 927 | @inline | ||
| 928 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 929 | val = v.start + (i - oneunit(i)) | ||
| 930 | @boundscheck _in_unit_range(v, val, i) || throw_boundserror(v, i) | ||
| 931 | val % T | ||
| 932 | end | ||
| 933 | |||
| 934 | function getindex(v::OneTo{T}, i::Integer) where T | ||
| 935 | @inline | ||
| 936 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 937 | @boundscheck ((i > 0) & (i <= v.stop)) || throw_boundserror(v, i) | ||
| 938 | convert(T, i) | ||
| 939 | end | ||
| 940 | |||
| 941 | function getindex(v::AbstractRange{T}, i::Integer) where T | ||
| 942 | @inline | ||
| 943 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 944 | ret = convert(T, first(v) + (i - oneunit(i))*step_hp(v)) | ||
| 945 | ok = ifelse(step(v) > zero(step(v)), | ||
| 946 | (ret <= last(v)) & (ret >= first(v)), | ||
| 947 | (ret <= first(v)) & (ret >= last(v))) | ||
| 948 | @boundscheck ((i > 0) & ok) || throw_boundserror(v, i) | ||
| 949 | ret | ||
| 950 | end | ||
| 951 | |||
| 952 | function getindex(r::Union{StepRangeLen,LinRange}, i::Integer) | ||
| 953 | @inline | ||
| 954 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 955 | @boundscheck checkbounds(r, i) | ||
| 956 | unsafe_getindex(r, i) | ||
| 957 | end | ||
| 958 | |||
| 959 | # This is separate to make it useful even when running with --check-bounds=yes | ||
| 960 | function unsafe_getindex(r::StepRangeLen{T}, i::Integer) where T | ||
| 961 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 962 | u = oftype(r.offset, i) - r.offset | ||
| 963 | T(r.ref + u*r.step) | ||
| 964 | end | ||
| 965 | |||
| 966 | function _getindex_hiprec(r::StepRangeLen, i::Integer) # without rounding by T | ||
| 967 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 968 | u = oftype(r.offset, i) - r.offset | ||
| 969 | r.ref + u*r.step | ||
| 970 | end | ||
| 971 | |||
| 972 | function unsafe_getindex(r::LinRange, i::Integer) | ||
| 973 | i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) | ||
| 974 | lerpi(i-oneunit(i), r.lendiv, r.start, r.stop) | ||
| 975 | end | ||
| 976 | |||
| 977 | function lerpi(j::Integer, d::Integer, a::T, b::T) where T | ||
| 978 | @inline | ||
| 979 | t = j/d # ∈ [0,1] | ||
| 980 | # compute approximately fma(t, b, -fma(t, a, a)) | ||
| 981 | return T((1-t)*a + t*b) | ||
| 982 | end | ||
| 983 | |||
| 984 | getindex(r::AbstractRange, ::Colon) = copy(r) | ||
| 985 | |||
| 986 | function getindex(r::AbstractUnitRange, s::AbstractUnitRange{T}) where {T<:Integer} | ||
| 987 | @inline | ||
| 988 | @boundscheck checkbounds(r, s) | ||
| 989 | |||
| 990 | if T === Bool | ||
| 991 | return range(first(s) ? first(r) : last(r), length = last(s)) | ||
| 992 | else | ||
| 993 | f = first(r) | ||
| 994 | start = oftype(f, f + first(s) - firstindex(r)) | ||
| 995 | len = length(s) | ||
| 996 | stop = oftype(f, start + (len - oneunit(len))) | ||
| 997 | return range(start, stop) | ||
| 998 | end | ||
| 999 | end | ||
| 1000 | |||
| 1001 | function getindex(r::OneTo{T}, s::OneTo) where T | ||
| 1002 | @inline | ||
| 1003 | @boundscheck checkbounds(r, s) | ||
| 1004 | return OneTo(T(s.stop)) | ||
| 1005 | end | ||
| 1006 | |||
| 1007 | function getindex(r::AbstractUnitRange, s::StepRange{T}) where {T<:Integer} | ||
| 1008 | @inline | ||
| 1009 | @boundscheck checkbounds(r, s) | ||
| 1010 | |||
| 1011 | if T === Bool | ||
| 1012 | return range(first(s) ? first(r) : last(r), step=oneunit(eltype(r)), length=last(s)) | ||
| 1013 | else | ||
| 1014 | f = first(r) | ||
| 1015 | start = oftype(f, f + s.start - firstindex(r)) | ||
| 1016 | st = step(s) | ||
| 1017 | len = length(s) | ||
| 1018 | stop = oftype(f, start + (len - oneunit(len)) * st) | ||
| 1019 | return range(start, stop; step=st) | ||
| 1020 | end | ||
| 1021 | end | ||
| 1022 | |||
| 1023 | function getindex(r::StepRange, s::AbstractRange{T}) where {T<:Integer} | ||
| 1024 | @inline | ||
| 1025 | @boundscheck checkbounds(r, s) | ||
| 1026 | |||
| 1027 | if T === Bool | ||
| 1028 | if length(s) == 0 | ||
| 1029 | start, len = first(r), 0 | ||
| 1030 | elseif length(s) == 1 | ||
| 1031 | if first(s) | ||
| 1032 | start, len = first(r), 1 | ||
| 1033 | else | ||
| 1034 | start, len = first(r), 0 | ||
| 1035 | end | ||
| 1036 | else # length(s) == 2 | ||
| 1037 | start, len = last(r), 1 | ||
| 1038 | end | ||
| 1039 | return range(start, step=step(r); length=len) | ||
| 1040 | else | ||
| 1041 | f = r.start | ||
| 1042 | fs = first(s) | ||
| 1043 | st = r.step | ||
| 1044 | start = oftype(f, f + (fs - oneunit(fs)) * st) | ||
| 1045 | st = st * step(s) | ||
| 1046 | len = length(s) | ||
| 1047 | stop = oftype(f, start + (len - oneunit(len)) * st) | ||
| 1048 | return range(start, stop; step=st) | ||
| 1049 | end | ||
| 1050 | end | ||
| 1051 | |||
| 1052 | function getindex(r::StepRangeLen{T}, s::OrdinalRange{S}) where {T, S<:Integer} | ||
| 1053 | @inline | ||
| 1054 | @boundscheck checkbounds(r, s) | ||
| 1055 | |||
| 1056 | len = length(s) | ||
| 1057 | sstep = step_hp(s) | ||
| 1058 | rstep = step_hp(r) | ||
| 1059 | L = typeof(len) | ||
| 1060 | if S === Bool | ||
| 1061 | rstep *= one(sstep) | ||
| 1062 | if len == 0 | ||
| 1063 | return StepRangeLen{T}(first(r), rstep, zero(L), oneunit(L)) | ||
| 1064 | elseif len == 1 | ||
| 1065 | if first(s) | ||
| 1066 | return StepRangeLen{T}(first(r), rstep, oneunit(L), oneunit(L)) | ||
| 1067 | else | ||
| 1068 | return StepRangeLen{T}(first(r), rstep, zero(L), oneunit(L)) | ||
| 1069 | end | ||
| 1070 | else # len == 2 | ||
| 1071 | return StepRangeLen{T}(last(r), rstep, oneunit(L), oneunit(L)) | ||
| 1072 | end | ||
| 1073 | else | ||
| 1074 | # Find closest approach to offset by s | ||
| 1075 | ind = LinearIndices(s) | ||
| 1076 | offset = L(max(min(1 + round(L, (r.offset - first(s))/sstep), last(ind)), first(ind))) | ||
| 1077 | ref = _getindex_hiprec(r, first(s) + (offset - oneunit(offset)) * sstep) | ||
| 1078 | return StepRangeLen{T}(ref, rstep*sstep, len, offset) | ||
| 1079 | end | ||
| 1080 | end | ||
| 1081 | |||
| 1082 | function getindex(r::LinRange{T}, s::OrdinalRange{S}) where {T, S<:Integer} | ||
| 1083 | @inline | ||
| 1084 | @boundscheck checkbounds(r, s) | ||
| 1085 | |||
| 1086 | len = length(s) | ||
| 1087 | L = typeof(len) | ||
| 1088 | if S === Bool | ||
| 1089 | if len == 0 | ||
| 1090 | return LinRange{T}(first(r), first(r), len) | ||
| 1091 | elseif len == 1 | ||
| 1092 | if first(s) | ||
| 1093 | return LinRange{T}(first(r), first(r), len) | ||
| 1094 | else | ||
| 1095 | return LinRange{T}(first(r), first(r), zero(L)) | ||
| 1096 | end | ||
| 1097 | else # length(s) == 2 | ||
| 1098 | return LinRange{T}(last(r), last(r), oneunit(L)) | ||
| 1099 | end | ||
| 1100 | else | ||
| 1101 | vfirst = unsafe_getindex(r, first(s)) | ||
| 1102 | vlast = unsafe_getindex(r, last(s)) | ||
| 1103 | return LinRange{T}(vfirst, vlast, len) | ||
| 1104 | end | ||
| 1105 | end | ||
| 1106 | |||
| 1107 | show(io::IO, r::AbstractRange) = print(io, repr(first(r)), ':', repr(step(r)), ':', repr(last(r))) | ||
| 1108 | show(io::IO, r::UnitRange) = print(io, repr(first(r)), ':', repr(last(r))) | ||
| 1109 | show(io::IO, r::OneTo) = print(io, "Base.OneTo(", r.stop, ")") | ||
| 1110 | function show(io::IO, r::StepRangeLen) | ||
| 1111 | if !iszero(step(r)) | ||
| 1112 | print(io, repr(first(r)), ':', repr(step(r)), ':', repr(last(r))) | ||
| 1113 | else | ||
| 1114 | # ugly temporary printing, to avoid 0:0:0 etc. | ||
| 1115 | print(io, "StepRangeLen(", repr(first(r)), ", ", repr(step(r)), ", ", repr(length(r)), ")") | ||
| 1116 | end | ||
| 1117 | end | ||
| 1118 | |||
| 1119 | function ==(r::T, s::T) where {T<:AbstractRange} | ||
| 1120 | isempty(r) && return isempty(s) | ||
| 1121 | _has_length_one(r) && return _has_length_one(s) & (first(r) == first(s)) | ||
| 1122 | (first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)) | ||
| 1123 | end | ||
| 1124 | |||
| 1125 | function ==(r::OrdinalRange, s::OrdinalRange) | ||
| 1126 | isempty(r) && return isempty(s) | ||
| 1127 | _has_length_one(r) && return _has_length_one(s) & (first(r) == first(s)) | ||
| 1128 | (first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)) | ||
| 1129 | end | ||
| 1130 | |||
| 1131 | ==(r::AbstractUnitRange, s::AbstractUnitRange) = | ||
| 1132 | (isempty(r) & isempty(s)) | ((first(r) == first(s)) & (last(r) == last(s))) | ||
| 1133 | |||
| 1134 | ==(r::OneTo, s::OneTo) = last(r) == last(s) | ||
| 1135 | |||
| 1136 | ==(r::T, s::T) where {T<:Union{StepRangeLen,LinRange}} = | ||
| 1137 | (isempty(r) & isempty(s)) | ((first(r) == first(s)) & (length(r) == length(s)) & (last(r) == last(s))) | ||
| 1138 | |||
| 1139 | function ==(r::Union{StepRange{T},StepRangeLen{T,T}}, s::Union{StepRange{T},StepRangeLen{T,T}}) where {T} | ||
| 1140 | isempty(r) && return isempty(s) | ||
| 1141 | _has_length_one(r) && return _has_length_one(s) & (first(r) == first(s)) | ||
| 1142 | (first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)) | ||
| 1143 | end | ||
| 1144 | |||
| 1145 | _has_length_one(r::OrdinalRange) = first(r) == last(r) | ||
| 1146 | _has_length_one(r::AbstractRange) = isone(length(r)) | ||
| 1147 | |||
| 1148 | function ==(r::AbstractRange, s::AbstractRange) | ||
| 1149 | lr = length(r) | ||
| 1150 | if lr != length(s) | ||
| 1151 | return false | ||
| 1152 | elseif iszero(lr) | ||
| 1153 | return true | ||
| 1154 | end | ||
| 1155 | yr, ys = iterate(r), iterate(s) | ||
| 1156 | while yr !== nothing | ||
| 1157 | yr[1] == ys[1] || return false | ||
| 1158 | yr, ys = iterate(r, yr[2]), iterate(s, ys[2]) | ||
| 1159 | end | ||
| 1160 | return true | ||
| 1161 | end | ||
| 1162 | |||
| 1163 | intersect(r::OneTo, s::OneTo) = OneTo(min(r.stop,s.stop)) | ||
| 1164 | union(r::OneTo, s::OneTo) = OneTo(max(r.stop,s.stop)) | ||
| 1165 | |||
| 1166 | intersect(r::AbstractUnitRange{<:Integer}, s::AbstractUnitRange{<:Integer}) = max(first(r),first(s)):min(last(r),last(s)) | ||
| 1167 | |||
| 1168 | intersect(i::Integer, r::AbstractUnitRange{<:Integer}) = range(max(i, first(r)), length=in(i, r)) | ||
| 1169 | |||
| 1170 | intersect(r::AbstractUnitRange{<:Integer}, i::Integer) = intersect(i, r) | ||
| 1171 | |||
| 1172 | function intersect(r::AbstractUnitRange{<:Integer}, s::StepRange{<:Integer}) | ||
| 1173 | T = promote_type(eltype(r), eltype(s)) | ||
| 1174 | if isempty(s) | ||
| 1175 | StepRange{T}(first(r), +step(s), first(r)-step(s)) | ||
| 1176 | else | ||
| 1177 | sta, ste, sto = first_step_last_ascending(s) | ||
| 1178 | lo = first(r) | ||
| 1179 | hi = last(r) | ||
| 1180 | i0 = max(sta, lo + mod(sta - lo, ste)) | ||
| 1181 | i1 = min(sto, hi - mod(hi - sta, ste)) | ||
| 1182 | StepRange{T}(i0, ste, i1) | ||
| 1183 | end | ||
| 1184 | end | ||
| 1185 | |||
| 1186 | function first_step_last_ascending(r::StepRange) | ||
| 1187 | if step(r) < zero(step(r)) | ||
| 1188 | last(r), -step(r), first(r) | ||
| 1189 | else | ||
| 1190 | first(r), +step(r), last(r) | ||
| 1191 | end | ||
| 1192 | end | ||
| 1193 | |||
| 1194 | function intersect(r::StepRange{<:Integer}, s::AbstractUnitRange{<:Integer}) | ||
| 1195 | if step(r) < 0 | ||
| 1196 | reverse(intersect(s, reverse(r))) | ||
| 1197 | else | ||
| 1198 | intersect(s, r) | ||
| 1199 | end | ||
| 1200 | end | ||
| 1201 | |||
| 1202 | function intersect(r::StepRange, s::StepRange) | ||
| 1203 | T = promote_type(eltype(r), eltype(s)) | ||
| 1204 | S = promote_type(typeof(step(r)), typeof(step(s))) | ||
| 1205 | if isempty(r) || isempty(s) | ||
| 1206 | return StepRange{T,S}(first(r), step(r), first(r)-step(r)) | ||
| 1207 | end | ||
| 1208 | |||
| 1209 | start1, step1, stop1 = first_step_last_ascending(r) | ||
| 1210 | start2, step2, stop2 = first_step_last_ascending(s) | ||
| 1211 | a = lcm(step1, step2) | ||
| 1212 | |||
| 1213 | g, x, y = gcdx(step1, step2) | ||
| 1214 | |||
| 1215 | if !iszero(rem(start1 - start2, g)) | ||
| 1216 | # Unaligned, no overlap possible. | ||
| 1217 | if step(r) < zero(step(r)) | ||
| 1218 | return StepRange{T,S}(stop1, -a, stop1+a) | ||
| 1219 | else | ||
| 1220 | return StepRange{T,S}(start1, a, start1-a) | ||
| 1221 | end | ||
| 1222 | end | ||
| 1223 | |||
| 1224 | z = div(start1 - start2, g) | ||
| 1225 | b = start1 - x * z * step1 | ||
| 1226 | # Possible points of the intersection of r and s are | ||
| 1227 | # ..., b-2a, b-a, b, b+a, b+2a, ... | ||
| 1228 | # Determine where in the sequence to start and stop. | ||
| 1229 | m = max(start1 + mod(b - start1, a), start2 + mod(b - start2, a)) | ||
| 1230 | n = min(stop1 - mod(stop1 - b, a), stop2 - mod(stop2 - b, a)) | ||
| 1231 | step(r) < zero(step(r)) ? StepRange{T,S}(n, -a, m) : StepRange{T,S}(m, a, n) | ||
| 1232 | end | ||
| 1233 | |||
| 1234 | function intersect(r1::AbstractRange, r2::AbstractRange) | ||
| 1235 | # To iterate over the shorter range | ||
| 1236 | length(r1) > length(r2) && return intersect(r2, r1) | ||
| 1237 | |||
| 1238 | r1 = unique(r1) | ||
| 1239 | T = promote_eltype(r1, r2) | ||
| 1240 | |||
| 1241 | return T[x for x in r1 if x ∈ r2] | ||
| 1242 | end | ||
| 1243 | |||
| 1244 | function intersect(r1::AbstractRange, r2::AbstractRange, r3::AbstractRange, r::AbstractRange...) | ||
| 1245 | i = intersect(intersect(r1, r2), r3) | ||
| 1246 | for t in r | ||
| 1247 | i = intersect(i, t) | ||
| 1248 | end | ||
| 1249 | i | ||
| 1250 | end | ||
| 1251 | |||
| 1252 | # _findin (the index of intersection) | ||
| 1253 | function _findin(r::AbstractRange{<:Integer}, span::AbstractUnitRange{<:Integer}) | ||
| 1254 | fspan = first(span) | ||
| 1255 | lspan = last(span) | ||
| 1256 | fr = first(r) | ||
| 1257 | lr = last(r) | ||
| 1258 | sr = step(r) | ||
| 1259 | if sr > 0 | ||
| 1260 | ifirst = fr >= fspan ? 1 : cld(fspan-fr, sr)+1 | ||
| 1261 | ilast = lr <= lspan ? length(r) : length(r) - cld(lr-lspan, sr) | ||
| 1262 | elseif sr < 0 | ||
| 1263 | ifirst = fr <= lspan ? 1 : cld(lspan-fr, sr)+1 | ||
| 1264 | ilast = lr >= fspan ? length(r) : length(r) - cld(lr-fspan, sr) | ||
| 1265 | else | ||
| 1266 | ifirst = fr >= fspan ? 1 : length(r)+1 | ||
| 1267 | ilast = fr <= lspan ? length(r) : 0 | ||
| 1268 | end | ||
| 1269 | r isa AbstractUnitRange ? (ifirst:ilast) : (ifirst:1:ilast) | ||
| 1270 | end | ||
| 1271 | |||
| 1272 | issubset(r::OneTo, s::OneTo) = r.stop <= s.stop | ||
| 1273 | |||
| 1274 | issubset(r::AbstractUnitRange{<:Integer}, s::AbstractUnitRange{<:Integer}) = | ||
| 1275 | isempty(r) || (first(r) >= first(s) && last(r) <= last(s)) | ||
| 1276 | |||
| 1277 | ## linear operations on ranges ## | ||
| 1278 | |||
| 1279 | -(r::OrdinalRange) = range(-first(r), step=negate(step(r)), length=length(r)) | ||
| 1280 | -(r::StepRangeLen{T,R,S,L}) where {T,R,S,L} = | ||
| 1281 | StepRangeLen{T,R,S,L}(-r.ref, -r.step, r.len, r.offset) | ||
| 1282 | function -(r::LinRange) | ||
| 1283 | start = -r.start | ||
| 1284 | LinRange{typeof(start)}(start, -r.stop, length(r)) | ||
| 1285 | end | ||
| 1286 | |||
| 1287 | # promote eltype if at least one container wouldn't change, otherwise join container types. | ||
| 1288 | el_same(::Type{T}, a::Type{<:AbstractArray{T,n}}, b::Type{<:AbstractArray{T,n}}) where {T,n} = a # we assume a === b | ||
| 1289 | el_same(::Type{T}, a::Type{<:AbstractArray{T,n}}, b::Type{<:AbstractArray{S,n}}) where {T,S,n} = a | ||
| 1290 | el_same(::Type{T}, a::Type{<:AbstractArray{S,n}}, b::Type{<:AbstractArray{T,n}}) where {T,S,n} = b | ||
| 1291 | el_same(::Type, a, b) = promote_typejoin(a, b) | ||
| 1292 | |||
| 1293 | promote_rule(a::Type{UnitRange{T1}}, b::Type{UnitRange{T2}}) where {T1,T2} = | ||
| 1294 | el_same(promote_type(T1, T2), a, b) | ||
| 1295 | UnitRange{T}(r::UnitRange{T}) where {T<:Real} = r | ||
| 1296 | UnitRange{T}(r::UnitRange) where {T<:Real} = UnitRange{T}(r.start, r.stop) | ||
| 1297 | |||
| 1298 | promote_rule(a::Type{OneTo{T1}}, b::Type{OneTo{T2}}) where {T1,T2} = | ||
| 1299 | el_same(promote_type(T1, T2), a, b) | ||
| 1300 | OneTo{T}(r::OneTo{T}) where {T<:Integer} = r | ||
| 1301 | OneTo{T}(r::OneTo) where {T<:Integer} = OneTo{T}(r.stop) | ||
| 1302 | |||
| 1303 | promote_rule(a::Type{UnitRange{T1}}, ::Type{UR}) where {T1,UR<:AbstractUnitRange} = | ||
| 1304 | promote_rule(a, UnitRange{eltype(UR)}) | ||
| 1305 | UnitRange{T}(r::AbstractUnitRange) where {T<:Real} = UnitRange{T}(first(r), last(r)) | ||
| 1306 | UnitRange(r::AbstractUnitRange) = UnitRange(first(r), last(r)) | ||
| 1307 | |||
| 1308 | AbstractUnitRange{T}(r::AbstractUnitRange{T}) where {T} = r | ||
| 1309 | AbstractUnitRange{T}(r::UnitRange) where {T} = UnitRange{T}(r) | ||
| 1310 | AbstractUnitRange{T}(r::OneTo) where {T} = OneTo{T}(r) | ||
| 1311 | |||
| 1312 | OrdinalRange{T, S}(r::OrdinalRange) where {T, S} = StepRange{T, S}(r) | ||
| 1313 | OrdinalRange{T, T}(r::AbstractUnitRange) where {T} = AbstractUnitRange{T}(r) | ||
| 1314 | |||
| 1315 | function promote_rule(::Type{StepRange{T1a,T1b}}, ::Type{StepRange{T2a,T2b}}) where {T1a,T1b,T2a,T2b} | ||
| 1316 | Tb = promote_type(T1b, T2b) | ||
| 1317 | # el_same only operates on array element type, so just promote second type parameter | ||
| 1318 | el_same(promote_type(T1a, T2a), StepRange{T1a,Tb}, StepRange{T2a,Tb}) | ||
| 1319 | end | ||
| 1320 | StepRange{T1,T2}(r::StepRange{T1,T2}) where {T1,T2} = r | ||
| 1321 | |||
| 1322 | promote_rule(a::Type{StepRange{T1a,T1b}}, ::Type{UR}) where {T1a,T1b,UR<:AbstractUnitRange} = | ||
| 1323 | promote_rule(a, StepRange{eltype(UR), eltype(UR)}) | ||
| 1324 | StepRange{T1,T2}(r::AbstractRange) where {T1,T2} = | ||
| 1325 | StepRange{T1,T2}(convert(T1, first(r)), convert(T2, step(r)), convert(T1, last(r))) | ||
| 1326 | StepRange(r::AbstractUnitRange{T}) where {T} = | ||
| 1327 | StepRange{T,T}(first(r), step(r), last(r)) | ||
| 1328 | (StepRange{T1,T2} where T1)(r::AbstractRange) where {T2} = StepRange{eltype(r),T2}(r) | ||
| 1329 | |||
| 1330 | function promote_rule(::Type{StepRangeLen{T1,R1,S1,L1}},::Type{StepRangeLen{T2,R2,S2,L2}}) where {T1,T2,R1,R2,S1,S2,L1,L2} | ||
| 1331 | R, S, L = promote_type(R1, R2), promote_type(S1, S2), promote_type(L1, L2) | ||
| 1332 | el_same(promote_type(T1, T2), StepRangeLen{T1,R,S,L}, StepRangeLen{T2,R,S,L}) | ||
| 1333 | end | ||
| 1334 | StepRangeLen{T,R,S,L}(r::StepRangeLen{T,R,S,L}) where {T,R,S,L} = r | ||
| 1335 | StepRangeLen{T,R,S,L}(r::StepRangeLen) where {T,R,S,L} = | ||
| 1336 | StepRangeLen{T,R,S,L}(convert(R, r.ref), convert(S, r.step), convert(L, r.len), convert(L, r.offset)) | ||
| 1337 | StepRangeLen{T}(r::StepRangeLen) where {T} = | ||
| 1338 | StepRangeLen(convert(T, r.ref), convert(T, r.step), r.len, r.offset) | ||
| 1339 | |||
| 1340 | promote_rule(a::Type{StepRangeLen{T,R,S,L}}, ::Type{OR}) where {T,R,S,L,OR<:AbstractRange} = | ||
| 1341 | promote_rule(a, StepRangeLen{eltype(OR), eltype(OR), eltype(OR), Int}) | ||
| 1342 | StepRangeLen{T,R,S,L}(r::AbstractRange) where {T,R,S,L} = | ||
| 1343 | StepRangeLen{T,R,S,L}(R(first(r)), S(step(r)), length(r)) | ||
| 1344 | StepRangeLen{T}(r::AbstractRange) where {T} = | ||
| 1345 | StepRangeLen(T(first(r)), T(step(r)), length(r)) | ||
| 1346 | StepRangeLen(r::AbstractRange) = StepRangeLen{eltype(r)}(r) | ||
| 1347 | |||
| 1348 | function promote_rule(a::Type{LinRange{T1,L1}}, b::Type{LinRange{T2,L2}}) where {T1,T2,L1,L2} | ||
| 1349 | L = promote_type(L1, L2) | ||
| 1350 | el_same(promote_type(T1, T2), LinRange{T1,L}, LinRange{T2,L}) | ||
| 1351 | end | ||
| 1352 | LinRange{T,L}(r::LinRange{T,L}) where {T,L} = r | ||
| 1353 | LinRange{T,L}(r::AbstractRange) where {T,L} = LinRange{T,L}(first(r), last(r), length(r)) | ||
| 1354 | LinRange{T}(r::AbstractRange) where {T} = LinRange{T,typeof(length(r))}(first(r), last(r), length(r)) | ||
| 1355 | LinRange(r::AbstractRange{T}) where {T} = LinRange{T}(r) | ||
| 1356 | |||
| 1357 | promote_rule(a::Type{LinRange{T,L}}, ::Type{OR}) where {T,L,OR<:OrdinalRange} = | ||
| 1358 | promote_rule(a, LinRange{eltype(OR),L}) | ||
| 1359 | |||
| 1360 | promote_rule(::Type{LinRange{A,L}}, b::Type{StepRangeLen{T2,R2,S2,L2}}) where {A,L,T2,R2,S2,L2} = | ||
| 1361 | promote_rule(StepRangeLen{A,A,A,L}, b) | ||
| 1362 | |||
| 1363 | ## concatenation ## | ||
| 1364 | |||
| 1365 | function vcat(rs::AbstractRange{T}...) where T | ||
| 1366 | n::Int = 0 | ||
| 1367 | for ra in rs | ||
| 1368 | n += length(ra) | ||
| 1369 | end | ||
| 1370 | a = Vector{T}(undef, n) | ||
| 1371 | i = 1 | ||
| 1372 | for ra in rs, x in ra | ||
| 1373 | @inbounds a[i] = x | ||
| 1374 | i += 1 | ||
| 1375 | end | ||
| 1376 | return a | ||
| 1377 | end | ||
| 1378 | |||
| 1379 | # This method differs from that for AbstractArrays as it | ||
| 1380 | # use iteration instead of indexing. This works even if certain | ||
| 1381 | # non-standard ranges don't support indexing. | ||
| 1382 | # See https://github.com/JuliaLang/julia/pull/27302 | ||
| 1383 | # Similarly, collect(r::AbstractRange) uses iteration | ||
| 1384 | function Array{T,1}(r::AbstractRange{T}) where {T} | ||
| 1385 | a = Vector{T}(undef, length(r)) | ||
| 1386 | i = 1 | ||
| 1387 | for x in r | ||
| 1388 | @inbounds a[i] = x | ||
| 1389 | i += 1 | ||
| 1390 | end | ||
| 1391 | return a | ||
| 1392 | end | ||
| 1393 | collect(r::AbstractRange) = Array(r) | ||
| 1394 | |||
| 1395 | _reverse(r::OrdinalRange, ::Colon) = (:)(last(r), negate(step(r)), first(r)) | ||
| 1396 | function _reverse(r::StepRangeLen, ::Colon) | ||
| 1397 | # If `r` is empty, `length(r) - r.offset + 1 will be nonpositive hence | ||
| 1398 | # invalid. As `reverse(r)` is also empty, any offset would work so we keep | ||
| 1399 | # `r.offset` | ||
| 1400 | offset = isempty(r) ? r.offset : length(r)-r.offset+1 | ||
| 1401 | return typeof(r)(r.ref, negate(r.step), length(r), offset) | ||
| 1402 | end | ||
| 1403 | _reverse(r::LinRange{T}, ::Colon) where {T} = typeof(r)(r.stop, r.start, length(r)) | ||
| 1404 | |||
| 1405 | ## sorting ## | ||
| 1406 | |||
| 1407 | issorted(r::AbstractUnitRange) = true | ||
| 1408 | issorted(r::AbstractRange) = length(r) <= 1 || step(r) >= zero(step(r)) | ||
| 1409 | |||
| 1410 | sort(r::AbstractUnitRange) = r | ||
| 1411 | sort!(r::AbstractUnitRange) = r | ||
| 1412 | |||
| 1413 | sort(r::AbstractRange) = issorted(r) ? r : reverse(r) | ||
| 1414 | |||
| 1415 | sortperm(r::AbstractUnitRange) = 1:length(r) | ||
| 1416 | sortperm(r::AbstractRange) = issorted(r) ? (1:1:length(r)) : (length(r):-1:1) | ||
| 1417 | |||
| 1418 | function sum(r::AbstractRange{<:Real}) | ||
| 1419 | l = length(r) | ||
| 1420 | # note that a little care is required to avoid overflow in l*(l-1)/2 | ||
| 1421 | return l * first(r) + (iseven(l) ? (step(r) * (l-1)) * (l>>1) | ||
| 1422 | : (step(r) * l) * ((l-1)>>1)) | ||
| 1423 | end | ||
| 1424 | |||
| 1425 | function _in_range(x, r::AbstractRange) | ||
| 1426 | isempty(r) && return false | ||
| 1427 | f, l = first(r), last(r) | ||
| 1428 | # check for NaN, Inf, and large x that may overflow in the next calculation | ||
| 1429 | f <= x <= l || l <= x <= f || return false | ||
| 1430 | iszero(step(r)) && return true | ||
| 1431 | n = round(Integer, (x - f) / step(r)) + 1 | ||
| 1432 | n >= 1 && n <= length(r) && r[n] == x | ||
| 1433 | end | ||
| 1434 | in(x::Real, r::AbstractRange{<:Real}) = _in_range(x, r) | ||
| 1435 | # This method needs to be defined separately since -(::T, ::T) can be implemented | ||
| 1436 | # even if -(::T, ::Real) is not | ||
| 1437 | in(x::T, r::AbstractRange{T}) where {T} = _in_range(x, r) | ||
| 1438 | |||
| 1439 | in(x::Integer, r::AbstractUnitRange{<:Integer}) = (first(r) <= x) & (x <= last(r)) | ||
| 1440 | |||
| 1441 | in(x::Real, r::AbstractRange{T}) where {T<:Integer} = | ||
| 1442 | isinteger(x) && !isempty(r) && | ||
| 1443 | (iszero(step(r)) ? x == first(r) : (x >= minimum(r) && x <= maximum(r) && | ||
| 1444 | (mod(convert(T,x),step(r))-mod(first(r),step(r)) == 0))) | ||
| 1445 | in(x::AbstractChar, r::AbstractRange{<:AbstractChar}) = | ||
| 1446 | !isempty(r) && | ||
| 1447 | (iszero(step(r)) ? x == first(r) : (x >= minimum(r) && x <= maximum(r) && | ||
| 1448 | (mod(Int(x) - Int(first(r)), step(r)) == 0))) | ||
| 1449 | |||
| 1450 | # Addition/subtraction of ranges | ||
| 1451 | |||
| 1452 | function _define_range_op(@nospecialize f) | ||
| 1453 | @eval begin | ||
| 1454 | function $f(r1::OrdinalRange, r2::OrdinalRange) | ||
| 1455 | r1l = length(r1) | ||
| 1456 | (r1l == length(r2) || | ||
| 1457 | throw(DimensionMismatch("argument dimensions must match: length of r1 is $r1l, length of r2 is $(length(r2))"))) | ||
| 1458 | StepRangeLen($f(first(r1), first(r2)), $f(step(r1), step(r2)), r1l) | ||
| 1459 | end | ||
| 1460 | |||
| 1461 | function $f(r1::LinRange{T}, r2::LinRange{T}) where T | ||
| 1462 | len = r1.len | ||
| 1463 | (len == r2.len || | ||
| 1464 | throw(DimensionMismatch("argument dimensions must match: length of r1 is $len, length of r2 is $(r2.len)"))) | ||
| 1465 | LinRange{T}(convert(T, $f(first(r1), first(r2))), | ||
| 1466 | convert(T, $f(last(r1), last(r2))), len) | ||
| 1467 | end | ||
| 1468 | |||
| 1469 | $f(r1::Union{StepRangeLen, OrdinalRange, LinRange}, | ||
| 1470 | r2::Union{StepRangeLen, OrdinalRange, LinRange}) = | ||
| 1471 | $f(promote(r1, r2)...) | ||
| 1472 | end | ||
| 1473 | end | ||
| 1474 | _define_range_op(:+) | ||
| 1475 | _define_range_op(:-) | ||
| 1476 | |||
| 1477 | function +(r1::StepRangeLen{T,S}, r2::StepRangeLen{T,S}) where {T,S} | ||
| 1478 | len = length(r1) | ||
| 1479 | (len == length(r2) || | ||
| 1480 | throw(DimensionMismatch("argument dimensions must match: length of r1 is $len, length of r2 is $(length(r2))"))) | ||
| 1481 | StepRangeLen(first(r1)+first(r2), step(r1)+step(r2), len) | ||
| 1482 | end | ||
| 1483 | |||
| 1484 | -(r1::StepRangeLen, r2::StepRangeLen) = +(r1, -r2) | ||
| 1485 | |||
| 1486 | # Modular arithmetic on ranges | ||
| 1487 | |||
| 1488 | """ | ||
| 1489 | mod(x::Integer, r::AbstractUnitRange) | ||
| 1490 | |||
| 1491 | Find `y` in the range `r` such that ``x ≡ y (mod n)``, where `n = length(r)`, | ||
| 1492 | i.e. `y = mod(x - first(r), n) + first(r)`. | ||
| 1493 | |||
| 1494 | See also [`mod1`](@ref). | ||
| 1495 | |||
| 1496 | # Examples | ||
| 1497 | ```jldoctest | ||
| 1498 | julia> mod(0, Base.OneTo(3)) # mod1(0, 3) | ||
| 1499 | 3 | ||
| 1500 | |||
| 1501 | julia> mod(3, 0:2) # mod(3, 3) | ||
| 1502 | 0 | ||
| 1503 | ``` | ||
| 1504 | |||
| 1505 | !!! compat "Julia 1.3" | ||
| 1506 | This method requires at least Julia 1.3. | ||
| 1507 | """ | ||
| 1508 | mod(i::Integer, r::OneTo) = mod1(i, last(r)) | ||
| 1509 | mod(i::Integer, r::AbstractUnitRange{<:Integer}) = mod(i-first(r), length(r)) + first(r) |