From 3d1bc89d906038a690ab2c5119a0a6a51c57eb50 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Wed, 30 Nov 2022 11:57:10 +0100 Subject: [PATCH 01/20] Make StaticInteger and Integer --- src/Static.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Static.jl b/src/Static.jl index 184eed7..64d2716 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -24,7 +24,7 @@ end Base.Symbol(@nospecialize(s::StaticSymbol)) = known(s) -abstract type StaticInteger{N} <: Number end +abstract type StaticInteger{N} <: Integer end """ StaticBool(x::Bool) -> True/False From 6326a116e547bdf0a58bee679be1e52dc2dd5542 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Wed, 30 Nov 2022 11:58:20 +0100 Subject: [PATCH 02/20] Remove custom range types --- src/Static.jl | 2 +- src/ranges.jl | 394 ----------------------------------------------- test/ranges.jl | 159 ------------------- test/runtests.jl | 2 - 4 files changed, 1 insertion(+), 556 deletions(-) delete mode 100644 src/ranges.jl delete mode 100644 test/ranges.jl diff --git a/src/Static.jl b/src/Static.jl index 64d2716..18da59d 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -963,6 +963,6 @@ function Base.show(io::IO, m::MIME"text/plain", @nospecialize(x::NDIndex)) nothing end -include("ranges.jl") +#include("ranges.jl") end diff --git a/src/ranges.jl b/src/ranges.jl deleted file mode 100644 index 6a15be8..0000000 --- a/src/ranges.jl +++ /dev/null @@ -1,394 +0,0 @@ - -""" - OptionallyStaticUnitRange(start, stop) <: AbstractUnitRange{Int} - -Similar to `UnitRange` except each field may be an `Int` or `StaticInt`. An -`OptionallyStaticUnitRange` is intended to be constructed internally from other valid -indices. Therefore, users should not expect the same checks are used to ensure construction -of a valid `OptionallyStaticUnitRange` as a `UnitRange`. -""" -struct OptionallyStaticUnitRange{F <: IntType, L <: IntType} <: - AbstractUnitRange{Int} - start::F - stop::L - - function OptionallyStaticUnitRange(start::IntType, - stop::IntType) - new{typeof(start), typeof(stop)}(start, stop) - end - function OptionallyStaticUnitRange(start, stop) - OptionallyStaticUnitRange(IntType(start), IntType(stop)) - end - OptionallyStaticUnitRange(@nospecialize x::OptionallyStaticUnitRange) = x - function OptionallyStaticUnitRange(x::AbstractRange) - step(x) == 1 && return OptionallyStaticUnitRange(static_first(x), static_last(x)) - - errmsg(x) = throw(ArgumentError("step must be 1, got $(step(x))")) # avoid GC frame - errmsg(x) - end - function OptionallyStaticUnitRange{F, L}(x::AbstractRange) where {F, L} - OptionallyStaticUnitRange(x) - end - function OptionallyStaticUnitRange{StaticInt{F}, StaticInt{L}}() where {F, L} - new{StaticInt{F}, StaticInt{L}}() - end -end - -""" - OptionallyStaticStepRange(start, step, stop) <: OrdinalRange{Int,Int} - -Similarly to [`OptionallyStaticUnitRange`](@ref), `OptionallyStaticStepRange` permits -a combination of static and standard primitive `Int`s to construct a range. It -specifically enables the use of ranges without a step size of 1. It may be constructed -through the use of `OptionallyStaticStepRange` directly or using static integers with -the range operator (i.e., `:`). - -```julia -julia> using Static - -julia> x = static(2); - -julia> x:x:10 -static(2):static(2):10 - -julia> Static.OptionallyStaticStepRange(x, x, 10) -static(2):static(2):10 - -``` -""" -struct OptionallyStaticStepRange{F <: IntType, S <: IntType, - L <: IntType} <: OrdinalRange{Int, Int} - start::F - step::S - stop::L - - global function _OptionallyStaticStepRange(@nospecialize(start::IntType), - @nospecialize(step::IntType), - @nospecialize(stop::IntType)) - new{typeof(start), typeof(step), typeof(stop)}(start, step, stop) - end -end -@noinline function OptionallyStaticStepRange(@nospecialize(start::IntType), - ::StaticInt{0}, - @nospecialize(stop::IntType)) - throw(ArgumentError("step cannot be zero")) -end -# we don't need to check the `stop` if we know it acts like a unit range -function OptionallyStaticStepRange(@nospecialize(start::IntType), - step::StaticInt{1}, - @nospecialize(stop::IntType)) - _OptionallyStaticStepRange(start, step, stop) -end -function OptionallyStaticStepRange(@nospecialize(start::IntType), - @nospecialize(step::StaticInt), - @nospecialize(stop::IntType)) - _OptionallyStaticStepRange(start, step, _steprange_last(start, step, stop)) -end -function OptionallyStaticStepRange(start, step, stop) - OptionallyStaticStepRange(IntType(start), IntType(step), IntType(stop)) -end -function OptionallyStaticStepRange(@nospecialize(start::IntType), - step::Int, - @nospecialize(stop::IntType)) - if step === 0 - throw(ArgumentError("step cannot be zero")) - else - _OptionallyStaticStepRange(start, step, _steprange_last(start, step, stop)) - end -end -OptionallyStaticStepRange(@nospecialize x::OptionallyStaticStepRange) = x -function OptionallyStaticStepRange(x::AbstractRange) - _OptionallyStaticStepRange(IntType(static_first(x)), IntType(static_step(x)), - IntType(static_last(x))) -end - -# to make StepRange constructor inlineable, so optimizer can see `step` value -@inline function _steprange_last(start::StaticInt, step::StaticInt, stop::StaticInt) - StaticInt(_steprange_last(Int(start), Int(step), Int(stop))) -end -@inline function _steprange_last(start::Union{StaticInt, Int}, - step::Union{StaticInt, Int}, - stop::Union{StaticInt, Int}) - _steprange_last(Int(start), Int(step), Int(stop)) -end -@inline function _steprange_last(start::Int, step::Int, stop::Int) - if stop === start - return stop - elseif step > 0 - if stop > start - return stop - rem(stop - start, step) - else - return start - 1 - end - else - if stop > start - return start + 1 - else - return stop + rem(start - stop, -step) - end - end -end - -""" - SUnitRange(start::Int, stop::Int) - -An alias for `OptionallyStaticUnitRange` where both the start and stop are known statically. -""" -const SUnitRange{F, L} = OptionallyStaticUnitRange{StaticInt{F}, StaticInt{L}} -SUnitRange(start::Int, stop::Int) = SUnitRange{start, stop}() - -""" - SOneTo(n::Int) - -An alias for `OptionallyStaticUnitRange` usfeul for statically sized axes. -""" -const SOneTo{L} = SUnitRange{1, L} -SOneTo(n::Int) = SOneTo{n}() - -const OptionallyStaticRange{F, L} = Union{OptionallyStaticUnitRange{F, L}, - OptionallyStaticStepRange{F, <:Any, L}} - -# these probide a generic method for extracting potentially static values. -static_first(x::Base.OneTo) = StaticInt(1) -static_first(x::Union{Base.Slice, Base.IdentityUnitRange}) = static_first(x.indices) -static_first(x::OptionallyStaticRange) = getfield(x, :start) -static_first(x) = first(x) - -static_step(@nospecialize x::AbstractUnitRange) = StaticInt(1) -static_step(x::OptionallyStaticStepRange) = getfield(x, :step) -static_step(x) = step(x) - -static_last(x::OptionallyStaticRange) = getfield(x, :stop) -static_last(x) = last(x) -static_last(x::Union{Base.Slice, Base.IdentityUnitRange}) = static_last(x.indices) - -Base.first(x::OptionallyStaticRange{Int}) = getfield(x, :start) -Base.first(::OptionallyStaticRange{StaticInt{F}}) where {F} = F -Base.step(x::OptionallyStaticStepRange{<:Any, Int}) = getfield(x, :step) -Base.step(::OptionallyStaticStepRange{<:Any, StaticInt{S}}) where {S} = S -Base.last(x::OptionallyStaticRange{<:Any, Int}) = getfield(x, :stop) -Base.last(::OptionallyStaticRange{<:Any, StaticInt{L}}) where {L} = L - -# FIXME this line causes invalidations -Base.:(:)(L::Integer, ::StaticInt{U}) where {U} = OptionallyStaticUnitRange(L, StaticInt(U)) -Base.:(:)(::StaticInt{L}, U::Integer) where {L} = OptionallyStaticUnitRange(StaticInt(L), U) -function Base.:(:)(::StaticInt{L}, ::StaticInt{U}) where {L, U} - OptionallyStaticUnitRange(StaticInt(L), StaticInt(U)) -end -function Base.:(:)(::StaticInt{F}, ::StaticInt{S}, ::StaticInt{L}) where {F, S, L} - OptionallyStaticStepRange(StaticInt(F), StaticInt(S), StaticInt(L)) -end -function Base.:(:)(start::Integer, ::StaticInt{S}, ::StaticInt{L}) where {S, L} - OptionallyStaticStepRange(start, StaticInt(S), StaticInt(L)) -end -function Base.:(:)(::StaticInt{F}, ::StaticInt{S}, stop::Integer) where {F, S} - OptionallyStaticStepRange(StaticInt(F), StaticInt(S), stop) -end -function Base.:(:)(::StaticInt{F}, step::Integer, ::StaticInt{L}) where {F, L} - OptionallyStaticStepRange(StaticInt(F), step, StaticInt(L)) -end -function Base.:(:)(start::Integer, step::Integer, ::StaticInt{L}) where {L} - OptionallyStaticStepRange(start, step, StaticInt(L)) -end -function Base.:(:)(start::Integer, ::StaticInt{S}, stop::Integer) where {S} - OptionallyStaticStepRange(start, StaticInt(S), stop) -end -function Base.:(:)(::StaticInt{F}, step::Integer, stop::Integer) where {F} - OptionallyStaticStepRange(StaticInt(F), step, stop) -end -Base.:(:)(start::StaticInt{F}, ::StaticInt{1}, stop::StaticInt{L}) where {F, L} = start:stop -Base.:(:)(start::Integer, ::StaticInt{1}, stop::StaticInt{L}) where {L} = start:stop -Base.:(:)(start::StaticInt{F}, ::StaticInt{1}, stop::Integer) where {F} = start:stop -function Base.:(:)(start::Integer, ::StaticInt{1}, stop::Integer) - OptionallyStaticUnitRange(start, stop) -end - -Base.isempty(r::OptionallyStaticUnitRange) = first(r) > last(r) -@inline function Base.isempty(x::OptionallyStaticStepRange) - start = first(x) - stop = last(x) - if start === stop - return false - else - s = step(x) - s > 0 ? start > stop : start < stop - end -end - -function Base.checkindex(::Type{Bool}, - ::SUnitRange{F1, L1}, - ::SUnitRange{F2, L2}) where {F1, L1, F2, L2} - (F1::Int <= F2::Int) && (L1::Int >= L2::Int) -end - -function Base.getindex(r::OptionallyStaticUnitRange, - s::AbstractUnitRange{<:Integer}) - @boundscheck checkbounds(r, s) - f = static_first(r) - fnew = f - one(f) - return (fnew + static_first(s)):(fnew + static_last(s)) -end - -function Base.getindex(x::OptionallyStaticUnitRange{StaticInt{1}}, i::Int) - @boundscheck checkbounds(x, i) - i -end -function Base.getindex(x::OptionallyStaticUnitRange, i::Int) - val = first(x) + (i - 1) - @boundscheck ((i < 1) || val > last(x)) && throw(BoundsError(x, i)) - val::Int -end - -## length -@inline function Base.length(x::OptionallyStaticUnitRange) - start = first(x) - stop = last(x) - start > stop ? 0 : stop - start + 1 -end -Base.length(r::OptionallyStaticStepRange) = _range_length(first(r), step(r), last(r)) -@inline function _range_length(start::Int, s::Int, stop::Int) - if s > 0 - stop < start ? 0 : div(stop - start, s) + 1 - else - stop > start ? 0 : div(start - stop, -s) + 1 - end -end - -Base.AbstractUnitRange{Int}(r::OptionallyStaticUnitRange) = r -function Base.AbstractUnitRange{T}(r::OptionallyStaticUnitRange) where {T} - start = static_first(r) - if isa(start, StaticInt{1}) && T <: Integer - return Base.OneTo{T}(T(static_last(r))) - else - return UnitRange{T}(T(static_first(r)), T(static_last(r))) - end -end - -Base.isdone(x::OptionallyStaticRange, state::Int) = state === last(x) -function _next(x::OptionallyStaticRange) - new_state = first(x) - (new_state, new_state) -end -@inline function _next(@nospecialize(x::OptionallyStaticUnitRange), state::Int) - new_state = state + 1 - (new_state, new_state) -end -@inline function _next(x::OptionallyStaticStepRange, state::Int) - new_state = state + step(x) - (new_state, new_state) -end -@inline Base.iterate(x::OptionallyStaticRange) = isempty(x) ? nothing : _next(x) -@inline function Base.iterate(x::OptionallyStaticRange, s::Int) - Base.isdone(x, s) ? nothing : _next(x, s) -end - -Base.to_shape(x::OptionallyStaticRange) = length(x) -Base.to_shape(x::Base.Slice{T}) where {T <: OptionallyStaticRange} = length(x) -Base.axes(S::Base.Slice{<:OptionallyStaticUnitRange{StaticInt{1}}}) = (S.indices,) -Base.axes(S::Base.Slice{<:OptionallyStaticRange}) = (Base.IdentityUnitRange(S.indices),) - -Base.axes(x::OptionallyStaticRange) = (Base.axes1(x),) -function Base.axes1(x::OptionallyStaticUnitRange) - OptionallyStaticUnitRange(StaticInt(1), length(x)) -end -Base.axes1(x::OptionallyStaticUnitRange{StaticInt{1}}) = x -function Base.axes1(x::OptionallyStaticUnitRange{StaticInt{F}, StaticInt{L}}) where {F, L} - OptionallyStaticUnitRange(StaticInt(1), StaticInt(L - F + 1)) -end -function Base.axes1(x::OptionallyStaticStepRange) - OptionallyStaticUnitRange(StaticInt(1), length(x)) -end -function Base.axes1(x::OptionallyStaticStepRange{StaticInt{F}, StaticInt{S}, StaticInt{L}}) where { - F, - S, - L - } - OptionallyStaticUnitRange(StaticInt(1), StaticInt(_range_length(F, S, L))) -end -Base.axes1(x::Base.Slice{<:OptionallyStaticUnitRange{One}}) = x.indices -Base.axes1(x::Base.Slice{<:OptionallyStaticRange}) = Base.IdentityUnitRange(x.indices) - -Base.:(-)(r::OptionallyStaticRange) = (-static_first(r)):(-static_step(r)):(-static_last(r)) - -function Base.reverse(x::OptionallyStaticUnitRange) - _OptionallyStaticStepRange(getfield(x, :stop), StaticInt(-1), getfield(x, :start)) -end -function Base.reverse(x::OptionallyStaticStepRange) - _OptionallyStaticStepRange(getfield(x, :stop), -getfield(x, :step), getfield(x, :start)) -end - -Base.show(io::IO, @nospecialize(x::OptionallyStaticRange)) = show(io, MIME"text/plain"(), x) -function Base.show(io::IO, ::MIME"text/plain", @nospecialize(r::OptionallyStaticUnitRange)) - print(io, "$(getfield(r, :start)):$(getfield(r, :stop))") -end -function Base.show(io::IO, ::MIME"text/plain", @nospecialize(r::OptionallyStaticStepRange)) - print(io, "$(getfield(r, :start)):$(getfield(r, :step)):$(getfield(r, :stop))") -end - -# we overload properties because occasionally Base assumes that abstract range types have -# the same exact same set up as native types where `x.start === first(x)` -@inline function Base.getproperty(x::OptionallyStaticRange, s::Symbol) - if s === :start - return first(x) - elseif s === :step - return step(x) - elseif s === :stop - return last(x) - else - error("$x has no property $s") - end -end - -function Base.Broadcast.axistype(r::OptionallyStaticUnitRange{StaticInt{1}}, _) - Base.OneTo(last(r)) -end -function Base.Broadcast.axistype(_, r::OptionallyStaticUnitRange{StaticInt{1}}) - Base.OneTo(last(r)) -end -function Base.Broadcast.axistype(r::OptionallyStaticUnitRange{StaticInt{1}}, - ::OptionallyStaticUnitRange{StaticInt{1}}) - Base.OneTo(last(r)) -end -function Base.similar(::Type{<:Array{T}}, - axes::Tuple{OptionallyStaticUnitRange{StaticInt{1}}, - Vararg{ - Union{Base.OneTo, - OptionallyStaticUnitRange{StaticInt{1}}}}}) where { - T - } - Array{T}(undef, map(last, axes)) -end -function Base.similar(::Type{<:Array{T}}, - axes::Tuple{Base.OneTo, OptionallyStaticUnitRange{StaticInt{1}}, - Vararg{ - Union{Base.OneTo, - OptionallyStaticUnitRange{StaticInt{1}}}}}) where { - T - } - Array{T}(undef, map(last, axes)) -end - -function Base.first(x::OptionallyStaticUnitRange, n::IntType) - n < 0 && throw(ArgumentError("Number of elements must be nonnegative")) - start = static_first(x) - OptionallyStaticUnitRange(start, min(start - one(start) + n, static_last(x))) -end -function Base.first(x::OptionallyStaticStepRange, n::IntType) - n < 0 && throw(ArgumentError("Number of elements must be nonnegative")) - start = static_first(x) - s = static_step(x) - stop = min(((n - one(n)) * s) + static_first(x), static_last(x)) - OptionallyStaticStepRange(start, s, stop) -end -function Base.last(x::OptionallyStaticUnitRange, n::IntType) - n < 0 && throw(ArgumentError("Number of elements must be nonnegative")) - stop = static_last(x) - OptionallyStaticUnitRange(max(stop + one(stop) - n, static_first(x)), stop) -end -function Base.last(x::OptionallyStaticStepRange, n::IntType) - n < 0 && throw(ArgumentError("Number of elements must be nonnegative")) - start = static_first(x) - s = static_step(x) - stop = static_last(x) - OptionallyStaticStepRange(max(stop + one(stop) - (n * s), start), s, stop) -end diff --git a/test/ranges.jl b/test/ranges.jl deleted file mode 100644 index e7e1e9d..0000000 --- a/test/ranges.jl +++ /dev/null @@ -1,159 +0,0 @@ - -@testset "Range Constructors" begin - @test @inferred(static(1):static(10)) == 1:10 - @test @inferred(Static.SUnitRange{1, 10}()) == 1:10 - @test @inferred(static(1):static(2):static(10)) == 1:2:10 - @test @inferred(1:static(2):static(10)) == 1:2:10 - @test @inferred(static(1):static(2):10) == 1:2:10 - @test @inferred(static(1):2:static(10)) == 1:2:10 - @test @inferred(1:2:static(10)) == 1:2:10 - @test @inferred(1:static(2):10) == 1:2:10 - @test @inferred(static(1):2:10) == 1:2:10 - @test @inferred(static(1):UInt(10)) === static(1):10 - @test @inferred(UInt(1):static(1):static(10)) === 1:static(10) - @test Static.SUnitRange(1, 10) == 1:10 - @test @inferred(Static.OptionallyStaticUnitRange{Int, Int}(1:10)) == 1:10 - @test @inferred(Static.OptionallyStaticUnitRange(1:10)) == 1:10 == - @inferred(Static.OptionallyStaticUnitRange(Static.OptionallyStaticUnitRange(1:10))) - - sr = Static.OptionallyStaticStepRange(static(1), static(1), static(1)) - @test @inferred(Static.OptionallyStaticStepRange(sr)) == sr == 1:1:1 - @test @inferred(Static.OptionallyStaticStepRange(static(1), 1, UInt(10))) == - static(1):1:10 == Static.SOneTo(10) - @test @inferred(Static.OptionallyStaticStepRange(UInt(1), 1, static(10))) == - static(1):1:10 - @test @inferred(Static.OptionallyStaticStepRange(1:10)) == 1:1:10 - - @test_throws ArgumentError Static.OptionallyStaticUnitRange(1:2:10) - @test_throws ArgumentError Static.OptionallyStaticUnitRange{Int, Int}(1:2:10) - @test_throws ArgumentError Static.OptionallyStaticStepRange(1, 0, 10) - @test_throws ArgumentError Static.OptionallyStaticStepRange(1, StaticInt(0), 10) - - @test @inferred(static(1):static(1):static(10)) === - Static.OptionallyStaticUnitRange(static(1), static(10)) - @test @inferred(static(1):static(1):10) === - Static.OptionallyStaticUnitRange(static(1), 10) - @test @inferred(1:static(1):10) === Static.OptionallyStaticUnitRange(1, 10) - @test length(static(-1):static(-1):static(-10)) == 10 == - lastindex(static(-1):static(-1):static(-10)) - - @test UnitRange(Static.OptionallyStaticUnitRange(static(1), static(10))) === - UnitRange(1, 10) - @test UnitRange{Int}(Static.OptionallyStaticUnitRange(static(1), static(10))) === - UnitRange(1, 10) - - @test AbstractUnitRange{Int}(Static.OptionallyStaticUnitRange(static(1), static(10))) isa - Static.OptionallyStaticUnitRange - @test AbstractUnitRange{UInt}(Static.OptionallyStaticUnitRange(static(1), static(10))) isa - Base.OneTo - @test AbstractUnitRange{UInt}(Static.OptionallyStaticUnitRange(static(2), static(10))) isa - UnitRange - - @test @inferred((static(1):static(10))[static(2):static(3)]) === static(2):static(3) - @test @inferred((static(1):static(10))[static(2):3]) === static(2):3 - @test @inferred((static(1):static(10))[2:3]) === 2:3 - @test @inferred((1:static(10))[static(2):static(3)]) === 2:3 - - @test Base.checkindex(Bool, static(1):static(10), static(1):static(5)) - @test -(static(1):static(10)) === static(-1):static(-1):static(-10) - - @test reverse(static(1):static(10)) === static(10):static(-1):static(1) - @test reverse(static(1):static(2):static(9)) === static(9):static(-2):static(1) -end - -@testset "range properties" begin - x = static(1):static(2):static(9) - @test getproperty(x, :start) === first(x) - @test getproperty(x, :step) === step(x) - @test getproperty(x, :stop) === last(x) - @test_throws ErrorException getproperty(x, :foo) -end - -@testset "iterate" begin - @test iterate(static(1):static(5)) === (1, 1) - @test iterate(static(1):static(5), 1) === (2, 2) - @test iterate(static(1):static(5), 5) === nothing - @test iterate(static(2):static(5), 5) === nothing - @test iterate(static(1):static(2):static(9), 1) === (3, 3) - @test iterate(static(1):static(2):static(9), 9) === nothing - # make sure single length ranges work correctly - @test iterate(static(2):static(3):static(2))[1] === 2 === - (static(2):static(3):static(2))[1] - @test iterate(static(2):static(3):static(2), 2) === nothing -end - -# CartesianIndices -CI = CartesianIndices((static(1):static(2), static(1):static(2))) - -@testset "length" begin - @test @inferred(length(Static.OptionallyStaticUnitRange(1, 0))) == 0 - @test @inferred(length(Static.OptionallyStaticUnitRange(1, 10))) == 10 - @test @inferred(length(Static.OptionallyStaticUnitRange(static(1), 10))) == 10 - @test @inferred(length(Static.OptionallyStaticUnitRange(static(0), 10))) == 11 - @test @inferred(length(Static.OptionallyStaticUnitRange(static(1), static(10)))) == 10 - @test @inferred(length(Static.OptionallyStaticUnitRange(static(0), static(10)))) == 11 - - @test @inferred(length(static(1):static(2):static(0))) == 0 - @test @inferred(length(static(0):static(-2):static(1))) == 0 - - @test @inferred(length(Static.OptionallyStaticStepRange(static(1), 2, 10))) == 5 - @test @inferred(length(Static.OptionallyStaticStepRange(static(1), static(1), - static(10)))) == 10 - @test @inferred(length(Static.OptionallyStaticStepRange(static(2), static(1), - static(10)))) == 9 - @test @inferred(length(Static.OptionallyStaticStepRange(static(2), static(2), - static(10)))) == 5 -end - -@test @inferred(getindex(static(1):10, Base.Slice(static(1):10))) === static(1):10 -@test @inferred(getindex(Static.OptionallyStaticUnitRange(static(1), 10), 1)) == 1 -@test @inferred(getindex(Static.OptionallyStaticUnitRange(static(0), 10), 1)) == 0 -@test_throws BoundsError getindex(Static.OptionallyStaticUnitRange(static(1), 10), 0) -@test_throws BoundsError getindex(Static.OptionallyStaticStepRange(static(1), 2, 10), 0) -@test_throws BoundsError getindex(Static.OptionallyStaticUnitRange(static(1), 10), 11) -@test_throws BoundsError getindex(Static.OptionallyStaticStepRange(static(1), 2, 10), 11) - -@test Static.static_first(Base.OneTo(one(UInt))) === static(1) -@test Static.static_step(Base.OneTo(one(UInt))) === static(1) - -@test @inferred(eachindex(static(-7):static(7))) === static(1):static(15) -@test @inferred((static(-7):static(7))[first(eachindex(static(-7):static(7)))]) == -7 - -@test @inferred(firstindex(128:static(-1):1)) == 1 - -@test identity.(static(1):5) isa Vector{Int} -@test (static(1):5) .+ (1:3)' isa Matrix{Int} -@test similar(Array{Int}, (static(1):(4),)) isa Vector{Int} -@test similar(Array{Int}, (static(1):(4), Base.OneTo(4))) isa Matrix{Int} -@test similar(Array{Int}, (Base.OneTo(4), static(1):(4))) isa Matrix{Int} - -@test Base.to_shape(static(1):10) == 10 -@test Base.to_shape(Base.Slice(static(1):10)) == 10 -@test Base.axes1(Base.Slice(static(1):10)) === static(1):10 -@test axes(Base.Slice(static(1):10)) === (static(1):10,) -@test isa(axes(Base.Slice(static(0):static(1):10))[1], Base.IdentityUnitRange) -@test isa(Base.axes1(Base.Slice(static(0):static(1):10)), Base.IdentityUnitRange) - -@test Base.Broadcast.axistype(static(1):10, static(1):10) === Base.OneTo(10) -@test Base.Broadcast.axistype(Base.OneTo(10), static(1):10) === Base.OneTo(10) - -@testset "static_promote(::AbstractRange, ::AbstractRange)" begin - ur1 = static(1):10 - ur2 = 1:static(10) - @test @inferred(static_promote(ur1, ur2)) === static(1):static(10) - @test static_promote(Base.Slice(ur1), Base.Slice(ur2)) === - Base.Slice(static(1):static(10)) - sr1 = static(1):2:10 - sr2 = static(1):static(2):static(10) - @test @inferred(static_promote(sr1, sr2)) === sr2 -end - -@testset "n-last/first" begin - ur = static(2):static(10) - sr = static(2):static(2):static(10) - n3 = static(3) - @test @inferred(first(ur, n3)) === static(2):static(4) - @test @inferred(last(ur, n3)) === static(8):static(10) - @test @inferred(first(sr, n3)) === static(2):static(2):static(6) - @test @inferred(last(sr, n3)) === static(5):static(2):static(9) -end diff --git a/test/runtests.jl b/test/runtests.jl index 440a86a..66c7be6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -524,5 +524,3 @@ end @test repr(static(1):static(10)) == "static(1):static(10)" @test repr(static(1):static(2):static(9)) == "static(1):static(2):static(9)" end - -include("ranges.jl") From db0edd52881a1025fce83e9e6ccc489958609384 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Wed, 30 Nov 2022 11:59:00 +0100 Subject: [PATCH 03/20] Remove IntType typedef --- src/Static.jl | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index 18da59d..032f6b1 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -61,15 +61,6 @@ struct StaticInt{N} <: StaticInteger{N} StaticInt(::Val{N}) where {N} = StaticInt(N) end -""" - IntType(x::Integer) -> Union{Int,StaticInt} - -`IntType` is a union of `Int` and `StaticInt`. As a function, it ensures that `x` one of the -two. -""" -const IntType = Union{StaticInt, Int} -IntType(x::Integer) = Int(x) -IntType(@nospecialize x::Union{Int, StaticInt}) = x include("float.jl") @@ -963,6 +954,4 @@ function Base.show(io::IO, m::MIME"text/plain", @nospecialize(x::NDIndex)) nothing end -#include("ranges.jl") - end From e604908a4db5b346dba151ffd31da1f287cf194d Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Wed, 30 Nov 2022 12:42:31 +0100 Subject: [PATCH 04/20] STASH fix ambiguities --- src/Static.jl | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index 032f6b1..1038def 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -425,15 +425,11 @@ Base.:(+)(::StaticInt{N}, y::Ptr) where {N} = y + N function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::RoundingMode) where {X, Y} static(div(X, Y, m)) end -Base.div(x::Real, ::StaticInteger{Y}, m::RoundingMode) where {Y} = div(x, Y, m) -Base.div(::StaticNumber{X}, y::Real, m::RoundingMode) where {X} = div(X, y, m) Base.div(x::StaticBool, y::False) = throw(DivideError()) Base.div(x::StaticBool, y::True) = x Base.rem(@nospecialize(x::StaticNumber), T::Type{<:Integer}) = rem(known(x), T) Base.rem(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = static(rem(X, Y)) -Base.rem(x::Real, ::StaticInteger{Y}) where {Y} = rem(x, Y) -Base.rem(::StaticInteger{X}, y::Real) where {X} = rem(X, y) Base.mod(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = static(mod(X, Y)) Base.:(==)(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = ==(X, Y) @@ -441,50 +437,40 @@ Base.:(==)(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = ==(X, Y) Base.:(<)(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = <(X, Y) Base.isless(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = isless(X, Y) -Base.isless(::StaticInteger{X}, y::Real) where {X} = isless(X, y) -Base.isless(x::Real, ::StaticInteger{Y}) where {Y} = isless(x, Y) Base.min(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(min(X, Y)) -Base.min(::StaticInteger{X}, y::Number) where {X} = min(X, y) -Base.min(x::Number, ::StaticInteger{Y}) where {Y} = min(x, Y) Base.max(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(max(X, Y)) -Base.max(::StaticInteger{X}, y::Number) where {X} = max(X, y) -Base.max(x::Number, ::StaticInteger{Y}) where {Y} = max(x, Y) Base.minmax(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = static(minmax(X, Y)) Base.:(<<)(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(<<(X, Y)) -Base.:(<<)(::StaticInteger{X}, n::Integer) where {X} = <<(X, n) -Base.:(<<)(x::Integer, ::StaticInteger{N}) where {N} = <<(x, N) +Base.:(<<)(::StaticInteger{X}, n::UInt) where {X} = <<(X, n) Base.:(>>)(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(>>(X, Y)) -Base.:(>>)(::StaticInteger{X}, n::Integer) where {X} = >>(X, n) -Base.:(>>)(x::Integer, ::StaticInteger{N}) where {N} = >>(x, N) +Base.:(>>)(::StaticInteger{X}, n::UInt) where {X} = >>(X, n) Base.:(>>>)(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(>>>(X, Y)) -Base.:(>>>)(::StaticInteger{X}, n::Integer) where {X} = >>>(X, n) -Base.:(>>>)(x::Integer, ::StaticInteger{N}) where {N} = >>>(x, N) +Base.:(>>>)(::StaticInteger{X}, n::UInt) where {X} = >>>(X, n) + Base.:(&)(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(X & Y) -Base.:(&)(::StaticInteger{X}, y::Union{Integer, Missing}) where {X} = X & y -Base.:(&)(x::Union{Integer, Missing}, ::StaticInteger{Y}) where {Y} = x & Y -Base.:(&)(x::Bool, y::True) = x -Base.:(&)(x::Bool, y::False) = y -Base.:(&)(x::True, y::Bool) = y -Base.:(&)(x::False, y::Bool) = x +#!!Base.:(&)(x::Bool, y::True) = x +#!!Base.:(&)(x::Bool, y::False) = y +#!!Base.:(&)(x::True, y::Bool) = y +#!!Base.:(&)(x::False, y::Bool) = x Base.:(|)(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(|(X, Y)) -Base.:(|)(::StaticInteger{X}, y::Union{Integer, Missing}) where {X} = X | y -Base.:(|)(x::Union{Integer, Missing}, ::StaticInteger{Y}) where {Y} = x | Y -Base.:(|)(x::Bool, y::True) = y -Base.:(|)(x::Bool, y::False) = x -Base.:(|)(x::True, y::Bool) = x -Base.:(|)(x::False, y::Bool) = y +#!!Base.:(|)(::StaticInteger{X}, y::Union{Integer, Missing}) where {X} = X | y +#!!Base.:(|)(x::Union{Integer, Missing}, ::StaticInteger{Y}) where {Y} = x | Y +#!!Base.:(|)(x::Bool, y::True) = y +#!!Base.:(|)(x::Bool, y::False) = x +#!!Base.:(|)(x::True, y::Bool) = x +#!!Base.:(|)(x::False, y::Bool) = y Base.xor(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(xor(X, Y)) -Base.xor(::StaticInteger{X}, y::Union{Integer, Missing}) where {X} = xor(X, y) -Base.xor(x::Union{Integer, Missing}, ::StaticInteger{Y}) where {Y} = xor(x, Y) +#!!Base.xor(::StaticInteger{X}, y::Union{Integer, Missing}) where {X} = xor(X, y) +#!!Base.xor(x::Union{Integer, Missing}, ::StaticInteger{Y}) where {Y} = xor(x, Y) Base.:(!)(::True) = False() Base.:(!)(::False) = True() From 812fb0bfe69ab3c0615c8f06fcc0af73026f34b0 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Wed, 30 Nov 2022 16:03:47 +0100 Subject: [PATCH 05/20] STASH fix ambig --- src/Static.jl | 30 ++++++++++++++++++++++-------- src/float.jl | 6 +++--- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index 1038def..2bfc777 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -401,16 +401,24 @@ end #Base.Bool(::StaticInt{N}) where {N} = Bool(N) Base.Integer(@nospecialize(x::StaticInt)) = x -(::Type{T})(x::StaticInteger) where {T <: Real} = T(known(x)) -function (@nospecialize(T::Type{<:StaticNumber}))(x::Union{AbstractFloat, - AbstractIrrational, Integer, - Rational}) - static(convert(eltype(T), x)) -end + +#!!!(@nospecialize(T::Type{<:StaticNumber}))(x::AbstractFloat) = static(convert(eltype(T), x)) +#!!!(@nospecialize(T::Type{<:StaticNumber}))(x::AbstractIrrational) = static(convert(eltype(T), x)) +#!!!(@nospecialize(T::Type{<:StaticNumber}))(x::Integer) = static(convert(eltype(T), x)) +#!!!(@nospecialize(T::Type{<:StaticNumber}))(x::Rational) = static(convert(eltype(T), x)) + + @inline Base.:(-)(::StaticNumber{N}) where {N} = static(-N) -Base.:(*)(::Union{AbstractFloat, AbstractIrrational, Integer, Rational}, y::Zero) = y -Base.:(*)(x::Zero, ::Union{AbstractFloat, AbstractIrrational, Integer, Rational}) = x +Base.:(*)(x::Zero, ::Zero) = x +Base.:(*)(::Real, y::Zero) = y +Base.:(*)(::Integer, y::Zero) = y +Base.:(*)(::Rational, y::Zero) = y +Base.:(*)(x::Zero, ::Real) = x +Base.:(*)(x::Zero, ::Integer) = x +Base.:(*)(x::Zero, ::Rational) = x +Base.:(*)(x::Zero, ::StaticInteger{Y}) where {Y} = x +Base.:(*)(::StaticInteger{X}, y::Zero) where {X} = y Base.:(*)(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(X * Y) Base.:(/)(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(X / Y) Base.:(-)(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = static(X - Y) @@ -425,6 +433,12 @@ Base.:(+)(::StaticInt{N}, y::Ptr) where {N} = y + N function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::RoundingMode) where {X, Y} static(div(X, Y, m)) end +function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::Union{RoundingMode{:Nearest}, RoundingMode{:NearestTiesAway}, RoundingMode{:NearestTiesUp}}) where {X, Y} + static(div(X, Y, m)) +end +function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::RoundingMode{:Up}) where {X, Y} + static(div(X, Y, m)) +end Base.div(x::StaticBool, y::False) = throw(DivideError()) Base.div(x::StaticBool, y::True) = x diff --git a/src/float.jl b/src/float.jl index 3bb17bb..b297161 100644 --- a/src/float.jl +++ b/src/float.jl @@ -74,9 +74,9 @@ Base.asec(x::StaticFloat64{M}) where {M} = acos(inv(x)) Base.acsc(x::StaticFloat64{M}) where {M} = asin(inv(x)) Base.acot(x::StaticFloat64{M}) where {M} = atan(inv(x)) -Base.rem(x::Real, ::StaticFloat64{Y}) where {Y} = rem(x, Y) -Base.rem(::StaticFloat64{X}, y::Real) where {X} = rem(X, y) -Base.rem(::StaticFloat64{X}, ::StaticFloat64{Y}) where {X, Y} = StaticFloat64(rem(X, Y)) +#!!!Base.rem(x::Real, ::StaticFloat64{Y}) where {Y} = rem(x, Y) +#!!!Base.rem(::StaticFloat64{X}, y::Real) where {X} = rem(X, y) +#!!!Base.rem(::StaticFloat64{X}, ::StaticFloat64{Y}) where {X, Y} = StaticFloat64(rem(X, Y)) Base.min(x::StaticFloat64{X}, y::StaticFloat64{Y}) where {X, Y} = X > Y ? y : x Base.min(x::Real, ::StaticFloat64{Y}) where {Y} = min(x, Y) From ad0dabb2d456313966fce368d014fb14a0a0834f Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Wed, 30 Nov 2022 16:47:14 +0100 Subject: [PATCH 06/20] STASH ambig --- src/Static.jl | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index 2bfc777..04ea1ba 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -430,19 +430,29 @@ Base.:(+)(::StaticInt{N}, y::Ptr) where {N} = y + N @generated Base.sqrt(::StaticNumber{N}) where {N} = :($(static(sqrt(N)))) -function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::RoundingMode) where {X, Y} - static(div(X, Y, m)) -end -function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::Union{RoundingMode{:Nearest}, RoundingMode{:NearestTiesAway}, RoundingMode{:NearestTiesUp}}) where {X, Y} +#=function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::RoundingMode) where {X, Y} static(div(X, Y, m)) +end=# +for mode in (:RoundUp, :RoundDown, :ToZero, :Nearest, :NearestTiesAway, :NearestTiesUp) + @eval function Base.div(::StaticBool{X}, ::StaticBool{Y}, m::RoundingMode{$(QuoteNode(mode))}) where {X, Y} + static(div(X, Y, m)) + end + @eval function Base.div(::StaticFloat64{X}, ::StaticFloat64{Y}, m::RoundingMode{$(QuoteNode(mode))}) where {X, Y} + static(div(X, Y, m)) + end + @eval function Base.div(::StaticInt{X}, ::StaticInt{Y}, m::RoundingMode{$(QuoteNode(mode))}) where {X, Y} + static(div(X, Y, m)) + end end -function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::RoundingMode{:Up}) where {X, Y} +#=function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::Union{RoundingMode{:RoundUp},RoundingMode{:RoundDown},RoundingMode{:Nearest}, RoundingMode{:NearestTiesAway}, RoundingMode{:NearestTiesUp}}) where {X, Y} static(div(X, Y, m)) -end +end=# Base.div(x::StaticBool, y::False) = throw(DivideError()) Base.div(x::StaticBool, y::True) = x Base.rem(@nospecialize(x::StaticNumber), T::Type{<:Integer}) = rem(known(x), T) +Base.rem(@nospecialize(x::StaticNumber), T::Type{Bool}) = rem(known(x), T) +Base.rem(@nospecialize(x::StaticNumber), T::Type{BigInt}) = rem(known(x), T) Base.rem(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = static(rem(X, Y)) Base.mod(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = static(mod(X, Y)) From 671352404a85ee296593c7b95fe13cd36399df24 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Wed, 30 Nov 2022 18:09:16 +0100 Subject: [PATCH 07/20] STASH disabig --- src/Static.jl | 22 +++++++++++++++------- src/float.jl | 3 ++- test/runtests.jl | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index 04ea1ba..65f6701 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -47,6 +47,8 @@ function StaticBool(x::Bool) return False() end end +#!!!StaticBool(x::Real) = StaticBool(convert(Bool, x)) + """ StaticInt(N::Int) -> StaticInt{N}() @@ -59,6 +61,8 @@ struct StaticInt{N} <: StaticInteger{N} StaticInt(N::Int) = new{N}() StaticInt(@nospecialize N::StaticInt) = N StaticInt(::Val{N}) where {N} = StaticInt(N) + StaticInt(N::UInt) = StaticInt(Int(N)) + #!!!StaticInt(x::Real) = StaticInt(convert(Int, x)) end @@ -66,6 +70,10 @@ include("float.jl") const StaticNumber{N} = Union{StaticInt{N}, StaticBool{N}, StaticFloat64{N}} +StaticInt(::StaticNumber{X}) where X = StaticInt{convert(Int, x)}() +StaticBool(::StaticNumber{X}) where X = StaticBool{convert(Bool, x)}() +StaticFloat64(::StaticNumber{X}) where {X} = StaticFloat64{convert(Float64, X)}() + Base.getindex(x::Tuple, ::StaticInt{N}) where {N} = getfield(x, N) Base.zero(@nospecialize(::StaticInt)) = StaticInt{0}() @@ -85,8 +93,8 @@ const FloatZero = StaticFloat64{zero(Float64)} const StaticType{T} = Union{StaticNumber{T}, StaticSymbol{T}} -StaticInt(x::False) = Zero() -StaticInt(x::True) = One() +#!!!StaticInt(x::False) = Zero() +#!!!StaticInt(x::True) = One() Base.Bool(::True) = true Base.Bool(::False) = false @@ -213,7 +221,7 @@ static(:x) ``` """ static(@nospecialize(x::Union{StaticSymbol, StaticNumber})) = x -static(x::Integer) = StaticInt(x) +static(x::Integer) = StaticInt{convert(Int, x)}() function static(x::Union{AbstractFloat, Complex, Rational, AbstractIrrational}) StaticFloat64(Float64(x)) end @@ -371,11 +379,11 @@ Base.:(~)(::StaticInteger{N}) where {N} = static(~N) Base.inv(x::StaticInteger{N}) where {N} = one(x) / x -Base.zero(@nospecialize T::Type{<:StaticInt}) = StaticInt(0) +Base.zero(@nospecialize T::Type{<:StaticInt}) = static(0) Base.zero(@nospecialize T::Type{<:StaticBool}) = False() Base.one(@nospecialize T::Type{<:StaticBool}) = True() -Base.one(@nospecialize T::Type{<:StaticInt}) = StaticInt(1) +Base.one(@nospecialize T::Type{<:StaticInt}) = static(1) @inline Base.iszero(::Union{StaticInt{0}, StaticFloat64{0.0}, False}) = true @inline Base.iszero(@nospecialize x::Union{StaticInt, True, StaticFloat64}) = false @@ -547,7 +555,7 @@ Base.:(^)(x::BigInt, y::True) = x end @inline function invariant_permutation(@nospecialize(x::Tuple), @nospecialize(y::Tuple)) - if y === x === ntuple(static, StaticInt(nfields(x))) + if y === x === ntuple(static, static(nfields(x))) return True() else return False() @@ -618,7 +626,7 @@ value is a `StaticInt`. end function Base.invperm(p::Tuple{StaticInt, Vararg{StaticInt, N}}) where {N} - map(Base.Fix2(find_first_eq, p), ntuple(static, StaticInt(N + 1))) + map(Base.Fix2(find_first_eq, p), ntuple(static, static(N + 1))) end """ diff --git a/src/float.jl b/src/float.jl index b297161..668b3fe 100644 --- a/src/float.jl +++ b/src/float.jl @@ -9,11 +9,12 @@ struct StaticFloat64{N} <: Real StaticFloat64{N}() where {N} = new{N::Float64}() StaticFloat64(x::Float64) = new{x}() StaticFloat64(x::Int) = new{Base.sitofp(Float64, x)::Float64}() - StaticFloat64(x::StaticInt{N}) where {N} = StaticFloat64(convert(Float64, N)) StaticFloat64(x::Complex) = StaticFloat64(convert(Float64, x)) StaticFloat64(@nospecialize x::StaticFloat64) = x + #!!!StaticFloat64(x::Real) = StaticFloat64(convert(Float64, x)) end + Base.zero(@nospecialize T::Type{<:StaticFloat64}) = Float64(0.0) Base.one(@nospecialize T::Type{<:StaticFloat64}) = Float64(1.0) diff --git a/test/runtests.jl b/test/runtests.jl index 66c7be6..6263b08 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -44,6 +44,7 @@ end for j in Any[StaticInt(0), StaticInt(1), StaticInt(2), 3] i === j === 3 && continue for f in [+, -, *, ÷, %, <<, >>, >>>, &, |, ⊻, ==, ≤, ≥, min, max] + @info "XXXXXXXXXXX" i, j, f (iszero(j) && ((f === ÷) || (f === %))) && continue # integer division error @test convert(Int, @inferred(f(i, j))) == f(convert(Int, i), convert(Int, j)) From 03b16f87372d7ce9817bc6ca450407cec2fb8a5a Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Wed, 30 Nov 2022 18:20:29 +0100 Subject: [PATCH 08/20] STASH fixes --- src/Static.jl | 3 ++- test/runtests.jl | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index 65f6701..f3188aa 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -441,7 +441,7 @@ Base.:(+)(::StaticInt{N}, y::Ptr) where {N} = y + N #=function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::RoundingMode) where {X, Y} static(div(X, Y, m)) end=# -for mode in (:RoundUp, :RoundDown, :ToZero, :Nearest, :NearestTiesAway, :NearestTiesUp) +for mode in (:Up, :Down, :ToZero, :Nearest, :NearestTiesAway, :NearestTiesUp) @eval function Base.div(::StaticBool{X}, ::StaticBool{Y}, m::RoundingMode{$(QuoteNode(mode))}) where {X, Y} static(div(X, Y, m)) end @@ -467,6 +467,7 @@ Base.mod(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = static(mod(X, Y)) Base.:(==)(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = ==(X, Y) Base.:(<)(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = <(X, Y) +Base.:(<=)(::StaticNumber{X}, ::StaticNumber{Y}) where {X, Y} = <=(X, Y) Base.isless(::StaticInteger{X}, ::StaticInteger{Y}) where {X, Y} = isless(X, Y) diff --git a/test/runtests.jl b/test/runtests.jl index 6263b08..66c7be6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -44,7 +44,6 @@ end for j in Any[StaticInt(0), StaticInt(1), StaticInt(2), 3] i === j === 3 && continue for f in [+, -, *, ÷, %, <<, >>, >>>, &, |, ⊻, ==, ≤, ≥, min, max] - @info "XXXXXXXXXXX" i, j, f (iszero(j) && ((f === ÷) || (f === %))) && continue # integer division error @test convert(Int, @inferred(f(i, j))) == f(convert(Int, i), convert(Int, j)) From 7e3263ec0552dcb67fa6fa58cb0b6b7112e29ae2 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 13:31:21 +0100 Subject: [PATCH 09/20] STASH --- src/Static.jl | 32 ++++++++++++++++++++++---------- test/runtests.jl | 8 ++++---- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index f3188aa..5b998ac 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -70,10 +70,19 @@ include("float.jl") const StaticNumber{N} = Union{StaticInt{N}, StaticBool{N}, StaticFloat64{N}} -StaticInt(::StaticNumber{X}) where X = StaticInt{convert(Int, x)}() -StaticBool(::StaticNumber{X}) where X = StaticBool{convert(Bool, x)}() +StaticInt(::StaticNumber{X}) where X = StaticInt{convert(Int, X)}() +StaticBool(::StaticNumber{X}) where X = StaticBool{convert(Bool, X)}() StaticFloat64(::StaticNumber{X}) where {X} = StaticFloat64{convert(Float64, X)}() +Base.convert(::Type{StaticInt}, x::StaticNumber) = StaticInt(x) +Base.convert(::Type{StaticBool}, x::StaticNumber) = StaticBool(x) +Base.convert(::Type{StaticFloat64}, x::StaticNumber) = StaticFloat64(x) + +Base.convert(::Type{StaticInt{X}}, y::StaticNumber) where X = StaticInt{X}(StaticInt(y)) +Base.convert(::Type{StaticBool{X}}, y::StaticNumber) where X = StaticBool{X}(StaticBool(y)) +Base.convert(::Type{StaticFloat64{X}}, y::StaticNumber) where X = StaticFloat64{X}(StaticFloat64(y)) + + Base.getindex(x::Tuple, ::StaticInt{N}) where {N} = getfield(x, N) Base.zero(@nospecialize(::StaticInt)) = StaticInt{0}() @@ -366,14 +375,17 @@ function Base.promote_rule(@nospecialize(T1::Type{<:StaticNumber}), @nospecialize(T2::Type{<:StaticNumber})) promote_rule(eltype(T1), eltype(T2)) end -function Base.promote_rule(::Type{<:Base.TwicePrecision{R}}, - @nospecialize(T::Type{<:StaticNumber})) where {R <: Number} - promote_rule(Base.TwicePrecision{R}, eltype(T)) -end -function Base.promote_rule(@nospecialize(T1::Type{<:StaticNumber}), - T2::Type{<:Union{Rational, AbstractFloat, Signed}}) - promote_rule(T2, eltype(T1)) -end +Base.promote_rule(@nospecialize(T1::Type{<:StaticNumber}), T2::Type{<:Real}) = promote_type(eltype(T1), T2) + +# Bool needs special handling, Base defines `promote_rule(::Type{Bool}, ::Type{T}) where {T<:Number} = T` +Base.promote_rule(::Type{Bool}, @nospecialize(T::Type{<:StaticNumber})) = eltype(T) +Base.promote_rule(@nospecialize(T::Type{<:StaticNumber}), ::Type{Bool}) = eltype(T) + + +@inline Base.promote(@nospecialize(a::StaticInt), @nospecialize(b::StaticInt)) = (a, b) +@inline Base.promote(@nospecialize(a::StaticBool), @nospecialize(b::StaticBool)) = (a, b) +@inline Base.promote(@nospecialize(a::StaticFloat64), @nospecialize(b::StaticFloat64)) = (a, b) + Base.:(~)(::StaticInteger{N}) where {N} = static(~N) diff --git a/test/runtests.jl b/test/runtests.jl index 66c7be6..220cb8c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -142,17 +142,17 @@ end @test @inferred(xor(t, t)) === f @test @inferred(|(true, f)) - @test @inferred(|(true, t)) === t + @test @inferred(|(true, t)) === true @test @inferred(|(f, true)) - @test @inferred(|(t, true)) === t + @test @inferred(|(t, true)) === true @test @inferred(|(f, f)) === f @test @inferred(|(f, t)) === t @test @inferred(|(t, f)) === t @test @inferred(|(t, t)) === t - @test @inferred(Base.:(&)(true, f)) === f + @test @inferred(Base.:(&)(true, f)) === false @test @inferred(Base.:(&)(true, t)) - @test @inferred(Base.:(&)(f, true)) === f + @test @inferred(Base.:(&)(f, true)) === false @test @inferred(Base.:(&)(t, true)) @test @inferred(Base.:(&)(f, f)) === f @test @inferred(Base.:(&)(f, t)) === f From d1c3ef3753c3d07f110e1ac48d17965ff41a685d Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 14:12:40 +0100 Subject: [PATCH 10/20] STASH --- src/Static.jl | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index 5b998ac..f9134bc 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -70,6 +70,16 @@ include("float.jl") const StaticNumber{N} = Union{StaticInt{N}, StaticBool{N}, StaticFloat64{N}} +StaticInt(x::Real) = StaticInt{Int(x)}() +StaticInt(x::Rational) = StaticInt{Int(x)}() # Resolves ambiguities with Base +StaticInt(x::BigFloat) = StaticInt{Int(x)}() # Resolves ambiguities with Base + +StaticBool(x::Real) = StaticBool{Bool(x)}() +StaticBool(x::Rational) = StaticBool{Bool(x)}() # Resolves ambiguities with Base +StaticBool(x::BigFloat) = StaticBool{Bool(x)}() # Resolves ambiguities with Base + +StaticFloat64(x::Real) = StaticInt{Float64(x)}() + StaticInt(::StaticNumber{X}) where X = StaticInt{convert(Int, X)}() StaticBool(::StaticNumber{X}) where X = StaticBool{convert(Bool, X)}() StaticFloat64(::StaticNumber{X}) where {X} = StaticFloat64{convert(Float64, X)}() @@ -83,6 +93,15 @@ Base.convert(::Type{StaticBool{X}}, y::StaticNumber) where X = StaticBool{X}(Sta Base.convert(::Type{StaticFloat64{X}}, y::StaticNumber) where X = StaticFloat64{X}(StaticFloat64(y)) +function Base.convert(::Type{T}, @nospecialize(N::StaticNumber)) where {T <: Number} + convert(T, known(N)) +end + +#Base.Bool(::StaticInt{N}) where {N} = Bool(N) + +(::Type{T})(@nospecialize x::StaticNumber) where {T <: Union{Base.BitInteger,Float32,Float64}} = T(known(x)) + + Base.getindex(x::Tuple, ::StaticInt{N}) where {N} = getfield(x, N) Base.zero(@nospecialize(::StaticInt)) = StaticInt{0}() @@ -414,19 +433,6 @@ Base.sign(::StaticNumber{N}) where {N} = static(sign(N)) Base.widen(@nospecialize(x::StaticNumber)) = widen(known(x)) -function Base.convert(::Type{T}, @nospecialize(N::StaticNumber)) where {T <: Number} - convert(T, known(N)) -end - -#Base.Bool(::StaticInt{N}) where {N} = Bool(N) - -Base.Integer(@nospecialize(x::StaticInt)) = x - -#!!!(@nospecialize(T::Type{<:StaticNumber}))(x::AbstractFloat) = static(convert(eltype(T), x)) -#!!!(@nospecialize(T::Type{<:StaticNumber}))(x::AbstractIrrational) = static(convert(eltype(T), x)) -#!!!(@nospecialize(T::Type{<:StaticNumber}))(x::Integer) = static(convert(eltype(T), x)) -#!!!(@nospecialize(T::Type{<:StaticNumber}))(x::Rational) = static(convert(eltype(T), x)) - @inline Base.:(-)(::StaticNumber{N}) where {N} = static(-N) @@ -448,6 +454,9 @@ Base.:(-)(::StaticInt{N}, y::Ptr) where {N} = y - N Base.:(+)(x::Ptr, ::StaticInt{N}) where {N} = x + N Base.:(+)(::StaticInt{N}, y::Ptr) where {N} = y + N +Base.leading_zeros(x::StaticInt) = leading_zeros(known(x)) +Base.trailing_zeros(x::StaticInt) = leading_zeros(known(x)) + @generated Base.sqrt(::StaticNumber{N}) where {N} = :($(static(sqrt(N)))) #=function Base.div(::StaticNumber{X}, ::StaticNumber{Y}, m::RoundingMode) where {X, Y} From 952b666ac1925ba9c769835a7daa1308a507f632 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 14:22:15 +0100 Subject: [PATCH 11/20] STASH --- src/Static.jl | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index f9134bc..d765441 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -74,23 +74,20 @@ StaticInt(x::Real) = StaticInt{Int(x)}() StaticInt(x::Rational) = StaticInt{Int(x)}() # Resolves ambiguities with Base StaticInt(x::BigFloat) = StaticInt{Int(x)}() # Resolves ambiguities with Base +StaticInt{X}(y::Real) where X = StaticInt{Int(y)}() +StaticInt{X}(x::Rational) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base +StaticInt{X}(x::BigFloat) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base + StaticBool(x::Real) = StaticBool{Bool(x)}() StaticBool(x::Rational) = StaticBool{Bool(x)}() # Resolves ambiguities with Base StaticBool(x::BigFloat) = StaticBool{Bool(x)}() # Resolves ambiguities with Base -StaticFloat64(x::Real) = StaticInt{Float64(x)}() - -StaticInt(::StaticNumber{X}) where X = StaticInt{convert(Int, X)}() -StaticBool(::StaticNumber{X}) where X = StaticBool{convert(Bool, X)}() -StaticFloat64(::StaticNumber{X}) where {X} = StaticFloat64{convert(Float64, X)}() - -Base.convert(::Type{StaticInt}, x::StaticNumber) = StaticInt(x) -Base.convert(::Type{StaticBool}, x::StaticNumber) = StaticBool(x) -Base.convert(::Type{StaticFloat64}, x::StaticNumber) = StaticFloat64(x) +StaticBool{X}(y::Real) where X = StaticBool{Bool(y)}() +StaticBool{X}(x::Rational) where X = StaticBool{Bool(y)}() # Resolves ambiguities with Base +StaticBool{X}(x::BigFloat) where X = StaticBool{Bool(y)}() # Resolves ambiguities with Base -Base.convert(::Type{StaticInt{X}}, y::StaticNumber) where X = StaticInt{X}(StaticInt(y)) -Base.convert(::Type{StaticBool{X}}, y::StaticNumber) where X = StaticBool{X}(StaticBool(y)) -Base.convert(::Type{StaticFloat64{X}}, y::StaticNumber) where X = StaticFloat64{X}(StaticFloat64(y)) +StaticFloat64(x::Real) = StaticFloat64{Float64(x)}() +StaticFloat64{X}(y::Real) where X = StaticFloat64{Int(y)}() function Base.convert(::Type{T}, @nospecialize(N::StaticNumber)) where {T <: Number} From ea92722c550d8197b5ec976c397e4eec7cc8a082 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 14:26:56 +0100 Subject: [PATCH 12/20] STASH --- src/Static.jl | 10 +++++----- src/float.jl | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index d765441..16b7d43 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -75,19 +75,19 @@ StaticInt(x::Rational) = StaticInt{Int(x)}() # Resolves ambiguities with Base StaticInt(x::BigFloat) = StaticInt{Int(x)}() # Resolves ambiguities with Base StaticInt{X}(y::Real) where X = StaticInt{Int(y)}() -StaticInt{X}(x::Rational) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base -StaticInt{X}(x::BigFloat) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base +StaticInt{X}(y::Rational) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base +StaticInt{X}(y::BigFloat) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base StaticBool(x::Real) = StaticBool{Bool(x)}() StaticBool(x::Rational) = StaticBool{Bool(x)}() # Resolves ambiguities with Base StaticBool(x::BigFloat) = StaticBool{Bool(x)}() # Resolves ambiguities with Base StaticBool{X}(y::Real) where X = StaticBool{Bool(y)}() -StaticBool{X}(x::Rational) where X = StaticBool{Bool(y)}() # Resolves ambiguities with Base -StaticBool{X}(x::BigFloat) where X = StaticBool{Bool(y)}() # Resolves ambiguities with Base +StaticBool{X}(y::Rational) where X = StaticBool{Bool(y)}() # Resolves ambiguities with Base +StaticBool{X}(y::BigFloat) where X = StaticBool{Bool(y)}() # Resolves ambiguities with Base StaticFloat64(x::Real) = StaticFloat64{Float64(x)}() -StaticFloat64{X}(y::Real) where X = StaticFloat64{Int(y)}() +StaticFloat64{X}(y::Real) where X = StaticFloat64{Float64(y)}() function Base.convert(::Type{T}, @nospecialize(N::StaticNumber)) where {T <: Number} diff --git a/src/float.jl b/src/float.jl index 668b3fe..399b8c8 100644 --- a/src/float.jl +++ b/src/float.jl @@ -7,9 +7,9 @@ Use `StaticInt(N)` instead of `Val(N)` when you want it to behave like a number. """ struct StaticFloat64{N} <: Real StaticFloat64{N}() where {N} = new{N::Float64}() - StaticFloat64(x::Float64) = new{x}() + #!!!StaticFloat64(x::Float64) = new{x}() StaticFloat64(x::Int) = new{Base.sitofp(Float64, x)::Float64}() - StaticFloat64(x::Complex) = StaticFloat64(convert(Float64, x)) + #!!!StaticFloat64(x::Complex) = StaticFloat64(convert(Float64, x)) StaticFloat64(@nospecialize x::StaticFloat64) = x #!!!StaticFloat64(x::Real) = StaticFloat64(convert(Float64, x)) end From 4d35acc45a57f7738c6938f2d4ffd99ca00a1f08 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 14:59:28 +0100 Subject: [PATCH 13/20] STASH --- test/runtests.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 220cb8c..0e55a4a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -485,10 +485,10 @@ y = 1:10 @test typeof(fone)(1.0) isa Static.StaticFloat64 @test @inferred(eltype(Static.StaticFloat64(static(1)))) <: Float64 - @test @inferred(promote_rule(typeof(fone), Int)) <: promote_type(Float64, Int) - @test @inferred(promote_rule(typeof(fone), Float64)) <: Float64 - @test @inferred(promote_rule(typeof(fone), Float32)) <: Float32 - @test @inferred(promote_rule(typeof(fone), Float16)) <: Float16 + @test @inferred(promote_rule(typeof(fone), Int)) == Float64 + @test @inferred(promote_type(typeof(fone), Float64)) == Float64 + @test @inferred(promote_type(typeof(fone), Float32)) == Float32 + @test @inferred(promote_type(typeof(fone), Float16)) == Float16 @test @inferred(inv(static(2.0))) === static(inv(2.0)) === inv(static(2)) From b1b7512967bf744aacd323bf4b2f204e3acc34b4 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 15:06:59 +0100 Subject: [PATCH 14/20] STASH --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 0e55a4a..8baf83d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -487,8 +487,8 @@ y = 1:10 @test @inferred(eltype(Static.StaticFloat64(static(1)))) <: Float64 @test @inferred(promote_rule(typeof(fone), Int)) == Float64 @test @inferred(promote_type(typeof(fone), Float64)) == Float64 - @test @inferred(promote_type(typeof(fone), Float32)) == Float32 - @test @inferred(promote_type(typeof(fone), Float16)) == Float16 + @test @inferred(promote_type(typeof(fone), Float32)) == Float64 + @test @inferred(promote_type(typeof(fone), Float16)) == Float64 @test @inferred(inv(static(2.0))) === static(inv(2.0)) === inv(static(2)) From f3d06e32660081b1e8896795e36bfd504c45f0cb Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 15:11:32 +0100 Subject: [PATCH 15/20] STASH --- src/Static.jl | 10 +++++++++- test/runtests.jl | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Static.jl b/src/Static.jl index 16b7d43..abc160e 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -76,12 +76,20 @@ StaticInt(x::BigFloat) = StaticInt{Int(x)}() # Resolves ambiguities with Base StaticInt{X}(y::Real) where X = StaticInt{Int(y)}() StaticInt{X}(y::Rational) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base -StaticInt{X}(y::BigFloat) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base +StaticInt{X}(yt::BigFloat) where X = StaticInt{Int(y)}() # Resolves ambiguities with Base StaticBool(x::Real) = StaticBool{Bool(x)}() StaticBool(x::Rational) = StaticBool{Bool(x)}() # Resolves ambiguities with Base StaticBool(x::BigFloat) = StaticBool{Bool(x)}() # Resolves ambiguities with Base +True(x::Real) = StaticBool{Bool(x)}() +True(x::Rational) = StaticBool{Bool(x)}() # Resolves ambiguities with Base +True(x::BigFloat) = StaticBool{Bool(x)}() # Resolves ambiguities with Base + +False(x::Real) = StaticBool{Bool(x)}() +False(x::Rational) = StaticBool{Bool(x)}() # Resolves ambiguities with Base +False(x::BigFloat) = StaticBool{Bool(x)}() # Resolves ambiguities with Base + StaticBool{X}(y::Real) where X = StaticBool{Bool(y)}() StaticBool{X}(y::Rational) where X = StaticBool{Bool(y)}() # Resolves ambiguities with Base StaticBool{X}(y::BigFloat) where X = StaticBool{Bool(y)}() # Resolves ambiguities with Base diff --git a/test/runtests.jl b/test/runtests.jl index 8baf83d..d26dd4d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -520,7 +520,7 @@ end @test repr(static(:x)) == "static(:x)" @test repr(static(true)) == "static(true)" @test repr(static(CartesianIndex(1, 1))) == "NDIndex(static(1), static(1))" - @test string(static(true)) == "static(true)" == "$(static(true))" + @test repr(static(true)) == "static(true)" == "$(static(true))" @test repr(static(1):static(10)) == "static(1):static(10)" @test repr(static(1):static(2):static(9)) == "static(1):static(2):static(9)" end From b661282cce214bd4c87105c0671798fb0206529a Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 15:35:04 +0100 Subject: [PATCH 16/20] STASH --- src/Static.jl | 3 +++ test/runtests.jl | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Static.jl b/src/Static.jl index abc160e..9960301 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -985,6 +985,9 @@ end return (Base.to_index(A, I[1]), to_indices(A, indstail, Base.tail(I))...) end +Base.string(::True) = "static(true)" +Base.string(::False) = "static(false)" + function Base.show(io::IO, @nospecialize(x::Union{StaticNumber, StaticSymbol, NDIndex})) show(io, MIME"text/plain"(), x) end diff --git a/test/runtests.jl b/test/runtests.jl index d26dd4d..cf9524d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -520,7 +520,8 @@ end @test repr(static(:x)) == "static(:x)" @test repr(static(true)) == "static(true)" @test repr(static(CartesianIndex(1, 1))) == "NDIndex(static(1), static(1))" - @test repr(static(true)) == "static(true)" == "$(static(true))" + @test string(static(true)) == "static(true)" == "$(static(true))" + @test string(static(false)) == "static(false)" == "$(static(false))" @test repr(static(1):static(10)) == "static(1):static(10)" @test repr(static(1):static(2):static(9)) == "static(1):static(2):static(9)" end From b00eca33919ebee0c1b4aca9debdf06846ae39f3 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 15:49:53 +0100 Subject: [PATCH 17/20] STASH range --- src/Static.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Static.jl b/src/Static.jl index 9960301..a76227f 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -107,6 +107,9 @@ end (::Type{T})(@nospecialize x::StaticNumber) where {T <: Union{Base.BitInteger,Float32,Float64}} = T(known(x)) +Base.:(:)(a::StaticNumber, b::StaticNumber) = (:)(known(a), known(b)) + + Base.getindex(x::Tuple, ::StaticInt{N}) where {N} = getfield(x, N) Base.zero(@nospecialize(::StaticInt)) = StaticInt{0}() From 449c65d3403781d0f25eb1f5da12b60b14d9b73d Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 15:51:12 +0100 Subject: [PATCH 18/20] Revert "Remove custom range types" This reverts commit 6326a116e547bdf0a58bee679be1e52dc2dd5542. --- src/Static.jl | 2 + src/ranges.jl | 394 +++++++++++++++++++++++++++++++++++++++++++++++ test/ranges.jl | 159 +++++++++++++++++++ test/runtests.jl | 2 + 4 files changed, 557 insertions(+) create mode 100644 src/ranges.jl create mode 100644 test/ranges.jl diff --git a/src/Static.jl b/src/Static.jl index a76227f..eeb704a 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -1005,4 +1005,6 @@ function Base.show(io::IO, m::MIME"text/plain", @nospecialize(x::NDIndex)) nothing end +include("ranges.jl") + end diff --git a/src/ranges.jl b/src/ranges.jl new file mode 100644 index 0000000..6a15be8 --- /dev/null +++ b/src/ranges.jl @@ -0,0 +1,394 @@ + +""" + OptionallyStaticUnitRange(start, stop) <: AbstractUnitRange{Int} + +Similar to `UnitRange` except each field may be an `Int` or `StaticInt`. An +`OptionallyStaticUnitRange` is intended to be constructed internally from other valid +indices. Therefore, users should not expect the same checks are used to ensure construction +of a valid `OptionallyStaticUnitRange` as a `UnitRange`. +""" +struct OptionallyStaticUnitRange{F <: IntType, L <: IntType} <: + AbstractUnitRange{Int} + start::F + stop::L + + function OptionallyStaticUnitRange(start::IntType, + stop::IntType) + new{typeof(start), typeof(stop)}(start, stop) + end + function OptionallyStaticUnitRange(start, stop) + OptionallyStaticUnitRange(IntType(start), IntType(stop)) + end + OptionallyStaticUnitRange(@nospecialize x::OptionallyStaticUnitRange) = x + function OptionallyStaticUnitRange(x::AbstractRange) + step(x) == 1 && return OptionallyStaticUnitRange(static_first(x), static_last(x)) + + errmsg(x) = throw(ArgumentError("step must be 1, got $(step(x))")) # avoid GC frame + errmsg(x) + end + function OptionallyStaticUnitRange{F, L}(x::AbstractRange) where {F, L} + OptionallyStaticUnitRange(x) + end + function OptionallyStaticUnitRange{StaticInt{F}, StaticInt{L}}() where {F, L} + new{StaticInt{F}, StaticInt{L}}() + end +end + +""" + OptionallyStaticStepRange(start, step, stop) <: OrdinalRange{Int,Int} + +Similarly to [`OptionallyStaticUnitRange`](@ref), `OptionallyStaticStepRange` permits +a combination of static and standard primitive `Int`s to construct a range. It +specifically enables the use of ranges without a step size of 1. It may be constructed +through the use of `OptionallyStaticStepRange` directly or using static integers with +the range operator (i.e., `:`). + +```julia +julia> using Static + +julia> x = static(2); + +julia> x:x:10 +static(2):static(2):10 + +julia> Static.OptionallyStaticStepRange(x, x, 10) +static(2):static(2):10 + +``` +""" +struct OptionallyStaticStepRange{F <: IntType, S <: IntType, + L <: IntType} <: OrdinalRange{Int, Int} + start::F + step::S + stop::L + + global function _OptionallyStaticStepRange(@nospecialize(start::IntType), + @nospecialize(step::IntType), + @nospecialize(stop::IntType)) + new{typeof(start), typeof(step), typeof(stop)}(start, step, stop) + end +end +@noinline function OptionallyStaticStepRange(@nospecialize(start::IntType), + ::StaticInt{0}, + @nospecialize(stop::IntType)) + throw(ArgumentError("step cannot be zero")) +end +# we don't need to check the `stop` if we know it acts like a unit range +function OptionallyStaticStepRange(@nospecialize(start::IntType), + step::StaticInt{1}, + @nospecialize(stop::IntType)) + _OptionallyStaticStepRange(start, step, stop) +end +function OptionallyStaticStepRange(@nospecialize(start::IntType), + @nospecialize(step::StaticInt), + @nospecialize(stop::IntType)) + _OptionallyStaticStepRange(start, step, _steprange_last(start, step, stop)) +end +function OptionallyStaticStepRange(start, step, stop) + OptionallyStaticStepRange(IntType(start), IntType(step), IntType(stop)) +end +function OptionallyStaticStepRange(@nospecialize(start::IntType), + step::Int, + @nospecialize(stop::IntType)) + if step === 0 + throw(ArgumentError("step cannot be zero")) + else + _OptionallyStaticStepRange(start, step, _steprange_last(start, step, stop)) + end +end +OptionallyStaticStepRange(@nospecialize x::OptionallyStaticStepRange) = x +function OptionallyStaticStepRange(x::AbstractRange) + _OptionallyStaticStepRange(IntType(static_first(x)), IntType(static_step(x)), + IntType(static_last(x))) +end + +# to make StepRange constructor inlineable, so optimizer can see `step` value +@inline function _steprange_last(start::StaticInt, step::StaticInt, stop::StaticInt) + StaticInt(_steprange_last(Int(start), Int(step), Int(stop))) +end +@inline function _steprange_last(start::Union{StaticInt, Int}, + step::Union{StaticInt, Int}, + stop::Union{StaticInt, Int}) + _steprange_last(Int(start), Int(step), Int(stop)) +end +@inline function _steprange_last(start::Int, step::Int, stop::Int) + if stop === start + return stop + elseif step > 0 + if stop > start + return stop - rem(stop - start, step) + else + return start - 1 + end + else + if stop > start + return start + 1 + else + return stop + rem(start - stop, -step) + end + end +end + +""" + SUnitRange(start::Int, stop::Int) + +An alias for `OptionallyStaticUnitRange` where both the start and stop are known statically. +""" +const SUnitRange{F, L} = OptionallyStaticUnitRange{StaticInt{F}, StaticInt{L}} +SUnitRange(start::Int, stop::Int) = SUnitRange{start, stop}() + +""" + SOneTo(n::Int) + +An alias for `OptionallyStaticUnitRange` usfeul for statically sized axes. +""" +const SOneTo{L} = SUnitRange{1, L} +SOneTo(n::Int) = SOneTo{n}() + +const OptionallyStaticRange{F, L} = Union{OptionallyStaticUnitRange{F, L}, + OptionallyStaticStepRange{F, <:Any, L}} + +# these probide a generic method for extracting potentially static values. +static_first(x::Base.OneTo) = StaticInt(1) +static_first(x::Union{Base.Slice, Base.IdentityUnitRange}) = static_first(x.indices) +static_first(x::OptionallyStaticRange) = getfield(x, :start) +static_first(x) = first(x) + +static_step(@nospecialize x::AbstractUnitRange) = StaticInt(1) +static_step(x::OptionallyStaticStepRange) = getfield(x, :step) +static_step(x) = step(x) + +static_last(x::OptionallyStaticRange) = getfield(x, :stop) +static_last(x) = last(x) +static_last(x::Union{Base.Slice, Base.IdentityUnitRange}) = static_last(x.indices) + +Base.first(x::OptionallyStaticRange{Int}) = getfield(x, :start) +Base.first(::OptionallyStaticRange{StaticInt{F}}) where {F} = F +Base.step(x::OptionallyStaticStepRange{<:Any, Int}) = getfield(x, :step) +Base.step(::OptionallyStaticStepRange{<:Any, StaticInt{S}}) where {S} = S +Base.last(x::OptionallyStaticRange{<:Any, Int}) = getfield(x, :stop) +Base.last(::OptionallyStaticRange{<:Any, StaticInt{L}}) where {L} = L + +# FIXME this line causes invalidations +Base.:(:)(L::Integer, ::StaticInt{U}) where {U} = OptionallyStaticUnitRange(L, StaticInt(U)) +Base.:(:)(::StaticInt{L}, U::Integer) where {L} = OptionallyStaticUnitRange(StaticInt(L), U) +function Base.:(:)(::StaticInt{L}, ::StaticInt{U}) where {L, U} + OptionallyStaticUnitRange(StaticInt(L), StaticInt(U)) +end +function Base.:(:)(::StaticInt{F}, ::StaticInt{S}, ::StaticInt{L}) where {F, S, L} + OptionallyStaticStepRange(StaticInt(F), StaticInt(S), StaticInt(L)) +end +function Base.:(:)(start::Integer, ::StaticInt{S}, ::StaticInt{L}) where {S, L} + OptionallyStaticStepRange(start, StaticInt(S), StaticInt(L)) +end +function Base.:(:)(::StaticInt{F}, ::StaticInt{S}, stop::Integer) where {F, S} + OptionallyStaticStepRange(StaticInt(F), StaticInt(S), stop) +end +function Base.:(:)(::StaticInt{F}, step::Integer, ::StaticInt{L}) where {F, L} + OptionallyStaticStepRange(StaticInt(F), step, StaticInt(L)) +end +function Base.:(:)(start::Integer, step::Integer, ::StaticInt{L}) where {L} + OptionallyStaticStepRange(start, step, StaticInt(L)) +end +function Base.:(:)(start::Integer, ::StaticInt{S}, stop::Integer) where {S} + OptionallyStaticStepRange(start, StaticInt(S), stop) +end +function Base.:(:)(::StaticInt{F}, step::Integer, stop::Integer) where {F} + OptionallyStaticStepRange(StaticInt(F), step, stop) +end +Base.:(:)(start::StaticInt{F}, ::StaticInt{1}, stop::StaticInt{L}) where {F, L} = start:stop +Base.:(:)(start::Integer, ::StaticInt{1}, stop::StaticInt{L}) where {L} = start:stop +Base.:(:)(start::StaticInt{F}, ::StaticInt{1}, stop::Integer) where {F} = start:stop +function Base.:(:)(start::Integer, ::StaticInt{1}, stop::Integer) + OptionallyStaticUnitRange(start, stop) +end + +Base.isempty(r::OptionallyStaticUnitRange) = first(r) > last(r) +@inline function Base.isempty(x::OptionallyStaticStepRange) + start = first(x) + stop = last(x) + if start === stop + return false + else + s = step(x) + s > 0 ? start > stop : start < stop + end +end + +function Base.checkindex(::Type{Bool}, + ::SUnitRange{F1, L1}, + ::SUnitRange{F2, L2}) where {F1, L1, F2, L2} + (F1::Int <= F2::Int) && (L1::Int >= L2::Int) +end + +function Base.getindex(r::OptionallyStaticUnitRange, + s::AbstractUnitRange{<:Integer}) + @boundscheck checkbounds(r, s) + f = static_first(r) + fnew = f - one(f) + return (fnew + static_first(s)):(fnew + static_last(s)) +end + +function Base.getindex(x::OptionallyStaticUnitRange{StaticInt{1}}, i::Int) + @boundscheck checkbounds(x, i) + i +end +function Base.getindex(x::OptionallyStaticUnitRange, i::Int) + val = first(x) + (i - 1) + @boundscheck ((i < 1) || val > last(x)) && throw(BoundsError(x, i)) + val::Int +end + +## length +@inline function Base.length(x::OptionallyStaticUnitRange) + start = first(x) + stop = last(x) + start > stop ? 0 : stop - start + 1 +end +Base.length(r::OptionallyStaticStepRange) = _range_length(first(r), step(r), last(r)) +@inline function _range_length(start::Int, s::Int, stop::Int) + if s > 0 + stop < start ? 0 : div(stop - start, s) + 1 + else + stop > start ? 0 : div(start - stop, -s) + 1 + end +end + +Base.AbstractUnitRange{Int}(r::OptionallyStaticUnitRange) = r +function Base.AbstractUnitRange{T}(r::OptionallyStaticUnitRange) where {T} + start = static_first(r) + if isa(start, StaticInt{1}) && T <: Integer + return Base.OneTo{T}(T(static_last(r))) + else + return UnitRange{T}(T(static_first(r)), T(static_last(r))) + end +end + +Base.isdone(x::OptionallyStaticRange, state::Int) = state === last(x) +function _next(x::OptionallyStaticRange) + new_state = first(x) + (new_state, new_state) +end +@inline function _next(@nospecialize(x::OptionallyStaticUnitRange), state::Int) + new_state = state + 1 + (new_state, new_state) +end +@inline function _next(x::OptionallyStaticStepRange, state::Int) + new_state = state + step(x) + (new_state, new_state) +end +@inline Base.iterate(x::OptionallyStaticRange) = isempty(x) ? nothing : _next(x) +@inline function Base.iterate(x::OptionallyStaticRange, s::Int) + Base.isdone(x, s) ? nothing : _next(x, s) +end + +Base.to_shape(x::OptionallyStaticRange) = length(x) +Base.to_shape(x::Base.Slice{T}) where {T <: OptionallyStaticRange} = length(x) +Base.axes(S::Base.Slice{<:OptionallyStaticUnitRange{StaticInt{1}}}) = (S.indices,) +Base.axes(S::Base.Slice{<:OptionallyStaticRange}) = (Base.IdentityUnitRange(S.indices),) + +Base.axes(x::OptionallyStaticRange) = (Base.axes1(x),) +function Base.axes1(x::OptionallyStaticUnitRange) + OptionallyStaticUnitRange(StaticInt(1), length(x)) +end +Base.axes1(x::OptionallyStaticUnitRange{StaticInt{1}}) = x +function Base.axes1(x::OptionallyStaticUnitRange{StaticInt{F}, StaticInt{L}}) where {F, L} + OptionallyStaticUnitRange(StaticInt(1), StaticInt(L - F + 1)) +end +function Base.axes1(x::OptionallyStaticStepRange) + OptionallyStaticUnitRange(StaticInt(1), length(x)) +end +function Base.axes1(x::OptionallyStaticStepRange{StaticInt{F}, StaticInt{S}, StaticInt{L}}) where { + F, + S, + L + } + OptionallyStaticUnitRange(StaticInt(1), StaticInt(_range_length(F, S, L))) +end +Base.axes1(x::Base.Slice{<:OptionallyStaticUnitRange{One}}) = x.indices +Base.axes1(x::Base.Slice{<:OptionallyStaticRange}) = Base.IdentityUnitRange(x.indices) + +Base.:(-)(r::OptionallyStaticRange) = (-static_first(r)):(-static_step(r)):(-static_last(r)) + +function Base.reverse(x::OptionallyStaticUnitRange) + _OptionallyStaticStepRange(getfield(x, :stop), StaticInt(-1), getfield(x, :start)) +end +function Base.reverse(x::OptionallyStaticStepRange) + _OptionallyStaticStepRange(getfield(x, :stop), -getfield(x, :step), getfield(x, :start)) +end + +Base.show(io::IO, @nospecialize(x::OptionallyStaticRange)) = show(io, MIME"text/plain"(), x) +function Base.show(io::IO, ::MIME"text/plain", @nospecialize(r::OptionallyStaticUnitRange)) + print(io, "$(getfield(r, :start)):$(getfield(r, :stop))") +end +function Base.show(io::IO, ::MIME"text/plain", @nospecialize(r::OptionallyStaticStepRange)) + print(io, "$(getfield(r, :start)):$(getfield(r, :step)):$(getfield(r, :stop))") +end + +# we overload properties because occasionally Base assumes that abstract range types have +# the same exact same set up as native types where `x.start === first(x)` +@inline function Base.getproperty(x::OptionallyStaticRange, s::Symbol) + if s === :start + return first(x) + elseif s === :step + return step(x) + elseif s === :stop + return last(x) + else + error("$x has no property $s") + end +end + +function Base.Broadcast.axistype(r::OptionallyStaticUnitRange{StaticInt{1}}, _) + Base.OneTo(last(r)) +end +function Base.Broadcast.axistype(_, r::OptionallyStaticUnitRange{StaticInt{1}}) + Base.OneTo(last(r)) +end +function Base.Broadcast.axistype(r::OptionallyStaticUnitRange{StaticInt{1}}, + ::OptionallyStaticUnitRange{StaticInt{1}}) + Base.OneTo(last(r)) +end +function Base.similar(::Type{<:Array{T}}, + axes::Tuple{OptionallyStaticUnitRange{StaticInt{1}}, + Vararg{ + Union{Base.OneTo, + OptionallyStaticUnitRange{StaticInt{1}}}}}) where { + T + } + Array{T}(undef, map(last, axes)) +end +function Base.similar(::Type{<:Array{T}}, + axes::Tuple{Base.OneTo, OptionallyStaticUnitRange{StaticInt{1}}, + Vararg{ + Union{Base.OneTo, + OptionallyStaticUnitRange{StaticInt{1}}}}}) where { + T + } + Array{T}(undef, map(last, axes)) +end + +function Base.first(x::OptionallyStaticUnitRange, n::IntType) + n < 0 && throw(ArgumentError("Number of elements must be nonnegative")) + start = static_first(x) + OptionallyStaticUnitRange(start, min(start - one(start) + n, static_last(x))) +end +function Base.first(x::OptionallyStaticStepRange, n::IntType) + n < 0 && throw(ArgumentError("Number of elements must be nonnegative")) + start = static_first(x) + s = static_step(x) + stop = min(((n - one(n)) * s) + static_first(x), static_last(x)) + OptionallyStaticStepRange(start, s, stop) +end +function Base.last(x::OptionallyStaticUnitRange, n::IntType) + n < 0 && throw(ArgumentError("Number of elements must be nonnegative")) + stop = static_last(x) + OptionallyStaticUnitRange(max(stop + one(stop) - n, static_first(x)), stop) +end +function Base.last(x::OptionallyStaticStepRange, n::IntType) + n < 0 && throw(ArgumentError("Number of elements must be nonnegative")) + start = static_first(x) + s = static_step(x) + stop = static_last(x) + OptionallyStaticStepRange(max(stop + one(stop) - (n * s), start), s, stop) +end diff --git a/test/ranges.jl b/test/ranges.jl new file mode 100644 index 0000000..e7e1e9d --- /dev/null +++ b/test/ranges.jl @@ -0,0 +1,159 @@ + +@testset "Range Constructors" begin + @test @inferred(static(1):static(10)) == 1:10 + @test @inferred(Static.SUnitRange{1, 10}()) == 1:10 + @test @inferred(static(1):static(2):static(10)) == 1:2:10 + @test @inferred(1:static(2):static(10)) == 1:2:10 + @test @inferred(static(1):static(2):10) == 1:2:10 + @test @inferred(static(1):2:static(10)) == 1:2:10 + @test @inferred(1:2:static(10)) == 1:2:10 + @test @inferred(1:static(2):10) == 1:2:10 + @test @inferred(static(1):2:10) == 1:2:10 + @test @inferred(static(1):UInt(10)) === static(1):10 + @test @inferred(UInt(1):static(1):static(10)) === 1:static(10) + @test Static.SUnitRange(1, 10) == 1:10 + @test @inferred(Static.OptionallyStaticUnitRange{Int, Int}(1:10)) == 1:10 + @test @inferred(Static.OptionallyStaticUnitRange(1:10)) == 1:10 == + @inferred(Static.OptionallyStaticUnitRange(Static.OptionallyStaticUnitRange(1:10))) + + sr = Static.OptionallyStaticStepRange(static(1), static(1), static(1)) + @test @inferred(Static.OptionallyStaticStepRange(sr)) == sr == 1:1:1 + @test @inferred(Static.OptionallyStaticStepRange(static(1), 1, UInt(10))) == + static(1):1:10 == Static.SOneTo(10) + @test @inferred(Static.OptionallyStaticStepRange(UInt(1), 1, static(10))) == + static(1):1:10 + @test @inferred(Static.OptionallyStaticStepRange(1:10)) == 1:1:10 + + @test_throws ArgumentError Static.OptionallyStaticUnitRange(1:2:10) + @test_throws ArgumentError Static.OptionallyStaticUnitRange{Int, Int}(1:2:10) + @test_throws ArgumentError Static.OptionallyStaticStepRange(1, 0, 10) + @test_throws ArgumentError Static.OptionallyStaticStepRange(1, StaticInt(0), 10) + + @test @inferred(static(1):static(1):static(10)) === + Static.OptionallyStaticUnitRange(static(1), static(10)) + @test @inferred(static(1):static(1):10) === + Static.OptionallyStaticUnitRange(static(1), 10) + @test @inferred(1:static(1):10) === Static.OptionallyStaticUnitRange(1, 10) + @test length(static(-1):static(-1):static(-10)) == 10 == + lastindex(static(-1):static(-1):static(-10)) + + @test UnitRange(Static.OptionallyStaticUnitRange(static(1), static(10))) === + UnitRange(1, 10) + @test UnitRange{Int}(Static.OptionallyStaticUnitRange(static(1), static(10))) === + UnitRange(1, 10) + + @test AbstractUnitRange{Int}(Static.OptionallyStaticUnitRange(static(1), static(10))) isa + Static.OptionallyStaticUnitRange + @test AbstractUnitRange{UInt}(Static.OptionallyStaticUnitRange(static(1), static(10))) isa + Base.OneTo + @test AbstractUnitRange{UInt}(Static.OptionallyStaticUnitRange(static(2), static(10))) isa + UnitRange + + @test @inferred((static(1):static(10))[static(2):static(3)]) === static(2):static(3) + @test @inferred((static(1):static(10))[static(2):3]) === static(2):3 + @test @inferred((static(1):static(10))[2:3]) === 2:3 + @test @inferred((1:static(10))[static(2):static(3)]) === 2:3 + + @test Base.checkindex(Bool, static(1):static(10), static(1):static(5)) + @test -(static(1):static(10)) === static(-1):static(-1):static(-10) + + @test reverse(static(1):static(10)) === static(10):static(-1):static(1) + @test reverse(static(1):static(2):static(9)) === static(9):static(-2):static(1) +end + +@testset "range properties" begin + x = static(1):static(2):static(9) + @test getproperty(x, :start) === first(x) + @test getproperty(x, :step) === step(x) + @test getproperty(x, :stop) === last(x) + @test_throws ErrorException getproperty(x, :foo) +end + +@testset "iterate" begin + @test iterate(static(1):static(5)) === (1, 1) + @test iterate(static(1):static(5), 1) === (2, 2) + @test iterate(static(1):static(5), 5) === nothing + @test iterate(static(2):static(5), 5) === nothing + @test iterate(static(1):static(2):static(9), 1) === (3, 3) + @test iterate(static(1):static(2):static(9), 9) === nothing + # make sure single length ranges work correctly + @test iterate(static(2):static(3):static(2))[1] === 2 === + (static(2):static(3):static(2))[1] + @test iterate(static(2):static(3):static(2), 2) === nothing +end + +# CartesianIndices +CI = CartesianIndices((static(1):static(2), static(1):static(2))) + +@testset "length" begin + @test @inferred(length(Static.OptionallyStaticUnitRange(1, 0))) == 0 + @test @inferred(length(Static.OptionallyStaticUnitRange(1, 10))) == 10 + @test @inferred(length(Static.OptionallyStaticUnitRange(static(1), 10))) == 10 + @test @inferred(length(Static.OptionallyStaticUnitRange(static(0), 10))) == 11 + @test @inferred(length(Static.OptionallyStaticUnitRange(static(1), static(10)))) == 10 + @test @inferred(length(Static.OptionallyStaticUnitRange(static(0), static(10)))) == 11 + + @test @inferred(length(static(1):static(2):static(0))) == 0 + @test @inferred(length(static(0):static(-2):static(1))) == 0 + + @test @inferred(length(Static.OptionallyStaticStepRange(static(1), 2, 10))) == 5 + @test @inferred(length(Static.OptionallyStaticStepRange(static(1), static(1), + static(10)))) == 10 + @test @inferred(length(Static.OptionallyStaticStepRange(static(2), static(1), + static(10)))) == 9 + @test @inferred(length(Static.OptionallyStaticStepRange(static(2), static(2), + static(10)))) == 5 +end + +@test @inferred(getindex(static(1):10, Base.Slice(static(1):10))) === static(1):10 +@test @inferred(getindex(Static.OptionallyStaticUnitRange(static(1), 10), 1)) == 1 +@test @inferred(getindex(Static.OptionallyStaticUnitRange(static(0), 10), 1)) == 0 +@test_throws BoundsError getindex(Static.OptionallyStaticUnitRange(static(1), 10), 0) +@test_throws BoundsError getindex(Static.OptionallyStaticStepRange(static(1), 2, 10), 0) +@test_throws BoundsError getindex(Static.OptionallyStaticUnitRange(static(1), 10), 11) +@test_throws BoundsError getindex(Static.OptionallyStaticStepRange(static(1), 2, 10), 11) + +@test Static.static_first(Base.OneTo(one(UInt))) === static(1) +@test Static.static_step(Base.OneTo(one(UInt))) === static(1) + +@test @inferred(eachindex(static(-7):static(7))) === static(1):static(15) +@test @inferred((static(-7):static(7))[first(eachindex(static(-7):static(7)))]) == -7 + +@test @inferred(firstindex(128:static(-1):1)) == 1 + +@test identity.(static(1):5) isa Vector{Int} +@test (static(1):5) .+ (1:3)' isa Matrix{Int} +@test similar(Array{Int}, (static(1):(4),)) isa Vector{Int} +@test similar(Array{Int}, (static(1):(4), Base.OneTo(4))) isa Matrix{Int} +@test similar(Array{Int}, (Base.OneTo(4), static(1):(4))) isa Matrix{Int} + +@test Base.to_shape(static(1):10) == 10 +@test Base.to_shape(Base.Slice(static(1):10)) == 10 +@test Base.axes1(Base.Slice(static(1):10)) === static(1):10 +@test axes(Base.Slice(static(1):10)) === (static(1):10,) +@test isa(axes(Base.Slice(static(0):static(1):10))[1], Base.IdentityUnitRange) +@test isa(Base.axes1(Base.Slice(static(0):static(1):10)), Base.IdentityUnitRange) + +@test Base.Broadcast.axistype(static(1):10, static(1):10) === Base.OneTo(10) +@test Base.Broadcast.axistype(Base.OneTo(10), static(1):10) === Base.OneTo(10) + +@testset "static_promote(::AbstractRange, ::AbstractRange)" begin + ur1 = static(1):10 + ur2 = 1:static(10) + @test @inferred(static_promote(ur1, ur2)) === static(1):static(10) + @test static_promote(Base.Slice(ur1), Base.Slice(ur2)) === + Base.Slice(static(1):static(10)) + sr1 = static(1):2:10 + sr2 = static(1):static(2):static(10) + @test @inferred(static_promote(sr1, sr2)) === sr2 +end + +@testset "n-last/first" begin + ur = static(2):static(10) + sr = static(2):static(2):static(10) + n3 = static(3) + @test @inferred(first(ur, n3)) === static(2):static(4) + @test @inferred(last(ur, n3)) === static(8):static(10) + @test @inferred(first(sr, n3)) === static(2):static(2):static(6) + @test @inferred(last(sr, n3)) === static(5):static(2):static(9) +end diff --git a/test/runtests.jl b/test/runtests.jl index cf9524d..bc9ed39 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -525,3 +525,5 @@ end @test repr(static(1):static(10)) == "static(1):static(10)" @test repr(static(1):static(2):static(9)) == "static(1):static(2):static(9)" end + +include("ranges.jl") From c3b060e2ded4dcd4ad113af1f0913a4c6473ee9a Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 15:53:24 +0100 Subject: [PATCH 19/20] Revert "Remove IntType typedef" This reverts commit db0edd52881a1025fce83e9e6ccc489958609384. --- src/Static.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Static.jl b/src/Static.jl index eeb704a..eb253a7 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -65,6 +65,15 @@ struct StaticInt{N} <: StaticInteger{N} #!!!StaticInt(x::Real) = StaticInt(convert(Int, x)) end +""" + IntType(x::Integer) -> Union{Int,StaticInt} + +`IntType` is a union of `Int` and `StaticInt`. As a function, it ensures that `x` one of the +two. +""" +const IntType = Union{StaticInt, Int} +IntType(x::Integer) = Int(x) +IntType(@nospecialize x::Union{Int, StaticInt}) = x include("float.jl") From 310ed3cf5912db3b83f2bbfffd8e148a450e0b83 Mon Sep 17 00:00:00 2001 From: Oliver Schulz Date: Thu, 1 Dec 2022 18:41:25 +0100 Subject: [PATCH 20/20] STASH ranges, passes tests locally --- .vscode/settings.json | 3 +++ src/Static.jl | 3 --- src/ranges.jl | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..58e6b99 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "julia.environmentPath": "/user/.julia/environments/static-dev" +} \ No newline at end of file diff --git a/src/Static.jl b/src/Static.jl index eb253a7..b319d23 100644 --- a/src/Static.jl +++ b/src/Static.jl @@ -116,9 +116,6 @@ end (::Type{T})(@nospecialize x::StaticNumber) where {T <: Union{Base.BitInteger,Float32,Float64}} = T(known(x)) -Base.:(:)(a::StaticNumber, b::StaticNumber) = (:)(known(a), known(b)) - - Base.getindex(x::Tuple, ::StaticInt{N}) where {N} = getfield(x, N) Base.zero(@nospecialize(::StaticInt)) = StaticInt{0}() diff --git a/src/ranges.jl b/src/ranges.jl index 6a15be8..ccd65e8 100644 --- a/src/ranges.jl +++ b/src/ranges.jl @@ -203,6 +203,9 @@ function Base.:(:)(start::Integer, ::StaticInt{1}, stop::Integer) OptionallyStaticUnitRange(start, stop) end +Base.:(:)(a::StaticFloat64, b::StaticFloat64) = (:)(known(a), known(b)) + + Base.isempty(r::OptionallyStaticUnitRange) = first(r) > last(r) @inline function Base.isempty(x::OptionallyStaticStepRange) start = first(x)