From a548d9d0f7b889627c43b18811357fad88760b2d Mon Sep 17 00:00:00 2001 From: aarzilli Date: Fri, 2 May 2014 15:09:23 +0200 Subject: Fix Issue #21: automatic calculation of alignment padding after lists --- nexgb/xgbgen/aligngap.go | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 nexgb/xgbgen/aligngap.go (limited to 'nexgb/xgbgen/aligngap.go') diff --git a/nexgb/xgbgen/aligngap.go b/nexgb/xgbgen/aligngap.go new file mode 100644 index 0000000..1e07e18 --- /dev/null +++ b/nexgb/xgbgen/aligngap.go @@ -0,0 +1,130 @@ +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 + } +} -- cgit v1.2.3-70-g09d2