Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proper layout for unions #7

Open
dennwc opened this issue Jan 10, 2021 · 2 comments
Open

Proper layout for unions #7

dennwc opened this issue Jan 10, 2021 · 2 comments
Labels
enhancement New feature or request

Comments

@dennwc
Copy link
Contributor

dennwc commented Jan 10, 2021

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 dennwc added the enhancement New feature or request label Jan 10, 2021
@TotallyGamerJet
Copy link
Contributor

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

@dennwc
Copy link
Contributor Author

dennwc commented Nov 14, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants