cxgo
cxgo copied to clipboard
Proper layout for unions
Currently union
layout is ignored. Instead fields are flattened into the parent structure.
Proper layout should be implemented at some point if we want to transpile ~anything that touches the disk/network.
Would this be a good way of representing it? Given this C code:
union Data {
int i;
float f;
char str[20];
};
Generate this Go code:
type Data [20]byte // enough bytes for the largest field
func (d Data) I() int32 {
return *(*int32)(unsafe.Pointer(&d[0]))
}
func (d *Data) SetI(i int32) {
*(*int32)(unsafe.Pointer(&d[0])) = i
}
func (d Data) F() float32 {
return *(*float32)(unsafe.Pointer(&d[0]))
}
func (d *Data) SetF(f float32) {
*(*float32)(unsafe.Pointer(&d[0])) = f
}
func (d Data) Str() [20]byte {
return *(*[20]byte)(unsafe.Pointer(&d[0]))
}
func (d *Data) SetStr(str [20]byte) {
*(*[20]byte)(unsafe.Pointer(&d[0])) = str
}
It is a lot of boilerplate but it accurately represents the memory footprint of unions in c
Sorry, missed the notification somehow.
Yes, that's a good option. The only downside is that it breaks Go pointers, so GC can miss them.
Because of this we might want to make it optional or use some other approach, for example:
type Data interface{
isDataUnion()
}
type DataI int32
func (*DataI) isDataUnion() {}
type DataF float32
func (*DataF) isDataUnion() {}
type DataStr [20]byte
func (*DataStr) isDataUnion() {}
Setters and getters will get weird, but they will at least preserve pointers and will verify that the access is using the correct part of the union:
var d Data
// ...
*d.(*DataF) = DataF(v)
I know that there are cases when unions are intentionally used to read the same data via two or more different representations, so we might need both modes.