aboutsummaryrefslogtreecommitdiff
path: root/nexgb/xgbgen/aligngap.go
diff options
context:
space:
mode:
authoraarzilli <alessandro.arzilli@gmail.com>2014-05-02 15:09:23 +0200
committerPřemysl Janouch <p@janouch.name>2018-09-08 16:49:22 +0200
commita548d9d0f7b889627c43b18811357fad88760b2d (patch)
tree0d4a0ad302d753638dfdb16159e03d1fb87b0872 /nexgb/xgbgen/aligngap.go
parent1f8bd79abee5d96a41a934d1eb8c74e90ccbcc8f (diff)
downloadhaven-a548d9d0f7b889627c43b18811357fad88760b2d.tar.gz
haven-a548d9d0f7b889627c43b18811357fad88760b2d.tar.xz
haven-a548d9d0f7b889627c43b18811357fad88760b2d.zip
Fix Issue #21: automatic calculation of alignment padding after lists
Diffstat (limited to 'nexgb/xgbgen/aligngap.go')
-rw-r--r--nexgb/xgbgen/aligngap.go130
1 files changed, 130 insertions, 0 deletions
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
+ }
+}