cxgo icon indicating copy to clipboard operation
cxgo copied to clipboard

Proper layout for unions

Open dennwc opened this issue 4 years ago • 2 comments

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.

dennwc avatar Jan 10 '21 19:01 dennwc

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

TotallyGamerJet avatar Oct 25 '21 02:10 TotallyGamerJet

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.

dennwc avatar Nov 14 '21 19:11 dennwc