I seemed to remember reading that a struct’s size is based on the largest field’s size and alignment, so running with that I did some stuff to print size and alignment in 3 different ways to show the numbers all add up.
The below prints the values for:
- Component(T) where T is [2]f32
** Then comp1 := Component([2]f32)
- Component(T) where T is [2]f64
** Then comp2 := Component([2]f64)
- total of types := [2]typeid{ [2]f64, [2]f32 }
It appears all you need for size of Component(T) to be the same as size of typeid is
type_info_of(t).size + type_info_of(t).align
Note the print_comp_size_by_types procedure for the ultimate proof. It adds the values together of the first 2 approaches by utilizing typeid array of both types. Hopefully this is easy to follow. I had to print everything in a formatted manner to be able to wrap my head around it.
Component_Header :: struct {
set: bool,
}
Component :: struct($T: typeid) {
header: Component_Header,
component: T,
}
print3columns :: proc(cols: [3]any) {
fmt.printfln("%-20v%6v%6v", fmt.tprint(cols[0]), fmt.tprint(cols[1]), fmt.tprint(cols[2]))
}
print_comp_size_by_T :: proc($T: typeid, expr := #caller_expression) {
p1, p2 := strings.index(expr, "("), strings.last_index(expr, ")")
size, align := size_of(T), align_of(T)
print3columns({expr[p1+1:p2], "Bytes", "Bits"})
print3columns({"size", size, 8*size})
print3columns({"align", align, 8*align})
}
print_comp_size_by_var :: proc(comp: $T, expr := #caller_expression) {
p1, p2 := strings.index(expr, "("), strings.last_index(expr, ")")
size, align := size_of(T), align_of(T)
print3columns({expr[p1+1:p2], "Bytes", "Bits"})
print3columns({"size", size, 8*size})
print3columns({"align", align, 8*align})
}
print_comp_size_by_types :: proc(types: []typeid, expr := #caller_expression) {
size, align: int
for t in types {
ti := type_info_of(t)
size += ti.size + ti.align
align += ti.align
}
print3columns({fmt.tprintf("typeid[%v]", len(types)), "Bytes", "Bits"})
print3columns({"size", size, 8*size})
print3columns({"align", align, 8*align})
}
main :: proc() {
// Component([2]f32) approach
print_comp_size_by_T(Component([2]f32))
fmt.println()
// comp1 := Component([2]f32) approach
comp1 := Component([2]f32) {Component_Header{true}, {42, 42}}
print_comp_size_by_var(comp1)
fmt.println()
// Component([2]f64) approach
print_comp_size_by_T(Component([2]f64))
fmt.println()
// comp2 := Component([2]f64) approach
comp2 := Component([2]f64) {Component_Header{true}, {42, 42}}
print_comp_size_by_var(comp2)
fmt.println()
// Ultimate goal: types := []typeid method
types := []typeid{[2]f32, [2]f64}
print_comp_size_by_types(types)
}
Output:
Component([2]f32) Bytes Bits
size 12 96
align 4 32
comp1 Bytes Bits
size 12 96
align 4 32
Component([2]f64) Bytes Bits
size 24 192
align 8 64
comp2 Bytes Bits
size 24 192
align 8 64
typeid[2] Bytes Bits
size 36 288
align 12 96