Skip to content

Instantly share code, notes, and snippets.

@simonbyrne
Last active January 6, 2018 21:44
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simonbyrne/8194a2134f08d41af6c0ea2d65999c95 to your computer and use it in GitHub Desktop.
Save simonbyrne/8194a2134f08d41af6c0ea2d65999c95 to your computer and use it in GitHub Desktop.
# To ensure correct alignment (e.g. for an 80-bit type)
struct StrWrap{T}
value::T
end
function unsafe_reinterpret(T, a::A) where {A}
if sizeof(T) <= sizeof(A)
r = Ref(a)
Base.@gc_preserve r begin
u = convert(Ptr{T}, Base.unsafe_convert(Ptr{A}, r))
unsafe_load(u)
end
else
s = Ref{T}()
Base.@gc_preserve s begin
v = convert(Ptr{A}, Base.unsafe_convert(Ptr{T}, s))
unsafe_store!(v, a)
end
s[]
end
end
decl!(dict, expr::LineNumberNode) = nothing
function decl!(dict, expr::Expr)
if expr.head == :block
for a in expr.args
decl!(dict, a)
end
elseif expr.head == :(::)
dict[expr.args[1]] = expr.args[2]
else
error("Invalid expression")
end
end
macro Cunion(name, expr)
d = Dict{Symbol, Any}()
decl!(d, expr)
maxsize = maximum(T -> eval(__module__, :(sizeof(StrWrap{$T})*8)), values(d))
defs = quote end
lookup = :(getfield(obj, field))
for (k,T) in d
lookup = :(field == $(QuoteNode(k)) ? unsafe_reinterpret($(esc(T)), obj) : $lookup)
push!(defs.args, :($(esc(name))(x::NamedTuple{($(QuoteNode(k)),),Tuple{$(esc(T))}}) = unsafe_reinterpret($(esc(name)), x.$k) ))
end
quote
primitive type $(esc(name)) $maxsize
end
$(esc(name))(;kwargs...) = $(esc(name))(kwargs.data)
$defs
function Base.getproperty(obj::$(esc(name)), field::Symbol)
$lookup
end
end
end
@Cunion Foo begin
a::Int64
b::Float64
end
u = Foo(a=1)
u.b
@Cunion Bar begin
a::Int64
b::NTuple{10,UInt8}
end
v = Bar(a=1)
v.b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment