if n == 0 {
return 0
}
- offsets := t.offsets
- if t.offsets == nil {
- // compute offsets on demand
- offsets = s.Offsetsof(t.fields)
- t.offsets = offsets
- }
- return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+ setOffsets(t, s)
+ return t.offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
case *Interface:
return s.WordSize * 2
}
}
func (conf *Config) offsetsof(T *Struct) []int64 {
- offsets := T.offsets
- if offsets == nil && T.NumFields() > 0 {
+ var offsets []int64
+ if T.NumFields() > 0 {
// compute offsets on demand
if s := conf.Sizes; s != nil {
- offsets = s.Offsetsof(T.fields)
- // sanity checks
- if len(offsets) != T.NumFields() {
- panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
- }
- for _, o := range offsets {
- if o < 0 {
- panic("Config.Sizes.Offsetsof returned an offset < 0")
+ calculated := setOffsets(T, s)
+ offsets = T.offsets
+ if calculated {
+ // sanity checks
+ if len(offsets) != T.NumFields() {
+ panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+ }
+ for _, o := range offsets {
+ if o < 0 {
+ panic("Config.Sizes.Offsetsof returned an offset < 0")
+ }
}
}
} else {
- offsets = stdSizes.Offsetsof(T.fields)
+ setOffsets(T, &stdSizes)
+ offsets = T.offsets
}
- T.offsets = offsets
}
return offsets
}
y := x + a - 1
return y - y%a
}
+
+// setOffsets sets the offsets of s for the given sizes if necessary.
+// The result is true if the offsets were not set before; otherwise it
+// is false.
+func setOffsets(s *Struct, sizes Sizes) bool {
+ var calculated bool
+ s.offsetsOnce.Do(func() {
+ calculated = true
+ s.offsets = sizes.Offsetsof(s.fields)
+ })
+ return calculated
+}
package types
-import "sort"
-
-// TODO(gri) Revisit factory functions - make sure they have all relevant parameters.
+import (
+ "sort"
+ "sync"
+)
// A Type represents a type of Go.
// All types implement the Type interface.
// A Struct represents a struct type.
type Struct struct {
- fields []*Var
- tags []string // field tags; nil if there are no tags
- // TODO(gri) access to offsets is not threadsafe - fix this
- offsets []int64 // field offsets in bytes, lazily initialized
+ fields []*Var
+ tags []string // field tags; nil if there are no tags
+ offsets []int64 // field offsets in bytes, lazily initialized
+ offsetsOnce sync.Once // for threadsafe lazy initialization of offsets
}
// NewStruct returns a new struct with the given fields and corresponding field tags.