1 // structlayout-optimize reorders struct fields to minimize the amount
14 st "honnef.co/go/tools/structlayout"
15 "honnef.co/go/tools/version"
25 flag.BoolVar(&fJSON, "json", false, "Format data as JSON")
26 flag.BoolVar(&fRecurse, "r", false, "Break up structs and reorder their fields freely")
27 flag.BoolVar(&fVersion, "version", false, "Print version and exit")
40 if err := json.NewDecoder(os.Stdin).Decode(&in); err != nil {
50 for _, field := range in {
54 fields = append(fields, field)
60 json.NewEncoder(os.Stdout).Encode(fields)
62 for _, field := range fields {
68 func combine(fields []st.Field) []st.Field {
73 for _, field := range fields {
79 p := strings.Split(field.Name, ".")
80 prefix = strings.Join(p[:2], ".")
81 if field.Align > new.Align {
82 new.Align = field.Align
86 new.Size = new.End - new.Start
90 out = append(out, new)
100 new.Size = new.End - new.Start
101 out = append(out, new)
105 func optimize(fields []st.Field) {
106 sort.Sort(&byAlignAndSize{fields})
109 func pad(fields []st.Field) []st.Field {
110 if len(fields) == 0 {
115 offsets := offsetsof(fields)
116 alignment := int64(1)
117 for i, field := range fields {
118 if field.Align > alignment {
119 alignment = field.Align
121 if offsets[i] > pos {
122 padding := offsets[i] - pos
123 out = append(out, st.Field{
132 field.End = pos + field.Size
133 out = append(out, field)
137 pad := align(sz, alignment) - sz
139 field := out[len(out)-1]
140 out = append(out, st.Field{
143 End: field.End + pad,
150 func size(fields []st.Field) int64 {
152 for _, field := range fields {
158 type byAlignAndSize struct {
162 func (s *byAlignAndSize) Len() int { return len(s.fields) }
163 func (s *byAlignAndSize) Swap(i, j int) {
164 s.fields[i], s.fields[j] = s.fields[j], s.fields[i]
167 func (s *byAlignAndSize) Less(i, j int) bool {
168 // Place zero sized objects before non-zero sized objects.
169 if s.fields[i].Size == 0 && s.fields[j].Size != 0 {
172 if s.fields[j].Size == 0 && s.fields[i].Size != 0 {
176 // Next, place more tightly aligned objects before less tightly aligned objects.
177 if s.fields[i].Align != s.fields[j].Align {
178 return s.fields[i].Align > s.fields[j].Align
181 // Lastly, order by size.
182 if s.fields[i].Size != s.fields[j].Size {
183 return s.fields[i].Size > s.fields[j].Size
189 func offsetsof(fields []st.Field) []int64 {
190 offsets := make([]int64, len(fields))
192 for i, f := range fields {
201 // align returns the smallest y >= x such that y % a == 0.
202 func align(x, a int64) int64 {