github.com/orijtech/structslop@v0.0.9-0.20230520012622-069644583b8b/sizes.go (about) 1 // Copyright 2020 Orijtech, Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package structslop 16 17 import ( 18 "go/types" 19 ) 20 21 type sizes struct { 22 stdSizes types.Sizes 23 maxAlign int64 24 } 25 26 func (s *sizes) Offsetsof(fields []*types.Var) []int64 { 27 offsets := make([]int64, len(fields)) 28 var o int64 29 for i, f := range fields { 30 a := s.Alignof(f.Type()) 31 o = align(o, a) 32 offsets[i] = o 33 o += s.Sizeof(f.Type()) 34 } 35 return offsets 36 } 37 38 func (s *sizes) Sizeof(T types.Type) int64 { 39 switch t := T.Underlying().(type) { 40 case *types.Array: 41 return t.Len() * s.Sizeof(t.Elem()) 42 case *types.Struct: 43 nf := t.NumFields() 44 if nf == 0 { 45 return 0 46 } 47 o := int64(0) 48 max := int64(1) 49 for i := 0; i < nf; i++ { 50 ft := t.Field(i).Type() 51 a, sz := s.Alignof(ft), s.Sizeof(ft) 52 if a > max { 53 max = a 54 } 55 if i == nf-1 && sz == 0 && o != 0 { 56 sz = 1 57 } 58 o = align(o, a) + sz 59 } 60 return align(o, max) 61 } 62 return s.stdSizes.Sizeof(T) 63 } 64 65 func (s *sizes) Alignof(T types.Type) int64 { 66 switch t := T.Underlying().(type) { 67 case *types.Array: 68 return s.Alignof(t.Elem()) 69 case *types.Struct: 70 max := int64(1) 71 for i, nf := 0, t.NumFields(); i < nf; i++ { 72 if a := s.Alignof(t.Field(i).Type()); a > max { 73 max = a 74 } 75 } 76 return max 77 case *types.Slice, *types.Interface, *types.Basic: 78 return s.stdSizes.Alignof(T) 79 } 80 81 // All other types. 82 a := s.Sizeof(T) 83 if a < 1 { 84 return 1 85 } 86 // complex{64,128} are aligned like [2]float{32,64}. 87 if isComplex(T) { 88 a /= 2 89 } 90 if a > s.maxAlign { 91 return s.maxAlign 92 } 93 return a 94 } 95 96 // align returns the smallest x >= subject such that x % target == 0. 97 func align(subject, target int64) int64 { 98 x := subject + target - 1 99 return x - x%target 100 } 101 102 func isComplex(typ types.Type) bool { 103 t, ok := typ.Underlying().(*types.Basic) 104 return ok && t.Info()&types.IsComplex != 0 105 }