132 lines
4.3 KiB
Julia
132 lines
4.3 KiB
Julia
struct FieldInfo
|
|
i::Int
|
|
face::Union{Symbol, Face}
|
|
offset::Int
|
|
size::Int
|
|
contentsize::Int
|
|
ispointer::Bool
|
|
name::Union{Symbol, Int}
|
|
type::Type
|
|
end
|
|
|
|
function structinfo(T::Type)
|
|
map(1:fieldcount(T)) do i
|
|
if hassizeof(T)
|
|
offset = fieldoffset(T, i) |> Int
|
|
size = Int(if i < fieldcount(T)
|
|
fieldoffset(T, i+1)
|
|
else
|
|
sizeof(T)
|
|
end - fieldoffset(T, i))
|
|
contentsize = if hassizeof(fieldtype(T, i))
|
|
sizeof(fieldtype(T, i))
|
|
else
|
|
0
|
|
end
|
|
if contentsize > size # Pointer?
|
|
contentsize = 0
|
|
end
|
|
else
|
|
offset = size = contentsize = -1 # Cannot deduce easily
|
|
end
|
|
FieldInfo(i, FACE_CYCLE[i % length(FACE_CYCLE) + 1],
|
|
offset,
|
|
size, contentsize,
|
|
contentsize == 0, # ispointer
|
|
fieldname(T, i), fieldtype(T, i))
|
|
end
|
|
end
|
|
|
|
function about(io::IO, type::Type)
|
|
if isprimitivetype(type)
|
|
print(io, "Primitive ")
|
|
elseif isconcretetype(type)
|
|
print(io, "Concrete ")
|
|
if Base.datatype_haspadding(type)
|
|
print(io, S"{shadow:(padded)} ")
|
|
end
|
|
elseif isabstracttype(type)
|
|
print(io, "Abstract ")
|
|
end
|
|
if Base.issingletontype(type)
|
|
print(io, "singleton ")
|
|
end
|
|
print(Base.summary(type))
|
|
print(io, S" defined in {about_module:$(parentmodule(type))}, ")
|
|
hassizeof(type) && print(io, "$(join(humansize(sizeof(type))))")
|
|
print(io, "\n ")
|
|
supertypeinfo(io, type)
|
|
(!isstructtype(type) || fieldcount(type) == 0) && return
|
|
println(io, S"\n\nStruct with {bold:$(fieldcount(type))} fields:")
|
|
fieldinfo = AnnotatedString[]
|
|
if type isa DataType
|
|
sinfo = structinfo(type)
|
|
namepad = maximum(fi -> textwidth(string(fi.name)), sinfo) + 1
|
|
for (; face, name, type, ispointer) in sinfo
|
|
push!(fieldinfo, rpad(S"{$face:$name}", namepad) * S"{about_pointer:$(ifelse(ispointer, \"*\", \" \"))}$type")
|
|
end
|
|
else
|
|
for (; name, type) in structinfo(type)
|
|
push!(fieldinfo, S"$name{shadow:::$type}")
|
|
end
|
|
end
|
|
if length(fieldinfo) < 32
|
|
columnlist(io, fieldinfo, maxcols=1)
|
|
else
|
|
columnlist(io, fieldinfo, spacing=3)
|
|
end
|
|
if type isa DataType
|
|
memorylayout(io, type)
|
|
end
|
|
end
|
|
|
|
function supertypeinfo(io::IO, type::Type)
|
|
typestr(t) = highlight(sprint(show, Base.unwrap_unionall(t)))
|
|
join(io, map(typestr, supertypes(type)),
|
|
S" {julia_comparator:<:} ")
|
|
end
|
|
|
|
function memorylayout(io::IO, type::DataType)
|
|
hassizeof(type) || return
|
|
si = structinfo(type)
|
|
!isempty(si) || return
|
|
memstep = memstep = gcd((getfield.(si, :size), getfield.(si, :contentsize)) |>
|
|
Iterators.flatten |> collect)
|
|
memscale = max(1, floor(Int, 70/(sizeof(type)/memstep)))
|
|
bars = AnnotatedString[]
|
|
descs = AnnotatedString[]
|
|
for (; i, size, contentsize, ispointer) in si
|
|
size <= 0 && continue
|
|
color = FACE_CYCLE[i % length(FACE_CYCLE) + 1]
|
|
width = max(2, memscale * size÷memstep)
|
|
fsize, funits = humansize(size)
|
|
desc = if ispointer
|
|
cpad(S" {$color,bold:*} ", width)
|
|
elseif contentsize < size
|
|
csize, cunits = humansize(contentsize)
|
|
psize, punits = humansize(size - contentsize)
|
|
cpad(S" {$color:$csize$cunits}{shadow:+$psize$punits} ", width, ' ', RoundUp)
|
|
else
|
|
cpad(S" {$color:$fsize$funits} ", width)
|
|
end
|
|
push!(descs, desc)
|
|
width = textwidth(desc)
|
|
contentwidth = round(Int, width * contentsize / size)
|
|
bar = S"{$color:$('■'^contentwidth)}"
|
|
if contentsize < size
|
|
paddwidth = width - contentwidth
|
|
if ispointer
|
|
bar *= S"{about_pointer,light:$('■'^paddwidth)}"
|
|
else
|
|
bar *= S"{shadow:$('■'^paddwidth)}"
|
|
end
|
|
end
|
|
push!(bars, bar)
|
|
end
|
|
println(io)
|
|
multirow_wrap(io, permutedims(hcat(bars, descs)))
|
|
if any(i -> i.ispointer, si)
|
|
println(io, S"\n {about_pointer,bold:*} = {about_pointer:Pointer} {light:(8B)}")
|
|
end
|
|
end
|