Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
name = "Static"
uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
authors = ["chriselrod", "ChrisRackauckas", "Tokazama"]
version = "1.2.0"
version = "1.3.0"

[deps]
CommonWorldInvalidations = "f70d9fcc-98c5-4d4a-abd7-e4cdeebd8ca8"
IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
SciMLPublic = "431bcebd-1456-4ced-9d72-93c2757fff0b"

[compat]
Aqua = "0.8.4"
CommonWorldInvalidations = "1"
IfElse = "0.1"
PrecompileTools = "1.1"
SciMLPublic = "1.0.0"
Test = "1"
julia = "1.10"

Expand Down
114 changes: 83 additions & 31 deletions src/Static.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
module Static

import IfElse: ifelse
using SciMLPublic: @public

export StaticInt, StaticFloat64, StaticSymbol, True, False, StaticBool, NDIndex
export dynamic, is_static, known, static, static_promote
export dynamic, is_static, known, static, static_promote, static_first, static_step,
static_last

@public OptionallyStaticRange,
OptionallyStaticUnitRange, OptionallyStaticStepRange, SUnitRange, SOneTo
@public eachop, eachop_tuple, reduce_tup, eq, ne, gt, ge, le, lt, mul, add

import PrecompileTools: @recompile_invalidations

Expand All @@ -12,7 +18,7 @@ import PrecompileTools: @recompile_invalidations
end

"""
StaticSymbol
StaticSymbol(S::Symbol)::StaticSymbol{S}

A statically typed `Symbol`.
"""
Expand All @@ -33,7 +39,7 @@ Base.Symbol(@nospecialize(s::StaticSymbol)) = known(s)
abstract type StaticInteger{N} <: Number end

"""
StaticBool(x::Bool) -> True/False
StaticBool(x::Bool)::Union{True, False}

A statically typed `Bool`.
"""
Expand All @@ -55,7 +61,7 @@ function StaticBool(x::Bool)
end

"""
StaticInt(N::Int) -> StaticInt{N}()
StaticInt(N::Int)::StaticInt{N}

A statically sized `Int`.
Use `StaticInt(N)` instead of `Val(N)` when you want it to behave like a number.
Expand All @@ -68,7 +74,7 @@ struct StaticInt{N} <: StaticInteger{N}
end

"""
IntType(x::Integer) -> Union{Int,StaticInt}
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.
Expand Down Expand Up @@ -256,9 +262,10 @@ function static(x::X) where {X}
end

"""
is_static(::Type{T}) -> StaticBool
is_static(::Type{T})::Union{True, False}

Returns `True` if `T` is a static type.
If `T` is a static type return `static(true)::True` and otherwise returns
`static(false)::False`

See also: [`static`](@ref), [`known`](@ref)
"""
Expand Down Expand Up @@ -582,7 +589,7 @@ permute(@nospecialize(x::Tuple), @nospecialize(perm::Val)) = permute(x, static(p
end

"""
eachop(op, args...; iterator::Tuple{Vararg{StaticInt}}) -> Tuple
Static.eachop(op, args...; iterator::Tuple{Vararg{StaticInt}})::Tuple

Produces a tuple of `(op(args..., iterator[1]), op(args..., iterator[2]),...)`.
"""
Expand All @@ -592,7 +599,7 @@ end
eachop(::F, ::Tuple{}, args::Vararg{Any}) where {F} = ()

"""
eachop_tuple(op, arg, args...; iterator::Tuple{Vararg{StaticInt}}) -> Type{Tuple}
Static.eachop_tuple(op, arg, args...; iterator::Tuple{Vararg{StaticInt}})::Type{Tuple}

Produces a tuple type of `Tuple{op(arg, args..., iterator[1]), op(arg, args..., iterator[2]),...}`.
Note that if one of the arguments passed to `op` is a `Tuple` type then it should be the first argument
Expand Down Expand Up @@ -781,66 +788,109 @@ end
end

"""
eq(x, y)
Static.eq(x, y)::Union{Bool, True, False}

Equivalent to `!=` but if `x` and `y` are both static returns a `StaticBool.
Equivalent to `==` but if `x` and `y` are static the return value is a `StaticBool.
"""
eq(x::X, y::Y) where {X, Y} = ifelse(is_static(X) & is_static(Y), static, identity)(x == y)

"""
Static.eq(x)::Base.Fix2{typeof(Static.eq}}

Create a function that compares `x` to other values using `Static.eq` (i.e. a
function equivalent to `y -> Static.eq(y, x)`).
"""
eq(x) = Base.Fix2(eq, x)

"""
ne(x, y)
Static.ne(x, y)::Union{Bool, True, False}

Equivalent to `!=` but if `x` and `y` are both static returns a `StaticBool.
Equivalent to `!=` but if `x` and `y` are static the return value is a `StaticBool.
"""
ne(x::X, y::Y) where {X, Y} = !eq(x, y)

"""
Static.ne(x)::Base.Fix2{typeof(Static.ne}}

Create a function that compares `x` to other values using `Static.ne` (i.e. a
function equivalent to `y -> Static.ne(y, x))`.
"""
ne(x) = Base.Fix2(ne, x)

"""
gt(x, y)
Static.ne(x, y)::Union{Bool, True, False}

Equivalent to `>` but if `x` and `y` are both static returns a `StaticBool.
Equivalent to `>` but if `x` and `y` are static the return value is a `StaticBool.
"""
gt(x::X, y::Y) where {X, Y} = ifelse(is_static(X) & is_static(Y), static, identity)(x > y)

"""
Static.gt(x)::Base.Fix2{typeof(Static.gt}}

Create a function that compares `x` to other values using `Static.gt` (i.e. a
function equivalent to `y -> Static.gt(y, x))`.
"""
gt(x) = Base.Fix2(gt, x)

"""
ge(x, y)
Static.ge(x, y)::Union{Bool, True, False}

Equivalent to `>=` but if `x` and `y` are both static returns a `StaticBool.
Equivalent to `>=` but if `x` and `y` are static the return value is a `StaticBool.
"""
ge(x::X, y::Y) where {X, Y} = ifelse(is_static(X) & is_static(Y), static, identity)(x >= y)

"""
Static.ge(x)::Base.Fix2{typeof(Static.ge}}

Create a function that compares `x` to other values using `Static.ge` (i.e. a
function equivalent to `y -> Static.ge(y, x)`).
"""
ge(x) = Base.Fix2(ge, x)

"""
le(x, y)
Static.le(x, y)::Union{Bool, True, False}

Equivalent to `<=` but if `x` and `y` are both static returns a `StaticBool.
Equivalent to `<=` but if `x` and `y` are static the return value is a `StaticBool.
"""
le(x::X, y::Y) where {X, Y} = ifelse(is_static(X) & is_static(Y), static, identity)(x <= y)

"""
Static.le(x)::Base.Fix2{typeof(Static.le}}

Create a function that compares `x` to other values using `Static.le` (i.e. a
function equivalent to `y -> Static.le(y, x)`).
"""
le(x) = Base.Fix2(le, x)

"""
lt(x, y)
Static.lt(x, y)::Union{Bool, True, False}

Equivalent to `<` but if `x` and `y` are both static returns a `StaticBool.
Equivalent to `<` but if `x` and `y` are static the return value is a `StaticBool.`
"""
lt(x::X, y::Y) where {X, Y} = ifelse(is_static(X) & is_static(Y), static, identity)(x < y)

"""
Static.lt(x)::Base.Fix2{typeof(Static.lt}}

Create a function that compares `x` to other values using `Static.lt` (i.e. a
function equivalent to y -> Static.lt(y, x)).
"""
lt(x) = Base.Fix2(lt, x)

"""
mul(x) -> Base.Fix2(*, x)
mul(x, y) ->
Static.mul(x)::Base.Fix2{typeof(*)}

Equivalent to `*` but allows for lazy multiplication when passing functions.
Create a function that multiplies `x` with other values (i.e. a function
equivalent to `y -> y * x`).
"""
mul(x) = Base.Fix2(*, x)

"""
add(x) -> Base.Fix2(+, x)
add(x, y) ->
Static.add(x) -> Base.Fix2(+, x)
Static.add(x, y)

Equivalent to `+` but allows for lazy addition when passing functions.
Create a function that adds `x` to other values (i.e. a function equivalent to
`y -> y + x`).
"""
add(x) = Base.Fix2(+, x)

Expand Down Expand Up @@ -966,15 +1016,17 @@ end
return (Base.to_index(A, I[1]), to_indices(A, indstail, Base.tail(I))...)
end

function Base.show(io::IO, @nospecialize(x::Union{StaticNumber, StaticSymbol, NDIndex}))
function Base.show(@nospecialize(io::IO), @nospecialize(x::Union{
StaticNumber, StaticSymbol, NDIndex}))
show(io, MIME"text/plain"(), x)
end
function Base.show(io::IO, ::MIME"text/plain",
@nospecialize(x::Union{StaticNumber, StaticSymbol}))
function Base.show(
@nospecialize(io::IO), ::MIME"text/plain", @nospecialize(x::Union{
StaticNumber, StaticSymbol}))
print(io, "static(" * repr(known(typeof(x))) * ")")
nothing
end
function Base.show(io::IO, m::MIME"text/plain", @nospecialize(x::NDIndex))
function Base.show(@nospecialize(io::IO), m::MIME"text/plain", @nospecialize(x::NDIndex))
print(io, "NDIndex")
show(io, m, Tuple(x))
nothing
Expand Down
2 changes: 1 addition & 1 deletion src/float.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

"""
StaticFloat64{N}
StaticFloat64(F::Float64)::StaticFloat64{F}

A statically sized `Float64`.
Use `StaticFloat64(N)` instead of `Val(N)` when you want it to behave like a number.
Expand Down
64 changes: 63 additions & 1 deletion src/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -150,16 +150,78 @@ 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::AbstractRange)

Attempt to return `static(first(x))`, if known at compile time. Otherwise, return
`first(x)`.

See also: [`static_step`](@ref), [`static_last`](@ref)

# Examples

```julia
julia> static_first(static(2):10)
static(2)

julia> static_first(1:10)
1

julia> static_first(Base.OneTo(10))
static(1)

```
"""
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(x::AbstractRange)

Attempt to return `static(step(x))`, if known at compile time. Otherwise, return
`step(x)`.

See also: [`static_first`](@ref), [`static_last`](@ref)

# Examples

```julia
julia> static_step(static(1):static(3):9)
static(3)

julia> static_step(1:3:9)
3

julia> static_step(1:9)
static(1)

```
"""
static_step(@nospecialize x::AbstractUnitRange) = StaticInt(1)
static_step(x::OptionallyStaticStepRange) = getfield(x, :step)
static_step(x) = step(x)

"""
static_last(x::AbstractRange)

Attempt to return `static(last(x))`, if known at compile time. Otherwise, return
`last(x)`.

See also: [`static_first`](@ref), [`static_step`](@ref)

# Examples

```julia
julia> static_last(static(1):static(10))
static(10)

julia> static_last(static(1):10)
10

```
"""
static_last(x::OptionallyStaticRange) = getfield(x, :stop)
static_last(x) = last(x)
static_last(x::Union{Base.Slice, Base.IdentityUnitRange}) = static_last(x.indices)
Expand Down
Loading