haven/nexgb/xgbgen/aligngap.go

121 lines
2.3 KiB
Go

package main
import (
"fmt"
"os"
)
func (p *Protocol) AddAlignGaps() {
for i := range p.Imports {
p.Imports[i].AddAlignGaps()
}
for i := range p.Types {
switch t := p.Types[i].(type) {
case *Struct:
t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
case *Event:
t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
case *Error:
t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
}
}
for i := range p.Requests {
p.Requests[i].Fields = addAlignGapsToFields(
p.Requests[i].xmlName, p.Requests[i].Fields)
if p.Requests[i].Reply != nil {
p.Requests[i].Reply.Fields = addAlignGapsToFields(
p.Requests[i].xmlName, p.Requests[i].Reply.Fields)
}
}
}
func addAlignGapsToFields(name string, fields []Field) []Field {
var i int
for i = 0; i < len(fields); i++ {
if _, ok := fields[i].(*ListField); ok {
break
}
}
if i >= len(fields) {
return fields
}
r := make([]Field, 0, len(fields)+2)
r = append(r, fields[:i]...)
r = append(r, fields[i])
for i = i + 1; i < len(fields); i++ {
switch f := fields[i].(type) {
case *ListField:
// ok, add padding
sz := xcbSizeOfType(f.Type)
switch {
case sz == 1:
// nothing
case sz == 2:
r = append(r, &PadField{0, 2})
case sz == 3:
panic(fmt.Errorf("Alignment is not a power of 2"))
case sz >= 4:
r = append(r, &PadField{0, 4})
}
case *LocalField:
// nothing
default:
fmt.Fprintf(os.Stderr,
"Can't add alignment gaps, mix of list and non-list "+
"fields: %s\n", name)
return fields
}
r = append(r, fields[i])
}
return r
}
func xcbSizeOfField(fld Field) int {
switch f := fld.(type) {
case *PadField:
return int(f.Bytes)
case *SingleField:
return xcbSizeOfType(f.Type)
case *ListField:
return 0
case *ExprField:
return xcbSizeOfType(f.Type)
case *ValueField:
return xcbSizeOfType(f.MaskType)
case *SwitchField:
return 0
default:
return 0
}
}
func xcbSizeOfType(typ Type) int {
switch t := typ.(type) {
case *Resource:
return 4
case *TypeDef:
return t.Size().Eval()
case *Base:
return t.Size().Eval()
case *Struct:
sz := 0
for i := range t.Fields {
sz += xcbSizeOfField(t.Fields[i])
}
return sz
case *Union:
sz := 0
for i := range t.Fields {
csz := xcbSizeOfField(t.Fields[i])
if csz > sz {
sz = csz
}
}
return sz
default:
return 0
}
}