github.com/BurntSushi/xgb@v0.0.0-20210121224620-deaf085860bc/xgbgen/aligngap.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  )
     7  
     8  func (p *Protocol) AddAlignGaps() {
     9  	for i := range p.Imports {
    10  		p.Imports[i].AddAlignGaps()
    11  	}
    12  	for i := range p.Types {
    13  		switch t := p.Types[i].(type) {
    14  		case *Struct:
    15  			t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
    16  		case *Event:
    17  			t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
    18  		case *Error:
    19  			t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
    20  		}
    21  	}
    22  	for i := range p.Requests {
    23  		p.Requests[i].Fields = addAlignGapsToFields(
    24  			p.Requests[i].xmlName, p.Requests[i].Fields)
    25  		if p.Requests[i].Reply != nil {
    26  			p.Requests[i].Reply.Fields = addAlignGapsToFields(
    27  				p.Requests[i].xmlName, p.Requests[i].Reply.Fields)
    28  		}
    29  	}
    30  }
    31  
    32  func addAlignGapsToFields(name string, fields []Field) []Field {
    33  	var i int
    34  	for i = 0; i < len(fields); i++ {
    35  		if _, ok := fields[i].(*ListField); ok {
    36  			break
    37  		}
    38  	}
    39  	if i >= len(fields) {
    40  		return fields
    41  	}
    42  
    43  	r := make([]Field, 0, len(fields)+2)
    44  	r = append(r, fields[:i]...)
    45  
    46  	r = append(r, fields[i])
    47  	for i = i + 1; i < len(fields); i++ {
    48  		switch f := fields[i].(type) {
    49  		case *ListField:
    50  			// ok, add padding
    51  			sz := xcbSizeOfType(f.Type)
    52  			switch {
    53  			case sz == 1:
    54  				// nothing
    55  			case sz == 2:
    56  				r = append(r, &PadField{0, 2})
    57  			case sz == 3:
    58  				panic(fmt.Errorf("Alignment is not a power of 2"))
    59  			case sz >= 4:
    60  				r = append(r, &PadField{0, 4})
    61  			}
    62  		case *LocalField:
    63  			// nothing
    64  		default:
    65  			fmt.Fprintf(os.Stderr,
    66  				"Can't add alignment gaps, mix of list and non-list "+
    67  					"fields: %s\n", name)
    68  			return fields
    69  		}
    70  		r = append(r, fields[i])
    71  	}
    72  	return r
    73  }
    74  
    75  func xcbSizeOfField(fld Field) int {
    76  	switch f := fld.(type) {
    77  	case *PadField:
    78  		return int(f.Bytes)
    79  	case *SingleField:
    80  		return xcbSizeOfType(f.Type)
    81  	case *ListField:
    82  		return 0
    83  	case *ExprField:
    84  		return xcbSizeOfType(f.Type)
    85  	case *ValueField:
    86  		return xcbSizeOfType(f.MaskType)
    87  	case *SwitchField:
    88  		return 0
    89  	default:
    90  		return 0
    91  	}
    92  }
    93  
    94  func xcbSizeOfType(typ Type) int {
    95  	switch t := typ.(type) {
    96  	case *Resource:
    97  		return 4
    98  	case *TypeDef:
    99  		return t.Size().Eval()
   100  	case *Base:
   101  		return t.Size().Eval()
   102  	case *Struct:
   103  		sz := 0
   104  		for i := range t.Fields {
   105  			sz += xcbSizeOfField(t.Fields[i])
   106  		}
   107  		return sz
   108  	case *Union:
   109  		sz := 0
   110  		for i := range t.Fields {
   111  			csz := xcbSizeOfField(t.Fields[i])
   112  			if csz > sz {
   113  				sz = csz
   114  			}
   115  		}
   116  		return sz
   117  	default:
   118  		return 0
   119  	}
   120  }