I’m not sure I properly understand what you want - if you just have struct Node{T}
and some functions f1(::Node{Int})
, f2(::Node{Float64})
, etc… then the compiler will specialize f1
and f2
and you see no run-time cost. This should almost always be what you want.
However, I did make a compile-time dictionary a couple of years back, I don’t remember for what purpose. Posting code inline below. You can use it like:
julia> using Base: setindex
julia> f1(x) = x * 2
f1 (generic function with 1 method)
julia> f2(x) = x + 2
f2 (generic function with 1 method)
julia> const lookup = let d = StaticDict()
d = setindex(d, f1, Int)
d = setindex(d, f2, Float64)
end
StaticDict{Int64, f1, StaticDict{Float64, f2, StaticDict{StaticDictionary.NullTag, StaticDictionary.NullTag, StaticDictionary.NullTag}}}()
julia> function using_lookup(x::T) where T
lookup[T](x)
end
using_lookup (generic function with 1 method)
julia> using_lookup(3)
6
julia> using_lookup(3.0)
5.0
julia> @code_warntype using_lookup(3.0)
MethodInstance for using_lookup(::Float64)
from using_lookup(x::T) where T in Main at REPL[8]:1
Static Parameters
T = Float64
Arguments
#self#::Core.Const(using_lookup)
x::Float64
Body::Float64
1 ─ %1 = Base.getindex(Main.lookup, $(Expr(:static_parameter, 1)))::Core.Const(f2)
│ %2 = (%1)(x)::Float64
└── return %2
Probably missing some methods that it should have.
module StaticDictionary
export StaticDict
import Base: keys, values, getindex, haskey, setindex
struct NullTag end
struct StaticDict{K, V, D}
StaticDict{K, V}() where {K, V} = new{K, V, StaticDict{NullTag, NullTag, NullTag}}()
StaticDict() = new{NullTag, NullTag, NullTag}()
function StaticDict{K, V}(::Type{C}) where {K, V} where C <: StaticDict
if haskey(C, Val(K))
KeyError("Will not implicity merge StaticDicts with " *
"duplicate keys (duplicated key: $K") |> throw
else
new{K, V, C}()
end
end
end
const NullDictionaryType = StaticDict{NullTag, NullTag, D} where D
StaticDict{K, V}(::C) where {K, V} where C <: StaticDict = StaticDict{K, V}(C)
StaticDict(::Val{K}, ::Val{V}) where {K, V} = StaticDict{K, V}()
StaticDict(::Val{K}, ::Val{V}, ::C) where {K, V} where C <: StaticDict = StaticDict{K, V}(C)
keys(::D) where D <: StaticDict = keys(D)
keys(::NullDictionaryType) = ()
keys(::Type{StaticDict{K, V, NullTag}}) where {K, V} = (K,)
keys(::Type{StaticDict{K, V, D}}) where {K, V} where D <: StaticDict = (K, keys(D)...)
values(::D) where D <: StaticDict = values(D)
values(::Type{StaticDict{NullDictionaryType}}) = ()
values(::Type{StaticDict{K, V, NullTag}}) where {K, V} = (V,)
values(::Type{StaticDict{K, V, D}}) where {K, V} where D <: StaticDict = (V, values(D)...)
getindex(::D, ::Val{K}) where D <: StaticDict where K = getindex(D, Val(K))
getindex(::D, k) where D <: StaticDict = getindex(D, Val(k))
function getindex(::Type{D}, ::Val{K}) where D <: NullDictionaryType where K
KeyError("Did not find key $K in StaticDict") |> throw
end
function getindex(::Type{StaticDict{K, V, D}}, ::Val{K2}) where {K, V, K2} where D <: StaticDict
K === K2 ? V : getindex(D, Val(K2))
end
haskey(::D, ::Val{K}) where D <: StaticDict where K = haskey(D, Val(K))
haskey(::D, k) where D <: StaticDict = haskey(D, Val(k))
Base.@pure haskey(::Type{D}, ::Val{K}) where D <: NullDictionaryType where K = false
function haskey(::Type{StaticDict{K, V, D}}, ::Val{K2}) where {K, V, K2} where D <: StaticDict
K === K2 || haskey(D, Val(K2))
end
setindex(::D, ::Val{V}, ::Val{K}) where D <: StaticDict where {K, V} = setindex(D, Val(V), Val(K))
setindex(::D, v, k) where D <: StaticDict = setindex(D, Val(v), Val(k))
setindex(::Type{D}, ::Val{V}, ::Val{K}) where D <: NullDictionaryType where {K, V} = StaticDict{K, V}()
function setindex(::Type{StaticDict{K}}, _, ::Val{K}) where K
KeyError("Refusing to set different mapping for key $K in StaticDict") |> throw
end
function setindex(::Type{StaticDict{K, V, D}}, ::Val{V2}, ::Val{K2}) where {K, V, K2, V2} where D <: StaticDict
StaticDict{K, V}(setindex(D, Val(V2), Val(K2)))
end
end # module